2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
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>
39 #include <pulsecore/native-common.h>
40 #include <pulsecore/packet.h>
41 #include <pulsecore/client.h>
42 #include <pulsecore/source-output.h>
43 #include <pulsecore/sink-input.h>
44 #include <pulsecore/pstream.h>
45 #include <pulsecore/tagstruct.h>
46 #include <pulsecore/pdispatch.h>
47 #include <pulsecore/pstream-util.h>
48 #include <pulsecore/authkey.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/core-subscribe.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/llist.h>
57 #include <pulsecore/creds.h>
58 #include <pulsecore/core-util.h>
59 #include <pulsecore/ipacl.h>
60 #include <pulsecore/thread-mq.h>
62 #include "protocol-native.h"
64 /* Kick a client if it doesn't authenticate within this time */
65 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
67 /* Don't accept more connection than this */
68 #define MAX_CONNECTIONS 64
70 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
71 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
72 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
73 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
75 struct pa_native_protocol
;
77 typedef struct record_stream
{
80 pa_native_connection
*connection
;
83 pa_source_output
*source_output
;
84 pa_memblockq
*memblockq
;
86 pa_bool_t adjust_latency
:1;
87 pa_bool_t early_requests
:1;
89 pa_buffer_attr buffer_attr
;
91 pa_atomic_t on_the_fly
;
92 pa_usec_t configured_source_latency
;
95 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
96 size_t on_the_fly_snapshot
;
97 pa_usec_t current_monitor_latency
;
98 pa_usec_t current_source_latency
;
101 #define RECORD_STREAM(o) (record_stream_cast(o))
102 PA_DEFINE_PRIVATE_CLASS(record_stream
, pa_msgobject
);
104 typedef struct output_stream
{
108 #define OUTPUT_STREAM(o) (output_stream_cast(o))
109 PA_DEFINE_PRIVATE_CLASS(output_stream
, pa_msgobject
);
111 typedef struct playback_stream
{
112 output_stream parent
;
114 pa_native_connection
*connection
;
117 pa_sink_input
*sink_input
;
118 pa_memblockq
*memblockq
;
120 pa_bool_t adjust_latency
:1;
121 pa_bool_t early_requests
:1;
123 pa_bool_t is_underrun
:1;
124 pa_bool_t drain_request
:1;
129 pa_usec_t configured_sink_latency
;
130 pa_buffer_attr buffer_attr
;
132 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
133 int64_t read_index
, write_index
;
134 size_t render_memblockq_length
;
135 pa_usec_t current_sink_latency
;
136 uint64_t playing_for
, underrun_for
;
139 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
140 PA_DEFINE_PRIVATE_CLASS(playback_stream
, output_stream
);
142 typedef struct upload_stream
{
143 output_stream parent
;
145 pa_native_connection
*connection
;
148 pa_memchunk memchunk
;
151 pa_sample_spec sample_spec
;
152 pa_channel_map channel_map
;
153 pa_proplist
*proplist
;
156 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
157 PA_DEFINE_PRIVATE_CLASS(upload_stream
, output_stream
);
159 struct pa_native_connection
{
161 pa_native_protocol
*protocol
;
162 pa_native_options
*options
;
163 pa_bool_t authorized
:1;
164 pa_bool_t is_local
:1;
168 pa_pdispatch
*pdispatch
;
169 pa_idxset
*record_streams
, *output_streams
;
170 uint32_t rrobin_index
;
171 pa_subscription
*subscription
;
172 pa_time_event
*auth_timeout_event
;
175 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
176 PA_DEFINE_PRIVATE_CLASS(pa_native_connection
, pa_msgobject
);
178 struct pa_native_protocol
{
182 pa_idxset
*connections
;
185 pa_hook hooks
[PA_NATIVE_HOOK_MAX
];
187 pa_hashmap
*extensions
;
191 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
= PA_SOURCE_OUTPUT_MESSAGE_MAX
195 SINK_INPUT_MESSAGE_POST_DATA
= PA_SINK_INPUT_MESSAGE_MAX
, /* data from main loop to sink input */
196 SINK_INPUT_MESSAGE_DRAIN
, /* disabled prebuf, get playback started. */
197 SINK_INPUT_MESSAGE_FLUSH
,
198 SINK_INPUT_MESSAGE_TRIGGER
,
199 SINK_INPUT_MESSAGE_SEEK
,
200 SINK_INPUT_MESSAGE_PREBUF_FORCE
,
201 SINK_INPUT_MESSAGE_UPDATE_LATENCY
,
202 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
206 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, /* data requested from sink input from the main loop */
207 PLAYBACK_STREAM_MESSAGE_UNDERFLOW
,
208 PLAYBACK_STREAM_MESSAGE_OVERFLOW
,
209 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
,
210 PLAYBACK_STREAM_MESSAGE_STARTED
,
211 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
215 RECORD_STREAM_MESSAGE_POST_DATA
/* data from source output to main loop */
219 CONNECTION_MESSAGE_RELEASE
,
220 CONNECTION_MESSAGE_REVOKE
223 static int sink_input_pop_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
);
224 static void sink_input_kill_cb(pa_sink_input
*i
);
225 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
);
226 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
);
227 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
228 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
229 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
);
230 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
);
232 static void native_connection_send_memblock(pa_native_connection
*c
);
233 static void playback_stream_request_bytes(struct playback_stream
*s
);
235 static void source_output_kill_cb(pa_source_output
*o
);
236 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
);
237 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
);
238 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
);
239 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
);
240 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
);
242 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
243 static int source_output_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
245 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
246 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
247 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
248 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
249 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
250 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
251 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
252 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
253 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
254 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
255 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
256 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
257 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
258 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
259 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
260 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
261 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
262 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
263 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
264 static void command_set_volume(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
265 static void command_set_mute(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
266 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
267 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
268 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
269 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
270 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
271 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
272 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
273 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
274 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
275 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
276 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
277 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
278 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
279 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
280 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
281 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
282 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
283 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
285 static const pa_pdispatch_cb_t command_table
[PA_COMMAND_MAX
] = {
286 [PA_COMMAND_ERROR
] = NULL
,
287 [PA_COMMAND_TIMEOUT
] = NULL
,
288 [PA_COMMAND_REPLY
] = NULL
,
289 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = command_create_playback_stream
,
290 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = command_delete_stream
,
291 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = command_drain_playback_stream
,
292 [PA_COMMAND_CREATE_RECORD_STREAM
] = command_create_record_stream
,
293 [PA_COMMAND_DELETE_RECORD_STREAM
] = command_delete_stream
,
294 [PA_COMMAND_AUTH
] = command_auth
,
295 [PA_COMMAND_REQUEST
] = NULL
,
296 [PA_COMMAND_EXIT
] = command_exit
,
297 [PA_COMMAND_SET_CLIENT_NAME
] = command_set_client_name
,
298 [PA_COMMAND_LOOKUP_SINK
] = command_lookup
,
299 [PA_COMMAND_LOOKUP_SOURCE
] = command_lookup
,
300 [PA_COMMAND_STAT
] = command_stat
,
301 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = command_get_playback_latency
,
302 [PA_COMMAND_GET_RECORD_LATENCY
] = command_get_record_latency
,
303 [PA_COMMAND_CREATE_UPLOAD_STREAM
] = command_create_upload_stream
,
304 [PA_COMMAND_DELETE_UPLOAD_STREAM
] = command_delete_stream
,
305 [PA_COMMAND_FINISH_UPLOAD_STREAM
] = command_finish_upload_stream
,
306 [PA_COMMAND_PLAY_SAMPLE
] = command_play_sample
,
307 [PA_COMMAND_REMOVE_SAMPLE
] = command_remove_sample
,
308 [PA_COMMAND_GET_SINK_INFO
] = command_get_info
,
309 [PA_COMMAND_GET_SOURCE_INFO
] = command_get_info
,
310 [PA_COMMAND_GET_CLIENT_INFO
] = command_get_info
,
311 [PA_COMMAND_GET_CARD_INFO
] = command_get_info
,
312 [PA_COMMAND_GET_MODULE_INFO
] = command_get_info
,
313 [PA_COMMAND_GET_SINK_INPUT_INFO
] = command_get_info
,
314 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO
] = command_get_info
,
315 [PA_COMMAND_GET_SAMPLE_INFO
] = command_get_info
,
316 [PA_COMMAND_GET_SINK_INFO_LIST
] = command_get_info_list
,
317 [PA_COMMAND_GET_SOURCE_INFO_LIST
] = command_get_info_list
,
318 [PA_COMMAND_GET_MODULE_INFO_LIST
] = command_get_info_list
,
319 [PA_COMMAND_GET_CLIENT_INFO_LIST
] = command_get_info_list
,
320 [PA_COMMAND_GET_CARD_INFO_LIST
] = command_get_info_list
,
321 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST
] = command_get_info_list
,
322 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
] = command_get_info_list
,
323 [PA_COMMAND_GET_SAMPLE_INFO_LIST
] = command_get_info_list
,
324 [PA_COMMAND_GET_SERVER_INFO
] = command_get_server_info
,
325 [PA_COMMAND_SUBSCRIBE
] = command_subscribe
,
327 [PA_COMMAND_SET_SINK_VOLUME
] = command_set_volume
,
328 [PA_COMMAND_SET_SINK_INPUT_VOLUME
] = command_set_volume
,
329 [PA_COMMAND_SET_SOURCE_VOLUME
] = command_set_volume
,
331 [PA_COMMAND_SET_SINK_MUTE
] = command_set_mute
,
332 [PA_COMMAND_SET_SINK_INPUT_MUTE
] = command_set_mute
,
333 [PA_COMMAND_SET_SOURCE_MUTE
] = command_set_mute
,
335 [PA_COMMAND_SUSPEND_SINK
] = command_suspend
,
336 [PA_COMMAND_SUSPEND_SOURCE
] = command_suspend
,
338 [PA_COMMAND_CORK_PLAYBACK_STREAM
] = command_cork_playback_stream
,
339 [PA_COMMAND_FLUSH_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
340 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
341 [PA_COMMAND_PREBUF_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
343 [PA_COMMAND_CORK_RECORD_STREAM
] = command_cork_record_stream
,
344 [PA_COMMAND_FLUSH_RECORD_STREAM
] = command_flush_record_stream
,
346 [PA_COMMAND_SET_DEFAULT_SINK
] = command_set_default_sink_or_source
,
347 [PA_COMMAND_SET_DEFAULT_SOURCE
] = command_set_default_sink_or_source
,
348 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME
] = command_set_stream_name
,
349 [PA_COMMAND_SET_RECORD_STREAM_NAME
] = command_set_stream_name
,
350 [PA_COMMAND_KILL_CLIENT
] = command_kill
,
351 [PA_COMMAND_KILL_SINK_INPUT
] = command_kill
,
352 [PA_COMMAND_KILL_SOURCE_OUTPUT
] = command_kill
,
353 [PA_COMMAND_LOAD_MODULE
] = command_load_module
,
354 [PA_COMMAND_UNLOAD_MODULE
] = command_unload_module
,
356 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE
] = NULL
,
357 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE
] = NULL
,
358 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE
] = NULL
,
359 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE
] = NULL
,
361 [PA_COMMAND_MOVE_SINK_INPUT
] = command_move_stream
,
362 [PA_COMMAND_MOVE_SOURCE_OUTPUT
] = command_move_stream
,
364 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
365 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
367 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
368 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
370 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
] = command_update_proplist
,
371 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
] = command_update_proplist
,
372 [PA_COMMAND_UPDATE_CLIENT_PROPLIST
] = command_update_proplist
,
374 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
] = command_remove_proplist
,
375 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
] = command_remove_proplist
,
376 [PA_COMMAND_REMOVE_CLIENT_PROPLIST
] = command_remove_proplist
,
378 [PA_COMMAND_SET_CARD_PROFILE
] = command_set_card_profile
,
380 [PA_COMMAND_SET_SINK_PORT
] = command_set_sink_or_source_port
,
381 [PA_COMMAND_SET_SOURCE_PORT
] = command_set_sink_or_source_port
,
383 [PA_COMMAND_EXTENSION
] = command_extension
386 /* structure management */
388 /* Called from main context */
389 static void upload_stream_unlink(upload_stream
*s
) {
395 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
396 s
->connection
= NULL
;
397 upload_stream_unref(s
);
400 /* Called from main context */
401 static void upload_stream_free(pa_object
*o
) {
402 upload_stream
*s
= UPLOAD_STREAM(o
);
405 upload_stream_unlink(s
);
410 pa_proplist_free(s
->proplist
);
412 if (s
->memchunk
.memblock
)
413 pa_memblock_unref(s
->memchunk
.memblock
);
418 /* Called from main context */
419 static upload_stream
* upload_stream_new(
420 pa_native_connection
*c
,
421 const pa_sample_spec
*ss
,
422 const pa_channel_map
*map
,
432 pa_assert(length
> 0);
435 s
= pa_msgobject_new(upload_stream
);
436 s
->parent
.parent
.parent
.free
= upload_stream_free
;
438 s
->sample_spec
= *ss
;
439 s
->channel_map
= *map
;
440 s
->name
= pa_xstrdup(name
);
441 pa_memchunk_reset(&s
->memchunk
);
443 s
->proplist
= pa_proplist_copy(p
);
444 pa_proplist_update(s
->proplist
, PA_UPDATE_MERGE
, c
->client
->proplist
);
446 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
451 /* Called from main context */
452 static void record_stream_unlink(record_stream
*s
) {
458 if (s
->source_output
) {
459 pa_source_output_unlink(s
->source_output
);
460 pa_source_output_unref(s
->source_output
);
461 s
->source_output
= NULL
;
464 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->record_streams
, s
, NULL
) == s
);
465 s
->connection
= NULL
;
466 record_stream_unref(s
);
469 /* Called from main context */
470 static void record_stream_free(pa_object
*o
) {
471 record_stream
*s
= RECORD_STREAM(o
);
474 record_stream_unlink(s
);
476 pa_memblockq_free(s
->memblockq
);
480 /* Called from main context */
481 static int record_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
482 record_stream
*s
= RECORD_STREAM(o
);
483 record_stream_assert_ref(s
);
490 case RECORD_STREAM_MESSAGE_POST_DATA
:
492 /* We try to keep up to date with how many bytes are
493 * currently on the fly */
494 pa_atomic_sub(&s
->on_the_fly
, chunk
->length
);
496 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
497 /* pa_log_warn("Failed to push data into output queue."); */
501 if (!pa_pstream_is_pending(s
->connection
->pstream
))
502 native_connection_send_memblock(s
->connection
);
510 /* Called from main context */
511 static void fix_record_buffer_attr_pre(record_stream
*s
) {
514 pa_usec_t orig_fragsize_usec
, fragsize_usec
, source_usec
;
518 /* This function will be called from the main thread, before as
519 * well as after the source output has been activated using
520 * pa_source_output_put()! That means it may not touch any
521 * ->thread_info data! */
523 frame_size
= pa_frame_size(&s
->source_output
->sample_spec
);
525 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
526 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
527 if (s
->buffer_attr
.maxlength
<= 0)
528 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
530 if (s
->buffer_attr
.fragsize
== (uint32_t) -1)
531 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC
*PA_USEC_PER_MSEC
, &s
->source_output
->sample_spec
);
532 if (s
->buffer_attr
.fragsize
<= 0)
533 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
535 orig_fragsize_usec
= fragsize_usec
= pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &s
->source_output
->sample_spec
);
537 if (s
->early_requests
) {
539 /* In early request mode we need to emulate the classic
540 * fragment-based playback model. We do this setting the source
541 * latency to the fragment size. */
543 source_usec
= fragsize_usec
;
545 } else if (s
->adjust_latency
) {
547 /* So, the user asked us to adjust the latency according to
548 * what the source can provide. Half the latency will be
549 * spent on the hw buffer, half of it in the async buffer
550 * queue we maintain for each client. */
552 source_usec
= fragsize_usec
/2;
556 /* Ok, the user didn't ask us to adjust the latency, hence we
559 source_usec
= (pa_usec_t
) -1;
562 if (source_usec
!= (pa_usec_t
) -1)
563 s
->configured_source_latency
= pa_source_output_set_requested_latency(s
->source_output
, source_usec
);
565 s
->configured_source_latency
= 0;
567 if (s
->early_requests
) {
569 /* Ok, we didn't necessarily get what we were asking for, so
570 * let's tell the user */
572 fragsize_usec
= s
->configured_source_latency
;
574 } else if (s
->adjust_latency
) {
576 /* Now subtract what we actually got */
578 if (fragsize_usec
>= s
->configured_source_latency
*2)
579 fragsize_usec
-= s
->configured_source_latency
;
581 fragsize_usec
= s
->configured_source_latency
;
584 if (pa_usec_to_bytes(orig_fragsize_usec
, &s
->source_output
->sample_spec
) !=
585 pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
))
587 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
);
589 if (s
->buffer_attr
.fragsize
<= 0)
590 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
593 /* Called from main context */
594 static void fix_record_buffer_attr_post(record_stream
*s
) {
599 /* This function will be called from the main thread, before as
600 * well as after the source output has been activated using
601 * pa_source_output_put()! That means it may not touch and
602 * ->thread_info data! */
604 base
= pa_frame_size(&s
->source_output
->sample_spec
);
606 s
->buffer_attr
.fragsize
= (s
->buffer_attr
.fragsize
/base
)*base
;
607 if (s
->buffer_attr
.fragsize
<= 0)
608 s
->buffer_attr
.fragsize
= base
;
610 if (s
->buffer_attr
.fragsize
> s
->buffer_attr
.maxlength
)
611 s
->buffer_attr
.fragsize
= s
->buffer_attr
.maxlength
;
614 /* Called from main context */
615 static record_stream
* record_stream_new(
616 pa_native_connection
*c
,
620 pa_bool_t peak_detect
,
621 pa_buffer_attr
*attr
,
622 pa_source_output_flags_t flags
,
624 pa_bool_t adjust_latency
,
625 pa_sink_input
*direct_on_input
,
626 pa_bool_t early_requests
,
630 pa_source_output
*source_output
= NULL
;
631 pa_source_output_new_data data
;
638 pa_source_output_new_data_init(&data
);
640 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
641 data
.driver
= __FILE__
;
642 data
.module
= c
->options
->module
;
643 data
.client
= c
->client
;
644 data
.source
= source
;
645 data
.direct_on_input
= direct_on_input
;
646 pa_source_output_new_data_set_sample_spec(&data
, ss
);
647 pa_source_output_new_data_set_channel_map(&data
, map
);
649 data
.resample_method
= PA_RESAMPLER_PEAKS
;
652 *ret
= -pa_source_output_new(&source_output
, c
->protocol
->core
, &data
);
654 pa_source_output_new_data_done(&data
);
659 s
= pa_msgobject_new(record_stream
);
660 s
->parent
.parent
.free
= record_stream_free
;
661 s
->parent
.process_msg
= record_stream_process_msg
;
663 s
->source_output
= source_output
;
664 s
->buffer_attr
= *attr
;
665 s
->adjust_latency
= adjust_latency
;
666 s
->early_requests
= early_requests
;
667 pa_atomic_store(&s
->on_the_fly
, 0);
669 s
->source_output
->parent
.process_msg
= source_output_process_msg
;
670 s
->source_output
->push
= source_output_push_cb
;
671 s
->source_output
->kill
= source_output_kill_cb
;
672 s
->source_output
->get_latency
= source_output_get_latency_cb
;
673 s
->source_output
->moving
= source_output_moving_cb
;
674 s
->source_output
->suspend
= source_output_suspend_cb
;
675 s
->source_output
->send_event
= source_output_send_event_cb
;
676 s
->source_output
->userdata
= s
;
678 fix_record_buffer_attr_pre(s
);
680 s
->memblockq
= pa_memblockq_new(
682 s
->buffer_attr
.maxlength
,
684 pa_frame_size(&source_output
->sample_spec
),
690 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
691 fix_record_buffer_attr_post(s
);
693 *ss
= s
->source_output
->sample_spec
;
694 *map
= s
->source_output
->channel_map
;
696 pa_idxset_put(c
->record_streams
, s
, &s
->index
);
698 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
699 ((double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) + (double) s
->configured_source_latency
) / PA_USEC_PER_MSEC
,
700 (double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) / PA_USEC_PER_MSEC
,
701 (double) s
->configured_source_latency
/ PA_USEC_PER_MSEC
);
703 pa_source_output_put(s
->source_output
);
707 /* Called from main context */
708 static void record_stream_send_killed(record_stream
*r
) {
710 record_stream_assert_ref(r
);
712 t
= pa_tagstruct_new(NULL
, 0);
713 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_KILLED
);
714 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
715 pa_tagstruct_putu32(t
, r
->index
);
716 pa_pstream_send_tagstruct(r
->connection
->pstream
, t
);
719 /* Called from main context */
720 static void playback_stream_unlink(playback_stream
*s
) {
727 pa_sink_input_unlink(s
->sink_input
);
728 pa_sink_input_unref(s
->sink_input
);
729 s
->sink_input
= NULL
;
732 if (s
->drain_request
)
733 pa_pstream_send_error(s
->connection
->pstream
, s
->drain_tag
, PA_ERR_NOENTITY
);
735 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
736 s
->connection
= NULL
;
737 playback_stream_unref(s
);
740 /* Called from main context */
741 static void playback_stream_free(pa_object
* o
) {
742 playback_stream
*s
= PLAYBACK_STREAM(o
);
745 playback_stream_unlink(s
);
747 pa_memblockq_free(s
->memblockq
);
751 /* Called from main context */
752 static int playback_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
753 playback_stream
*s
= PLAYBACK_STREAM(o
);
754 playback_stream_assert_ref(s
);
761 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
: {
766 if ((l
= pa_atomic_load(&s
->missing
)) <= 0)
769 if (pa_atomic_cmpxchg(&s
->missing
, l
, 0))
773 t
= pa_tagstruct_new(NULL
, 0);
774 pa_tagstruct_putu32(t
, PA_COMMAND_REQUEST
);
775 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
776 pa_tagstruct_putu32(t
, s
->index
);
777 pa_tagstruct_putu32(t
, (uint32_t) l
);
778 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
780 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
784 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW
: {
787 /* pa_log("signalling underflow"); */
789 /* Report that we're empty */
790 t
= pa_tagstruct_new(NULL
, 0);
791 pa_tagstruct_putu32(t
, PA_COMMAND_UNDERFLOW
);
792 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
793 pa_tagstruct_putu32(t
, s
->index
);
794 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
798 case PLAYBACK_STREAM_MESSAGE_OVERFLOW
: {
801 /* Notify the user we're overflowed*/
802 t
= pa_tagstruct_new(NULL
, 0);
803 pa_tagstruct_putu32(t
, PA_COMMAND_OVERFLOW
);
804 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
805 pa_tagstruct_putu32(t
, s
->index
);
806 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
810 case PLAYBACK_STREAM_MESSAGE_STARTED
:
812 if (s
->connection
->version
>= 13) {
815 /* Notify the user we started playback */
816 t
= pa_tagstruct_new(NULL
, 0);
817 pa_tagstruct_putu32(t
, PA_COMMAND_STARTED
);
818 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
819 pa_tagstruct_putu32(t
, s
->index
);
820 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
825 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
:
826 pa_pstream_send_simple_ack(s
->connection
->pstream
, PA_PTR_TO_UINT(userdata
));
829 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
:
831 s
->buffer_attr
.tlength
= (uint32_t) offset
;
833 if (s
->connection
->version
>= 15) {
836 t
= pa_tagstruct_new(NULL
, 0);
837 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
);
838 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
839 pa_tagstruct_putu32(t
, s
->index
);
840 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
841 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
842 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
843 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
844 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
845 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
854 /* Called from main context */
855 static void fix_playback_buffer_attr(playback_stream
*s
) {
856 size_t frame_size
, max_prebuf
;
857 pa_usec_t orig_tlength_usec
, tlength_usec
, orig_minreq_usec
, minreq_usec
, sink_usec
;
861 /* This function will be called from the main thread, before as
862 * well as after the sink input has been activated using
863 * pa_sink_input_put()! That means it may not touch any
864 * ->thread_info data, such as the memblockq! */
866 frame_size
= pa_frame_size(&s
->sink_input
->sample_spec
);
868 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
869 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
870 if (s
->buffer_attr
.maxlength
<= 0)
871 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
873 if (s
->buffer_attr
.tlength
== (uint32_t) -1)
874 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
875 if (s
->buffer_attr
.tlength
<= 0)
876 s
->buffer_attr
.tlength
= (uint32_t) frame_size
;
878 if (s
->buffer_attr
.minreq
== (uint32_t) -1)
879 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
880 if (s
->buffer_attr
.minreq
<= 0)
881 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
883 if (s
->buffer_attr
.tlength
< s
->buffer_attr
.minreq
+frame_size
)
884 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
+(uint32_t) frame_size
;
886 orig_tlength_usec
= tlength_usec
= pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
);
887 orig_minreq_usec
= minreq_usec
= pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
);
889 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
890 (double) tlength_usec
/ PA_USEC_PER_MSEC
,
891 (double) minreq_usec
/ PA_USEC_PER_MSEC
);
893 if (s
->early_requests
) {
895 /* In early request mode we need to emulate the classic
896 * fragment-based playback model. We do this setting the sink
897 * latency to the fragment size. */
899 sink_usec
= minreq_usec
;
900 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
902 } else if (s
->adjust_latency
) {
904 /* So, the user asked us to adjust the latency of the stream
905 * buffer according to the what the sink can provide. The
906 * tlength passed in shall be the overall latency. Roughly
907 * half the latency will be spent on the hw buffer, the other
908 * half of it in the async buffer queue we maintain for each
909 * client. In between we'll have a safety space of size
910 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
911 * empty and needs to be filled, then our buffer must have
912 * enough data to fulfill this request immediatly and thus
913 * have at least the same tlength as the size of the hw
914 * buffer. It additionally needs space for 2 times minreq
915 * because if the buffer ran empty and a partial fillup
916 * happens immediately on the next iteration we need to be
917 * able to fulfill it and give the application also minreq
918 * time to fill it up again for the next request Makes 2 times
919 * minreq in plus.. */
921 if (tlength_usec
> minreq_usec
*2)
922 sink_usec
= (tlength_usec
- minreq_usec
*2)/2;
926 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
930 /* Ok, the user didn't ask us to adjust the latency, but we
931 * still need to make sure that the parameters from the user
934 if (tlength_usec
> minreq_usec
*2)
935 sink_usec
= (tlength_usec
- minreq_usec
*2);
939 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
942 s
->configured_sink_latency
= pa_sink_input_set_requested_latency(s
->sink_input
, sink_usec
);
944 if (s
->early_requests
) {
946 /* Ok, we didn't necessarily get what we were asking for, so
947 * let's tell the user */
949 minreq_usec
= s
->configured_sink_latency
;
951 } else if (s
->adjust_latency
) {
953 /* Ok, we didn't necessarily get what we were asking for, so
954 * let's subtract from what we asked for for the remaining
957 if (tlength_usec
>= s
->configured_sink_latency
)
958 tlength_usec
-= s
->configured_sink_latency
;
961 /* FIXME: This is actually larger than necessary, since not all of
962 * the sink latency is actually rewritable. */
963 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
964 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
966 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
967 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
968 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
970 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
971 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
972 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
974 if (s
->buffer_attr
.minreq
<= 0) {
975 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
976 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
979 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
980 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
982 max_prebuf
= s
->buffer_attr
.tlength
+ (uint32_t)frame_size
- s
->buffer_attr
.minreq
;
984 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 ||
985 s
->buffer_attr
.prebuf
> max_prebuf
)
986 s
->buffer_attr
.prebuf
= max_prebuf
;
989 /* Called from main context */
990 static playback_stream
* playback_stream_new(
991 pa_native_connection
*c
,
1001 pa_sink_input_flags_t flags
,
1003 pa_bool_t adjust_latency
,
1004 pa_bool_t early_requests
,
1005 pa_bool_t relative_volume
,
1008 playback_stream
*s
, *ssync
;
1009 pa_sink_input
*sink_input
= NULL
;
1010 pa_memchunk silence
;
1012 int64_t start_index
;
1013 pa_sink_input_new_data data
;
1021 /* Find syncid group */
1022 for (ssync
= pa_idxset_first(c
->output_streams
, &idx
); ssync
; ssync
= pa_idxset_next(c
->output_streams
, &idx
)) {
1024 if (!playback_stream_isinstance(ssync
))
1027 if (ssync
->syncid
== syncid
)
1031 /* Synced streams must connect to the same sink */
1035 sink
= ssync
->sink_input
->sink
;
1036 else if (sink
!= ssync
->sink_input
->sink
) {
1037 *ret
= PA_ERR_INVALID
;
1042 pa_sink_input_new_data_init(&data
);
1044 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1045 data
.driver
= __FILE__
;
1046 data
.module
= c
->options
->module
;
1047 data
.client
= c
->client
;
1050 data
.save_sink
= TRUE
;
1052 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1053 pa_sink_input_new_data_set_channel_map(&data
, map
);
1055 pa_sink_input_new_data_set_volume(&data
, volume
);
1056 data
.volume_is_absolute
= !relative_volume
;
1057 data
.save_volume
= TRUE
;
1060 pa_sink_input_new_data_set_muted(&data
, muted
);
1061 data
.save_muted
= TRUE
;
1063 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1066 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
);
1068 pa_sink_input_new_data_done(&data
);
1073 s
= pa_msgobject_new(playback_stream
);
1074 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1075 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1078 s
->sink_input
= sink_input
;
1079 s
->is_underrun
= TRUE
;
1080 s
->drain_request
= FALSE
;
1081 pa_atomic_store(&s
->missing
, 0);
1082 s
->buffer_attr
= *a
;
1083 s
->adjust_latency
= adjust_latency
;
1084 s
->early_requests
= early_requests
;
1086 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1087 s
->sink_input
->pop
= sink_input_pop_cb
;
1088 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1089 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1090 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1091 s
->sink_input
->kill
= sink_input_kill_cb
;
1092 s
->sink_input
->moving
= sink_input_moving_cb
;
1093 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1094 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1095 s
->sink_input
->userdata
= s
;
1097 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1099 fix_playback_buffer_attr(s
);
1101 pa_sink_input_get_silence(sink_input
, &silence
);
1102 s
->memblockq
= pa_memblockq_new(
1104 s
->buffer_attr
.maxlength
,
1105 s
->buffer_attr
.tlength
,
1106 pa_frame_size(&sink_input
->sample_spec
),
1107 s
->buffer_attr
.prebuf
,
1108 s
->buffer_attr
.minreq
,
1111 pa_memblock_unref(silence
.memblock
);
1113 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1115 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1117 /* pa_log("missing original: %li", (long int) *missing); */
1119 *ss
= s
->sink_input
->sample_spec
;
1120 *map
= s
->sink_input
->channel_map
;
1122 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1124 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1125 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1126 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1127 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1128 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1130 pa_sink_input_put(s
->sink_input
);
1134 /* Called from IO context */
1135 static void playback_stream_request_bytes(playback_stream
*s
) {
1137 int previous_missing
;
1139 playback_stream_assert_ref(s
);
1141 m
= pa_memblockq_pop_missing(s
->memblockq
);
1143 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1144 /* (unsigned long) m, */
1145 /* pa_memblockq_get_tlength(s->memblockq), */
1146 /* pa_memblockq_get_minreq(s->memblockq), */
1147 /* pa_memblockq_get_length(s->memblockq), */
1148 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1153 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1155 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1156 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1158 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1159 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1160 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1163 /* Called from main context */
1164 static void playback_stream_send_killed(playback_stream
*p
) {
1166 playback_stream_assert_ref(p
);
1168 t
= pa_tagstruct_new(NULL
, 0);
1169 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1170 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1171 pa_tagstruct_putu32(t
, p
->index
);
1172 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1175 /* Called from main context */
1176 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1177 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1178 pa_native_connection_assert_ref(c
);
1185 case CONNECTION_MESSAGE_REVOKE
:
1186 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1189 case CONNECTION_MESSAGE_RELEASE
:
1190 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1197 /* Called from main context */
1198 static void native_connection_unlink(pa_native_connection
*c
) {
1207 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1210 pa_native_options_unref(c
->options
);
1212 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1213 record_stream_unlink(r
);
1215 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1216 if (playback_stream_isinstance(o
))
1217 playback_stream_unlink(PLAYBACK_STREAM(o
));
1219 upload_stream_unlink(UPLOAD_STREAM(o
));
1221 if (c
->subscription
)
1222 pa_subscription_free(c
->subscription
);
1225 pa_pstream_unlink(c
->pstream
);
1227 if (c
->auth_timeout_event
) {
1228 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1229 c
->auth_timeout_event
= NULL
;
1232 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1234 pa_native_connection_unref(c
);
1237 /* Called from main context */
1238 static void native_connection_free(pa_object
*o
) {
1239 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1243 native_connection_unlink(c
);
1245 pa_idxset_free(c
->record_streams
, NULL
, NULL
);
1246 pa_idxset_free(c
->output_streams
, NULL
, NULL
);
1248 pa_pdispatch_unref(c
->pdispatch
);
1249 pa_pstream_unref(c
->pstream
);
1250 pa_client_free(c
->client
);
1255 /* Called from main context */
1256 static void native_connection_send_memblock(pa_native_connection
*c
) {
1260 start
= PA_IDXSET_INVALID
;
1264 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1267 if (start
== PA_IDXSET_INVALID
)
1268 start
= c
->rrobin_index
;
1269 else if (start
== c
->rrobin_index
)
1272 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1273 pa_memchunk schunk
= chunk
;
1275 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1276 schunk
.length
= r
->buffer_attr
.fragsize
;
1278 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1280 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1281 pa_memblock_unref(schunk
.memblock
);
1288 /*** sink input callbacks ***/
1290 /* Called from thread context */
1291 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1292 playback_stream_assert_ref(s
);
1294 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1296 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1298 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1300 if (pa_memblockq_is_readable(s
->memblockq
)) {
1302 /* We just ended an underrun, let's ask the sink
1303 * for a complete rewind rewrite */
1305 pa_log_debug("Requesting rewind due to end of underrun.");
1306 pa_sink_input_request_rewind(s
->sink_input
,
1307 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (uint64_t) -1 ? 0 :
1308 s
->sink_input
->thread_info
.underrun_for
),
1309 FALSE
, TRUE
, FALSE
);
1315 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1317 if (indexw
< indexr
) {
1318 /* OK, the sink already asked for this data, so
1319 * let's have it usk us again */
1321 pa_log_debug("Requesting rewind due to rewrite.");
1322 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), TRUE
, FALSE
, FALSE
);
1326 playback_stream_request_bytes(s
);
1329 /* Called from thread context */
1330 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1331 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1334 pa_sink_input_assert_ref(i
);
1335 s
= PLAYBACK_STREAM(i
->userdata
);
1336 playback_stream_assert_ref(s
);
1340 case SINK_INPUT_MESSAGE_SEEK
: {
1343 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1345 /* The client side is incapable of accounting correctly
1346 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1347 * able to deal with that. */
1349 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1351 handle_seek(s
, windex
);
1355 case SINK_INPUT_MESSAGE_POST_DATA
: {
1360 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1362 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1364 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1366 if (pa_log_ratelimit())
1367 pa_log_warn("Failed to push data into queue");
1368 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1369 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, TRUE
);
1372 handle_seek(s
, windex
);
1374 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1379 case SINK_INPUT_MESSAGE_DRAIN
:
1380 case SINK_INPUT_MESSAGE_FLUSH
:
1381 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1382 case SINK_INPUT_MESSAGE_TRIGGER
: {
1385 pa_sink_input
*isync
;
1386 void (*func
)(pa_memblockq
*bq
);
1389 case SINK_INPUT_MESSAGE_FLUSH
:
1390 func
= pa_memblockq_flush_write
;
1393 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1394 func
= pa_memblockq_prebuf_force
;
1397 case SINK_INPUT_MESSAGE_DRAIN
:
1398 case SINK_INPUT_MESSAGE_TRIGGER
:
1399 func
= pa_memblockq_prebuf_disable
;
1403 pa_assert_not_reached();
1406 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1408 handle_seek(s
, windex
);
1410 /* Do the same for all other members in the sync group */
1411 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1412 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1413 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1414 func(ssync
->memblockq
);
1415 handle_seek(ssync
, windex
);
1418 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1419 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1420 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1421 func(ssync
->memblockq
);
1422 handle_seek(ssync
, windex
);
1425 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1426 if (!pa_memblockq_is_readable(s
->memblockq
))
1427 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1429 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1430 s
->drain_request
= TRUE
;
1437 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1438 /* Atomically get a snapshot of all timing parameters... */
1439 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1440 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1441 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1442 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1443 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1444 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1448 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1451 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1453 pa_memblockq_prebuf_force(s
->memblockq
);
1455 handle_seek(s
, windex
);
1457 /* Fall through to the default handler */
1461 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1462 pa_usec_t
*r
= userdata
;
1464 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1466 /* Fall through, the default handler will add in the extra
1467 * latency added by the resampler */
1471 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1472 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1473 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1478 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1481 /* Called from thread context */
1482 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1485 pa_sink_input_assert_ref(i
);
1486 s
= PLAYBACK_STREAM(i
->userdata
);
1487 playback_stream_assert_ref(s
);
1490 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1492 if (pa_memblockq_is_readable(s
->memblockq
))
1493 s
->is_underrun
= FALSE
;
1495 if (!s
->is_underrun
)
1496 pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i
->proplist
, PA_PROP_MEDIA_NAME
)), (unsigned long) pa_memblockq_get_length(s
->memblockq
));
1498 if (s
->drain_request
&& pa_sink_input_safe_to_remove(i
)) {
1499 s
->drain_request
= FALSE
;
1500 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
);
1501 } else if (!s
->is_underrun
)
1502 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UNDERFLOW
, NULL
, 0, NULL
, NULL
);
1504 s
->is_underrun
= TRUE
;
1506 playback_stream_request_bytes(s
);
1509 /* This call will not fail with prebuf=0, hence we check for
1510 underrun explicitly above */
1511 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1514 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1516 if (i
->thread_info
.underrun_for
> 0)
1517 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1519 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1520 playback_stream_request_bytes(s
);
1525 /* Called from thread context */
1526 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1529 pa_sink_input_assert_ref(i
);
1530 s
= PLAYBACK_STREAM(i
->userdata
);
1531 playback_stream_assert_ref(s
);
1533 /* If we are in an underrun, then we don't rewind */
1534 if (i
->thread_info
.underrun_for
> 0)
1537 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1540 /* Called from thread context */
1541 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1544 pa_sink_input_assert_ref(i
);
1545 s
= PLAYBACK_STREAM(i
->userdata
);
1546 playback_stream_assert_ref(s
);
1548 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1551 /* Called from thread context */
1552 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1554 size_t new_tlength
, old_tlength
;
1556 pa_sink_input_assert_ref(i
);
1557 s
= PLAYBACK_STREAM(i
->userdata
);
1558 playback_stream_assert_ref(s
);
1560 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1561 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1563 if (old_tlength
< new_tlength
) {
1564 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1565 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1566 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1568 if (new_tlength
== old_tlength
)
1569 pa_log_debug("Failed to increase tlength");
1571 pa_log_debug("Notifying client about increased tlength");
1572 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
);
1577 /* Called from main context */
1578 static void sink_input_kill_cb(pa_sink_input
*i
) {
1581 pa_sink_input_assert_ref(i
);
1582 s
= PLAYBACK_STREAM(i
->userdata
);
1583 playback_stream_assert_ref(s
);
1585 playback_stream_send_killed(s
);
1586 playback_stream_unlink(s
);
1589 /* Called from main context */
1590 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1594 pa_sink_input_assert_ref(i
);
1595 s
= PLAYBACK_STREAM(i
->userdata
);
1596 playback_stream_assert_ref(s
);
1598 if (s
->connection
->version
< 15)
1601 t
= pa_tagstruct_new(NULL
, 0);
1602 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1603 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1604 pa_tagstruct_putu32(t
, s
->index
);
1605 pa_tagstruct_puts(t
, event
);
1606 pa_tagstruct_put_proplist(t
, pl
);
1607 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1610 /* Called from main context */
1611 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
) {
1615 pa_sink_input_assert_ref(i
);
1616 s
= PLAYBACK_STREAM(i
->userdata
);
1617 playback_stream_assert_ref(s
);
1619 if (s
->connection
->version
< 12)
1622 t
= pa_tagstruct_new(NULL
, 0);
1623 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1624 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1625 pa_tagstruct_putu32(t
, s
->index
);
1626 pa_tagstruct_put_boolean(t
, suspend
);
1627 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1630 /* Called from main context */
1631 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1635 pa_sink_input_assert_ref(i
);
1636 s
= PLAYBACK_STREAM(i
->userdata
);
1637 playback_stream_assert_ref(s
);
1642 fix_playback_buffer_attr(s
);
1643 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1644 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1646 if (s
->connection
->version
< 12)
1649 t
= pa_tagstruct_new(NULL
, 0);
1650 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1651 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1652 pa_tagstruct_putu32(t
, s
->index
);
1653 pa_tagstruct_putu32(t
, dest
->index
);
1654 pa_tagstruct_puts(t
, dest
->name
);
1655 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1657 if (s
->connection
->version
>= 13) {
1658 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1659 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1660 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1661 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1662 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1665 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1668 /*** source_output callbacks ***/
1670 /* Called from thread context */
1671 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1672 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1675 pa_source_output_assert_ref(o
);
1676 s
= RECORD_STREAM(o
->userdata
);
1677 record_stream_assert_ref(s
);
1680 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1681 /* Atomically get a snapshot of all timing parameters... */
1682 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1683 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1684 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1688 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1691 /* Called from thread context */
1692 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1695 pa_source_output_assert_ref(o
);
1696 s
= RECORD_STREAM(o
->userdata
);
1697 record_stream_assert_ref(s
);
1700 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1701 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1704 static void source_output_kill_cb(pa_source_output
*o
) {
1707 pa_source_output_assert_ref(o
);
1708 s
= RECORD_STREAM(o
->userdata
);
1709 record_stream_assert_ref(s
);
1711 record_stream_send_killed(s
);
1712 record_stream_unlink(s
);
1715 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1718 pa_source_output_assert_ref(o
);
1719 s
= RECORD_STREAM(o
->userdata
);
1720 record_stream_assert_ref(s
);
1722 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1724 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1727 /* Called from main context */
1728 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1732 pa_source_output_assert_ref(o
);
1733 s
= RECORD_STREAM(o
->userdata
);
1734 record_stream_assert_ref(s
);
1736 if (s
->connection
->version
< 15)
1739 t
= pa_tagstruct_new(NULL
, 0);
1740 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1741 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1742 pa_tagstruct_putu32(t
, s
->index
);
1743 pa_tagstruct_puts(t
, event
);
1744 pa_tagstruct_put_proplist(t
, pl
);
1745 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1748 /* Called from main context */
1749 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
) {
1753 pa_source_output_assert_ref(o
);
1754 s
= RECORD_STREAM(o
->userdata
);
1755 record_stream_assert_ref(s
);
1757 if (s
->connection
->version
< 12)
1760 t
= pa_tagstruct_new(NULL
, 0);
1761 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1762 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1763 pa_tagstruct_putu32(t
, s
->index
);
1764 pa_tagstruct_put_boolean(t
, suspend
);
1765 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1768 /* Called from main context */
1769 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1773 pa_source_output_assert_ref(o
);
1774 s
= RECORD_STREAM(o
->userdata
);
1775 record_stream_assert_ref(s
);
1780 fix_record_buffer_attr_pre(s
);
1781 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1782 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1783 fix_record_buffer_attr_post(s
);
1785 if (s
->connection
->version
< 12)
1788 t
= pa_tagstruct_new(NULL
, 0);
1789 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1790 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1791 pa_tagstruct_putu32(t
, s
->index
);
1792 pa_tagstruct_putu32(t
, dest
->index
);
1793 pa_tagstruct_puts(t
, dest
->name
);
1794 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1796 if (s
->connection
->version
>= 13) {
1797 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1798 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1799 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1802 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1805 /*** pdispatch callbacks ***/
1807 static void protocol_error(pa_native_connection
*c
) {
1808 pa_log("protocol error, kicking client");
1809 native_connection_unlink(c
);
1812 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1813 if (!(expression)) { \
1814 pa_pstream_send_error((pstream), (tag), (error)); \
1819 static pa_tagstruct
*reply_new(uint32_t tag
) {
1820 pa_tagstruct
*reply
;
1822 reply
= pa_tagstruct_new(NULL
, 0);
1823 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1824 pa_tagstruct_putu32(reply
, tag
);
1828 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1829 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1831 uint32_t sink_index
, syncid
, missing
;
1832 pa_buffer_attr attr
;
1833 const char *name
= NULL
, *sink_name
;
1836 pa_tagstruct
*reply
;
1837 pa_sink
*sink
= NULL
;
1845 fix_channels
= FALSE
,
1847 variable_rate
= FALSE
,
1849 adjust_latency
= FALSE
,
1850 early_requests
= FALSE
,
1851 dont_inhibit_auto_suspend
= FALSE
,
1853 fail_on_suspend
= FALSE
,
1854 relative_volume
= FALSE
;
1855 pa_sink_input_flags_t flags
= 0;
1857 pa_bool_t volume_set
= TRUE
;
1858 int ret
= PA_ERR_INVALID
;
1860 pa_native_connection_assert_ref(c
);
1862 memset(&attr
, 0, sizeof(attr
));
1864 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
1867 PA_TAG_SAMPLE_SPEC
, &ss
,
1868 PA_TAG_CHANNEL_MAP
, &map
,
1869 PA_TAG_U32
, &sink_index
,
1870 PA_TAG_STRING
, &sink_name
,
1871 PA_TAG_U32
, &attr
.maxlength
,
1872 PA_TAG_BOOLEAN
, &corked
,
1873 PA_TAG_U32
, &attr
.tlength
,
1874 PA_TAG_U32
, &attr
.prebuf
,
1875 PA_TAG_U32
, &attr
.minreq
,
1876 PA_TAG_U32
, &syncid
,
1877 PA_TAG_CVOLUME
, &volume
,
1878 PA_TAG_INVALID
) < 0) {
1884 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
1885 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
1886 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
1887 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
1888 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
1889 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
1890 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
1891 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
1893 p
= pa_proplist_new();
1896 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
1898 if (c
->version
>= 12) {
1899 /* Since 0.9.8 the user can ask for a couple of additional flags */
1901 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
1902 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
1903 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
1904 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
1905 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
1906 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
1907 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
1910 pa_proplist_free(p
);
1915 if (c
->version
>= 13) {
1917 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
1918 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
1919 pa_tagstruct_get_proplist(t
, p
) < 0) {
1921 pa_proplist_free(p
);
1926 if (c
->version
>= 14) {
1928 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
1929 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
1931 pa_proplist_free(p
);
1936 if (c
->version
>= 15) {
1938 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
1939 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
1940 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
1942 pa_proplist_free(p
);
1947 if (c
->version
>= 17) {
1949 if (pa_tagstruct_get_boolean(t
, &relative_volume
) < 0) {
1951 pa_proplist_free(p
);
1956 if (!pa_tagstruct_eof(t
)) {
1958 pa_proplist_free(p
);
1962 if (sink_index
!= PA_INVALID_INDEX
) {
1964 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
1965 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
1966 pa_proplist_free(p
);
1970 } else if (sink_name
) {
1972 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
1973 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
1974 pa_proplist_free(p
);
1980 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
1981 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
1982 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
1983 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
1984 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
1985 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
1986 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
1987 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
1988 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
1989 (fail_on_suspend
? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND
|PA_SINK_INPUT_KILL_ON_SUSPEND
: 0);
1991 /* Only since protocol version 15 there's a seperate muted_set
1992 * flag. For older versions we synthesize it here */
1993 muted_set
= muted_set
|| muted
;
1995 s
= playback_stream_new(c
, sink
, &ss
, &map
, &attr
, volume_set
? &volume
: NULL
, muted
, muted_set
, syncid
, &missing
, flags
, p
, adjust_latency
, early_requests
, relative_volume
, &ret
);
1996 pa_proplist_free(p
);
1998 CHECK_VALIDITY(c
->pstream
, s
, tag
, ret
);
2000 reply
= reply_new(tag
);
2001 pa_tagstruct_putu32(reply
, s
->index
);
2002 pa_assert(s
->sink_input
);
2003 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
2004 pa_tagstruct_putu32(reply
, missing
);
2006 /* pa_log("initial request is %u", missing); */
2008 if (c
->version
>= 9) {
2009 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2011 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2012 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
2013 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
2014 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
2017 if (c
->version
>= 12) {
2018 /* Since 0.9.8 we support sending the chosen sample
2019 * spec/channel map/device/suspend status back to the
2022 pa_tagstruct_put_sample_spec(reply
, &ss
);
2023 pa_tagstruct_put_channel_map(reply
, &map
);
2025 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
2026 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
2028 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
2031 if (c
->version
>= 13)
2032 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
2034 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2037 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2038 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2041 pa_native_connection_assert_ref(c
);
2044 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2045 !pa_tagstruct_eof(t
)) {
2050 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2054 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2056 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2057 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2061 playback_stream_unlink(s
);
2065 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2067 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2068 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2072 record_stream_unlink(s
);
2076 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2079 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2080 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2084 upload_stream_unlink(s
);
2089 pa_assert_not_reached();
2092 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2095 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2096 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2098 pa_buffer_attr attr
;
2099 uint32_t source_index
;
2100 const char *name
= NULL
, *source_name
;
2103 pa_tagstruct
*reply
;
2104 pa_source
*source
= NULL
;
2111 fix_channels
= FALSE
,
2113 variable_rate
= FALSE
,
2114 adjust_latency
= FALSE
,
2115 peak_detect
= FALSE
,
2116 early_requests
= FALSE
,
2117 dont_inhibit_auto_suspend
= FALSE
,
2118 fail_on_suspend
= FALSE
;
2119 pa_source_output_flags_t flags
= 0;
2121 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2122 pa_sink_input
*direct_on_input
= NULL
;
2123 int ret
= PA_ERR_INVALID
;
2125 pa_native_connection_assert_ref(c
);
2128 memset(&attr
, 0, sizeof(attr
));
2130 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2131 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2132 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2133 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2134 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2135 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2136 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2137 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2142 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2143 CHECK_VALIDITY(c
->pstream
, !source_name
|| pa_namereg_is_valid_name_or_wildcard(source_name
, PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
);
2144 CHECK_VALIDITY(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
);
2145 CHECK_VALIDITY(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2146 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2147 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2148 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2150 p
= pa_proplist_new();
2153 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2155 if (c
->version
>= 12) {
2156 /* Since 0.9.8 the user can ask for a couple of additional flags */
2158 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2159 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2160 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2161 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2162 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2163 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2164 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2167 pa_proplist_free(p
);
2172 if (c
->version
>= 13) {
2174 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2175 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2176 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2177 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2179 pa_proplist_free(p
);
2184 if (c
->version
>= 14) {
2186 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2188 pa_proplist_free(p
);
2193 if (c
->version
>= 15) {
2195 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2196 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2198 pa_proplist_free(p
);
2203 if (!pa_tagstruct_eof(t
)) {
2205 pa_proplist_free(p
);
2209 if (source_index
!= PA_INVALID_INDEX
) {
2211 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2212 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2213 pa_proplist_free(p
);
2217 } else if (source_name
) {
2219 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2220 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2221 pa_proplist_free(p
);
2226 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2228 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2229 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2230 pa_proplist_free(p
);
2236 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2237 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2238 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2239 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2240 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2241 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2242 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2243 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2244 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2245 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0);
2247 s
= record_stream_new(c
, source
, &ss
, &map
, peak_detect
, &attr
, flags
, p
, adjust_latency
, direct_on_input
, early_requests
, &ret
);
2248 pa_proplist_free(p
);
2250 CHECK_VALIDITY(c
->pstream
, s
, tag
, ret
);
2252 reply
= reply_new(tag
);
2253 pa_tagstruct_putu32(reply
, s
->index
);
2254 pa_assert(s
->source_output
);
2255 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2257 if (c
->version
>= 9) {
2258 /* Since 0.9 we support sending the buffer metrics back to the client */
2260 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2261 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2264 if (c
->version
>= 12) {
2265 /* Since 0.9.8 we support sending the chosen sample
2266 * spec/channel map/device/suspend status back to the
2269 pa_tagstruct_put_sample_spec(reply
, &ss
);
2270 pa_tagstruct_put_channel_map(reply
, &map
);
2272 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2273 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2275 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2278 if (c
->version
>= 13)
2279 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2281 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2284 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2285 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2288 pa_native_connection_assert_ref(c
);
2291 if (!pa_tagstruct_eof(t
)) {
2296 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2297 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2298 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2300 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2302 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2305 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2306 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2308 pa_tagstruct
*reply
;
2309 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2311 pa_native_connection_assert_ref(c
);
2314 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2315 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2316 !pa_tagstruct_eof(t
)) {
2321 /* Minimum supported version */
2322 if (c
->version
< 8) {
2323 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2327 /* Starting with protocol version 13 the MSB of the version tag
2328 reflects if shm is available for this pa_native_connection or
2330 if (c
->version
>= 13) {
2331 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2332 c
->version
&= 0x7FFFFFFFU
;
2335 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2337 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2339 if (!c
->authorized
) {
2340 pa_bool_t success
= FALSE
;
2343 const pa_creds
*creds
;
2345 if ((creds
= pa_pdispatch_creds(pd
))) {
2346 if (creds
->uid
== getuid())
2348 else if (c
->options
->auth_group
) {
2352 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2353 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2354 else if (gid
== creds
->gid
)
2358 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2359 pa_log_warn("Failed to check group membership.");
2365 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2366 (unsigned long) creds
->uid
,
2367 (unsigned long) creds
->gid
,
2372 if (!success
&& c
->options
->auth_cookie
) {
2375 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2376 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2381 pa_log_warn("Denied access to client with invalid authorization data.");
2382 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2386 c
->authorized
= TRUE
;
2387 if (c
->auth_timeout_event
) {
2388 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2389 c
->auth_timeout_event
= NULL
;
2393 /* Enable shared memory support if possible */
2395 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2398 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2401 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2406 /* Only enable SHM if both sides are owned by the same
2407 * user. This is a security measure because otherwise data
2408 * private to the user might leak. */
2410 const pa_creds
*creds
;
2411 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2416 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2417 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2419 reply
= reply_new(tag
);
2420 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2424 /* SHM support is only enabled after both sides made sure they are the same user. */
2428 ucred
.uid
= getuid();
2429 ucred
.gid
= getgid();
2431 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2434 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2438 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2439 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2440 const char *name
= NULL
;
2442 pa_tagstruct
*reply
;
2444 pa_native_connection_assert_ref(c
);
2447 p
= pa_proplist_new();
2449 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2450 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2451 !pa_tagstruct_eof(t
)) {
2454 pa_proplist_free(p
);
2459 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2460 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2461 pa_proplist_free(p
);
2465 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2466 pa_proplist_free(p
);
2468 reply
= reply_new(tag
);
2470 if (c
->version
>= 13)
2471 pa_tagstruct_putu32(reply
, c
->client
->index
);
2473 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2476 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2477 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2479 uint32_t idx
= PA_IDXSET_INVALID
;
2481 pa_native_connection_assert_ref(c
);
2484 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2485 !pa_tagstruct_eof(t
)) {
2490 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2491 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
);
2493 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2495 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2499 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2500 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2501 idx
= source
->index
;
2504 if (idx
== PA_IDXSET_INVALID
)
2505 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2507 pa_tagstruct
*reply
;
2508 reply
= reply_new(tag
);
2509 pa_tagstruct_putu32(reply
, idx
);
2510 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2514 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2515 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2519 pa_native_connection_assert_ref(c
);
2522 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2523 !pa_tagstruct_eof(t
)) {
2528 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2529 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2530 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2531 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2533 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
);
2536 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2537 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2538 pa_tagstruct
*reply
;
2539 const pa_mempool_stat
*stat
;
2541 pa_native_connection_assert_ref(c
);
2544 if (!pa_tagstruct_eof(t
)) {
2549 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2551 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2553 reply
= reply_new(tag
);
2554 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2555 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2556 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2557 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2558 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2559 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2562 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2563 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2564 pa_tagstruct
*reply
;
2566 struct timeval tv
, now
;
2569 pa_native_connection_assert_ref(c
);
2572 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2573 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2574 !pa_tagstruct_eof(t
)) {
2579 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2580 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2581 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2582 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2584 /* Get an atomic snapshot of all timing parameters */
2585 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);
2587 reply
= reply_new(tag
);
2588 pa_tagstruct_put_usec(reply
,
2589 s
->current_sink_latency
+
2590 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2591 pa_tagstruct_put_usec(reply
, 0);
2592 pa_tagstruct_put_boolean(reply
,
2593 s
->playing_for
> 0 &&
2594 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2595 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2596 pa_tagstruct_put_timeval(reply
, &tv
);
2597 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2598 pa_tagstruct_puts64(reply
, s
->write_index
);
2599 pa_tagstruct_puts64(reply
, s
->read_index
);
2601 if (c
->version
>= 13) {
2602 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2603 pa_tagstruct_putu64(reply
, s
->playing_for
);
2606 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2609 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2610 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2611 pa_tagstruct
*reply
;
2613 struct timeval tv
, now
;
2616 pa_native_connection_assert_ref(c
);
2619 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2620 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2621 !pa_tagstruct_eof(t
)) {
2626 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2627 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2628 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2630 /* Get an atomic snapshot of all timing parameters */
2631 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);
2633 reply
= reply_new(tag
);
2634 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2635 pa_tagstruct_put_usec(reply
,
2636 s
->current_source_latency
+
2637 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2638 pa_tagstruct_put_boolean(reply
,
2639 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2640 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2641 pa_tagstruct_put_timeval(reply
, &tv
);
2642 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2643 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2644 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2645 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2648 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2649 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2652 const char *name
= NULL
;
2655 pa_tagstruct
*reply
;
2658 pa_native_connection_assert_ref(c
);
2661 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2662 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2663 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2664 pa_tagstruct_getu32(t
, &length
) < 0) {
2669 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2670 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2671 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2672 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2673 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2674 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2676 p
= pa_proplist_new();
2678 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2679 !pa_tagstruct_eof(t
)) {
2682 pa_proplist_free(p
);
2686 if (c
->version
< 13)
2687 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2689 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2690 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2692 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2693 pa_proplist_free(p
);
2694 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2697 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2698 pa_proplist_free(p
);
2700 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2702 reply
= reply_new(tag
);
2703 pa_tagstruct_putu32(reply
, s
->index
);
2704 pa_tagstruct_putu32(reply
, length
);
2705 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2708 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2709 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2714 pa_native_connection_assert_ref(c
);
2717 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2718 !pa_tagstruct_eof(t
)) {
2723 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2725 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2726 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2727 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2729 if (!s
->memchunk
.memblock
)
2730 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
2731 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2732 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2734 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2736 upload_stream_unlink(s
);
2739 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2740 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2741 uint32_t sink_index
;
2744 const char *name
, *sink_name
;
2747 pa_tagstruct
*reply
;
2749 pa_native_connection_assert_ref(c
);
2752 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2754 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
2755 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
2756 pa_tagstruct_getu32(t
, &volume
) < 0 ||
2757 pa_tagstruct_gets(t
, &name
) < 0) {
2762 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
2763 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
2764 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2765 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2767 if (sink_index
!= PA_INVALID_INDEX
)
2768 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
2770 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
2772 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
2774 p
= pa_proplist_new();
2776 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2777 !pa_tagstruct_eof(t
)) {
2779 pa_proplist_free(p
);
2783 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
2785 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
2786 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2787 pa_proplist_free(p
);
2791 pa_proplist_free(p
);
2793 reply
= reply_new(tag
);
2795 if (c
->version
>= 13)
2796 pa_tagstruct_putu32(reply
, idx
);
2798 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2801 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2802 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2805 pa_native_connection_assert_ref(c
);
2808 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2809 !pa_tagstruct_eof(t
)) {
2814 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2815 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2817 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
2818 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2822 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2825 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
2828 pa_assert(original
);
2832 if (c
->version
< 12) {
2833 /* Before protocol version 12 we didn't support S32 samples,
2834 * so we need to lie about this to the client */
2836 if (fixed
->format
== PA_SAMPLE_S32LE
)
2837 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
2838 if (fixed
->format
== PA_SAMPLE_S32BE
)
2839 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
2842 if (c
->version
< 15) {
2843 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
2844 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
2845 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
2846 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
2850 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
2851 pa_sample_spec fixed_ss
;
2854 pa_sink_assert_ref(sink
);
2856 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
2860 PA_TAG_U32
, sink
->index
,
2861 PA_TAG_STRING
, sink
->name
,
2862 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
2863 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
2864 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
2865 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
2866 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
2867 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
2868 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
2869 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
2870 PA_TAG_USEC
, pa_sink_get_latency(sink
),
2871 PA_TAG_STRING
, sink
->driver
,
2872 PA_TAG_U32
, sink
->flags
,
2875 if (c
->version
>= 13) {
2876 pa_tagstruct_put_proplist(t
, sink
->proplist
);
2877 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
2880 if (c
->version
>= 15) {
2881 pa_tagstruct_put_volume(t
, sink
->base_volume
);
2882 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
2883 pa_log_error("Internal sink state is invalid.");
2884 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
2885 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
2886 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
2889 if (c
->version
>= 16) {
2890 pa_tagstruct_putu32(t
, sink
->ports
? pa_hashmap_size(sink
->ports
) : 0);
2896 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
2897 pa_tagstruct_puts(t
, p
->name
);
2898 pa_tagstruct_puts(t
, p
->description
);
2899 pa_tagstruct_putu32(t
, p
->priority
);
2903 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
2907 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
2908 pa_sample_spec fixed_ss
;
2911 pa_source_assert_ref(source
);
2913 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
2917 PA_TAG_U32
, source
->index
,
2918 PA_TAG_STRING
, source
->name
,
2919 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
2920 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
2921 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
2922 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
2923 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
2924 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
2925 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
2926 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
2927 PA_TAG_USEC
, pa_source_get_latency(source
),
2928 PA_TAG_STRING
, source
->driver
,
2929 PA_TAG_U32
, source
->flags
,
2932 if (c
->version
>= 13) {
2933 pa_tagstruct_put_proplist(t
, source
->proplist
);
2934 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
2937 if (c
->version
>= 15) {
2938 pa_tagstruct_put_volume(t
, source
->base_volume
);
2939 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
2940 pa_log_error("Internal source state is invalid.");
2941 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
2942 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
2943 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
2946 if (c
->version
>= 16) {
2948 pa_tagstruct_putu32(t
, source
->ports
? pa_hashmap_size(source
->ports
) : 0);
2950 if (source
->ports
) {
2954 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
2955 pa_tagstruct_puts(t
, p
->name
);
2956 pa_tagstruct_puts(t
, p
->description
);
2957 pa_tagstruct_putu32(t
, p
->priority
);
2961 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
2965 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
2969 pa_tagstruct_putu32(t
, client
->index
);
2970 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
2971 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
2972 pa_tagstruct_puts(t
, client
->driver
);
2974 if (c
->version
>= 13)
2975 pa_tagstruct_put_proplist(t
, client
->proplist
);
2978 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
2985 pa_tagstruct_putu32(t
, card
->index
);
2986 pa_tagstruct_puts(t
, card
->name
);
2987 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
2988 pa_tagstruct_puts(t
, card
->driver
);
2990 pa_tagstruct_putu32(t
, card
->profiles
? pa_hashmap_size(card
->profiles
) : 0);
2992 if (card
->profiles
) {
2993 while ((p
= pa_hashmap_iterate(card
->profiles
, &state
, NULL
))) {
2994 pa_tagstruct_puts(t
, p
->name
);
2995 pa_tagstruct_puts(t
, p
->description
);
2996 pa_tagstruct_putu32(t
, p
->n_sinks
);
2997 pa_tagstruct_putu32(t
, p
->n_sources
);
2998 pa_tagstruct_putu32(t
, p
->priority
);
3002 pa_tagstruct_puts(t
, card
->active_profile
? card
->active_profile
->name
: NULL
);
3003 pa_tagstruct_put_proplist(t
, card
->proplist
);
3006 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3010 pa_tagstruct_putu32(t
, module
->index
);
3011 pa_tagstruct_puts(t
, module
->name
);
3012 pa_tagstruct_puts(t
, module
->argument
);
3013 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3015 if (c
->version
< 15)
3016 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
3018 if (c
->version
>= 15)
3019 pa_tagstruct_put_proplist(t
, module
->proplist
);
3022 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3023 pa_sample_spec fixed_ss
;
3024 pa_usec_t sink_latency
;
3028 pa_sink_input_assert_ref(s
);
3030 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3032 pa_tagstruct_putu32(t
, s
->index
);
3033 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3034 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3035 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3036 pa_tagstruct_putu32(t
, s
->sink
->index
);
3037 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3038 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3039 pa_tagstruct_put_cvolume(t
, pa_sink_input_get_volume(s
, &v
, TRUE
));
3040 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3041 pa_tagstruct_put_usec(t
, sink_latency
);
3042 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3043 pa_tagstruct_puts(t
, s
->driver
);
3044 if (c
->version
>= 11)
3045 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
3046 if (c
->version
>= 13)
3047 pa_tagstruct_put_proplist(t
, s
->proplist
);
3050 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3051 pa_sample_spec fixed_ss
;
3052 pa_usec_t source_latency
;
3055 pa_source_output_assert_ref(s
);
3057 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3059 pa_tagstruct_putu32(t
, s
->index
);
3060 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3061 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3062 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3063 pa_tagstruct_putu32(t
, s
->source
->index
);
3064 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3065 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3066 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3067 pa_tagstruct_put_usec(t
, source_latency
);
3068 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3069 pa_tagstruct_puts(t
, s
->driver
);
3071 if (c
->version
>= 13)
3072 pa_tagstruct_put_proplist(t
, s
->proplist
);
3075 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3076 pa_sample_spec fixed_ss
;
3082 if (e
->memchunk
.memblock
)
3083 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3085 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3087 pa_tagstruct_putu32(t
, e
->index
);
3088 pa_tagstruct_puts(t
, e
->name
);
3090 if (e
->volume_is_set
)
3093 pa_cvolume_init(&v
);
3095 pa_tagstruct_put_cvolume(t
, &v
);
3096 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3097 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3098 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3099 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3100 pa_tagstruct_put_boolean(t
, e
->lazy
);
3101 pa_tagstruct_puts(t
, e
->filename
);
3103 if (c
->version
>= 13)
3104 pa_tagstruct_put_proplist(t
, e
->proplist
);
3107 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3108 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3110 pa_sink
*sink
= NULL
;
3111 pa_source
*source
= NULL
;
3112 pa_client
*client
= NULL
;
3113 pa_card
*card
= NULL
;
3114 pa_module
*module
= NULL
;
3115 pa_sink_input
*si
= NULL
;
3116 pa_source_output
*so
= NULL
;
3117 pa_scache_entry
*sce
= NULL
;
3118 const char *name
= NULL
;
3119 pa_tagstruct
*reply
;
3121 pa_native_connection_assert_ref(c
);
3124 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3125 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3126 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3127 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3128 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3129 pa_tagstruct_gets(t
, &name
) < 0) ||
3130 !pa_tagstruct_eof(t
)) {
3135 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3136 CHECK_VALIDITY(c
->pstream
, !name
||
3137 (command
== PA_COMMAND_GET_SINK_INFO
&&
3138 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3139 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3140 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3141 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3142 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3143 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3144 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3146 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3147 if (idx
!= PA_INVALID_INDEX
)
3148 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3150 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3151 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3152 if (idx
!= PA_INVALID_INDEX
)
3153 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3155 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3156 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3157 if (idx
!= PA_INVALID_INDEX
)
3158 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3160 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3161 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3162 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3163 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3164 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3165 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3166 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3167 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3168 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3170 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3171 if (idx
!= PA_INVALID_INDEX
)
3172 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3174 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3177 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3178 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3182 reply
= reply_new(tag
);
3184 sink_fill_tagstruct(c
, reply
, sink
);
3186 source_fill_tagstruct(c
, reply
, source
);
3188 client_fill_tagstruct(c
, reply
, client
);
3190 card_fill_tagstruct(c
, reply
, card
);
3192 module_fill_tagstruct(c
, reply
, module
);
3194 sink_input_fill_tagstruct(c
, reply
, si
);
3196 source_output_fill_tagstruct(c
, reply
, so
);
3198 scache_fill_tagstruct(c
, reply
, sce
);
3199 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3202 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3203 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3207 pa_tagstruct
*reply
;
3209 pa_native_connection_assert_ref(c
);
3212 if (!pa_tagstruct_eof(t
)) {
3217 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3219 reply
= reply_new(tag
);
3221 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3222 i
= c
->protocol
->core
->sinks
;
3223 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3224 i
= c
->protocol
->core
->sources
;
3225 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3226 i
= c
->protocol
->core
->clients
;
3227 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3228 i
= c
->protocol
->core
->cards
;
3229 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3230 i
= c
->protocol
->core
->modules
;
3231 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3232 i
= c
->protocol
->core
->sink_inputs
;
3233 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3234 i
= c
->protocol
->core
->source_outputs
;
3236 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3237 i
= c
->protocol
->core
->scache
;
3241 for (p
= pa_idxset_first(i
, &idx
); p
; p
= pa_idxset_next(i
, &idx
)) {
3242 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3243 sink_fill_tagstruct(c
, reply
, p
);
3244 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3245 source_fill_tagstruct(c
, reply
, p
);
3246 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3247 client_fill_tagstruct(c
, reply
, p
);
3248 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3249 card_fill_tagstruct(c
, reply
, p
);
3250 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3251 module_fill_tagstruct(c
, reply
, p
);
3252 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3253 sink_input_fill_tagstruct(c
, reply
, p
);
3254 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3255 source_output_fill_tagstruct(c
, reply
, p
);
3257 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3258 scache_fill_tagstruct(c
, reply
, p
);
3263 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3266 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3267 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3268 pa_tagstruct
*reply
;
3270 pa_source
*def_source
;
3271 pa_sample_spec fixed_ss
;
3274 pa_native_connection_assert_ref(c
);
3277 if (!pa_tagstruct_eof(t
)) {
3282 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3284 reply
= reply_new(tag
);
3285 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3286 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3288 u
= pa_get_user_name_malloc();
3289 pa_tagstruct_puts(reply
, u
);
3292 h
= pa_get_host_name_malloc();
3293 pa_tagstruct_puts(reply
, h
);
3296 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3297 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3299 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3300 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3301 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3302 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3304 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3306 if (c
->version
>= 15)
3307 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3309 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3312 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3314 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3316 pa_native_connection_assert_ref(c
);
3318 t
= pa_tagstruct_new(NULL
, 0);
3319 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3320 pa_tagstruct_putu32(t
, (uint32_t) -1);
3321 pa_tagstruct_putu32(t
, e
);
3322 pa_tagstruct_putu32(t
, idx
);
3323 pa_pstream_send_tagstruct(c
->pstream
, t
);
3326 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3327 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3328 pa_subscription_mask_t m
;
3330 pa_native_connection_assert_ref(c
);
3333 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3334 !pa_tagstruct_eof(t
)) {
3339 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3340 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3342 if (c
->subscription
)
3343 pa_subscription_free(c
->subscription
);
3346 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3347 pa_assert(c
->subscription
);
3349 c
->subscription
= NULL
;
3351 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3354 static void command_set_volume(
3361 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3364 pa_sink
*sink
= NULL
;
3365 pa_source
*source
= NULL
;
3366 pa_sink_input
*si
= NULL
;
3367 const char *name
= NULL
;
3368 const char *client_name
;
3370 pa_native_connection_assert_ref(c
);
3373 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3374 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3375 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3376 pa_tagstruct_get_cvolume(t
, &volume
) ||
3377 !pa_tagstruct_eof(t
)) {
3382 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3383 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
);
3384 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3385 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3386 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3387 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3391 case PA_COMMAND_SET_SINK_VOLUME
:
3392 if (idx
!= PA_INVALID_INDEX
)
3393 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3395 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3398 case PA_COMMAND_SET_SOURCE_VOLUME
:
3399 if (idx
!= PA_INVALID_INDEX
)
3400 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3402 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3405 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3406 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3410 pa_assert_not_reached();
3413 CHECK_VALIDITY(c
->pstream
, si
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3415 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3418 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3420 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3421 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3422 } else if (source
) {
3423 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3425 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3426 pa_source_set_volume(source
, &volume
, TRUE
);
3428 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3430 pa_log_debug("Client %s changes volume of sink input %s.",
3432 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3433 pa_sink_input_set_volume(si
, &volume
, TRUE
, TRUE
);
3436 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3439 static void command_set_mute(
3446 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3449 pa_sink
*sink
= NULL
;
3450 pa_source
*source
= NULL
;
3451 pa_sink_input
*si
= NULL
;
3452 const char *name
= NULL
, *client_name
;
3454 pa_native_connection_assert_ref(c
);
3457 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3458 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3459 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3460 pa_tagstruct_get_boolean(t
, &mute
) ||
3461 !pa_tagstruct_eof(t
)) {
3466 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3467 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
);
3468 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3469 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3470 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3474 case PA_COMMAND_SET_SINK_MUTE
:
3475 if (idx
!= PA_INVALID_INDEX
)
3476 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3478 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3482 case PA_COMMAND_SET_SOURCE_MUTE
:
3483 if (idx
!= PA_INVALID_INDEX
)
3484 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3486 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3490 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3491 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3495 pa_assert_not_reached();
3498 CHECK_VALIDITY(c
->pstream
, si
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3500 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3503 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3504 pa_sink_set_mute(sink
, mute
, TRUE
);
3505 } else if (source
) {
3506 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3507 pa_source_set_mute(source
, mute
, TRUE
);
3509 pa_log_debug("Client %s changes mute of sink input %s.",
3511 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3512 pa_sink_input_set_mute(si
, mute
, TRUE
);
3515 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3518 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3519 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3524 pa_native_connection_assert_ref(c
);
3527 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3528 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3529 !pa_tagstruct_eof(t
)) {
3534 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3535 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3536 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3537 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3538 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3540 pa_sink_input_cork(s
->sink_input
, b
);
3543 s
->is_underrun
= TRUE
;
3545 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3548 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3549 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3553 pa_native_connection_assert_ref(c
);
3556 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3557 !pa_tagstruct_eof(t
)) {
3562 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3563 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3564 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3565 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3566 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3569 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3570 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3573 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3574 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3577 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3578 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3582 pa_assert_not_reached();
3585 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3588 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3589 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3594 pa_native_connection_assert_ref(c
);
3597 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3598 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3599 !pa_tagstruct_eof(t
)) {
3604 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3605 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3606 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3608 pa_source_output_cork(s
->source_output
, b
);
3609 pa_memblockq_prebuf_force(s
->memblockq
);
3610 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3613 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3614 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3618 pa_native_connection_assert_ref(c
);
3621 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3622 !pa_tagstruct_eof(t
)) {
3627 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3628 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3629 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3631 pa_memblockq_flush_read(s
->memblockq
);
3632 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3635 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3636 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3639 pa_tagstruct
*reply
;
3641 pa_native_connection_assert_ref(c
);
3644 memset(&a
, 0, sizeof(a
));
3646 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3651 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3653 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
3655 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3657 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3658 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3659 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3661 if (pa_tagstruct_get(
3663 PA_TAG_U32
, &a
.maxlength
,
3664 PA_TAG_U32
, &a
.tlength
,
3665 PA_TAG_U32
, &a
.prebuf
,
3666 PA_TAG_U32
, &a
.minreq
,
3667 PA_TAG_INVALID
) < 0 ||
3668 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3669 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3670 !pa_tagstruct_eof(t
)) {
3675 s
->adjust_latency
= adjust_latency
;
3676 s
->early_requests
= early_requests
;
3679 fix_playback_buffer_attr(s
);
3680 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);
3682 reply
= reply_new(tag
);
3683 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3684 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
3685 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
3686 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
3688 if (c
->version
>= 13)
3689 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
3693 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3694 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
3696 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3697 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3699 if (pa_tagstruct_get(
3701 PA_TAG_U32
, &a
.maxlength
,
3702 PA_TAG_U32
, &a
.fragsize
,
3703 PA_TAG_INVALID
) < 0 ||
3704 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3705 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3706 !pa_tagstruct_eof(t
)) {
3711 s
->adjust_latency
= adjust_latency
;
3712 s
->early_requests
= early_requests
;
3715 fix_record_buffer_attr_pre(s
);
3716 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
3717 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
3718 fix_record_buffer_attr_post(s
);
3720 reply
= reply_new(tag
);
3721 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3722 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
3724 if (c
->version
>= 13)
3725 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
3728 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3731 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3732 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3736 pa_native_connection_assert_ref(c
);
3739 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3740 pa_tagstruct_getu32(t
, &rate
) < 0 ||
3741 !pa_tagstruct_eof(t
)) {
3746 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3747 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
3749 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
3752 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3753 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3754 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3756 pa_sink_input_set_rate(s
->sink_input
, rate
);
3760 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
3762 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3763 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3765 pa_source_output_set_rate(s
->source_output
, rate
);
3768 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3771 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3772 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3777 pa_native_connection_assert_ref(c
);
3780 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3782 p
= pa_proplist_new();
3784 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
3786 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
3787 pa_tagstruct_get_proplist(t
, p
) < 0 ||
3788 !pa_tagstruct_eof(t
)) {
3790 pa_proplist_free(p
);
3796 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3797 pa_tagstruct_getu32(t
, &mode
) < 0 ||
3798 pa_tagstruct_get_proplist(t
, p
) < 0 ||
3799 !pa_tagstruct_eof(t
)) {
3801 pa_proplist_free(p
);
3806 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
3807 pa_proplist_free(p
);
3808 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
3811 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
3814 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3815 if (!s
|| !playback_stream_isinstance(s
)) {
3816 pa_proplist_free(p
);
3817 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
3819 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
3821 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
3824 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
3825 pa_proplist_free(p
);
3826 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
3828 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
3831 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
3833 pa_client_update_proplist(c
->client
, mode
, p
);
3836 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3837 pa_proplist_free(p
);
3840 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3841 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3843 unsigned changed
= 0;
3845 pa_strlist
*l
= NULL
;
3847 pa_native_connection_assert_ref(c
);
3850 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3852 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
3854 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3860 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
3863 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3864 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3865 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3867 p
= s
->sink_input
->proplist
;
3869 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
3872 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3873 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3875 p
= s
->source_output
->proplist
;
3877 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
3879 p
= c
->client
->proplist
;
3885 if (pa_tagstruct_gets(t
, &k
) < 0) {
3894 l
= pa_strlist_prepend(l
, k
);
3897 if (!pa_tagstruct_eof(t
)) {
3906 l
= pa_strlist_pop(l
, &z
);
3911 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
3915 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3918 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
3921 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3922 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
3924 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
3927 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3928 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
3931 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
3932 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
3937 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3938 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3941 pa_native_connection_assert_ref(c
);
3944 if (pa_tagstruct_gets(t
, &s
) < 0 ||
3945 !pa_tagstruct_eof(t
)) {
3950 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3951 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
3953 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
3956 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
3957 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
3959 pa_namereg_set_default_source(c
->protocol
->core
, source
);
3962 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
3964 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
3965 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
3967 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
3970 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3973 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3974 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3978 pa_native_connection_assert_ref(c
);
3981 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3982 pa_tagstruct_gets(t
, &name
) < 0 ||
3983 !pa_tagstruct_eof(t
)) {
3988 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3989 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
3991 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
3994 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3995 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3996 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3998 pa_sink_input_set_name(s
->sink_input
, name
);
4002 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4004 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4005 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4007 pa_source_output_set_name(s
->source_output
, name
);
4010 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4013 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4014 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4017 pa_native_connection_assert_ref(c
);
4020 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4021 !pa_tagstruct_eof(t
)) {
4026 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4028 if (command
== PA_COMMAND_KILL_CLIENT
) {
4031 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4032 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4034 pa_native_connection_ref(c
);
4035 pa_client_kill(client
);
4037 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4040 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4041 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4043 pa_native_connection_ref(c
);
4044 pa_sink_input_kill(s
);
4046 pa_source_output
*s
;
4048 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4050 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4051 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4053 pa_native_connection_ref(c
);
4054 pa_source_output_kill(s
);
4057 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4058 pa_native_connection_unref(c
);
4061 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4062 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4064 const char *name
, *argument
;
4065 pa_tagstruct
*reply
;
4067 pa_native_connection_assert_ref(c
);
4070 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4071 pa_tagstruct_gets(t
, &argument
) < 0 ||
4072 !pa_tagstruct_eof(t
)) {
4077 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4078 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4079 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4081 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4082 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4086 reply
= reply_new(tag
);
4087 pa_tagstruct_putu32(reply
, m
->index
);
4088 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4091 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4092 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4096 pa_native_connection_assert_ref(c
);
4099 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4100 !pa_tagstruct_eof(t
)) {
4105 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4106 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4107 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4109 pa_module_unload_request(m
, FALSE
);
4110 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4113 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4114 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4115 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4116 const char *name_device
= NULL
;
4118 pa_native_connection_assert_ref(c
);
4121 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4122 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4123 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4124 !pa_tagstruct_eof(t
)) {
4129 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4130 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4132 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
);
4133 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4134 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4135 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4137 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4138 pa_sink_input
*si
= NULL
;
4139 pa_sink
*sink
= NULL
;
4141 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4143 if (idx_device
!= PA_INVALID_INDEX
)
4144 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4146 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4148 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4150 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4151 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4155 pa_source_output
*so
= NULL
;
4158 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4160 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4162 if (idx_device
!= PA_INVALID_INDEX
)
4163 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4165 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4167 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4169 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4170 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4175 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4178 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4179 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4180 uint32_t idx
= PA_INVALID_INDEX
;
4181 const char *name
= NULL
;
4184 pa_native_connection_assert_ref(c
);
4187 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4188 pa_tagstruct_gets(t
, &name
) < 0 ||
4189 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4190 !pa_tagstruct_eof(t
)) {
4195 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4196 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
);
4197 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4198 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4199 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4201 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4203 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4205 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4207 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4208 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4212 pa_sink
*sink
= NULL
;
4214 if (idx
!= PA_INVALID_INDEX
)
4215 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4217 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4219 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4221 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4222 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4228 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4230 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4232 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4234 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4235 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4242 if (idx
!= PA_INVALID_INDEX
)
4243 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4245 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4247 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4249 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4250 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4256 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4259 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4260 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4261 uint32_t idx
= PA_INVALID_INDEX
;
4262 const char *name
= NULL
;
4264 pa_native_protocol_ext_cb_t cb
;
4266 pa_native_connection_assert_ref(c
);
4269 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4270 pa_tagstruct_gets(t
, &name
) < 0) {
4275 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4276 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4277 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4278 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4279 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4281 if (idx
!= PA_INVALID_INDEX
)
4282 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4284 for (m
= pa_idxset_first(c
->protocol
->core
->modules
, &idx
); m
; m
= pa_idxset_next(c
->protocol
->core
->modules
, &idx
))
4285 if (strcmp(name
, m
->name
) == 0)
4289 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4290 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4292 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4293 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4295 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4299 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4300 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4301 uint32_t idx
= PA_INVALID_INDEX
;
4302 const char *name
= NULL
, *profile
= NULL
;
4303 pa_card
*card
= NULL
;
4306 pa_native_connection_assert_ref(c
);
4309 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4310 pa_tagstruct_gets(t
, &name
) < 0 ||
4311 pa_tagstruct_gets(t
, &profile
) < 0 ||
4312 !pa_tagstruct_eof(t
)) {
4317 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4318 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4319 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4320 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4321 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4323 if (idx
!= PA_INVALID_INDEX
)
4324 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4326 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4328 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4330 if ((ret
= pa_card_set_profile(card
, profile
, TRUE
)) < 0) {
4331 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4335 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4338 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4339 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4340 uint32_t idx
= PA_INVALID_INDEX
;
4341 const char *name
= NULL
, *port
= NULL
;
4344 pa_native_connection_assert_ref(c
);
4347 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4348 pa_tagstruct_gets(t
, &name
) < 0 ||
4349 pa_tagstruct_gets(t
, &port
) < 0 ||
4350 !pa_tagstruct_eof(t
)) {
4355 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4356 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
);
4357 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4358 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4359 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4361 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4364 if (idx
!= PA_INVALID_INDEX
)
4365 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4367 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4369 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4371 if ((ret
= pa_sink_set_port(sink
, port
, TRUE
)) < 0) {
4372 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4378 pa_assert(command
= PA_COMMAND_SET_SOURCE_PORT
);
4380 if (idx
!= PA_INVALID_INDEX
)
4381 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4383 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4385 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4387 if ((ret
= pa_source_set_port(source
, port
, TRUE
)) < 0) {
4388 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4393 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4396 /*** pstream callbacks ***/
4398 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4399 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4403 pa_native_connection_assert_ref(c
);
4405 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4406 pa_log("invalid packet.");
4407 native_connection_unlink(c
);
4411 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
) {
4412 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4413 output_stream
*stream
;
4417 pa_native_connection_assert_ref(c
);
4419 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4420 pa_log_debug("Client sent block for invalid stream.");
4425 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4427 if (playback_stream_isinstance(stream
)) {
4428 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4430 if (chunk
->memblock
) {
4431 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4432 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_SEEK
, PA_UINT_TO_PTR(seek
), offset
, NULL
, NULL
);
4434 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4436 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
);
4439 upload_stream
*u
= UPLOAD_STREAM(stream
);
4442 if (!u
->memchunk
.memblock
) {
4443 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4444 u
->memchunk
= *chunk
;
4445 pa_memblock_ref(u
->memchunk
.memblock
);
4448 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4449 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4453 pa_assert(u
->memchunk
.memblock
);
4456 if (l
> chunk
->length
)
4461 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4463 if (chunk
->memblock
) {
4465 src
= pa_memblock_acquire(chunk
->memblock
);
4467 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4468 (uint8_t*) src
+ chunk
->index
, l
);
4470 pa_memblock_release(chunk
->memblock
);
4472 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4474 pa_memblock_release(u
->memchunk
.memblock
);
4476 u
->memchunk
.length
+= l
;
4482 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4483 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4486 pa_native_connection_assert_ref(c
);
4488 native_connection_unlink(c
);
4489 pa_log_info("Connection died.");
4492 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4493 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4496 pa_native_connection_assert_ref(c
);
4498 native_connection_send_memblock(c
);
4501 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4504 if (!(q
= pa_thread_mq_get()))
4505 pa_pstream_send_revoke(p
, block_id
);
4507 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4510 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4513 if (!(q
= pa_thread_mq_get()))
4514 pa_pstream_send_release(p
, block_id
);
4516 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4519 /*** client callbacks ***/
4521 static void client_kill_cb(pa_client
*c
) {
4524 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4525 pa_log_info("Connection killed.");
4528 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4530 pa_native_connection
*c
;
4533 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4534 pa_native_connection_assert_ref(c
);
4536 if (c
->version
< 15)
4539 t
= pa_tagstruct_new(NULL
, 0);
4540 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4541 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4542 pa_tagstruct_puts(t
, event
);
4543 pa_tagstruct_put_proplist(t
, pl
);
4544 pa_pstream_send_tagstruct(c
->pstream
, t
);
4547 /*** module entry points ***/
4549 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4550 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4553 pa_native_connection_assert_ref(c
);
4554 pa_assert(c
->auth_timeout_event
== e
);
4556 if (!c
->authorized
) {
4557 native_connection_unlink(c
);
4558 pa_log_info("Connection terminated due to authentication timeout.");
4562 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4563 pa_native_connection
*c
;
4566 pa_client_new_data data
;
4572 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4573 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4574 pa_iochannel_free(io
);
4578 pa_client_new_data_init(&data
);
4579 data
.module
= o
->module
;
4580 data
.driver
= __FILE__
;
4581 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4582 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4583 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4584 client
= pa_client_new(p
->core
, &data
);
4585 pa_client_new_data_done(&data
);
4590 c
= pa_msgobject_new(pa_native_connection
);
4591 c
->parent
.parent
.free
= native_connection_free
;
4592 c
->parent
.process_msg
= native_connection_process_msg
;
4594 c
->options
= pa_native_options_ref(o
);
4595 c
->authorized
= FALSE
;
4597 if (o
->auth_anonymous
) {
4598 pa_log_info("Client authenticated anonymously.");
4599 c
->authorized
= TRUE
;
4602 if (!c
->authorized
&&
4604 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
4606 pa_log_info("Client authenticated by IP ACL.");
4607 c
->authorized
= TRUE
;
4611 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
4613 c
->auth_timeout_event
= NULL
;
4615 c
->is_local
= pa_iochannel_socket_is_local(io
);
4619 c
->client
->kill
= client_kill_cb
;
4620 c
->client
->send_event
= client_send_event_cb
;
4621 c
->client
->userdata
= c
;
4623 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
4624 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
4625 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
4626 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
4627 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
4628 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
4629 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
4631 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, TRUE
, command_table
, PA_COMMAND_MAX
);
4633 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
4634 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
4636 c
->rrobin_index
= PA_IDXSET_INVALID
;
4637 c
->subscription
= NULL
;
4639 pa_idxset_put(p
->connections
, c
, NULL
);
4642 if (pa_iochannel_creds_supported(io
))
4643 pa_iochannel_creds_enable(io
);
4646 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
4649 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
4650 pa_native_connection
*c
;
4656 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
4657 if (c
->options
->module
== m
)
4658 native_connection_unlink(c
);
4661 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
4662 pa_native_protocol
*p
;
4667 p
= pa_xnew(pa_native_protocol
, 1);
4670 p
->connections
= pa_idxset_new(NULL
, NULL
);
4674 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
4676 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4677 pa_hook_init(&p
->hooks
[h
], p
);
4679 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
4684 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
4685 pa_native_protocol
*p
;
4687 if ((p
= pa_shared_get(c
, "native-protocol")))
4688 return pa_native_protocol_ref(p
);
4690 return native_protocol_new(c
);
4693 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
4695 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4702 void pa_native_protocol_unref(pa_native_protocol
*p
) {
4703 pa_native_connection
*c
;
4707 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4709 if (PA_REFCNT_DEC(p
) > 0)
4712 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
4713 native_connection_unlink(c
);
4715 pa_idxset_free(p
->connections
, NULL
, NULL
);
4717 pa_strlist_free(p
->servers
);
4719 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4720 pa_hook_done(&p
->hooks
[h
]);
4722 pa_hashmap_free(p
->extensions
, NULL
, NULL
);
4724 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
4729 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
4731 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4734 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
4736 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
4739 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
4741 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4744 p
->servers
= pa_strlist_remove(p
->servers
, name
);
4746 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
4749 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
4751 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4756 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
4758 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4763 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
4765 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4768 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
4770 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
4774 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
4776 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4779 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
4782 pa_native_options
* pa_native_options_new(void) {
4783 pa_native_options
*o
;
4785 o
= pa_xnew0(pa_native_options
, 1);
4791 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
4793 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4800 void pa_native_options_unref(pa_native_options
*o
) {
4802 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4804 if (PA_REFCNT_DEC(o
) > 0)
4807 pa_xfree(o
->auth_group
);
4810 pa_ip_acl_free(o
->auth_ip_acl
);
4813 pa_auth_cookie_unref(o
->auth_cookie
);
4818 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
4823 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4826 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
4827 pa_log("auth-anonymous= expects a boolean argument.");
4832 if (pa_modargs_get_value_boolean(ma
, "auth-group-enabled", &enabled
) < 0) {
4833 pa_log("auth-group-enabled= expects a boolean argument.");
4837 pa_xfree(o
->auth_group
);
4838 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
4842 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4845 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
4848 if (!(ipa
= pa_ip_acl_new(acl
))) {
4849 pa_log("Failed to parse IP ACL '%s'", acl
);
4854 pa_ip_acl_free(o
->auth_ip_acl
);
4856 o
->auth_ip_acl
= ipa
;
4860 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
4861 pa_log("auth-cookie-enabled= expects a boolean argument.");
4866 pa_auth_cookie_unref(o
->auth_cookie
);
4871 /* The new name for this is 'auth-cookie', for compat reasons
4872 * we check the old name too */
4873 if (!(cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
)))
4874 if (!(cn
= pa_modargs_get_value(ma
, "cookie", NULL
)))
4875 cn
= PA_NATIVE_COOKIE_FILE
;
4877 if (!(o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, PA_NATIVE_COOKIE_LENGTH
)))
4881 o
->auth_cookie
= NULL
;
4886 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
4887 pa_native_connection_assert_ref(c
);
4892 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
4893 pa_native_connection_assert_ref(c
);