]> code.delx.au - pulseaudio/blob - src/pulsecore/protocol-native.c
native: improve logging for buffer_attrs
[pulseaudio] / src / pulsecore / protocol-native.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31
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
39 #include <pulsecore/native-common.h>
40 #include <pulsecore/packet.h>
41 #include <pulsecore/client.h>
42 #include <pulsecore/source-output.h>
43 #include <pulsecore/sink-input.h>
44 #include <pulsecore/pstream.h>
45 #include <pulsecore/tagstruct.h>
46 #include <pulsecore/pdispatch.h>
47 #include <pulsecore/pstream-util.h>
48 #include <pulsecore/authkey.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/core-subscribe.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/llist.h>
57 #include <pulsecore/creds.h>
58 #include <pulsecore/core-util.h>
59 #include <pulsecore/ipacl.h>
60 #include <pulsecore/thread-mq.h>
61
62 #include "protocol-native.h"
63
64 /* Kick a client if it doesn't authenticate within this time */
65 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
66
67 /* Don't accept more connection than this */
68 #define MAX_CONNECTIONS 64
69
70 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
71 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
72 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
73 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
74
75 struct pa_native_protocol;
76
77 typedef struct record_stream {
78 pa_msgobject parent;
79
80 pa_native_connection *connection;
81 uint32_t index;
82
83 pa_source_output *source_output;
84 pa_memblockq *memblockq;
85
86 pa_bool_t adjust_latency:1;
87 pa_bool_t early_requests:1;
88
89 pa_buffer_attr buffer_attr;
90
91 pa_atomic_t on_the_fly;
92 pa_usec_t configured_source_latency;
93 size_t drop_initial;
94
95 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
96 size_t on_the_fly_snapshot;
97 pa_usec_t current_monitor_latency;
98 pa_usec_t current_source_latency;
99 } record_stream;
100
101 #define RECORD_STREAM(o) (record_stream_cast(o))
102 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
103
104 typedef struct output_stream {
105 pa_msgobject parent;
106 } output_stream;
107
108 #define OUTPUT_STREAM(o) (output_stream_cast(o))
109 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
110
111 typedef struct playback_stream {
112 output_stream parent;
113
114 pa_native_connection *connection;
115 uint32_t index;
116
117 pa_sink_input *sink_input;
118 pa_memblockq *memblockq;
119
120 pa_bool_t adjust_latency:1;
121 pa_bool_t early_requests:1;
122
123 pa_bool_t is_underrun:1;
124 pa_bool_t drain_request:1;
125 uint32_t drain_tag;
126 uint32_t syncid;
127
128 pa_atomic_t missing;
129 pa_usec_t configured_sink_latency;
130 pa_buffer_attr buffer_attr;
131
132 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
133 int64_t read_index, write_index;
134 size_t render_memblockq_length;
135 pa_usec_t current_sink_latency;
136 uint64_t playing_for, underrun_for;
137 } playback_stream;
138
139 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
140 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
141
142 typedef struct upload_stream {
143 output_stream parent;
144
145 pa_native_connection *connection;
146 uint32_t index;
147
148 pa_memchunk memchunk;
149 size_t length;
150 char *name;
151 pa_sample_spec sample_spec;
152 pa_channel_map channel_map;
153 pa_proplist *proplist;
154 } upload_stream;
155
156 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
157 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
158
159 struct pa_native_connection {
160 pa_msgobject parent;
161 pa_native_protocol *protocol;
162 pa_native_options *options;
163 pa_bool_t authorized:1;
164 pa_bool_t is_local:1;
165 uint32_t version;
166 pa_client *client;
167 pa_pstream *pstream;
168 pa_pdispatch *pdispatch;
169 pa_idxset *record_streams, *output_streams;
170 uint32_t rrobin_index;
171 pa_subscription *subscription;
172 pa_time_event *auth_timeout_event;
173 };
174
175 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
176 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
177
178 struct pa_native_protocol {
179 PA_REFCNT_DECLARE;
180
181 pa_core *core;
182 pa_idxset *connections;
183
184 pa_strlist *servers;
185 pa_hook hooks[PA_NATIVE_HOOK_MAX];
186
187 pa_hashmap *extensions;
188 };
189
190 enum {
191 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
192 };
193
194 enum {
195 SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
196 SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
197 SINK_INPUT_MESSAGE_FLUSH,
198 SINK_INPUT_MESSAGE_TRIGGER,
199 SINK_INPUT_MESSAGE_SEEK,
200 SINK_INPUT_MESSAGE_PREBUF_FORCE,
201 SINK_INPUT_MESSAGE_UPDATE_LATENCY,
202 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
203 };
204
205 enum {
206 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
207 PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
208 PLAYBACK_STREAM_MESSAGE_OVERFLOW,
209 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
210 PLAYBACK_STREAM_MESSAGE_STARTED,
211 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
212 };
213
214 enum {
215 RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
216 };
217
218 enum {
219 CONNECTION_MESSAGE_RELEASE,
220 CONNECTION_MESSAGE_REVOKE
221 };
222
223 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
224 static void sink_input_kill_cb(pa_sink_input *i);
225 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend);
226 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
227 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
228 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
229 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
230 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
231
232 static void native_connection_send_memblock(pa_native_connection *c);
233 static void playback_stream_request_bytes(struct playback_stream*s);
234
235 static void source_output_kill_cb(pa_source_output *o);
236 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
237 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend);
238 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
239 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
240 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
241
242 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
243 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
244
245 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
246 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
247 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
248 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
249 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
250 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
251 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
252 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
253 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
254 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
255 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
256 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
257 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
258 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
259 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
260 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
261 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
262 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
263 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
264 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
265 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
266 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
267 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
268 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
269 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
284
285 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
286 [PA_COMMAND_ERROR] = NULL,
287 [PA_COMMAND_TIMEOUT] = NULL,
288 [PA_COMMAND_REPLY] = NULL,
289 [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
290 [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
291 [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
292 [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
293 [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
294 [PA_COMMAND_AUTH] = command_auth,
295 [PA_COMMAND_REQUEST] = NULL,
296 [PA_COMMAND_EXIT] = command_exit,
297 [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
298 [PA_COMMAND_LOOKUP_SINK] = command_lookup,
299 [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
300 [PA_COMMAND_STAT] = command_stat,
301 [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
302 [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
303 [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
304 [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
305 [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
306 [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
307 [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
308 [PA_COMMAND_GET_SINK_INFO] = command_get_info,
309 [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
310 [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
311 [PA_COMMAND_GET_CARD_INFO] = command_get_info,
312 [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
313 [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
314 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
315 [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
316 [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
317 [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
318 [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
319 [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
320 [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
321 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
322 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
323 [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
324 [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
325 [PA_COMMAND_SUBSCRIBE] = command_subscribe,
326
327 [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
328 [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
329 [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
330
331 [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
332 [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
333 [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
334
335 [PA_COMMAND_SUSPEND_SINK] = command_suspend,
336 [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
337
338 [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
339 [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
340 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
341 [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
342
343 [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
344 [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
345
346 [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
347 [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
348 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
349 [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
350 [PA_COMMAND_KILL_CLIENT] = command_kill,
351 [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
352 [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
353 [PA_COMMAND_LOAD_MODULE] = command_load_module,
354 [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
355
356 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
357 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
358 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
359 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
360
361 [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
362 [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
363
364 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
365 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
366
367 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
368 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
369
370 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
371 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
372 [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
373
374 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
375 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
376 [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
377
378 [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
379
380 [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
381 [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
382
383 [PA_COMMAND_EXTENSION] = command_extension
384 };
385
386 /* structure management */
387
388 /* Called from main context */
389 static void upload_stream_unlink(upload_stream *s) {
390 pa_assert(s);
391
392 if (!s->connection)
393 return;
394
395 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
396 s->connection = NULL;
397 upload_stream_unref(s);
398 }
399
400 /* Called from main context */
401 static void upload_stream_free(pa_object *o) {
402 upload_stream *s = UPLOAD_STREAM(o);
403 pa_assert(s);
404
405 upload_stream_unlink(s);
406
407 pa_xfree(s->name);
408
409 if (s->proplist)
410 pa_proplist_free(s->proplist);
411
412 if (s->memchunk.memblock)
413 pa_memblock_unref(s->memchunk.memblock);
414
415 pa_xfree(s);
416 }
417
418 /* Called from main context */
419 static upload_stream* upload_stream_new(
420 pa_native_connection *c,
421 const pa_sample_spec *ss,
422 const pa_channel_map *map,
423 const char *name,
424 size_t length,
425 pa_proplist *p) {
426
427 upload_stream *s;
428
429 pa_assert(c);
430 pa_assert(ss);
431 pa_assert(name);
432 pa_assert(length > 0);
433 pa_assert(p);
434
435 s = pa_msgobject_new(upload_stream);
436 s->parent.parent.parent.free = upload_stream_free;
437 s->connection = c;
438 s->sample_spec = *ss;
439 s->channel_map = *map;
440 s->name = pa_xstrdup(name);
441 pa_memchunk_reset(&s->memchunk);
442 s->length = length;
443 s->proplist = pa_proplist_copy(p);
444 pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
445
446 pa_idxset_put(c->output_streams, s, &s->index);
447
448 return s;
449 }
450
451 /* Called from main context */
452 static void record_stream_unlink(record_stream *s) {
453 pa_assert(s);
454
455 if (!s->connection)
456 return;
457
458 if (s->source_output) {
459 pa_source_output_unlink(s->source_output);
460 pa_source_output_unref(s->source_output);
461 s->source_output = NULL;
462 }
463
464 pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
465 s->connection = NULL;
466 record_stream_unref(s);
467 }
468
469 /* Called from main context */
470 static void record_stream_free(pa_object *o) {
471 record_stream *s = RECORD_STREAM(o);
472 pa_assert(s);
473
474 record_stream_unlink(s);
475
476 pa_memblockq_free(s->memblockq);
477 pa_xfree(s);
478 }
479
480 /* Called from main context */
481 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
482 record_stream *s = RECORD_STREAM(o);
483 record_stream_assert_ref(s);
484
485 if (!s->connection)
486 return -1;
487
488 switch (code) {
489
490 case RECORD_STREAM_MESSAGE_POST_DATA:
491
492 /* We try to keep up to date with how many bytes are
493 * currently on the fly */
494 pa_atomic_sub(&s->on_the_fly, chunk->length);
495
496 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
497 /* pa_log_warn("Failed to push data into output queue."); */
498 return -1;
499 }
500
501 if (!pa_pstream_is_pending(s->connection->pstream))
502 native_connection_send_memblock(s->connection);
503
504 break;
505 }
506
507 return 0;
508 }
509
510 /* Called from main context */
511 static void fix_record_buffer_attr_pre(record_stream *s) {
512
513 size_t frame_size;
514 pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
515
516 pa_assert(s);
517
518 /* This function will be called from the main thread, before as
519 * well as after the source output has been activated using
520 * pa_source_output_put()! That means it may not touch any
521 * ->thread_info data! */
522
523 frame_size = pa_frame_size(&s->source_output->sample_spec);
524
525 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
526 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
527 if (s->buffer_attr.maxlength <= 0)
528 s->buffer_attr.maxlength = (uint32_t) frame_size;
529
530 if (s->buffer_attr.fragsize == (uint32_t) -1)
531 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
532 if (s->buffer_attr.fragsize <= 0)
533 s->buffer_attr.fragsize = (uint32_t) frame_size;
534
535 orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
536
537 if (s->early_requests) {
538
539 /* In early request mode we need to emulate the classic
540 * fragment-based playback model. We do this setting the source
541 * latency to the fragment size. */
542
543 source_usec = fragsize_usec;
544
545 } else if (s->adjust_latency) {
546
547 /* So, the user asked us to adjust the latency according to
548 * what the source can provide. Half the latency will be
549 * spent on the hw buffer, half of it in the async buffer
550 * queue we maintain for each client. */
551
552 source_usec = fragsize_usec/2;
553
554 } else {
555
556 /* Ok, the user didn't ask us to adjust the latency, hence we
557 * don't */
558
559 source_usec = (pa_usec_t) -1;
560 }
561
562 if (source_usec != (pa_usec_t) -1)
563 s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
564 else
565 s->configured_source_latency = 0;
566
567 if (s->early_requests) {
568
569 /* Ok, we didn't necessarily get what we were asking for, so
570 * let's tell the user */
571
572 fragsize_usec = s->configured_source_latency;
573
574 } else if (s->adjust_latency) {
575
576 /* Now subtract what we actually got */
577
578 if (fragsize_usec >= s->configured_source_latency*2)
579 fragsize_usec -= s->configured_source_latency;
580 else
581 fragsize_usec = s->configured_source_latency;
582 }
583
584 if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
585 pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
586
587 s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
588
589 if (s->buffer_attr.fragsize <= 0)
590 s->buffer_attr.fragsize = (uint32_t) frame_size;
591 }
592
593 /* Called from main context */
594 static void fix_record_buffer_attr_post(record_stream *s) {
595 size_t base;
596
597 pa_assert(s);
598
599 /* This function will be called from the main thread, before as
600 * well as after the source output has been activated using
601 * pa_source_output_put()! That means it may not touch and
602 * ->thread_info data! */
603
604 base = pa_frame_size(&s->source_output->sample_spec);
605
606 s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
607 if (s->buffer_attr.fragsize <= 0)
608 s->buffer_attr.fragsize = base;
609
610 if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
611 s->buffer_attr.fragsize = s->buffer_attr.maxlength;
612 }
613
614 /* Called from main context */
615 static record_stream* record_stream_new(
616 pa_native_connection *c,
617 pa_source *source,
618 pa_sample_spec *ss,
619 pa_channel_map *map,
620 pa_bool_t peak_detect,
621 pa_buffer_attr *attr,
622 pa_source_output_flags_t flags,
623 pa_proplist *p,
624 pa_bool_t adjust_latency,
625 pa_sink_input *direct_on_input,
626 pa_bool_t early_requests,
627 int *ret) {
628
629 record_stream *s;
630 pa_source_output *source_output = NULL;
631 pa_source_output_new_data data;
632
633 pa_assert(c);
634 pa_assert(ss);
635 pa_assert(p);
636 pa_assert(ret);
637
638 pa_source_output_new_data_init(&data);
639
640 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
641 data.driver = __FILE__;
642 data.module = c->options->module;
643 data.client = c->client;
644 data.source = source;
645 data.direct_on_input = direct_on_input;
646 pa_source_output_new_data_set_sample_spec(&data, ss);
647 pa_source_output_new_data_set_channel_map(&data, map);
648 if (peak_detect)
649 data.resample_method = PA_RESAMPLER_PEAKS;
650 data.flags = flags;
651
652 *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
653
654 pa_source_output_new_data_done(&data);
655
656 if (!source_output)
657 return NULL;
658
659 s = pa_msgobject_new(record_stream);
660 s->parent.parent.free = record_stream_free;
661 s->parent.process_msg = record_stream_process_msg;
662 s->connection = c;
663 s->source_output = source_output;
664 s->buffer_attr = *attr;
665 s->adjust_latency = adjust_latency;
666 s->early_requests = early_requests;
667 pa_atomic_store(&s->on_the_fly, 0);
668
669 s->source_output->parent.process_msg = source_output_process_msg;
670 s->source_output->push = source_output_push_cb;
671 s->source_output->kill = source_output_kill_cb;
672 s->source_output->get_latency = source_output_get_latency_cb;
673 s->source_output->moving = source_output_moving_cb;
674 s->source_output->suspend = source_output_suspend_cb;
675 s->source_output->send_event = source_output_send_event_cb;
676 s->source_output->userdata = s;
677
678 fix_record_buffer_attr_pre(s);
679
680 s->memblockq = pa_memblockq_new(
681 0,
682 s->buffer_attr.maxlength,
683 0,
684 pa_frame_size(&source_output->sample_spec),
685 1,
686 0,
687 0,
688 NULL);
689
690 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
691 fix_record_buffer_attr_post(s);
692
693 *ss = s->source_output->sample_spec;
694 *map = s->source_output->channel_map;
695
696 pa_idxset_put(c->record_streams, s, &s->index);
697
698 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
699 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
700 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
701 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
702
703 pa_source_output_put(s->source_output);
704 return s;
705 }
706
707 /* Called from main context */
708 static void record_stream_send_killed(record_stream *r) {
709 pa_tagstruct *t;
710 record_stream_assert_ref(r);
711
712 t = pa_tagstruct_new(NULL, 0);
713 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
714 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
715 pa_tagstruct_putu32(t, r->index);
716 pa_pstream_send_tagstruct(r->connection->pstream, t);
717 }
718
719 /* Called from main context */
720 static void playback_stream_unlink(playback_stream *s) {
721 pa_assert(s);
722
723 if (!s->connection)
724 return;
725
726 if (s->sink_input) {
727 pa_sink_input_unlink(s->sink_input);
728 pa_sink_input_unref(s->sink_input);
729 s->sink_input = NULL;
730 }
731
732 if (s->drain_request)
733 pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
734
735 pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
736 s->connection = NULL;
737 playback_stream_unref(s);
738 }
739
740 /* Called from main context */
741 static void playback_stream_free(pa_object* o) {
742 playback_stream *s = PLAYBACK_STREAM(o);
743 pa_assert(s);
744
745 playback_stream_unlink(s);
746
747 pa_memblockq_free(s->memblockq);
748 pa_xfree(s);
749 }
750
751 /* Called from main context */
752 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
753 playback_stream *s = PLAYBACK_STREAM(o);
754 playback_stream_assert_ref(s);
755
756 if (!s->connection)
757 return -1;
758
759 switch (code) {
760
761 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
762 pa_tagstruct *t;
763 int l = 0;
764
765 for (;;) {
766 if ((l = pa_atomic_load(&s->missing)) <= 0)
767 return 0;
768
769 if (pa_atomic_cmpxchg(&s->missing, l, 0))
770 break;
771 }
772
773 t = pa_tagstruct_new(NULL, 0);
774 pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
775 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
776 pa_tagstruct_putu32(t, s->index);
777 pa_tagstruct_putu32(t, (uint32_t) l);
778 pa_pstream_send_tagstruct(s->connection->pstream, t);
779
780 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
781 break;
782 }
783
784 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
785 pa_tagstruct *t;
786
787 /* pa_log("signalling underflow"); */
788
789 /* Report that we're empty */
790 t = pa_tagstruct_new(NULL, 0);
791 pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
792 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
793 pa_tagstruct_putu32(t, s->index);
794 pa_pstream_send_tagstruct(s->connection->pstream, t);
795 break;
796 }
797
798 case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
799 pa_tagstruct *t;
800
801 /* Notify the user we're overflowed*/
802 t = pa_tagstruct_new(NULL, 0);
803 pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
804 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
805 pa_tagstruct_putu32(t, s->index);
806 pa_pstream_send_tagstruct(s->connection->pstream, t);
807 break;
808 }
809
810 case PLAYBACK_STREAM_MESSAGE_STARTED:
811
812 if (s->connection->version >= 13) {
813 pa_tagstruct *t;
814
815 /* Notify the user we started playback */
816 t = pa_tagstruct_new(NULL, 0);
817 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
818 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
819 pa_tagstruct_putu32(t, s->index);
820 pa_pstream_send_tagstruct(s->connection->pstream, t);
821 }
822
823 break;
824
825 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
826 pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
827 break;
828
829 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
830
831 s->buffer_attr.tlength = (uint32_t) offset;
832
833 if (s->connection->version >= 15) {
834 pa_tagstruct *t;
835
836 t = pa_tagstruct_new(NULL, 0);
837 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
838 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
839 pa_tagstruct_putu32(t, s->index);
840 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
841 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
842 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
843 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
844 pa_tagstruct_put_usec(t, s->configured_sink_latency);
845 pa_pstream_send_tagstruct(s->connection->pstream, t);
846 }
847
848 break;
849 }
850
851 return 0;
852 }
853
854 /* Called from main context */
855 static void fix_playback_buffer_attr(playback_stream *s) {
856 size_t frame_size, max_prebuf;
857 pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
858
859 pa_assert(s);
860
861 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
862 /* (long) s->buffer_attr.maxlength, */
863 /* (long) s->buffer_attr.tlength, */
864 /* (long) s->buffer_attr.minreq, */
865 /* (long) s->buffer_attr.prebuf); */
866
867 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
868 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
869 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
870 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
871 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
872
873 /* This function will be called from the main thread, before as
874 * well as after the sink input has been activated using
875 * pa_sink_input_put()! That means it may not touch any
876 * ->thread_info data, such as the memblockq! */
877
878 frame_size = pa_frame_size(&s->sink_input->sample_spec);
879
880 if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
881 s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
882 if (s->buffer_attr.maxlength <= 0)
883 s->buffer_attr.maxlength = (uint32_t) frame_size;
884
885 if (s->buffer_attr.tlength == (uint32_t) -1)
886 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
887 if (s->buffer_attr.tlength <= 0)
888 s->buffer_attr.tlength = (uint32_t) frame_size;
889
890 if (s->buffer_attr.minreq == (uint32_t) -1)
891 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
892 if (s->buffer_attr.minreq <= 0)
893 s->buffer_attr.minreq = (uint32_t) frame_size;
894
895 if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
896 s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
897
898 orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
899 orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
900
901 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
902 (double) tlength_usec / PA_USEC_PER_MSEC,
903 (double) minreq_usec / PA_USEC_PER_MSEC);
904
905 if (s->early_requests) {
906
907 /* In early request mode we need to emulate the classic
908 * fragment-based playback model. We do this setting the sink
909 * latency to the fragment size. */
910
911 sink_usec = minreq_usec;
912 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
913
914 } else if (s->adjust_latency) {
915
916 /* So, the user asked us to adjust the latency of the stream
917 * buffer according to the what the sink can provide. The
918 * tlength passed in shall be the overall latency. Roughly
919 * half the latency will be spent on the hw buffer, the other
920 * half of it in the async buffer queue we maintain for each
921 * client. In between we'll have a safety space of size
922 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
923 * empty and needs to be filled, then our buffer must have
924 * enough data to fulfill this request immediatly and thus
925 * have at least the same tlength as the size of the hw
926 * buffer. It additionally needs space for 2 times minreq
927 * because if the buffer ran empty and a partial fillup
928 * happens immediately on the next iteration we need to be
929 * able to fulfill it and give the application also minreq
930 * time to fill it up again for the next request Makes 2 times
931 * minreq in plus.. */
932
933 if (tlength_usec > minreq_usec*2)
934 sink_usec = (tlength_usec - minreq_usec*2)/2;
935 else
936 sink_usec = 0;
937
938 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
939
940 } else {
941
942 /* Ok, the user didn't ask us to adjust the latency, but we
943 * still need to make sure that the parameters from the user
944 * do make sense. */
945
946 if (tlength_usec > minreq_usec*2)
947 sink_usec = (tlength_usec - minreq_usec*2);
948 else
949 sink_usec = 0;
950
951 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
952 }
953
954 s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
955
956 if (s->early_requests) {
957
958 /* Ok, we didn't necessarily get what we were asking for, so
959 * let's tell the user */
960
961 minreq_usec = s->configured_sink_latency;
962
963 } else if (s->adjust_latency) {
964
965 /* Ok, we didn't necessarily get what we were asking for, so
966 * let's subtract from what we asked for for the remaining
967 * buffer space */
968
969 if (tlength_usec >= s->configured_sink_latency)
970 tlength_usec -= s->configured_sink_latency;
971 }
972
973 /* FIXME: This is actually larger than necessary, since not all of
974 * the sink latency is actually rewritable. */
975 if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
976 tlength_usec = s->configured_sink_latency + 2*minreq_usec;
977
978 if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
979 pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
980 s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
981
982 if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
983 pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
984 s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
985
986 if (s->buffer_attr.minreq <= 0) {
987 s->buffer_attr.minreq = (uint32_t) frame_size;
988 s->buffer_attr.tlength += (uint32_t) frame_size*2;
989 }
990
991 if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
992 s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
993
994 max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
995
996 if (s->buffer_attr.prebuf == (uint32_t) -1 ||
997 s->buffer_attr.prebuf > max_prebuf)
998 s->buffer_attr.prebuf = max_prebuf;
999
1000 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1001 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1002 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1003 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1004 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1005 }
1006
1007 /* Called from main context */
1008 static playback_stream* playback_stream_new(
1009 pa_native_connection *c,
1010 pa_sink *sink,
1011 pa_sample_spec *ss,
1012 pa_channel_map *map,
1013 pa_buffer_attr *a,
1014 pa_cvolume *volume,
1015 pa_bool_t muted,
1016 pa_bool_t muted_set,
1017 uint32_t syncid,
1018 uint32_t *missing,
1019 pa_sink_input_flags_t flags,
1020 pa_proplist *p,
1021 pa_bool_t adjust_latency,
1022 pa_bool_t early_requests,
1023 pa_bool_t relative_volume,
1024 int *ret) {
1025
1026 playback_stream *s, *ssync;
1027 pa_sink_input *sink_input = NULL;
1028 pa_memchunk silence;
1029 uint32_t idx;
1030 int64_t start_index;
1031 pa_sink_input_new_data data;
1032
1033 pa_assert(c);
1034 pa_assert(ss);
1035 pa_assert(missing);
1036 pa_assert(p);
1037 pa_assert(ret);
1038
1039 /* Find syncid group */
1040 for (ssync = pa_idxset_first(c->output_streams, &idx); ssync; ssync = pa_idxset_next(c->output_streams, &idx)) {
1041
1042 if (!playback_stream_isinstance(ssync))
1043 continue;
1044
1045 if (ssync->syncid == syncid)
1046 break;
1047 }
1048
1049 /* Synced streams must connect to the same sink */
1050 if (ssync) {
1051
1052 if (!sink)
1053 sink = ssync->sink_input->sink;
1054 else if (sink != ssync->sink_input->sink) {
1055 *ret = PA_ERR_INVALID;
1056 return NULL;
1057 }
1058 }
1059
1060 pa_sink_input_new_data_init(&data);
1061
1062 pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1063 data.driver = __FILE__;
1064 data.module = c->options->module;
1065 data.client = c->client;
1066 if (sink) {
1067 data.sink = sink;
1068 data.save_sink = TRUE;
1069 }
1070 pa_sink_input_new_data_set_sample_spec(&data, ss);
1071 pa_sink_input_new_data_set_channel_map(&data, map);
1072 if (volume) {
1073 pa_sink_input_new_data_set_volume(&data, volume);
1074 data.volume_is_absolute = !relative_volume;
1075 data.save_volume = TRUE;
1076 }
1077 if (muted_set) {
1078 pa_sink_input_new_data_set_muted(&data, muted);
1079 data.save_muted = TRUE;
1080 }
1081 data.sync_base = ssync ? ssync->sink_input : NULL;
1082 data.flags = flags;
1083
1084 *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1085
1086 pa_sink_input_new_data_done(&data);
1087
1088 if (!sink_input)
1089 return NULL;
1090
1091 s = pa_msgobject_new(playback_stream);
1092 s->parent.parent.parent.free = playback_stream_free;
1093 s->parent.parent.process_msg = playback_stream_process_msg;
1094 s->connection = c;
1095 s->syncid = syncid;
1096 s->sink_input = sink_input;
1097 s->is_underrun = TRUE;
1098 s->drain_request = FALSE;
1099 pa_atomic_store(&s->missing, 0);
1100 s->buffer_attr = *a;
1101 s->adjust_latency = adjust_latency;
1102 s->early_requests = early_requests;
1103
1104 s->sink_input->parent.process_msg = sink_input_process_msg;
1105 s->sink_input->pop = sink_input_pop_cb;
1106 s->sink_input->process_rewind = sink_input_process_rewind_cb;
1107 s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1108 s->sink_input->update_max_request = sink_input_update_max_request_cb;
1109 s->sink_input->kill = sink_input_kill_cb;
1110 s->sink_input->moving = sink_input_moving_cb;
1111 s->sink_input->suspend = sink_input_suspend_cb;
1112 s->sink_input->send_event = sink_input_send_event_cb;
1113 s->sink_input->userdata = s;
1114
1115 start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1116
1117 fix_playback_buffer_attr(s);
1118
1119 pa_sink_input_get_silence(sink_input, &silence);
1120 s->memblockq = pa_memblockq_new(
1121 start_index,
1122 s->buffer_attr.maxlength,
1123 s->buffer_attr.tlength,
1124 pa_frame_size(&sink_input->sample_spec),
1125 s->buffer_attr.prebuf,
1126 s->buffer_attr.minreq,
1127 0,
1128 &silence);
1129 pa_memblock_unref(silence.memblock);
1130
1131 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1132
1133 *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1134
1135 /* pa_log("missing original: %li", (long int) *missing); */
1136
1137 *ss = s->sink_input->sample_spec;
1138 *map = s->sink_input->channel_map;
1139
1140 pa_idxset_put(c->output_streams, s, &s->index);
1141
1142 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1143 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1144 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1145 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1146 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1147
1148 pa_sink_input_put(s->sink_input);
1149 return s;
1150 }
1151
1152 /* Called from IO context */
1153 static void playback_stream_request_bytes(playback_stream *s) {
1154 size_t m, minreq;
1155 int previous_missing;
1156
1157 playback_stream_assert_ref(s);
1158
1159 m = pa_memblockq_pop_missing(s->memblockq);
1160
1161 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1162 /* (unsigned long) m, */
1163 /* pa_memblockq_get_tlength(s->memblockq), */
1164 /* pa_memblockq_get_minreq(s->memblockq), */
1165 /* pa_memblockq_get_length(s->memblockq), */
1166 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1167
1168 if (m <= 0)
1169 return;
1170
1171 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1172
1173 previous_missing = pa_atomic_add(&s->missing, (int) m);
1174 minreq = pa_memblockq_get_minreq(s->memblockq);
1175
1176 if (pa_memblockq_prebuf_active(s->memblockq) ||
1177 (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1178 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1179 }
1180
1181 /* Called from main context */
1182 static void playback_stream_send_killed(playback_stream *p) {
1183 pa_tagstruct *t;
1184 playback_stream_assert_ref(p);
1185
1186 t = pa_tagstruct_new(NULL, 0);
1187 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1188 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1189 pa_tagstruct_putu32(t, p->index);
1190 pa_pstream_send_tagstruct(p->connection->pstream, t);
1191 }
1192
1193 /* Called from main context */
1194 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1195 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1196 pa_native_connection_assert_ref(c);
1197
1198 if (!c->protocol)
1199 return -1;
1200
1201 switch (code) {
1202
1203 case CONNECTION_MESSAGE_REVOKE:
1204 pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1205 break;
1206
1207 case CONNECTION_MESSAGE_RELEASE:
1208 pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1209 break;
1210 }
1211
1212 return 0;
1213 }
1214
1215 /* Called from main context */
1216 static void native_connection_unlink(pa_native_connection *c) {
1217 record_stream *r;
1218 output_stream *o;
1219
1220 pa_assert(c);
1221
1222 if (!c->protocol)
1223 return;
1224
1225 pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1226
1227 if (c->options)
1228 pa_native_options_unref(c->options);
1229
1230 while ((r = pa_idxset_first(c->record_streams, NULL)))
1231 record_stream_unlink(r);
1232
1233 while ((o = pa_idxset_first(c->output_streams, NULL)))
1234 if (playback_stream_isinstance(o))
1235 playback_stream_unlink(PLAYBACK_STREAM(o));
1236 else
1237 upload_stream_unlink(UPLOAD_STREAM(o));
1238
1239 if (c->subscription)
1240 pa_subscription_free(c->subscription);
1241
1242 if (c->pstream)
1243 pa_pstream_unlink(c->pstream);
1244
1245 if (c->auth_timeout_event) {
1246 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1247 c->auth_timeout_event = NULL;
1248 }
1249
1250 pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1251 c->protocol = NULL;
1252 pa_native_connection_unref(c);
1253 }
1254
1255 /* Called from main context */
1256 static void native_connection_free(pa_object *o) {
1257 pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1258
1259 pa_assert(c);
1260
1261 native_connection_unlink(c);
1262
1263 pa_idxset_free(c->record_streams, NULL, NULL);
1264 pa_idxset_free(c->output_streams, NULL, NULL);
1265
1266 pa_pdispatch_unref(c->pdispatch);
1267 pa_pstream_unref(c->pstream);
1268 pa_client_free(c->client);
1269
1270 pa_xfree(c);
1271 }
1272
1273 /* Called from main context */
1274 static void native_connection_send_memblock(pa_native_connection *c) {
1275 uint32_t start;
1276 record_stream *r;
1277
1278 start = PA_IDXSET_INVALID;
1279 for (;;) {
1280 pa_memchunk chunk;
1281
1282 if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1283 return;
1284
1285 if (start == PA_IDXSET_INVALID)
1286 start = c->rrobin_index;
1287 else if (start == c->rrobin_index)
1288 return;
1289
1290 if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1291 pa_memchunk schunk = chunk;
1292
1293 if (schunk.length > r->buffer_attr.fragsize)
1294 schunk.length = r->buffer_attr.fragsize;
1295
1296 pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1297
1298 pa_memblockq_drop(r->memblockq, schunk.length);
1299 pa_memblock_unref(schunk.memblock);
1300
1301 return;
1302 }
1303 }
1304 }
1305
1306 /*** sink input callbacks ***/
1307
1308 /* Called from thread context */
1309 static void handle_seek(playback_stream *s, int64_t indexw) {
1310 playback_stream_assert_ref(s);
1311
1312 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1313
1314 if (s->sink_input->thread_info.underrun_for > 0) {
1315
1316 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1317
1318 if (pa_memblockq_is_readable(s->memblockq)) {
1319
1320 /* We just ended an underrun, let's ask the sink
1321 * for a complete rewind rewrite */
1322
1323 pa_log_debug("Requesting rewind due to end of underrun.");
1324 pa_sink_input_request_rewind(s->sink_input,
1325 (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1326 s->sink_input->thread_info.underrun_for),
1327 FALSE, TRUE, FALSE);
1328 }
1329
1330 } else {
1331 int64_t indexr;
1332
1333 indexr = pa_memblockq_get_read_index(s->memblockq);
1334
1335 if (indexw < indexr) {
1336 /* OK, the sink already asked for this data, so
1337 * let's have it usk us again */
1338
1339 pa_log_debug("Requesting rewind due to rewrite.");
1340 pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
1341 }
1342 }
1343
1344 playback_stream_request_bytes(s);
1345 }
1346
1347 static void flush_write_no_account(pa_memblockq *q) {
1348 pa_memblockq_flush_write(q, FALSE);
1349 }
1350
1351 /* Called from thread context */
1352 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1353 pa_sink_input *i = PA_SINK_INPUT(o);
1354 playback_stream *s;
1355
1356 pa_sink_input_assert_ref(i);
1357 s = PLAYBACK_STREAM(i->userdata);
1358 playback_stream_assert_ref(s);
1359
1360 switch (code) {
1361
1362 case SINK_INPUT_MESSAGE_SEEK: {
1363 int64_t windex;
1364
1365 windex = pa_memblockq_get_write_index(s->memblockq);
1366
1367 /* The client side is incapable of accounting correctly
1368 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1369 * able to deal with that. */
1370
1371 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1372
1373 handle_seek(s, windex);
1374 return 0;
1375 }
1376
1377 case SINK_INPUT_MESSAGE_POST_DATA: {
1378 int64_t windex;
1379
1380 pa_assert(chunk);
1381
1382 windex = pa_memblockq_get_write_index(s->memblockq);
1383
1384 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1385
1386 if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1387
1388 if (pa_log_ratelimit())
1389 pa_log_warn("Failed to push data into queue");
1390 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1391 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
1392 }
1393
1394 handle_seek(s, windex);
1395
1396 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1397
1398 return 0;
1399 }
1400
1401 case SINK_INPUT_MESSAGE_DRAIN:
1402 case SINK_INPUT_MESSAGE_FLUSH:
1403 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1404 case SINK_INPUT_MESSAGE_TRIGGER: {
1405
1406 int64_t windex;
1407 pa_sink_input *isync;
1408 void (*func)(pa_memblockq *bq);
1409
1410 switch (code) {
1411 case SINK_INPUT_MESSAGE_FLUSH:
1412 func = flush_write_no_account;
1413 break;
1414
1415 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1416 func = pa_memblockq_prebuf_force;
1417 break;
1418
1419 case SINK_INPUT_MESSAGE_DRAIN:
1420 case SINK_INPUT_MESSAGE_TRIGGER:
1421 func = pa_memblockq_prebuf_disable;
1422 break;
1423
1424 default:
1425 pa_assert_not_reached();
1426 }
1427
1428 windex = pa_memblockq_get_write_index(s->memblockq);
1429 func(s->memblockq);
1430 handle_seek(s, windex);
1431
1432 /* Do the same for all other members in the sync group */
1433 for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1434 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1435 windex = pa_memblockq_get_write_index(ssync->memblockq);
1436 func(ssync->memblockq);
1437 handle_seek(ssync, windex);
1438 }
1439
1440 for (isync = i->sync_next; isync; isync = isync->sync_next) {
1441 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1442 windex = pa_memblockq_get_write_index(ssync->memblockq);
1443 func(ssync->memblockq);
1444 handle_seek(ssync, windex);
1445 }
1446
1447 if (code == SINK_INPUT_MESSAGE_DRAIN) {
1448 if (!pa_memblockq_is_readable(s->memblockq))
1449 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1450 else {
1451 s->drain_tag = PA_PTR_TO_UINT(userdata);
1452 s->drain_request = TRUE;
1453 }
1454 }
1455
1456 return 0;
1457 }
1458
1459 case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1460 /* Atomically get a snapshot of all timing parameters... */
1461 s->read_index = pa_memblockq_get_read_index(s->memblockq);
1462 s->write_index = pa_memblockq_get_write_index(s->memblockq);
1463 s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1464 s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1465 s->underrun_for = s->sink_input->thread_info.underrun_for;
1466 s->playing_for = s->sink_input->thread_info.playing_for;
1467
1468 return 0;
1469
1470 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1471 int64_t windex;
1472
1473 windex = pa_memblockq_get_write_index(s->memblockq);
1474
1475 pa_memblockq_prebuf_force(s->memblockq);
1476
1477 handle_seek(s, windex);
1478
1479 /* Fall through to the default handler */
1480 break;
1481 }
1482
1483 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1484 pa_usec_t *r = userdata;
1485
1486 *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1487
1488 /* Fall through, the default handler will add in the extra
1489 * latency added by the resampler */
1490 break;
1491 }
1492
1493 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1494 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1495 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1496 return 0;
1497 }
1498 }
1499
1500 return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1501 }
1502
1503 /* Called from thread context */
1504 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1505 playback_stream *s;
1506
1507 pa_sink_input_assert_ref(i);
1508 s = PLAYBACK_STREAM(i->userdata);
1509 playback_stream_assert_ref(s);
1510 pa_assert(chunk);
1511
1512 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1513
1514 if (pa_memblockq_is_readable(s->memblockq))
1515 s->is_underrun = FALSE;
1516 else {
1517 if (!s->is_underrun)
1518 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));
1519
1520 if (s->drain_request && pa_sink_input_safe_to_remove(i)) {
1521 s->drain_request = FALSE;
1522 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);
1523 } else if (!s->is_underrun)
1524 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
1525
1526 s->is_underrun = TRUE;
1527
1528 playback_stream_request_bytes(s);
1529 }
1530
1531 /* This call will not fail with prebuf=0, hence we check for
1532 underrun explicitly above */
1533 if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1534 return -1;
1535
1536 chunk->length = PA_MIN(nbytes, chunk->length);
1537
1538 if (i->thread_info.underrun_for > 0)
1539 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1540
1541 pa_memblockq_drop(s->memblockq, chunk->length);
1542 playback_stream_request_bytes(s);
1543
1544 return 0;
1545 }
1546
1547 /* Called from thread context */
1548 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1549 playback_stream *s;
1550
1551 pa_sink_input_assert_ref(i);
1552 s = PLAYBACK_STREAM(i->userdata);
1553 playback_stream_assert_ref(s);
1554
1555 /* If we are in an underrun, then we don't rewind */
1556 if (i->thread_info.underrun_for > 0)
1557 return;
1558
1559 pa_memblockq_rewind(s->memblockq, nbytes);
1560 }
1561
1562 /* Called from thread context */
1563 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1564 playback_stream *s;
1565
1566 pa_sink_input_assert_ref(i);
1567 s = PLAYBACK_STREAM(i->userdata);
1568 playback_stream_assert_ref(s);
1569
1570 pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1571 }
1572
1573 /* Called from thread context */
1574 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1575 playback_stream *s;
1576 size_t new_tlength, old_tlength;
1577
1578 pa_sink_input_assert_ref(i);
1579 s = PLAYBACK_STREAM(i->userdata);
1580 playback_stream_assert_ref(s);
1581
1582 old_tlength = pa_memblockq_get_tlength(s->memblockq);
1583 new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1584
1585 if (old_tlength < new_tlength) {
1586 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1587 pa_memblockq_set_tlength(s->memblockq, new_tlength);
1588 new_tlength = pa_memblockq_get_tlength(s->memblockq);
1589
1590 if (new_tlength == old_tlength)
1591 pa_log_debug("Failed to increase tlength");
1592 else {
1593 pa_log_debug("Notifying client about increased tlength");
1594 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);
1595 }
1596 }
1597 }
1598
1599 /* Called from main context */
1600 static void sink_input_kill_cb(pa_sink_input *i) {
1601 playback_stream *s;
1602
1603 pa_sink_input_assert_ref(i);
1604 s = PLAYBACK_STREAM(i->userdata);
1605 playback_stream_assert_ref(s);
1606
1607 playback_stream_send_killed(s);
1608 playback_stream_unlink(s);
1609 }
1610
1611 /* Called from main context */
1612 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1613 playback_stream *s;
1614 pa_tagstruct *t;
1615
1616 pa_sink_input_assert_ref(i);
1617 s = PLAYBACK_STREAM(i->userdata);
1618 playback_stream_assert_ref(s);
1619
1620 if (s->connection->version < 15)
1621 return;
1622
1623 t = pa_tagstruct_new(NULL, 0);
1624 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1625 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1626 pa_tagstruct_putu32(t, s->index);
1627 pa_tagstruct_puts(t, event);
1628 pa_tagstruct_put_proplist(t, pl);
1629 pa_pstream_send_tagstruct(s->connection->pstream, t);
1630 }
1631
1632 /* Called from main context */
1633 static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
1634 playback_stream *s;
1635 pa_tagstruct *t;
1636
1637 pa_sink_input_assert_ref(i);
1638 s = PLAYBACK_STREAM(i->userdata);
1639 playback_stream_assert_ref(s);
1640
1641 if (s->connection->version < 12)
1642 return;
1643
1644 t = pa_tagstruct_new(NULL, 0);
1645 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1646 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1647 pa_tagstruct_putu32(t, s->index);
1648 pa_tagstruct_put_boolean(t, suspend);
1649 pa_pstream_send_tagstruct(s->connection->pstream, t);
1650 }
1651
1652 /* Called from main context */
1653 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1654 playback_stream *s;
1655 pa_tagstruct *t;
1656
1657 pa_sink_input_assert_ref(i);
1658 s = PLAYBACK_STREAM(i->userdata);
1659 playback_stream_assert_ref(s);
1660
1661 if (!dest)
1662 return;
1663
1664 fix_playback_buffer_attr(s);
1665 pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1666 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1667
1668 if (s->connection->version < 12)
1669 return;
1670
1671 t = pa_tagstruct_new(NULL, 0);
1672 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1673 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1674 pa_tagstruct_putu32(t, s->index);
1675 pa_tagstruct_putu32(t, dest->index);
1676 pa_tagstruct_puts(t, dest->name);
1677 pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1678
1679 if (s->connection->version >= 13) {
1680 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1681 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1682 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1683 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1684 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1685 }
1686
1687 pa_pstream_send_tagstruct(s->connection->pstream, t);
1688 }
1689
1690 /*** source_output callbacks ***/
1691
1692 /* Called from thread context */
1693 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1694 pa_source_output *o = PA_SOURCE_OUTPUT(_o);
1695 record_stream *s;
1696
1697 pa_source_output_assert_ref(o);
1698 s = RECORD_STREAM(o->userdata);
1699 record_stream_assert_ref(s);
1700
1701 switch (code) {
1702 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
1703 /* Atomically get a snapshot of all timing parameters... */
1704 s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
1705 s->current_source_latency = pa_source_get_latency_within_thread(o->source);
1706 s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
1707 return 0;
1708 }
1709
1710 return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
1711 }
1712
1713 /* Called from thread context */
1714 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
1715 record_stream *s;
1716
1717 pa_source_output_assert_ref(o);
1718 s = RECORD_STREAM(o->userdata);
1719 record_stream_assert_ref(s);
1720 pa_assert(chunk);
1721
1722 pa_atomic_add(&s->on_the_fly, chunk->length);
1723 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
1724 }
1725
1726 static void source_output_kill_cb(pa_source_output *o) {
1727 record_stream *s;
1728
1729 pa_source_output_assert_ref(o);
1730 s = RECORD_STREAM(o->userdata);
1731 record_stream_assert_ref(s);
1732
1733 record_stream_send_killed(s);
1734 record_stream_unlink(s);
1735 }
1736
1737 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
1738 record_stream *s;
1739
1740 pa_source_output_assert_ref(o);
1741 s = RECORD_STREAM(o->userdata);
1742 record_stream_assert_ref(s);
1743
1744 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1745
1746 return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
1747 }
1748
1749 /* Called from main context */
1750 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
1751 record_stream *s;
1752 pa_tagstruct *t;
1753
1754 pa_source_output_assert_ref(o);
1755 s = RECORD_STREAM(o->userdata);
1756 record_stream_assert_ref(s);
1757
1758 if (s->connection->version < 15)
1759 return;
1760
1761 t = pa_tagstruct_new(NULL, 0);
1762 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
1763 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1764 pa_tagstruct_putu32(t, s->index);
1765 pa_tagstruct_puts(t, event);
1766 pa_tagstruct_put_proplist(t, pl);
1767 pa_pstream_send_tagstruct(s->connection->pstream, t);
1768 }
1769
1770 /* Called from main context */
1771 static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
1772 record_stream *s;
1773 pa_tagstruct *t;
1774
1775 pa_source_output_assert_ref(o);
1776 s = RECORD_STREAM(o->userdata);
1777 record_stream_assert_ref(s);
1778
1779 if (s->connection->version < 12)
1780 return;
1781
1782 t = pa_tagstruct_new(NULL, 0);
1783 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
1784 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1785 pa_tagstruct_putu32(t, s->index);
1786 pa_tagstruct_put_boolean(t, suspend);
1787 pa_pstream_send_tagstruct(s->connection->pstream, t);
1788 }
1789
1790 /* Called from main context */
1791 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
1792 record_stream *s;
1793 pa_tagstruct *t;
1794
1795 pa_source_output_assert_ref(o);
1796 s = RECORD_STREAM(o->userdata);
1797 record_stream_assert_ref(s);
1798
1799 if (!dest)
1800 return;
1801
1802 fix_record_buffer_attr_pre(s);
1803 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
1804 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1805 fix_record_buffer_attr_post(s);
1806
1807 if (s->connection->version < 12)
1808 return;
1809
1810 t = pa_tagstruct_new(NULL, 0);
1811 pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
1812 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1813 pa_tagstruct_putu32(t, s->index);
1814 pa_tagstruct_putu32(t, dest->index);
1815 pa_tagstruct_puts(t, dest->name);
1816 pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
1817
1818 if (s->connection->version >= 13) {
1819 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1820 pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1821 pa_tagstruct_put_usec(t, s->configured_source_latency);
1822 }
1823
1824 pa_pstream_send_tagstruct(s->connection->pstream, t);
1825 }
1826
1827 /*** pdispatch callbacks ***/
1828
1829 static void protocol_error(pa_native_connection *c) {
1830 pa_log("protocol error, kicking client");
1831 native_connection_unlink(c);
1832 }
1833
1834 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1835 if (!(expression)) { \
1836 pa_pstream_send_error((pstream), (tag), (error)); \
1837 return; \
1838 } \
1839 } while(0);
1840
1841 static pa_tagstruct *reply_new(uint32_t tag) {
1842 pa_tagstruct *reply;
1843
1844 reply = pa_tagstruct_new(NULL, 0);
1845 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1846 pa_tagstruct_putu32(reply, tag);
1847 return reply;
1848 }
1849
1850 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1851 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
1852 playback_stream *s;
1853 uint32_t sink_index, syncid, missing;
1854 pa_buffer_attr attr;
1855 const char *name = NULL, *sink_name;
1856 pa_sample_spec ss;
1857 pa_channel_map map;
1858 pa_tagstruct *reply;
1859 pa_sink *sink = NULL;
1860 pa_cvolume volume;
1861 pa_bool_t
1862 corked = FALSE,
1863 no_remap = FALSE,
1864 no_remix = FALSE,
1865 fix_format = FALSE,
1866 fix_rate = FALSE,
1867 fix_channels = FALSE,
1868 no_move = FALSE,
1869 variable_rate = FALSE,
1870 muted = FALSE,
1871 adjust_latency = FALSE,
1872 early_requests = FALSE,
1873 dont_inhibit_auto_suspend = FALSE,
1874 muted_set = FALSE,
1875 fail_on_suspend = FALSE,
1876 relative_volume = FALSE;
1877 pa_sink_input_flags_t flags = 0;
1878 pa_proplist *p;
1879 pa_bool_t volume_set = TRUE;
1880 int ret = PA_ERR_INVALID;
1881
1882 pa_native_connection_assert_ref(c);
1883 pa_assert(t);
1884 memset(&attr, 0, sizeof(attr));
1885
1886 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
1887 pa_tagstruct_get(
1888 t,
1889 PA_TAG_SAMPLE_SPEC, &ss,
1890 PA_TAG_CHANNEL_MAP, &map,
1891 PA_TAG_U32, &sink_index,
1892 PA_TAG_STRING, &sink_name,
1893 PA_TAG_U32, &attr.maxlength,
1894 PA_TAG_BOOLEAN, &corked,
1895 PA_TAG_U32, &attr.tlength,
1896 PA_TAG_U32, &attr.prebuf,
1897 PA_TAG_U32, &attr.minreq,
1898 PA_TAG_U32, &syncid,
1899 PA_TAG_CVOLUME, &volume,
1900 PA_TAG_INVALID) < 0) {
1901
1902 protocol_error(c);
1903 return;
1904 }
1905
1906 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
1907 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
1908 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
1909 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
1910 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
1911 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
1912 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
1913 CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
1914
1915 p = pa_proplist_new();
1916
1917 if (name)
1918 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
1919
1920 if (c->version >= 12) {
1921 /* Since 0.9.8 the user can ask for a couple of additional flags */
1922
1923 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
1924 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
1925 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
1926 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
1927 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
1928 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
1929 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
1930
1931 protocol_error(c);
1932 pa_proplist_free(p);
1933 return;
1934 }
1935 }
1936
1937 if (c->version >= 13) {
1938
1939 if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
1940 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
1941 pa_tagstruct_get_proplist(t, p) < 0) {
1942 protocol_error(c);
1943 pa_proplist_free(p);
1944 return;
1945 }
1946 }
1947
1948 if (c->version >= 14) {
1949
1950 if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
1951 pa_tagstruct_get_boolean(t, &early_requests) < 0) {
1952 protocol_error(c);
1953 pa_proplist_free(p);
1954 return;
1955 }
1956 }
1957
1958 if (c->version >= 15) {
1959
1960 if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
1961 pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
1962 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
1963 protocol_error(c);
1964 pa_proplist_free(p);
1965 return;
1966 }
1967 }
1968
1969 if (c->version >= 17) {
1970
1971 if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
1972 protocol_error(c);
1973 pa_proplist_free(p);
1974 return;
1975 }
1976 }
1977
1978 if (!pa_tagstruct_eof(t)) {
1979 protocol_error(c);
1980 pa_proplist_free(p);
1981 return;
1982 }
1983
1984 if (sink_index != PA_INVALID_INDEX) {
1985
1986 if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
1987 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1988 pa_proplist_free(p);
1989 return;
1990 }
1991
1992 } else if (sink_name) {
1993
1994 if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
1995 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
1996 pa_proplist_free(p);
1997 return;
1998 }
1999 }
2000
2001 flags =
2002 (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2003 (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2004 (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2005 (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2006 (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2007 (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2008 (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2009 (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2010 (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2011 (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0);
2012
2013 /* Only since protocol version 15 there's a seperate muted_set
2014 * flag. For older versions we synthesize it here */
2015 muted_set = muted_set || muted;
2016
2017 s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, relative_volume, &ret);
2018 pa_proplist_free(p);
2019
2020 CHECK_VALIDITY(c->pstream, s, tag, ret);
2021
2022 reply = reply_new(tag);
2023 pa_tagstruct_putu32(reply, s->index);
2024 pa_assert(s->sink_input);
2025 pa_tagstruct_putu32(reply, s->sink_input->index);
2026 pa_tagstruct_putu32(reply, missing);
2027
2028 /* pa_log("initial request is %u", missing); */
2029
2030 if (c->version >= 9) {
2031 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2032
2033 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2034 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2035 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2036 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2037 }
2038
2039 if (c->version >= 12) {
2040 /* Since 0.9.8 we support sending the chosen sample
2041 * spec/channel map/device/suspend status back to the
2042 * client */
2043
2044 pa_tagstruct_put_sample_spec(reply, &ss);
2045 pa_tagstruct_put_channel_map(reply, &map);
2046
2047 pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2048 pa_tagstruct_puts(reply, s->sink_input->sink->name);
2049
2050 pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2051 }
2052
2053 if (c->version >= 13)
2054 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2055
2056 pa_pstream_send_tagstruct(c->pstream, reply);
2057 }
2058
2059 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2060 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2061 uint32_t channel;
2062
2063 pa_native_connection_assert_ref(c);
2064 pa_assert(t);
2065
2066 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2067 !pa_tagstruct_eof(t)) {
2068 protocol_error(c);
2069 return;
2070 }
2071
2072 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2073
2074 switch (command) {
2075
2076 case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2077 playback_stream *s;
2078 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2079 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2080 return;
2081 }
2082
2083 playback_stream_unlink(s);
2084 break;
2085 }
2086
2087 case PA_COMMAND_DELETE_RECORD_STREAM: {
2088 record_stream *s;
2089 if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2090 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2091 return;
2092 }
2093
2094 record_stream_unlink(s);
2095 break;
2096 }
2097
2098 case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2099 upload_stream *s;
2100
2101 if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2102 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2103 return;
2104 }
2105
2106 upload_stream_unlink(s);
2107 break;
2108 }
2109
2110 default:
2111 pa_assert_not_reached();
2112 }
2113
2114 pa_pstream_send_simple_ack(c->pstream, tag);
2115 }
2116
2117 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2118 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2119 record_stream *s;
2120 pa_buffer_attr attr;
2121 uint32_t source_index;
2122 const char *name = NULL, *source_name;
2123 pa_sample_spec ss;
2124 pa_channel_map map;
2125 pa_tagstruct *reply;
2126 pa_source *source = NULL;
2127 pa_bool_t
2128 corked = FALSE,
2129 no_remap = FALSE,
2130 no_remix = FALSE,
2131 fix_format = FALSE,
2132 fix_rate = FALSE,
2133 fix_channels = FALSE,
2134 no_move = FALSE,
2135 variable_rate = FALSE,
2136 adjust_latency = FALSE,
2137 peak_detect = FALSE,
2138 early_requests = FALSE,
2139 dont_inhibit_auto_suspend = FALSE,
2140 fail_on_suspend = FALSE;
2141 pa_source_output_flags_t flags = 0;
2142 pa_proplist *p;
2143 uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2144 pa_sink_input *direct_on_input = NULL;
2145 int ret = PA_ERR_INVALID;
2146
2147 pa_native_connection_assert_ref(c);
2148 pa_assert(t);
2149
2150 memset(&attr, 0, sizeof(attr));
2151
2152 if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2153 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2154 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2155 pa_tagstruct_getu32(t, &source_index) < 0 ||
2156 pa_tagstruct_gets(t, &source_name) < 0 ||
2157 pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2158 pa_tagstruct_get_boolean(t, &corked) < 0 ||
2159 pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2160 protocol_error(c);
2161 return;
2162 }
2163
2164 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2165 CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID);
2166 CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID);
2167 CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2168 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2169 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2170 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2171
2172 p = pa_proplist_new();
2173
2174 if (name)
2175 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2176
2177 if (c->version >= 12) {
2178 /* Since 0.9.8 the user can ask for a couple of additional flags */
2179
2180 if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2181 pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2182 pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2183 pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2184 pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2185 pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2186 pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2187
2188 protocol_error(c);
2189 pa_proplist_free(p);
2190 return;
2191 }
2192 }
2193
2194 if (c->version >= 13) {
2195
2196 if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2197 pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2198 pa_tagstruct_get_proplist(t, p) < 0 ||
2199 pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2200 protocol_error(c);
2201 pa_proplist_free(p);
2202 return;
2203 }
2204 }
2205
2206 if (c->version >= 14) {
2207
2208 if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2209 protocol_error(c);
2210 pa_proplist_free(p);
2211 return;
2212 }
2213 }
2214
2215 if (c->version >= 15) {
2216
2217 if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2218 pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2219 protocol_error(c);
2220 pa_proplist_free(p);
2221 return;
2222 }
2223 }
2224
2225 if (!pa_tagstruct_eof(t)) {
2226 protocol_error(c);
2227 pa_proplist_free(p);
2228 return;
2229 }
2230
2231 if (source_index != PA_INVALID_INDEX) {
2232
2233 if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2234 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2235 pa_proplist_free(p);
2236 return;
2237 }
2238
2239 } else if (source_name) {
2240
2241 if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2242 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2243 pa_proplist_free(p);
2244 return;
2245 }
2246 }
2247
2248 if (direct_on_input_idx != PA_INVALID_INDEX) {
2249
2250 if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2251 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2252 pa_proplist_free(p);
2253 return;
2254 }
2255 }
2256
2257 flags =
2258 (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2259 (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2260 (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2261 (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2262 (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2263 (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2264 (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2265 (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2266 (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2267 (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0);
2268
2269 s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
2270 pa_proplist_free(p);
2271
2272 CHECK_VALIDITY(c->pstream, s, tag, ret);
2273
2274 reply = reply_new(tag);
2275 pa_tagstruct_putu32(reply, s->index);
2276 pa_assert(s->source_output);
2277 pa_tagstruct_putu32(reply, s->source_output->index);
2278
2279 if (c->version >= 9) {
2280 /* Since 0.9 we support sending the buffer metrics back to the client */
2281
2282 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2283 pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2284 }
2285
2286 if (c->version >= 12) {
2287 /* Since 0.9.8 we support sending the chosen sample
2288 * spec/channel map/device/suspend status back to the
2289 * client */
2290
2291 pa_tagstruct_put_sample_spec(reply, &ss);
2292 pa_tagstruct_put_channel_map(reply, &map);
2293
2294 pa_tagstruct_putu32(reply, s->source_output->source->index);
2295 pa_tagstruct_puts(reply, s->source_output->source->name);
2296
2297 pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2298 }
2299
2300 if (c->version >= 13)
2301 pa_tagstruct_put_usec(reply, s->configured_source_latency);
2302
2303 pa_pstream_send_tagstruct(c->pstream, reply);
2304 }
2305
2306 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2307 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2308 int ret;
2309
2310 pa_native_connection_assert_ref(c);
2311 pa_assert(t);
2312
2313 if (!pa_tagstruct_eof(t)) {
2314 protocol_error(c);
2315 return;
2316 }
2317
2318 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2319 ret = pa_core_exit(c->protocol->core, FALSE, 0);
2320 CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2321
2322 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2323
2324 pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2325 }
2326
2327 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2328 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2329 const void*cookie;
2330 pa_tagstruct *reply;
2331 pa_bool_t shm_on_remote = FALSE, do_shm;
2332
2333 pa_native_connection_assert_ref(c);
2334 pa_assert(t);
2335
2336 if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2337 pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2338 !pa_tagstruct_eof(t)) {
2339 protocol_error(c);
2340 return;
2341 }
2342
2343 /* Minimum supported version */
2344 if (c->version < 8) {
2345 pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2346 return;
2347 }
2348
2349 /* Starting with protocol version 13 the MSB of the version tag
2350 reflects if shm is available for this pa_native_connection or
2351 not. */
2352 if (c->version >= 13) {
2353 shm_on_remote = !!(c->version & 0x80000000U);
2354 c->version &= 0x7FFFFFFFU;
2355 }
2356
2357 pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2358
2359 pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2360
2361 if (!c->authorized) {
2362 pa_bool_t success = FALSE;
2363
2364 #ifdef HAVE_CREDS
2365 const pa_creds *creds;
2366
2367 if ((creds = pa_pdispatch_creds(pd))) {
2368 if (creds->uid == getuid())
2369 success = TRUE;
2370 else if (c->options->auth_group) {
2371 int r;
2372 gid_t gid;
2373
2374 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2375 pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2376 else if (gid == creds->gid)
2377 success = TRUE;
2378
2379 if (!success) {
2380 if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2381 pa_log_warn("Failed to check group membership.");
2382 else if (r > 0)
2383 success = TRUE;
2384 }
2385 }
2386
2387 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2388 (unsigned long) creds->uid,
2389 (unsigned long) creds->gid,
2390 (int) success);
2391 }
2392 #endif
2393
2394 if (!success && c->options->auth_cookie) {
2395 const uint8_t *ac;
2396
2397 if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2398 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2399 success = TRUE;
2400 }
2401
2402 if (!success) {
2403 pa_log_warn("Denied access to client with invalid authorization data.");
2404 pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2405 return;
2406 }
2407
2408 c->authorized = TRUE;
2409 if (c->auth_timeout_event) {
2410 c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2411 c->auth_timeout_event = NULL;
2412 }
2413 }
2414
2415 /* Enable shared memory support if possible */
2416 do_shm =
2417 pa_mempool_is_shared(c->protocol->core->mempool) &&
2418 c->is_local;
2419
2420 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2421
2422 if (do_shm)
2423 if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2424 do_shm = FALSE;
2425
2426 #ifdef HAVE_CREDS
2427 if (do_shm) {
2428 /* Only enable SHM if both sides are owned by the same
2429 * user. This is a security measure because otherwise data
2430 * private to the user might leak. */
2431
2432 const pa_creds *creds;
2433 if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2434 do_shm = FALSE;
2435 }
2436 #endif
2437
2438 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2439 pa_pstream_enable_shm(c->pstream, do_shm);
2440
2441 reply = reply_new(tag);
2442 pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2443
2444 #ifdef HAVE_CREDS
2445 {
2446 /* SHM support is only enabled after both sides made sure they are the same user. */
2447
2448 pa_creds ucred;
2449
2450 ucred.uid = getuid();
2451 ucred.gid = getgid();
2452
2453 pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2454 }
2455 #else
2456 pa_pstream_send_tagstruct(c->pstream, reply);
2457 #endif
2458 }
2459
2460 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2461 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2462 const char *name = NULL;
2463 pa_proplist *p;
2464 pa_tagstruct *reply;
2465
2466 pa_native_connection_assert_ref(c);
2467 pa_assert(t);
2468
2469 p = pa_proplist_new();
2470
2471 if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2472 (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2473 !pa_tagstruct_eof(t)) {
2474
2475 protocol_error(c);
2476 pa_proplist_free(p);
2477 return;
2478 }
2479
2480 if (name)
2481 if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2482 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2483 pa_proplist_free(p);
2484 return;
2485 }
2486
2487 pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2488 pa_proplist_free(p);
2489
2490 reply = reply_new(tag);
2491
2492 if (c->version >= 13)
2493 pa_tagstruct_putu32(reply, c->client->index);
2494
2495 pa_pstream_send_tagstruct(c->pstream, reply);
2496 }
2497
2498 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2499 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2500 const char *name;
2501 uint32_t idx = PA_IDXSET_INVALID;
2502
2503 pa_native_connection_assert_ref(c);
2504 pa_assert(t);
2505
2506 if (pa_tagstruct_gets(t, &name) < 0 ||
2507 !pa_tagstruct_eof(t)) {
2508 protocol_error(c);
2509 return;
2510 }
2511
2512 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2513 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);
2514
2515 if (command == PA_COMMAND_LOOKUP_SINK) {
2516 pa_sink *sink;
2517 if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
2518 idx = sink->index;
2519 } else {
2520 pa_source *source;
2521 pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
2522 if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
2523 idx = source->index;
2524 }
2525
2526 if (idx == PA_IDXSET_INVALID)
2527 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2528 else {
2529 pa_tagstruct *reply;
2530 reply = reply_new(tag);
2531 pa_tagstruct_putu32(reply, idx);
2532 pa_pstream_send_tagstruct(c->pstream, reply);
2533 }
2534 }
2535
2536 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2537 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2538 uint32_t idx;
2539 playback_stream *s;
2540
2541 pa_native_connection_assert_ref(c);
2542 pa_assert(t);
2543
2544 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2545 !pa_tagstruct_eof(t)) {
2546 protocol_error(c);
2547 return;
2548 }
2549
2550 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2551 s = pa_idxset_get_by_index(c->output_streams, idx);
2552 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2553 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2554
2555 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);
2556 }
2557
2558 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2559 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2560 pa_tagstruct *reply;
2561 const pa_mempool_stat *stat;
2562
2563 pa_native_connection_assert_ref(c);
2564 pa_assert(t);
2565
2566 if (!pa_tagstruct_eof(t)) {
2567 protocol_error(c);
2568 return;
2569 }
2570
2571 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2572
2573 stat = pa_mempool_get_stat(c->protocol->core->mempool);
2574
2575 reply = reply_new(tag);
2576 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
2577 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
2578 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
2579 pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
2580 pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
2581 pa_pstream_send_tagstruct(c->pstream, reply);
2582 }
2583
2584 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2585 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2586 pa_tagstruct *reply;
2587 playback_stream *s;
2588 struct timeval tv, now;
2589 uint32_t idx;
2590
2591 pa_native_connection_assert_ref(c);
2592 pa_assert(t);
2593
2594 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2595 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2596 !pa_tagstruct_eof(t)) {
2597 protocol_error(c);
2598 return;
2599 }
2600
2601 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2602 s = pa_idxset_get_by_index(c->output_streams, idx);
2603 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2604 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2605
2606 /* Get an atomic snapshot of all timing parameters */
2607 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);
2608
2609 reply = reply_new(tag);
2610 pa_tagstruct_put_usec(reply,
2611 s->current_sink_latency +
2612 pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
2613 pa_tagstruct_put_usec(reply, 0);
2614 pa_tagstruct_put_boolean(reply,
2615 s->playing_for > 0 &&
2616 pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
2617 pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
2618 pa_tagstruct_put_timeval(reply, &tv);
2619 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2620 pa_tagstruct_puts64(reply, s->write_index);
2621 pa_tagstruct_puts64(reply, s->read_index);
2622
2623 if (c->version >= 13) {
2624 pa_tagstruct_putu64(reply, s->underrun_for);
2625 pa_tagstruct_putu64(reply, s->playing_for);
2626 }
2627
2628 pa_pstream_send_tagstruct(c->pstream, reply);
2629 }
2630
2631 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2632 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2633 pa_tagstruct *reply;
2634 record_stream *s;
2635 struct timeval tv, now;
2636 uint32_t idx;
2637
2638 pa_native_connection_assert_ref(c);
2639 pa_assert(t);
2640
2641 if (pa_tagstruct_getu32(t, &idx) < 0 ||
2642 pa_tagstruct_get_timeval(t, &tv) < 0 ||
2643 !pa_tagstruct_eof(t)) {
2644 protocol_error(c);
2645 return;
2646 }
2647
2648 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2649 s = pa_idxset_get_by_index(c->record_streams, idx);
2650 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2651
2652 /* Get an atomic snapshot of all timing parameters */
2653 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);
2654
2655 reply = reply_new(tag);
2656 pa_tagstruct_put_usec(reply, s->current_monitor_latency);
2657 pa_tagstruct_put_usec(reply,
2658 s->current_source_latency +
2659 pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
2660 pa_tagstruct_put_boolean(reply,
2661 pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
2662 pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
2663 pa_tagstruct_put_timeval(reply, &tv);
2664 pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
2665 pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
2666 pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
2667 pa_pstream_send_tagstruct(c->pstream, reply);
2668 }
2669
2670 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2671 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2672 upload_stream *s;
2673 uint32_t length;
2674 const char *name = NULL;
2675 pa_sample_spec ss;
2676 pa_channel_map map;
2677 pa_tagstruct *reply;
2678 pa_proplist *p;
2679
2680 pa_native_connection_assert_ref(c);
2681 pa_assert(t);
2682
2683 if (pa_tagstruct_gets(t, &name) < 0 ||
2684 pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2685 pa_tagstruct_get_channel_map(t, &map) < 0 ||
2686 pa_tagstruct_getu32(t, &length) < 0) {
2687 protocol_error(c);
2688 return;
2689 }
2690
2691 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2692 CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
2693 CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
2694 CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
2695 CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
2696 CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
2697
2698 p = pa_proplist_new();
2699
2700 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2701 !pa_tagstruct_eof(t)) {
2702
2703 protocol_error(c);
2704 pa_proplist_free(p);
2705 return;
2706 }
2707
2708 if (c->version < 13)
2709 pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2710 else if (!name)
2711 if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
2712 name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
2713
2714 if (!name || !pa_namereg_is_valid_name(name)) {
2715 pa_proplist_free(p);
2716 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
2717 }
2718
2719 s = upload_stream_new(c, &ss, &map, name, length, p);
2720 pa_proplist_free(p);
2721
2722 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
2723
2724 reply = reply_new(tag);
2725 pa_tagstruct_putu32(reply, s->index);
2726 pa_tagstruct_putu32(reply, length);
2727 pa_pstream_send_tagstruct(c->pstream, reply);
2728 }
2729
2730 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2731 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2732 uint32_t channel;
2733 upload_stream *s;
2734 uint32_t idx;
2735
2736 pa_native_connection_assert_ref(c);
2737 pa_assert(t);
2738
2739 if (pa_tagstruct_getu32(t, &channel) < 0 ||
2740 !pa_tagstruct_eof(t)) {
2741 protocol_error(c);
2742 return;
2743 }
2744
2745 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2746
2747 s = pa_idxset_get_by_index(c->output_streams, channel);
2748 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
2749 CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
2750
2751 if (!s->memchunk.memblock)
2752 pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
2753 else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
2754 pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
2755 else
2756 pa_pstream_send_simple_ack(c->pstream, tag);
2757
2758 upload_stream_unlink(s);
2759 }
2760
2761 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2762 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2763 uint32_t sink_index;
2764 pa_volume_t volume;
2765 pa_sink *sink;
2766 const char *name, *sink_name;
2767 uint32_t idx;
2768 pa_proplist *p;
2769 pa_tagstruct *reply;
2770
2771 pa_native_connection_assert_ref(c);
2772 pa_assert(t);
2773
2774 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2775
2776 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
2777 pa_tagstruct_gets(t, &sink_name) < 0 ||
2778 pa_tagstruct_getu32(t, &volume) < 0 ||
2779 pa_tagstruct_gets(t, &name) < 0) {
2780 protocol_error(c);
2781 return;
2782 }
2783
2784 CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
2785 CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
2786 CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
2787 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2788
2789 if (sink_index != PA_INVALID_INDEX)
2790 sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
2791 else
2792 sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
2793
2794 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
2795
2796 p = pa_proplist_new();
2797
2798 if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2799 !pa_tagstruct_eof(t)) {
2800 protocol_error(c);
2801 pa_proplist_free(p);
2802 return;
2803 }
2804
2805 pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
2806
2807 if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
2808 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2809 pa_proplist_free(p);
2810 return;
2811 }
2812
2813 pa_proplist_free(p);
2814
2815 reply = reply_new(tag);
2816
2817 if (c->version >= 13)
2818 pa_tagstruct_putu32(reply, idx);
2819
2820 pa_pstream_send_tagstruct(c->pstream, reply);
2821 }
2822
2823 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2824 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2825 const char *name;
2826
2827 pa_native_connection_assert_ref(c);
2828 pa_assert(t);
2829
2830 if (pa_tagstruct_gets(t, &name) < 0 ||
2831 !pa_tagstruct_eof(t)) {
2832 protocol_error(c);
2833 return;
2834 }
2835
2836 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2837 CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
2838
2839 if (pa_scache_remove_item(c->protocol->core, name) < 0) {
2840 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2841 return;
2842 }
2843
2844 pa_pstream_send_simple_ack(c->pstream, tag);
2845 }
2846
2847 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
2848 pa_assert(c);
2849 pa_assert(fixed);
2850 pa_assert(original);
2851
2852 *fixed = *original;
2853
2854 if (c->version < 12) {
2855 /* Before protocol version 12 we didn't support S32 samples,
2856 * so we need to lie about this to the client */
2857
2858 if (fixed->format == PA_SAMPLE_S32LE)
2859 fixed->format = PA_SAMPLE_FLOAT32LE;
2860 if (fixed->format == PA_SAMPLE_S32BE)
2861 fixed->format = PA_SAMPLE_FLOAT32BE;
2862 }
2863
2864 if (c->version < 15) {
2865 if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
2866 fixed->format = PA_SAMPLE_FLOAT32LE;
2867 if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
2868 fixed->format = PA_SAMPLE_FLOAT32BE;
2869 }
2870 }
2871
2872 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
2873 pa_sample_spec fixed_ss;
2874
2875 pa_assert(t);
2876 pa_sink_assert_ref(sink);
2877
2878 fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
2879
2880 pa_tagstruct_put(
2881 t,
2882 PA_TAG_U32, sink->index,
2883 PA_TAG_STRING, sink->name,
2884 PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2885 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2886 PA_TAG_CHANNEL_MAP, &sink->channel_map,
2887 PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
2888 PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE),
2889 PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE),
2890 PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
2891 PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
2892 PA_TAG_USEC, pa_sink_get_latency(sink),
2893 PA_TAG_STRING, sink->driver,
2894 PA_TAG_U32, sink->flags,
2895 PA_TAG_INVALID);
2896
2897 if (c->version >= 13) {
2898 pa_tagstruct_put_proplist(t, sink->proplist);
2899 pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
2900 }
2901
2902 if (c->version >= 15) {
2903 pa_tagstruct_put_volume(t, sink->base_volume);
2904 if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
2905 pa_log_error("Internal sink state is invalid.");
2906 pa_tagstruct_putu32(t, pa_sink_get_state(sink));
2907 pa_tagstruct_putu32(t, sink->n_volume_steps);
2908 pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
2909 }
2910
2911 if (c->version >= 16) {
2912 pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
2913
2914 if (sink->ports) {
2915 void *state;
2916 pa_device_port *p;
2917
2918 PA_HASHMAP_FOREACH(p, sink->ports, state) {
2919 pa_tagstruct_puts(t, p->name);
2920 pa_tagstruct_puts(t, p->description);
2921 pa_tagstruct_putu32(t, p->priority);
2922 }
2923 }
2924
2925 pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
2926 }
2927 }
2928
2929 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
2930 pa_sample_spec fixed_ss;
2931
2932 pa_assert(t);
2933 pa_source_assert_ref(source);
2934
2935 fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
2936
2937 pa_tagstruct_put(
2938 t,
2939 PA_TAG_U32, source->index,
2940 PA_TAG_STRING, source->name,
2941 PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
2942 PA_TAG_SAMPLE_SPEC, &fixed_ss,
2943 PA_TAG_CHANNEL_MAP, &source->channel_map,
2944 PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
2945 PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE),
2946 PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE),
2947 PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
2948 PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
2949 PA_TAG_USEC, pa_source_get_latency(source),
2950 PA_TAG_STRING, source->driver,
2951 PA_TAG_U32, source->flags,
2952 PA_TAG_INVALID);
2953
2954 if (c->version >= 13) {
2955 pa_tagstruct_put_proplist(t, source->proplist);
2956 pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
2957 }
2958
2959 if (c->version >= 15) {
2960 pa_tagstruct_put_volume(t, source->base_volume);
2961 if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
2962 pa_log_error("Internal source state is invalid.");
2963 pa_tagstruct_putu32(t, pa_source_get_state(source));
2964 pa_tagstruct_putu32(t, source->n_volume_steps);
2965 pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
2966 }
2967
2968 if (c->version >= 16) {
2969
2970 pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
2971
2972 if (source->ports) {
2973 void *state;
2974 pa_device_port *p;
2975
2976 PA_HASHMAP_FOREACH(p, source->ports, state) {
2977 pa_tagstruct_puts(t, p->name);
2978 pa_tagstruct_puts(t, p->description);
2979 pa_tagstruct_putu32(t, p->priority);
2980 }
2981 }
2982
2983 pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
2984 }
2985 }
2986
2987 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
2988 pa_assert(t);
2989 pa_assert(client);
2990
2991 pa_tagstruct_putu32(t, client->index);
2992 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
2993 pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
2994 pa_tagstruct_puts(t, client->driver);
2995
2996 if (c->version >= 13)
2997 pa_tagstruct_put_proplist(t, client->proplist);
2998 }
2999
3000 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3001 void *state = NULL;
3002 pa_card_profile *p;
3003
3004 pa_assert(t);
3005 pa_assert(card);
3006
3007 pa_tagstruct_putu32(t, card->index);
3008 pa_tagstruct_puts(t, card->name);
3009 pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3010 pa_tagstruct_puts(t, card->driver);
3011
3012 pa_tagstruct_putu32(t, card->profiles ? pa_hashmap_size(card->profiles) : 0);
3013
3014 if (card->profiles) {
3015 while ((p = pa_hashmap_iterate(card->profiles, &state, NULL))) {
3016 pa_tagstruct_puts(t, p->name);
3017 pa_tagstruct_puts(t, p->description);
3018 pa_tagstruct_putu32(t, p->n_sinks);
3019 pa_tagstruct_putu32(t, p->n_sources);
3020 pa_tagstruct_putu32(t, p->priority);
3021 }
3022 }
3023
3024 pa_tagstruct_puts(t, card->active_profile ? card->active_profile->name : NULL);
3025 pa_tagstruct_put_proplist(t, card->proplist);
3026 }
3027
3028 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3029 pa_assert(t);
3030 pa_assert(module);
3031
3032 pa_tagstruct_putu32(t, module->index);
3033 pa_tagstruct_puts(t, module->name);
3034 pa_tagstruct_puts(t, module->argument);
3035 pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3036
3037 if (c->version < 15)
3038 pa_tagstruct_put_boolean(t, FALSE); /* autoload is obsolete */
3039
3040 if (c->version >= 15)
3041 pa_tagstruct_put_proplist(t, module->proplist);
3042 }
3043
3044 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3045 pa_sample_spec fixed_ss;
3046 pa_usec_t sink_latency;
3047 pa_cvolume v;
3048
3049 pa_assert(t);
3050 pa_sink_input_assert_ref(s);
3051
3052 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3053
3054 pa_tagstruct_putu32(t, s->index);
3055 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3056 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3057 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3058 pa_tagstruct_putu32(t, s->sink->index);
3059 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3060 pa_tagstruct_put_channel_map(t, &s->channel_map);
3061 pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s, &v, TRUE));
3062 pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3063 pa_tagstruct_put_usec(t, sink_latency);
3064 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3065 pa_tagstruct_puts(t, s->driver);
3066 if (c->version >= 11)
3067 pa_tagstruct_put_boolean(t, pa_sink_input_get_mute(s));
3068 if (c->version >= 13)
3069 pa_tagstruct_put_proplist(t, s->proplist);
3070 }
3071
3072 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3073 pa_sample_spec fixed_ss;
3074 pa_usec_t source_latency;
3075
3076 pa_assert(t);
3077 pa_source_output_assert_ref(s);
3078
3079 fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3080
3081 pa_tagstruct_putu32(t, s->index);
3082 pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3083 pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3084 pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3085 pa_tagstruct_putu32(t, s->source->index);
3086 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3087 pa_tagstruct_put_channel_map(t, &s->channel_map);
3088 pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3089 pa_tagstruct_put_usec(t, source_latency);
3090 pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3091 pa_tagstruct_puts(t, s->driver);
3092
3093 if (c->version >= 13)
3094 pa_tagstruct_put_proplist(t, s->proplist);
3095 }
3096
3097 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3098 pa_sample_spec fixed_ss;
3099 pa_cvolume v;
3100
3101 pa_assert(t);
3102 pa_assert(e);
3103
3104 if (e->memchunk.memblock)
3105 fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3106 else
3107 memset(&fixed_ss, 0, sizeof(fixed_ss));
3108
3109 pa_tagstruct_putu32(t, e->index);
3110 pa_tagstruct_puts(t, e->name);
3111
3112 if (e->volume_is_set)
3113 v = e->volume;
3114 else
3115 pa_cvolume_init(&v);
3116
3117 pa_tagstruct_put_cvolume(t, &v);
3118 pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3119 pa_tagstruct_put_sample_spec(t, &fixed_ss);
3120 pa_tagstruct_put_channel_map(t, &e->channel_map);
3121 pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3122 pa_tagstruct_put_boolean(t, e->lazy);
3123 pa_tagstruct_puts(t, e->filename);
3124
3125 if (c->version >= 13)
3126 pa_tagstruct_put_proplist(t, e->proplist);
3127 }
3128
3129 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3130 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3131 uint32_t idx;
3132 pa_sink *sink = NULL;
3133 pa_source *source = NULL;
3134 pa_client *client = NULL;
3135 pa_card *card = NULL;
3136 pa_module *module = NULL;
3137 pa_sink_input *si = NULL;
3138 pa_source_output *so = NULL;
3139 pa_scache_entry *sce = NULL;
3140 const char *name = NULL;
3141 pa_tagstruct *reply;
3142
3143 pa_native_connection_assert_ref(c);
3144 pa_assert(t);
3145
3146 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3147 (command != PA_COMMAND_GET_CLIENT_INFO &&
3148 command != PA_COMMAND_GET_MODULE_INFO &&
3149 command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3150 command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3151 pa_tagstruct_gets(t, &name) < 0) ||
3152 !pa_tagstruct_eof(t)) {
3153 protocol_error(c);
3154 return;
3155 }
3156
3157 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3158 CHECK_VALIDITY(c->pstream, !name ||
3159 (command == PA_COMMAND_GET_SINK_INFO &&
3160 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3161 (command == PA_COMMAND_GET_SOURCE_INFO &&
3162 pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3163 pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3164 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3165 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3166 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3167
3168 if (command == PA_COMMAND_GET_SINK_INFO) {
3169 if (idx != PA_INVALID_INDEX)
3170 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3171 else
3172 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3173 } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3174 if (idx != PA_INVALID_INDEX)
3175 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3176 else
3177 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3178 } else if (command == PA_COMMAND_GET_CARD_INFO) {
3179 if (idx != PA_INVALID_INDEX)
3180 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3181 else
3182 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3183 } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3184 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3185 else if (command == PA_COMMAND_GET_MODULE_INFO)
3186 module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3187 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3188 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3189 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3190 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3191 else {
3192 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3193 if (idx != PA_INVALID_INDEX)
3194 sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3195 else
3196 sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3197 }
3198
3199 if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3200 pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3201 return;
3202 }
3203
3204 reply = reply_new(tag);
3205 if (sink)
3206 sink_fill_tagstruct(c, reply, sink);
3207 else if (source)
3208 source_fill_tagstruct(c, reply, source);
3209 else if (client)
3210 client_fill_tagstruct(c, reply, client);
3211 else if (card)
3212 card_fill_tagstruct(c, reply, card);
3213 else if (module)
3214 module_fill_tagstruct(c, reply, module);
3215 else if (si)
3216 sink_input_fill_tagstruct(c, reply, si);
3217 else if (so)
3218 source_output_fill_tagstruct(c, reply, so);
3219 else
3220 scache_fill_tagstruct(c, reply, sce);
3221 pa_pstream_send_tagstruct(c->pstream, reply);
3222 }
3223
3224 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3225 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3226 pa_idxset *i;
3227 uint32_t idx;
3228 void *p;
3229 pa_tagstruct *reply;
3230
3231 pa_native_connection_assert_ref(c);
3232 pa_assert(t);
3233
3234 if (!pa_tagstruct_eof(t)) {
3235 protocol_error(c);
3236 return;
3237 }
3238
3239 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3240
3241 reply = reply_new(tag);
3242
3243 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3244 i = c->protocol->core->sinks;
3245 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3246 i = c->protocol->core->sources;
3247 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3248 i = c->protocol->core->clients;
3249 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3250 i = c->protocol->core->cards;
3251 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3252 i = c->protocol->core->modules;
3253 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3254 i = c->protocol->core->sink_inputs;
3255 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3256 i = c->protocol->core->source_outputs;
3257 else {
3258 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3259 i = c->protocol->core->scache;
3260 }
3261
3262 if (i) {
3263 for (p = pa_idxset_first(i, &idx); p; p = pa_idxset_next(i, &idx)) {
3264 if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3265 sink_fill_tagstruct(c, reply, p);
3266 else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3267 source_fill_tagstruct(c, reply, p);
3268 else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3269 client_fill_tagstruct(c, reply, p);
3270 else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3271 card_fill_tagstruct(c, reply, p);
3272 else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3273 module_fill_tagstruct(c, reply, p);
3274 else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3275 sink_input_fill_tagstruct(c, reply, p);
3276 else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3277 source_output_fill_tagstruct(c, reply, p);
3278 else {
3279 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3280 scache_fill_tagstruct(c, reply, p);
3281 }
3282 }
3283 }
3284
3285 pa_pstream_send_tagstruct(c->pstream, reply);
3286 }
3287
3288 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3289 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3290 pa_tagstruct *reply;
3291 pa_sink *def_sink;
3292 pa_source *def_source;
3293 pa_sample_spec fixed_ss;
3294 char *h, *u;
3295
3296 pa_native_connection_assert_ref(c);
3297 pa_assert(t);
3298
3299 if (!pa_tagstruct_eof(t)) {
3300 protocol_error(c);
3301 return;
3302 }
3303
3304 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3305
3306 reply = reply_new(tag);
3307 pa_tagstruct_puts(reply, PACKAGE_NAME);
3308 pa_tagstruct_puts(reply, PACKAGE_VERSION);
3309
3310 u = pa_get_user_name_malloc();
3311 pa_tagstruct_puts(reply, u);
3312 pa_xfree(u);
3313
3314 h = pa_get_host_name_malloc();
3315 pa_tagstruct_puts(reply, h);
3316 pa_xfree(h);
3317
3318 fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3319 pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3320
3321 def_sink = pa_namereg_get_default_sink(c->protocol->core);
3322 pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3323 def_source = pa_namereg_get_default_source(c->protocol->core);
3324 pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3325
3326 pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3327
3328 if (c->version >= 15)
3329 pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3330
3331 pa_pstream_send_tagstruct(c->pstream, reply);
3332 }
3333
3334 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3335 pa_tagstruct *t;
3336 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3337
3338 pa_native_connection_assert_ref(c);
3339
3340 t = pa_tagstruct_new(NULL, 0);
3341 pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3342 pa_tagstruct_putu32(t, (uint32_t) -1);
3343 pa_tagstruct_putu32(t, e);
3344 pa_tagstruct_putu32(t, idx);
3345 pa_pstream_send_tagstruct(c->pstream, t);
3346 }
3347
3348 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3349 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3350 pa_subscription_mask_t m;
3351
3352 pa_native_connection_assert_ref(c);
3353 pa_assert(t);
3354
3355 if (pa_tagstruct_getu32(t, &m) < 0 ||
3356 !pa_tagstruct_eof(t)) {
3357 protocol_error(c);
3358 return;
3359 }
3360
3361 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3362 CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3363
3364 if (c->subscription)
3365 pa_subscription_free(c->subscription);
3366
3367 if (m != 0) {
3368 c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3369 pa_assert(c->subscription);
3370 } else
3371 c->subscription = NULL;
3372
3373 pa_pstream_send_simple_ack(c->pstream, tag);
3374 }
3375
3376 static void command_set_volume(
3377 pa_pdispatch *pd,
3378 uint32_t command,
3379 uint32_t tag,
3380 pa_tagstruct *t,
3381 void *userdata) {
3382
3383 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3384 uint32_t idx;
3385 pa_cvolume volume;
3386 pa_sink *sink = NULL;
3387 pa_source *source = NULL;
3388 pa_sink_input *si = NULL;
3389 const char *name = NULL;
3390 const char *client_name;
3391
3392 pa_native_connection_assert_ref(c);
3393 pa_assert(t);
3394
3395 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3396 (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3397 (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3398 pa_tagstruct_get_cvolume(t, &volume) ||
3399 !pa_tagstruct_eof(t)) {
3400 protocol_error(c);
3401 return;
3402 }
3403
3404 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3405 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);
3406 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3407 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3408 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3409 CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3410
3411 switch (command) {
3412
3413 case PA_COMMAND_SET_SINK_VOLUME:
3414 if (idx != PA_INVALID_INDEX)
3415 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3416 else
3417 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3418 break;
3419
3420 case PA_COMMAND_SET_SOURCE_VOLUME:
3421 if (idx != PA_INVALID_INDEX)
3422 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3423 else
3424 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3425 break;
3426
3427 case PA_COMMAND_SET_SINK_INPUT_VOLUME:
3428 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3429 break;
3430
3431 default:
3432 pa_assert_not_reached();
3433 }
3434
3435 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3436
3437 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3438
3439 if (sink) {
3440 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
3441
3442 pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
3443 pa_sink_set_volume(sink, &volume, TRUE, TRUE);
3444 } else if (source) {
3445 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
3446
3447 pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
3448 pa_source_set_volume(source, &volume, TRUE);
3449 } else if (si) {
3450 CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
3451
3452 pa_log_debug("Client %s changes volume of sink input %s.",
3453 client_name,
3454 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3455 pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
3456 }
3457
3458 pa_pstream_send_simple_ack(c->pstream, tag);
3459 }
3460
3461 static void command_set_mute(
3462 pa_pdispatch *pd,
3463 uint32_t command,
3464 uint32_t tag,
3465 pa_tagstruct *t,
3466 void *userdata) {
3467
3468 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3469 uint32_t idx;
3470 pa_bool_t mute;
3471 pa_sink *sink = NULL;
3472 pa_source *source = NULL;
3473 pa_sink_input *si = NULL;
3474 const char *name = NULL, *client_name;
3475
3476 pa_native_connection_assert_ref(c);
3477 pa_assert(t);
3478
3479 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3480 (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3481 (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
3482 pa_tagstruct_get_boolean(t, &mute) ||
3483 !pa_tagstruct_eof(t)) {
3484 protocol_error(c);
3485 return;
3486 }
3487
3488 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3489 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);
3490 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
3491 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3492 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3493
3494 switch (command) {
3495
3496 case PA_COMMAND_SET_SINK_MUTE:
3497 if (idx != PA_INVALID_INDEX)
3498 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3499 else
3500 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3501
3502 break;
3503
3504 case PA_COMMAND_SET_SOURCE_MUTE:
3505 if (idx != PA_INVALID_INDEX)
3506 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3507 else
3508 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3509
3510 break;
3511
3512 case PA_COMMAND_SET_SINK_INPUT_MUTE:
3513 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3514 break;
3515
3516 default:
3517 pa_assert_not_reached();
3518 }
3519
3520 CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
3521
3522 client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
3523
3524 if (sink) {
3525 pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
3526 pa_sink_set_mute(sink, mute, TRUE);
3527 } else if (source) {
3528 pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
3529 pa_source_set_mute(source, mute, TRUE);
3530 } else if (si) {
3531 pa_log_debug("Client %s changes mute of sink input %s.",
3532 client_name,
3533 pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
3534 pa_sink_input_set_mute(si, mute, TRUE);
3535 }
3536
3537 pa_pstream_send_simple_ack(c->pstream, tag);
3538 }
3539
3540 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3541 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3542 uint32_t idx;
3543 pa_bool_t b;
3544 playback_stream *s;
3545
3546 pa_native_connection_assert_ref(c);
3547 pa_assert(t);
3548
3549 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3550 pa_tagstruct_get_boolean(t, &b) < 0 ||
3551 !pa_tagstruct_eof(t)) {
3552 protocol_error(c);
3553 return;
3554 }
3555
3556 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3557 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3558 s = pa_idxset_get_by_index(c->output_streams, idx);
3559 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3560 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3561
3562 pa_sink_input_cork(s->sink_input, b);
3563
3564 if (b)
3565 s->is_underrun = TRUE;
3566
3567 pa_pstream_send_simple_ack(c->pstream, tag);
3568 }
3569
3570 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3571 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3572 uint32_t idx;
3573 playback_stream *s;
3574
3575 pa_native_connection_assert_ref(c);
3576 pa_assert(t);
3577
3578 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3579 !pa_tagstruct_eof(t)) {
3580 protocol_error(c);
3581 return;
3582 }
3583
3584 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3585 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3586 s = pa_idxset_get_by_index(c->output_streams, idx);
3587 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3588 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3589
3590 switch (command) {
3591 case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
3592 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
3593 break;
3594
3595 case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
3596 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
3597 break;
3598
3599 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
3600 pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
3601 break;
3602
3603 default:
3604 pa_assert_not_reached();
3605 }
3606
3607 pa_pstream_send_simple_ack(c->pstream, tag);
3608 }
3609
3610 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3611 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3612 uint32_t idx;
3613 record_stream *s;
3614 pa_bool_t b;
3615
3616 pa_native_connection_assert_ref(c);
3617 pa_assert(t);
3618
3619 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3620 pa_tagstruct_get_boolean(t, &b) < 0 ||
3621 !pa_tagstruct_eof(t)) {
3622 protocol_error(c);
3623 return;
3624 }
3625
3626 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3627 s = pa_idxset_get_by_index(c->record_streams, idx);
3628 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3629
3630 pa_source_output_cork(s->source_output, b);
3631 pa_memblockq_prebuf_force(s->memblockq);
3632 pa_pstream_send_simple_ack(c->pstream, tag);
3633 }
3634
3635 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3636 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3637 uint32_t idx;
3638 record_stream *s;
3639
3640 pa_native_connection_assert_ref(c);
3641 pa_assert(t);
3642
3643 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3644 !pa_tagstruct_eof(t)) {
3645 protocol_error(c);
3646 return;
3647 }
3648
3649 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3650 s = pa_idxset_get_by_index(c->record_streams, idx);
3651 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3652
3653 pa_memblockq_flush_read(s->memblockq);
3654 pa_pstream_send_simple_ack(c->pstream, tag);
3655 }
3656
3657 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3658 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3659 uint32_t idx;
3660 pa_buffer_attr a;
3661 pa_tagstruct *reply;
3662
3663 pa_native_connection_assert_ref(c);
3664 pa_assert(t);
3665
3666 memset(&a, 0, sizeof(a));
3667
3668 if (pa_tagstruct_getu32(t, &idx) < 0) {
3669 protocol_error(c);
3670 return;
3671 }
3672
3673 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3674
3675 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
3676 playback_stream *s;
3677 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3678
3679 s = pa_idxset_get_by_index(c->output_streams, idx);
3680 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3681 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3682
3683 if (pa_tagstruct_get(
3684 t,
3685 PA_TAG_U32, &a.maxlength,
3686 PA_TAG_U32, &a.tlength,
3687 PA_TAG_U32, &a.prebuf,
3688 PA_TAG_U32, &a.minreq,
3689 PA_TAG_INVALID) < 0 ||
3690 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3691 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3692 !pa_tagstruct_eof(t)) {
3693 protocol_error(c);
3694 return;
3695 }
3696
3697 s->adjust_latency = adjust_latency;
3698 s->early_requests = early_requests;
3699 s->buffer_attr = a;
3700
3701 fix_playback_buffer_attr(s);
3702 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);
3703
3704 reply = reply_new(tag);
3705 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3706 pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
3707 pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
3708 pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
3709
3710 if (c->version >= 13)
3711 pa_tagstruct_put_usec(reply, s->configured_sink_latency);
3712
3713 } else {
3714 record_stream *s;
3715 pa_bool_t adjust_latency = FALSE, early_requests = FALSE;
3716 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
3717
3718 s = pa_idxset_get_by_index(c->record_streams, idx);
3719 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3720
3721 if (pa_tagstruct_get(
3722 t,
3723 PA_TAG_U32, &a.maxlength,
3724 PA_TAG_U32, &a.fragsize,
3725 PA_TAG_INVALID) < 0 ||
3726 (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
3727 (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
3728 !pa_tagstruct_eof(t)) {
3729 protocol_error(c);
3730 return;
3731 }
3732
3733 s->adjust_latency = adjust_latency;
3734 s->early_requests = early_requests;
3735 s->buffer_attr = a;
3736
3737 fix_record_buffer_attr_pre(s);
3738 pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
3739 pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
3740 fix_record_buffer_attr_post(s);
3741
3742 reply = reply_new(tag);
3743 pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
3744 pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
3745
3746 if (c->version >= 13)
3747 pa_tagstruct_put_usec(reply, s->configured_source_latency);
3748 }
3749
3750 pa_pstream_send_tagstruct(c->pstream, reply);
3751 }
3752
3753 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3754 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3755 uint32_t idx;
3756 uint32_t rate;
3757
3758 pa_native_connection_assert_ref(c);
3759 pa_assert(t);
3760
3761 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3762 pa_tagstruct_getu32(t, &rate) < 0 ||
3763 !pa_tagstruct_eof(t)) {
3764 protocol_error(c);
3765 return;
3766 }
3767
3768 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3769 CHECK_VALIDITY(c->pstream, rate > 0 && rate <= PA_RATE_MAX, tag, PA_ERR_INVALID);
3770
3771 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
3772 playback_stream *s;
3773
3774 s = pa_idxset_get_by_index(c->output_streams, idx);
3775 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3776 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3777
3778 pa_sink_input_set_rate(s->sink_input, rate);
3779
3780 } else {
3781 record_stream *s;
3782 pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
3783
3784 s = pa_idxset_get_by_index(c->record_streams, idx);
3785 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3786
3787 pa_source_output_set_rate(s->source_output, rate);
3788 }
3789
3790 pa_pstream_send_simple_ack(c->pstream, tag);
3791 }
3792
3793 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3794 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3795 uint32_t idx;
3796 uint32_t mode;
3797 pa_proplist *p;
3798
3799 pa_native_connection_assert_ref(c);
3800 pa_assert(t);
3801
3802 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3803
3804 p = pa_proplist_new();
3805
3806 if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
3807
3808 if (pa_tagstruct_getu32(t, &mode) < 0 ||
3809 pa_tagstruct_get_proplist(t, p) < 0 ||
3810 !pa_tagstruct_eof(t)) {
3811 protocol_error(c);
3812 pa_proplist_free(p);
3813 return;
3814 }
3815
3816 } else {
3817
3818 if (pa_tagstruct_getu32(t, &idx) < 0 ||
3819 pa_tagstruct_getu32(t, &mode) < 0 ||
3820 pa_tagstruct_get_proplist(t, p) < 0 ||
3821 !pa_tagstruct_eof(t)) {
3822 protocol_error(c);
3823 pa_proplist_free(p);
3824 return;
3825 }
3826 }
3827
3828 if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
3829 pa_proplist_free(p);
3830 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_INVALID);
3831 }
3832
3833 if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
3834 playback_stream *s;
3835
3836 s = pa_idxset_get_by_index(c->output_streams, idx);
3837 if (!s || !playback_stream_isinstance(s)) {
3838 pa_proplist_free(p);
3839 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3840 }
3841 pa_sink_input_update_proplist(s->sink_input, mode, p);
3842
3843 } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
3844 record_stream *s;
3845
3846 if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
3847 pa_proplist_free(p);
3848 CHECK_VALIDITY(c->pstream, FALSE, tag, PA_ERR_NOENTITY);
3849 }
3850 pa_source_output_update_proplist(s->source_output, mode, p);
3851
3852 } else {
3853 pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
3854
3855 pa_client_update_proplist(c->client, mode, p);
3856 }
3857
3858 pa_pstream_send_simple_ack(c->pstream, tag);
3859 pa_proplist_free(p);
3860 }
3861
3862 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3863 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3864 uint32_t idx;
3865 unsigned changed = 0;
3866 pa_proplist *p;
3867 pa_strlist *l = NULL;
3868
3869 pa_native_connection_assert_ref(c);
3870 pa_assert(t);
3871
3872 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3873
3874 if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
3875
3876 if (pa_tagstruct_getu32(t, &idx) < 0) {
3877 protocol_error(c);
3878 return;
3879 }
3880 }
3881
3882 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3883 playback_stream *s;
3884
3885 s = pa_idxset_get_by_index(c->output_streams, idx);
3886 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3887 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3888
3889 p = s->sink_input->proplist;
3890
3891 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3892 record_stream *s;
3893
3894 s = pa_idxset_get_by_index(c->record_streams, idx);
3895 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3896
3897 p = s->source_output->proplist;
3898 } else {
3899 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3900
3901 p = c->client->proplist;
3902 }
3903
3904 for (;;) {
3905 const char *k;
3906
3907 if (pa_tagstruct_gets(t, &k) < 0) {
3908 protocol_error(c);
3909 pa_strlist_free(l);
3910 return;
3911 }
3912
3913 if (!k)
3914 break;
3915
3916 l = pa_strlist_prepend(l, k);
3917 }
3918
3919 if (!pa_tagstruct_eof(t)) {
3920 protocol_error(c);
3921 pa_strlist_free(l);
3922 return;
3923 }
3924
3925 for (;;) {
3926 char *z;
3927
3928 l = pa_strlist_pop(l, &z);
3929
3930 if (!z)
3931 break;
3932
3933 changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
3934 pa_xfree(z);
3935 }
3936
3937 pa_pstream_send_simple_ack(c->pstream, tag);
3938
3939 if (changed) {
3940 if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
3941 playback_stream *s;
3942
3943 s = pa_idxset_get_by_index(c->output_streams, idx);
3944 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
3945
3946 } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
3947 record_stream *s;
3948
3949 s = pa_idxset_get_by_index(c->record_streams, idx);
3950 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
3951
3952 } else {
3953 pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
3954 pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
3955 }
3956 }
3957 }
3958
3959 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3960 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3961 const char *s;
3962
3963 pa_native_connection_assert_ref(c);
3964 pa_assert(t);
3965
3966 if (pa_tagstruct_gets(t, &s) < 0 ||
3967 !pa_tagstruct_eof(t)) {
3968 protocol_error(c);
3969 return;
3970 }
3971
3972 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3973 CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
3974
3975 if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
3976 pa_source *source;
3977
3978 source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
3979 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
3980
3981 pa_namereg_set_default_source(c->protocol->core, source);
3982 } else {
3983 pa_sink *sink;
3984 pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
3985
3986 sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
3987 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3988
3989 pa_namereg_set_default_sink(c->protocol->core, sink);
3990 }
3991
3992 pa_pstream_send_simple_ack(c->pstream, tag);
3993 }
3994
3995 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3996 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3997 uint32_t idx;
3998 const char *name;
3999
4000 pa_native_connection_assert_ref(c);
4001 pa_assert(t);
4002
4003 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4004 pa_tagstruct_gets(t, &name) < 0 ||
4005 !pa_tagstruct_eof(t)) {
4006 protocol_error(c);
4007 return;
4008 }
4009
4010 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4011 CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4012
4013 if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4014 playback_stream *s;
4015
4016 s = pa_idxset_get_by_index(c->output_streams, idx);
4017 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4018 CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4019
4020 pa_sink_input_set_name(s->sink_input, name);
4021
4022 } else {
4023 record_stream *s;
4024 pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4025
4026 s = pa_idxset_get_by_index(c->record_streams, idx);
4027 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4028
4029 pa_source_output_set_name(s->source_output, name);
4030 }
4031
4032 pa_pstream_send_simple_ack(c->pstream, tag);
4033 }
4034
4035 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4036 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4037 uint32_t idx;
4038
4039 pa_native_connection_assert_ref(c);
4040 pa_assert(t);
4041
4042 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4043 !pa_tagstruct_eof(t)) {
4044 protocol_error(c);
4045 return;
4046 }
4047
4048 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4049
4050 if (command == PA_COMMAND_KILL_CLIENT) {
4051 pa_client *client;
4052
4053 client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4054 CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4055
4056 pa_native_connection_ref(c);
4057 pa_client_kill(client);
4058
4059 } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4060 pa_sink_input *s;
4061
4062 s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4063 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4064
4065 pa_native_connection_ref(c);
4066 pa_sink_input_kill(s);
4067 } else {
4068 pa_source_output *s;
4069
4070 pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4071
4072 s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4073 CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4074
4075 pa_native_connection_ref(c);
4076 pa_source_output_kill(s);
4077 }
4078
4079 pa_pstream_send_simple_ack(c->pstream, tag);
4080 pa_native_connection_unref(c);
4081 }
4082
4083 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4084 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4085 pa_module *m;
4086 const char *name, *argument;
4087 pa_tagstruct *reply;
4088
4089 pa_native_connection_assert_ref(c);
4090 pa_assert(t);
4091
4092 if (pa_tagstruct_gets(t, &name) < 0 ||
4093 pa_tagstruct_gets(t, &argument) < 0 ||
4094 !pa_tagstruct_eof(t)) {
4095 protocol_error(c);
4096 return;
4097 }
4098
4099 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4100 CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4101 CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4102
4103 if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4104 pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4105 return;
4106 }
4107
4108 reply = reply_new(tag);
4109 pa_tagstruct_putu32(reply, m->index);
4110 pa_pstream_send_tagstruct(c->pstream, reply);
4111 }
4112
4113 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4114 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4115 uint32_t idx;
4116 pa_module *m;
4117
4118 pa_native_connection_assert_ref(c);
4119 pa_assert(t);
4120
4121 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4122 !pa_tagstruct_eof(t)) {
4123 protocol_error(c);
4124 return;
4125 }
4126
4127 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4128 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4129 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4130
4131 pa_module_unload_request(m, FALSE);
4132 pa_pstream_send_simple_ack(c->pstream, tag);
4133 }
4134
4135 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4136 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4137 uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4138 const char *name_device = NULL;
4139
4140 pa_native_connection_assert_ref(c);
4141 pa_assert(t);
4142
4143 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4144 pa_tagstruct_getu32(t, &idx_device) < 0 ||
4145 pa_tagstruct_gets(t, &name_device) < 0 ||
4146 !pa_tagstruct_eof(t)) {
4147 protocol_error(c);
4148 return;
4149 }
4150
4151 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4152 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4153
4154 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);
4155 CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID);
4156 CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID);
4157 CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4158
4159 if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4160 pa_sink_input *si = NULL;
4161 pa_sink *sink = NULL;
4162
4163 si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4164
4165 if (idx_device != PA_INVALID_INDEX)
4166 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4167 else
4168 sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4169
4170 CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4171
4172 if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
4173 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4174 return;
4175 }
4176 } else {
4177 pa_source_output *so = NULL;
4178 pa_source *source;
4179
4180 pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4181
4182 so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4183
4184 if (idx_device != PA_INVALID_INDEX)
4185 source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4186 else
4187 source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4188
4189 CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4190
4191 if (pa_source_output_move_to(so, source, TRUE) < 0) {
4192 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4193 return;
4194 }
4195 }
4196
4197 pa_pstream_send_simple_ack(c->pstream, tag);
4198 }
4199
4200 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4201 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4202 uint32_t idx = PA_INVALID_INDEX;
4203 const char *name = NULL;
4204 pa_bool_t b;
4205
4206 pa_native_connection_assert_ref(c);
4207 pa_assert(t);
4208
4209 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4210 pa_tagstruct_gets(t, &name) < 0 ||
4211 pa_tagstruct_get_boolean(t, &b) < 0 ||
4212 !pa_tagstruct_eof(t)) {
4213 protocol_error(c);
4214 return;
4215 }
4216
4217 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4218 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);
4219 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4220 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4221 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4222
4223 if (command == PA_COMMAND_SUSPEND_SINK) {
4224
4225 if (idx == PA_INVALID_INDEX && name && !*name) {
4226
4227 pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
4228
4229 if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4230 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4231 return;
4232 }
4233 } else {
4234 pa_sink *sink = NULL;
4235
4236 if (idx != PA_INVALID_INDEX)
4237 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4238 else
4239 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4240
4241 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4242
4243 if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
4244 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4245 return;
4246 }
4247 }
4248 } else {
4249
4250 pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
4251
4252 if (idx == PA_INVALID_INDEX && name && !*name) {
4253
4254 pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
4255
4256 if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
4257 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4258 return;
4259 }
4260
4261 } else {
4262 pa_source *source;
4263
4264 if (idx != PA_INVALID_INDEX)
4265 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4266 else
4267 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4268
4269 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4270
4271 if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
4272 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4273 return;
4274 }
4275 }
4276 }
4277
4278 pa_pstream_send_simple_ack(c->pstream, tag);
4279 }
4280
4281 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4282 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4283 uint32_t idx = PA_INVALID_INDEX;
4284 const char *name = NULL;
4285 pa_module *m;
4286 pa_native_protocol_ext_cb_t cb;
4287
4288 pa_native_connection_assert_ref(c);
4289 pa_assert(t);
4290
4291 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4292 pa_tagstruct_gets(t, &name) < 0) {
4293 protocol_error(c);
4294 return;
4295 }
4296
4297 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4298 CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
4299 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4300 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4301 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4302
4303 if (idx != PA_INVALID_INDEX)
4304 m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4305 else {
4306 for (m = pa_idxset_first(c->protocol->core->modules, &idx); m; m = pa_idxset_next(c->protocol->core->modules, &idx))
4307 if (strcmp(name, m->name) == 0)
4308 break;
4309 }
4310
4311 CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
4312 CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4313
4314 cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
4315 CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
4316
4317 if (cb(c->protocol, m, c, tag, t) < 0)
4318 protocol_error(c);
4319 }
4320
4321 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4322 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4323 uint32_t idx = PA_INVALID_INDEX;
4324 const char *name = NULL, *profile = NULL;
4325 pa_card *card = NULL;
4326 int ret;
4327
4328 pa_native_connection_assert_ref(c);
4329 pa_assert(t);
4330
4331 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4332 pa_tagstruct_gets(t, &name) < 0 ||
4333 pa_tagstruct_gets(t, &profile) < 0 ||
4334 !pa_tagstruct_eof(t)) {
4335 protocol_error(c);
4336 return;
4337 }
4338
4339 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4340 CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
4341 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4342 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4343 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4344
4345 if (idx != PA_INVALID_INDEX)
4346 card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
4347 else
4348 card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
4349
4350 CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
4351
4352 if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
4353 pa_pstream_send_error(c->pstream, tag, -ret);
4354 return;
4355 }
4356
4357 pa_pstream_send_simple_ack(c->pstream, tag);
4358 }
4359
4360 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4361 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4362 uint32_t idx = PA_INVALID_INDEX;
4363 const char *name = NULL, *port = NULL;
4364 int ret;
4365
4366 pa_native_connection_assert_ref(c);
4367 pa_assert(t);
4368
4369 if (pa_tagstruct_getu32(t, &idx) < 0 ||
4370 pa_tagstruct_gets(t, &name) < 0 ||
4371 pa_tagstruct_gets(t, &port) < 0 ||
4372 !pa_tagstruct_eof(t)) {
4373 protocol_error(c);
4374 return;
4375 }
4376
4377 CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4378 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);
4379 CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4380 CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4381 CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4382
4383 if (command == PA_COMMAND_SET_SINK_PORT) {
4384 pa_sink *sink;
4385
4386 if (idx != PA_INVALID_INDEX)
4387 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4388 else
4389 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4390
4391 CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4392
4393 if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
4394 pa_pstream_send_error(c->pstream, tag, -ret);
4395 return;
4396 }
4397 } else {
4398 pa_source *source;
4399
4400 pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
4401
4402 if (idx != PA_INVALID_INDEX)
4403 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4404 else
4405 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4406
4407 CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4408
4409 if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
4410 pa_pstream_send_error(c->pstream, tag, -ret);
4411 return;
4412 }
4413 }
4414
4415 pa_pstream_send_simple_ack(c->pstream, tag);
4416 }
4417
4418 /*** pstream callbacks ***/
4419
4420 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
4421 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4422
4423 pa_assert(p);
4424 pa_assert(packet);
4425 pa_native_connection_assert_ref(c);
4426
4427 if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
4428 pa_log("invalid packet.");
4429 native_connection_unlink(c);
4430 }
4431 }
4432
4433 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) {
4434 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4435 output_stream *stream;
4436
4437 pa_assert(p);
4438 pa_assert(chunk);
4439 pa_native_connection_assert_ref(c);
4440
4441 if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
4442 pa_log_debug("Client sent block for invalid stream.");
4443 /* Ignoring */
4444 return;
4445 }
4446
4447 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4448
4449 if (playback_stream_isinstance(stream)) {
4450 playback_stream *ps = PLAYBACK_STREAM(stream);
4451
4452 if (chunk->memblock) {
4453 if (seek != PA_SEEK_RELATIVE || offset != 0)
4454 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, NULL, NULL);
4455
4456 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
4457 } else
4458 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);
4459
4460 } else {
4461 upload_stream *u = UPLOAD_STREAM(stream);
4462 size_t l;
4463
4464 if (!u->memchunk.memblock) {
4465 if (u->length == chunk->length && chunk->memblock) {
4466 u->memchunk = *chunk;
4467 pa_memblock_ref(u->memchunk.memblock);
4468 u->length = 0;
4469 } else {
4470 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
4471 u->memchunk.index = u->memchunk.length = 0;
4472 }
4473 }
4474
4475 pa_assert(u->memchunk.memblock);
4476
4477 l = u->length;
4478 if (l > chunk->length)
4479 l = chunk->length;
4480
4481 if (l > 0) {
4482 void *dst;
4483 dst = pa_memblock_acquire(u->memchunk.memblock);
4484
4485 if (chunk->memblock) {
4486 void *src;
4487 src = pa_memblock_acquire(chunk->memblock);
4488
4489 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
4490 (uint8_t*) src + chunk->index, l);
4491
4492 pa_memblock_release(chunk->memblock);
4493 } else
4494 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
4495
4496 pa_memblock_release(u->memchunk.memblock);
4497
4498 u->memchunk.length += l;
4499 u->length -= l;
4500 }
4501 }
4502 }
4503
4504 static void pstream_die_callback(pa_pstream *p, void *userdata) {
4505 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4506
4507 pa_assert(p);
4508 pa_native_connection_assert_ref(c);
4509
4510 native_connection_unlink(c);
4511 pa_log_info("Connection died.");
4512 }
4513
4514 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
4515 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4516
4517 pa_assert(p);
4518 pa_native_connection_assert_ref(c);
4519
4520 native_connection_send_memblock(c);
4521 }
4522
4523 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4524 pa_thread_mq *q;
4525
4526 if (!(q = pa_thread_mq_get()))
4527 pa_pstream_send_revoke(p, block_id);
4528 else
4529 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4530 }
4531
4532 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
4533 pa_thread_mq *q;
4534
4535 if (!(q = pa_thread_mq_get()))
4536 pa_pstream_send_release(p, block_id);
4537 else
4538 pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
4539 }
4540
4541 /*** client callbacks ***/
4542
4543 static void client_kill_cb(pa_client *c) {
4544 pa_assert(c);
4545
4546 native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
4547 pa_log_info("Connection killed.");
4548 }
4549
4550 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
4551 pa_tagstruct *t;
4552 pa_native_connection *c;
4553
4554 pa_assert(client);
4555 c = PA_NATIVE_CONNECTION(client->userdata);
4556 pa_native_connection_assert_ref(c);
4557
4558 if (c->version < 15)
4559 return;
4560
4561 t = pa_tagstruct_new(NULL, 0);
4562 pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
4563 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
4564 pa_tagstruct_puts(t, event);
4565 pa_tagstruct_put_proplist(t, pl);
4566 pa_pstream_send_tagstruct(c->pstream, t);
4567 }
4568
4569 /*** module entry points ***/
4570
4571 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
4572 pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4573
4574 pa_assert(m);
4575 pa_native_connection_assert_ref(c);
4576 pa_assert(c->auth_timeout_event == e);
4577
4578 if (!c->authorized) {
4579 native_connection_unlink(c);
4580 pa_log_info("Connection terminated due to authentication timeout.");
4581 }
4582 }
4583
4584 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
4585 pa_native_connection *c;
4586 char pname[128];
4587 pa_client *client;
4588 pa_client_new_data data;
4589
4590 pa_assert(p);
4591 pa_assert(io);
4592 pa_assert(o);
4593
4594 if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
4595 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
4596 pa_iochannel_free(io);
4597 return;
4598 }
4599
4600 pa_client_new_data_init(&data);
4601 data.module = o->module;
4602 data.driver = __FILE__;
4603 pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
4604 pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
4605 pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
4606 client = pa_client_new(p->core, &data);
4607 pa_client_new_data_done(&data);
4608
4609 if (!client)
4610 return;
4611
4612 c = pa_msgobject_new(pa_native_connection);
4613 c->parent.parent.free = native_connection_free;
4614 c->parent.process_msg = native_connection_process_msg;
4615 c->protocol = p;
4616 c->options = pa_native_options_ref(o);
4617 c->authorized = FALSE;
4618
4619 if (o->auth_anonymous) {
4620 pa_log_info("Client authenticated anonymously.");
4621 c->authorized = TRUE;
4622 }
4623
4624 if (!c->authorized &&
4625 o->auth_ip_acl &&
4626 pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
4627
4628 pa_log_info("Client authenticated by IP ACL.");
4629 c->authorized = TRUE;
4630 }
4631
4632 if (!c->authorized)
4633 c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
4634 else
4635 c->auth_timeout_event = NULL;
4636
4637 c->is_local = pa_iochannel_socket_is_local(io);
4638 c->version = 8;
4639
4640 c->client = client;
4641 c->client->kill = client_kill_cb;
4642 c->client->send_event = client_send_event_cb;
4643 c->client->userdata = c;
4644
4645 c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
4646 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
4647 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
4648 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
4649 pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
4650 pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
4651 pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
4652
4653 c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
4654
4655 c->record_streams = pa_idxset_new(NULL, NULL);
4656 c->output_streams = pa_idxset_new(NULL, NULL);
4657
4658 c->rrobin_index = PA_IDXSET_INVALID;
4659 c->subscription = NULL;
4660
4661 pa_idxset_put(p->connections, c, NULL);
4662
4663 #ifdef HAVE_CREDS
4664 if (pa_iochannel_creds_supported(io))
4665 pa_iochannel_creds_enable(io);
4666 #endif
4667
4668 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
4669 }
4670
4671 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
4672 pa_native_connection *c;
4673 void *state = NULL;
4674
4675 pa_assert(p);
4676 pa_assert(m);
4677
4678 while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
4679 if (c->options->module == m)
4680 native_connection_unlink(c);
4681 }
4682
4683 static pa_native_protocol* native_protocol_new(pa_core *c) {
4684 pa_native_protocol *p;
4685 pa_native_hook_t h;
4686
4687 pa_assert(c);
4688
4689 p = pa_xnew(pa_native_protocol, 1);
4690 PA_REFCNT_INIT(p);
4691 p->core = c;
4692 p->connections = pa_idxset_new(NULL, NULL);
4693
4694 p->servers = NULL;
4695
4696 p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
4697
4698 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4699 pa_hook_init(&p->hooks[h], p);
4700
4701 pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
4702
4703 return p;
4704 }
4705
4706 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
4707 pa_native_protocol *p;
4708
4709 if ((p = pa_shared_get(c, "native-protocol")))
4710 return pa_native_protocol_ref(p);
4711
4712 return native_protocol_new(c);
4713 }
4714
4715 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
4716 pa_assert(p);
4717 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4718
4719 PA_REFCNT_INC(p);
4720
4721 return p;
4722 }
4723
4724 void pa_native_protocol_unref(pa_native_protocol *p) {
4725 pa_native_connection *c;
4726 pa_native_hook_t h;
4727
4728 pa_assert(p);
4729 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4730
4731 if (PA_REFCNT_DEC(p) > 0)
4732 return;
4733
4734 while ((c = pa_idxset_first(p->connections, NULL)))
4735 native_connection_unlink(c);
4736
4737 pa_idxset_free(p->connections, NULL, NULL);
4738
4739 pa_strlist_free(p->servers);
4740
4741 for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
4742 pa_hook_done(&p->hooks[h]);
4743
4744 pa_hashmap_free(p->extensions, NULL, NULL);
4745
4746 pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
4747
4748 pa_xfree(p);
4749 }
4750
4751 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
4752 pa_assert(p);
4753 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4754 pa_assert(name);
4755
4756 p->servers = pa_strlist_prepend(p->servers, name);
4757
4758 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4759 }
4760
4761 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
4762 pa_assert(p);
4763 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4764 pa_assert(name);
4765
4766 p->servers = pa_strlist_remove(p->servers, name);
4767
4768 pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
4769 }
4770
4771 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
4772 pa_assert(p);
4773 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4774
4775 return p->hooks;
4776 }
4777
4778 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
4779 pa_assert(p);
4780 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4781
4782 return p->servers;
4783 }
4784
4785 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
4786 pa_assert(p);
4787 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4788 pa_assert(m);
4789 pa_assert(cb);
4790 pa_assert(!pa_hashmap_get(p->extensions, m));
4791
4792 pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
4793 return 0;
4794 }
4795
4796 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
4797 pa_assert(p);
4798 pa_assert(PA_REFCNT_VALUE(p) >= 1);
4799 pa_assert(m);
4800
4801 pa_assert_se(pa_hashmap_remove(p->extensions, m));
4802 }
4803
4804 pa_native_options* pa_native_options_new(void) {
4805 pa_native_options *o;
4806
4807 o = pa_xnew0(pa_native_options, 1);
4808 PA_REFCNT_INIT(o);
4809
4810 return o;
4811 }
4812
4813 pa_native_options* pa_native_options_ref(pa_native_options *o) {
4814 pa_assert(o);
4815 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4816
4817 PA_REFCNT_INC(o);
4818
4819 return o;
4820 }
4821
4822 void pa_native_options_unref(pa_native_options *o) {
4823 pa_assert(o);
4824 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4825
4826 if (PA_REFCNT_DEC(o) > 0)
4827 return;
4828
4829 pa_xfree(o->auth_group);
4830
4831 if (o->auth_ip_acl)
4832 pa_ip_acl_free(o->auth_ip_acl);
4833
4834 if (o->auth_cookie)
4835 pa_auth_cookie_unref(o->auth_cookie);
4836
4837 pa_xfree(o);
4838 }
4839
4840 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
4841 pa_bool_t enabled;
4842 const char *acl;
4843
4844 pa_assert(o);
4845 pa_assert(PA_REFCNT_VALUE(o) >= 1);
4846 pa_assert(ma);
4847
4848 if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
4849 pa_log("auth-anonymous= expects a boolean argument.");
4850 return -1;
4851 }
4852
4853 enabled = TRUE;
4854 if (pa_modargs_get_value_boolean(ma, "auth-group-enabled", &enabled) < 0) {
4855 pa_log("auth-group-enabled= expects a boolean argument.");
4856 return -1;
4857 }
4858
4859 pa_xfree(o->auth_group);
4860 o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
4861
4862 #ifndef HAVE_CREDS
4863 if (o->auth_group)
4864 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4865 #endif
4866
4867 if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
4868 pa_ip_acl *ipa;
4869
4870 if (!(ipa = pa_ip_acl_new(acl))) {
4871 pa_log("Failed to parse IP ACL '%s'", acl);
4872 return -1;
4873 }
4874
4875 if (o->auth_ip_acl)
4876 pa_ip_acl_free(o->auth_ip_acl);
4877
4878 o->auth_ip_acl = ipa;
4879 }
4880
4881 enabled = TRUE;
4882 if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
4883 pa_log("auth-cookie-enabled= expects a boolean argument.");
4884 return -1;
4885 }
4886
4887 if (o->auth_cookie)
4888 pa_auth_cookie_unref(o->auth_cookie);
4889
4890 if (enabled) {
4891 const char *cn;
4892
4893 /* The new name for this is 'auth-cookie', for compat reasons
4894 * we check the old name too */
4895 if (!(cn = pa_modargs_get_value(ma, "auth-cookie", NULL)))
4896 if (!(cn = pa_modargs_get_value(ma, "cookie", NULL)))
4897 cn = PA_NATIVE_COOKIE_FILE;
4898
4899 if (!(o->auth_cookie = pa_auth_cookie_get(c, cn, PA_NATIVE_COOKIE_LENGTH)))
4900 return -1;
4901
4902 } else
4903 o->auth_cookie = NULL;
4904
4905 return 0;
4906 }
4907
4908 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
4909 pa_native_connection_assert_ref(c);
4910
4911 return c->pstream;
4912 }
4913
4914 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
4915 pa_native_connection_assert_ref(c);
4916
4917 return c->client;
4918 }