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