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 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
862 /* (long) s->buffer_attr.maxlength, */
863 /* (long) s->buffer_attr.tlength, */
864 /* (long) s->buffer_attr.minreq, */
865 /* (long) s->buffer_attr.prebuf); */
867 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
868 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
869 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
870 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
871 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
873 /* This function will be called from the main thread, before as
874 * well as after the sink input has been activated using
875 * pa_sink_input_put()! That means it may not touch any
876 * ->thread_info data, such as the memblockq! */
878 frame_size
= pa_frame_size(&s
->sink_input
->sample_spec
);
880 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
881 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
882 if (s
->buffer_attr
.maxlength
<= 0)
883 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
885 if (s
->buffer_attr
.tlength
== (uint32_t) -1)
886 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
887 if (s
->buffer_attr
.tlength
<= 0)
888 s
->buffer_attr
.tlength
= (uint32_t) frame_size
;
890 if (s
->buffer_attr
.minreq
== (uint32_t) -1)
891 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
892 if (s
->buffer_attr
.minreq
<= 0)
893 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
895 if (s
->buffer_attr
.tlength
< s
->buffer_attr
.minreq
+frame_size
)
896 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
+(uint32_t) frame_size
;
898 orig_tlength_usec
= tlength_usec
= pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
);
899 orig_minreq_usec
= minreq_usec
= pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
);
901 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
902 (double) tlength_usec
/ PA_USEC_PER_MSEC
,
903 (double) minreq_usec
/ PA_USEC_PER_MSEC
);
905 if (s
->early_requests
) {
907 /* In early request mode we need to emulate the classic
908 * fragment-based playback model. We do this setting the sink
909 * latency to the fragment size. */
911 sink_usec
= minreq_usec
;
912 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
914 } else if (s
->adjust_latency
) {
916 /* So, the user asked us to adjust the latency of the stream
917 * buffer according to the what the sink can provide. The
918 * tlength passed in shall be the overall latency. Roughly
919 * half the latency will be spent on the hw buffer, the other
920 * half of it in the async buffer queue we maintain for each
921 * client. In between we'll have a safety space of size
922 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
923 * empty and needs to be filled, then our buffer must have
924 * enough data to fulfill this request immediatly and thus
925 * have at least the same tlength as the size of the hw
926 * buffer. It additionally needs space for 2 times minreq
927 * because if the buffer ran empty and a partial fillup
928 * happens immediately on the next iteration we need to be
929 * able to fulfill it and give the application also minreq
930 * time to fill it up again for the next request Makes 2 times
931 * minreq in plus.. */
933 if (tlength_usec
> minreq_usec
*2)
934 sink_usec
= (tlength_usec
- minreq_usec
*2)/2;
938 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
942 /* Ok, the user didn't ask us to adjust the latency, but we
943 * still need to make sure that the parameters from the user
946 if (tlength_usec
> minreq_usec
*2)
947 sink_usec
= (tlength_usec
- minreq_usec
*2);
951 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
954 s
->configured_sink_latency
= pa_sink_input_set_requested_latency(s
->sink_input
, sink_usec
);
956 if (s
->early_requests
) {
958 /* Ok, we didn't necessarily get what we were asking for, so
959 * let's tell the user */
961 minreq_usec
= s
->configured_sink_latency
;
963 } else if (s
->adjust_latency
) {
965 /* Ok, we didn't necessarily get what we were asking for, so
966 * let's subtract from what we asked for for the remaining
969 if (tlength_usec
>= s
->configured_sink_latency
)
970 tlength_usec
-= s
->configured_sink_latency
;
973 /* FIXME: This is actually larger than necessary, since not all of
974 * the sink latency is actually rewritable. */
975 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
976 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
978 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
979 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
980 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
982 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
983 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
984 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
986 if (s
->buffer_attr
.minreq
<= 0) {
987 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
988 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
991 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
992 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
994 max_prebuf
= s
->buffer_attr
.tlength
+ (uint32_t)frame_size
- s
->buffer_attr
.minreq
;
996 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 ||
997 s
->buffer_attr
.prebuf
> max_prebuf
)
998 s
->buffer_attr
.prebuf
= max_prebuf
;
1000 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1001 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1002 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1003 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1004 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1007 /* Called from main context */
1008 static playback_stream
* playback_stream_new(
1009 pa_native_connection
*c
,
1012 pa_channel_map
*map
,
1016 pa_bool_t muted_set
,
1019 pa_sink_input_flags_t flags
,
1021 pa_bool_t adjust_latency
,
1022 pa_bool_t early_requests
,
1023 pa_bool_t relative_volume
,
1026 playback_stream
*s
, *ssync
;
1027 pa_sink_input
*sink_input
= NULL
;
1028 pa_memchunk silence
;
1030 int64_t start_index
;
1031 pa_sink_input_new_data data
;
1039 /* Find syncid group */
1040 PA_IDXSET_FOREACH(ssync
, c
->output_streams
, idx
) {
1042 if (!playback_stream_isinstance(ssync
))
1045 if (ssync
->syncid
== syncid
)
1049 /* Synced streams must connect to the same sink */
1053 sink
= ssync
->sink_input
->sink
;
1054 else if (sink
!= ssync
->sink_input
->sink
) {
1055 *ret
= PA_ERR_INVALID
;
1060 pa_sink_input_new_data_init(&data
);
1062 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1063 data
.driver
= __FILE__
;
1064 data
.module
= c
->options
->module
;
1065 data
.client
= c
->client
;
1068 data
.save_sink
= TRUE
;
1070 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1071 pa_sink_input_new_data_set_channel_map(&data
, map
);
1073 pa_sink_input_new_data_set_volume(&data
, volume
);
1074 data
.volume_is_absolute
= !relative_volume
;
1075 data
.save_volume
= TRUE
;
1078 pa_sink_input_new_data_set_muted(&data
, muted
);
1079 data
.save_muted
= TRUE
;
1081 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1084 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
);
1086 pa_sink_input_new_data_done(&data
);
1091 s
= pa_msgobject_new(playback_stream
);
1092 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1093 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1096 s
->sink_input
= sink_input
;
1097 s
->is_underrun
= TRUE
;
1098 s
->drain_request
= FALSE
;
1099 pa_atomic_store(&s
->missing
, 0);
1100 s
->buffer_attr
= *a
;
1101 s
->adjust_latency
= adjust_latency
;
1102 s
->early_requests
= early_requests
;
1104 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1105 s
->sink_input
->pop
= sink_input_pop_cb
;
1106 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1107 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1108 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1109 s
->sink_input
->kill
= sink_input_kill_cb
;
1110 s
->sink_input
->moving
= sink_input_moving_cb
;
1111 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1112 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1113 s
->sink_input
->userdata
= s
;
1115 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1117 fix_playback_buffer_attr(s
);
1119 pa_sink_input_get_silence(sink_input
, &silence
);
1120 s
->memblockq
= pa_memblockq_new(
1122 s
->buffer_attr
.maxlength
,
1123 s
->buffer_attr
.tlength
,
1124 pa_frame_size(&sink_input
->sample_spec
),
1125 s
->buffer_attr
.prebuf
,
1126 s
->buffer_attr
.minreq
,
1129 pa_memblock_unref(silence
.memblock
);
1131 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1133 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1135 /* pa_log("missing original: %li", (long int) *missing); */
1137 *ss
= s
->sink_input
->sample_spec
;
1138 *map
= s
->sink_input
->channel_map
;
1140 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1142 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1143 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1144 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1145 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1146 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1148 pa_sink_input_put(s
->sink_input
);
1152 /* Called from IO context */
1153 static void playback_stream_request_bytes(playback_stream
*s
) {
1155 int previous_missing
;
1157 playback_stream_assert_ref(s
);
1159 m
= pa_memblockq_pop_missing(s
->memblockq
);
1161 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1162 /* (unsigned long) m, */
1163 /* pa_memblockq_get_tlength(s->memblockq), */
1164 /* pa_memblockq_get_minreq(s->memblockq), */
1165 /* pa_memblockq_get_length(s->memblockq), */
1166 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1171 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1173 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1174 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1176 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1177 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1178 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1181 /* Called from main context */
1182 static void playback_stream_send_killed(playback_stream
*p
) {
1184 playback_stream_assert_ref(p
);
1186 t
= pa_tagstruct_new(NULL
, 0);
1187 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1188 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1189 pa_tagstruct_putu32(t
, p
->index
);
1190 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1193 /* Called from main context */
1194 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1195 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1196 pa_native_connection_assert_ref(c
);
1203 case CONNECTION_MESSAGE_REVOKE
:
1204 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1207 case CONNECTION_MESSAGE_RELEASE
:
1208 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1215 /* Called from main context */
1216 static void native_connection_unlink(pa_native_connection
*c
) {
1225 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1228 pa_native_options_unref(c
->options
);
1230 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1231 record_stream_unlink(r
);
1233 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1234 if (playback_stream_isinstance(o
))
1235 playback_stream_unlink(PLAYBACK_STREAM(o
));
1237 upload_stream_unlink(UPLOAD_STREAM(o
));
1239 if (c
->subscription
)
1240 pa_subscription_free(c
->subscription
);
1243 pa_pstream_unlink(c
->pstream
);
1245 if (c
->auth_timeout_event
) {
1246 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1247 c
->auth_timeout_event
= NULL
;
1250 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1252 pa_native_connection_unref(c
);
1255 /* Called from main context */
1256 static void native_connection_free(pa_object
*o
) {
1257 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1261 native_connection_unlink(c
);
1263 pa_idxset_free(c
->record_streams
, NULL
, NULL
);
1264 pa_idxset_free(c
->output_streams
, NULL
, NULL
);
1266 pa_pdispatch_unref(c
->pdispatch
);
1267 pa_pstream_unref(c
->pstream
);
1268 pa_client_free(c
->client
);
1273 /* Called from main context */
1274 static void native_connection_send_memblock(pa_native_connection
*c
) {
1278 start
= PA_IDXSET_INVALID
;
1282 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1285 if (start
== PA_IDXSET_INVALID
)
1286 start
= c
->rrobin_index
;
1287 else if (start
== c
->rrobin_index
)
1290 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1291 pa_memchunk schunk
= chunk
;
1293 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1294 schunk
.length
= r
->buffer_attr
.fragsize
;
1296 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1298 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1299 pa_memblock_unref(schunk
.memblock
);
1306 /*** sink input callbacks ***/
1308 /* Called from thread context */
1309 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1310 playback_stream_assert_ref(s
);
1312 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1314 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1316 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1318 if (pa_memblockq_is_readable(s
->memblockq
)) {
1320 /* We just ended an underrun, let's ask the sink
1321 * for a complete rewind rewrite */
1323 pa_log_debug("Requesting rewind due to end of underrun.");
1324 pa_sink_input_request_rewind(s
->sink_input
,
1325 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (uint64_t) -1 ? 0 :
1326 s
->sink_input
->thread_info
.underrun_for
),
1327 FALSE
, TRUE
, FALSE
);
1333 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1335 if (indexw
< indexr
) {
1336 /* OK, the sink already asked for this data, so
1337 * let's have it usk us again */
1339 pa_log_debug("Requesting rewind due to rewrite.");
1340 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), TRUE
, FALSE
, FALSE
);
1344 playback_stream_request_bytes(s
);
1347 static void flush_write_no_account(pa_memblockq
*q
) {
1348 pa_memblockq_flush_write(q
, FALSE
);
1351 /* Called from thread context */
1352 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1353 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1356 pa_sink_input_assert_ref(i
);
1357 s
= PLAYBACK_STREAM(i
->userdata
);
1358 playback_stream_assert_ref(s
);
1362 case SINK_INPUT_MESSAGE_SEEK
: {
1365 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1367 /* The client side is incapable of accounting correctly
1368 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1369 * able to deal with that. */
1371 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1373 handle_seek(s
, windex
);
1377 case SINK_INPUT_MESSAGE_POST_DATA
: {
1382 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1384 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1386 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1388 if (pa_log_ratelimit())
1389 pa_log_warn("Failed to push data into queue");
1390 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1391 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, TRUE
);
1394 handle_seek(s
, windex
);
1396 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1401 case SINK_INPUT_MESSAGE_DRAIN
:
1402 case SINK_INPUT_MESSAGE_FLUSH
:
1403 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1404 case SINK_INPUT_MESSAGE_TRIGGER
: {
1407 pa_sink_input
*isync
;
1408 void (*func
)(pa_memblockq
*bq
);
1411 case SINK_INPUT_MESSAGE_FLUSH
:
1412 func
= flush_write_no_account
;
1415 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1416 func
= pa_memblockq_prebuf_force
;
1419 case SINK_INPUT_MESSAGE_DRAIN
:
1420 case SINK_INPUT_MESSAGE_TRIGGER
:
1421 func
= pa_memblockq_prebuf_disable
;
1425 pa_assert_not_reached();
1428 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1430 handle_seek(s
, windex
);
1432 /* Do the same for all other members in the sync group */
1433 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1434 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1435 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1436 func(ssync
->memblockq
);
1437 handle_seek(ssync
, windex
);
1440 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1441 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1442 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1443 func(ssync
->memblockq
);
1444 handle_seek(ssync
, windex
);
1447 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1448 if (!pa_memblockq_is_readable(s
->memblockq
))
1449 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1451 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1452 s
->drain_request
= TRUE
;
1459 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1460 /* Atomically get a snapshot of all timing parameters... */
1461 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1462 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1463 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1464 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1465 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1466 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1470 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1473 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1475 pa_memblockq_prebuf_force(s
->memblockq
);
1477 handle_seek(s
, windex
);
1479 /* Fall through to the default handler */
1483 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1484 pa_usec_t
*r
= userdata
;
1486 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1488 /* Fall through, the default handler will add in the extra
1489 * latency added by the resampler */
1493 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1494 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1495 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1500 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1503 /* Called from thread context */
1504 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1507 pa_sink_input_assert_ref(i
);
1508 s
= PLAYBACK_STREAM(i
->userdata
);
1509 playback_stream_assert_ref(s
);
1512 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1514 if (pa_memblockq_is_readable(s
->memblockq
))
1515 s
->is_underrun
= FALSE
;
1517 if (!s
->is_underrun
)
1518 pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i
->proplist
, PA_PROP_MEDIA_NAME
)), (unsigned long) pa_memblockq_get_length(s
->memblockq
));
1520 if (s
->drain_request
&& pa_sink_input_safe_to_remove(i
)) {
1521 s
->drain_request
= FALSE
;
1522 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, PA_UINT_TO_PTR(s
->drain_tag
), 0, NULL
, NULL
);
1523 } else if (!s
->is_underrun
)
1524 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UNDERFLOW
, NULL
, 0, NULL
, NULL
);
1526 s
->is_underrun
= TRUE
;
1528 playback_stream_request_bytes(s
);
1531 /* This call will not fail with prebuf=0, hence we check for
1532 underrun explicitly above */
1533 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1536 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1538 if (i
->thread_info
.underrun_for
> 0)
1539 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1541 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1542 playback_stream_request_bytes(s
);
1547 /* Called from thread context */
1548 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1551 pa_sink_input_assert_ref(i
);
1552 s
= PLAYBACK_STREAM(i
->userdata
);
1553 playback_stream_assert_ref(s
);
1555 /* If we are in an underrun, then we don't rewind */
1556 if (i
->thread_info
.underrun_for
> 0)
1559 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1562 /* Called from thread context */
1563 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1566 pa_sink_input_assert_ref(i
);
1567 s
= PLAYBACK_STREAM(i
->userdata
);
1568 playback_stream_assert_ref(s
);
1570 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1573 /* Called from thread context */
1574 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1576 size_t new_tlength
, old_tlength
;
1578 pa_sink_input_assert_ref(i
);
1579 s
= PLAYBACK_STREAM(i
->userdata
);
1580 playback_stream_assert_ref(s
);
1582 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1583 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1585 if (old_tlength
< new_tlength
) {
1586 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1587 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1588 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1590 if (new_tlength
== old_tlength
)
1591 pa_log_debug("Failed to increase tlength");
1593 pa_log_debug("Notifying client about increased tlength");
1594 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
, NULL
, pa_memblockq_get_tlength(s
->memblockq
), NULL
, NULL
);
1599 /* Called from main context */
1600 static void sink_input_kill_cb(pa_sink_input
*i
) {
1603 pa_sink_input_assert_ref(i
);
1604 s
= PLAYBACK_STREAM(i
->userdata
);
1605 playback_stream_assert_ref(s
);
1607 playback_stream_send_killed(s
);
1608 playback_stream_unlink(s
);
1611 /* Called from main context */
1612 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1616 pa_sink_input_assert_ref(i
);
1617 s
= PLAYBACK_STREAM(i
->userdata
);
1618 playback_stream_assert_ref(s
);
1620 if (s
->connection
->version
< 15)
1623 t
= pa_tagstruct_new(NULL
, 0);
1624 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1625 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1626 pa_tagstruct_putu32(t
, s
->index
);
1627 pa_tagstruct_puts(t
, event
);
1628 pa_tagstruct_put_proplist(t
, pl
);
1629 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1632 /* Called from main context */
1633 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
) {
1637 pa_sink_input_assert_ref(i
);
1638 s
= PLAYBACK_STREAM(i
->userdata
);
1639 playback_stream_assert_ref(s
);
1641 if (s
->connection
->version
< 12)
1644 t
= pa_tagstruct_new(NULL
, 0);
1645 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1646 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1647 pa_tagstruct_putu32(t
, s
->index
);
1648 pa_tagstruct_put_boolean(t
, suspend
);
1649 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1652 /* Called from main context */
1653 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1657 pa_sink_input_assert_ref(i
);
1658 s
= PLAYBACK_STREAM(i
->userdata
);
1659 playback_stream_assert_ref(s
);
1664 fix_playback_buffer_attr(s
);
1665 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1666 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1668 if (s
->connection
->version
< 12)
1671 t
= pa_tagstruct_new(NULL
, 0);
1672 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1673 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1674 pa_tagstruct_putu32(t
, s
->index
);
1675 pa_tagstruct_putu32(t
, dest
->index
);
1676 pa_tagstruct_puts(t
, dest
->name
);
1677 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1679 if (s
->connection
->version
>= 13) {
1680 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1681 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1682 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1683 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1684 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1687 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1690 /*** source_output callbacks ***/
1692 /* Called from thread context */
1693 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1694 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1697 pa_source_output_assert_ref(o
);
1698 s
= RECORD_STREAM(o
->userdata
);
1699 record_stream_assert_ref(s
);
1702 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1703 /* Atomically get a snapshot of all timing parameters... */
1704 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1705 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1706 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1710 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1713 /* Called from thread context */
1714 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1717 pa_source_output_assert_ref(o
);
1718 s
= RECORD_STREAM(o
->userdata
);
1719 record_stream_assert_ref(s
);
1722 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1723 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1726 static void source_output_kill_cb(pa_source_output
*o
) {
1729 pa_source_output_assert_ref(o
);
1730 s
= RECORD_STREAM(o
->userdata
);
1731 record_stream_assert_ref(s
);
1733 record_stream_send_killed(s
);
1734 record_stream_unlink(s
);
1737 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1740 pa_source_output_assert_ref(o
);
1741 s
= RECORD_STREAM(o
->userdata
);
1742 record_stream_assert_ref(s
);
1744 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1746 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1749 /* Called from main context */
1750 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1754 pa_source_output_assert_ref(o
);
1755 s
= RECORD_STREAM(o
->userdata
);
1756 record_stream_assert_ref(s
);
1758 if (s
->connection
->version
< 15)
1761 t
= pa_tagstruct_new(NULL
, 0);
1762 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1763 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1764 pa_tagstruct_putu32(t
, s
->index
);
1765 pa_tagstruct_puts(t
, event
);
1766 pa_tagstruct_put_proplist(t
, pl
);
1767 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1770 /* Called from main context */
1771 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
) {
1775 pa_source_output_assert_ref(o
);
1776 s
= RECORD_STREAM(o
->userdata
);
1777 record_stream_assert_ref(s
);
1779 if (s
->connection
->version
< 12)
1782 t
= pa_tagstruct_new(NULL
, 0);
1783 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1784 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1785 pa_tagstruct_putu32(t
, s
->index
);
1786 pa_tagstruct_put_boolean(t
, suspend
);
1787 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1790 /* Called from main context */
1791 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1795 pa_source_output_assert_ref(o
);
1796 s
= RECORD_STREAM(o
->userdata
);
1797 record_stream_assert_ref(s
);
1802 fix_record_buffer_attr_pre(s
);
1803 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1804 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1805 fix_record_buffer_attr_post(s
);
1807 if (s
->connection
->version
< 12)
1810 t
= pa_tagstruct_new(NULL
, 0);
1811 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1812 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1813 pa_tagstruct_putu32(t
, s
->index
);
1814 pa_tagstruct_putu32(t
, dest
->index
);
1815 pa_tagstruct_puts(t
, dest
->name
);
1816 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1818 if (s
->connection
->version
>= 13) {
1819 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1820 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1821 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1824 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1827 /*** pdispatch callbacks ***/
1829 static void protocol_error(pa_native_connection
*c
) {
1830 pa_log("protocol error, kicking client");
1831 native_connection_unlink(c
);
1834 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1835 if (!(expression)) { \
1836 pa_pstream_send_error((pstream), (tag), (error)); \
1841 static pa_tagstruct
*reply_new(uint32_t tag
) {
1842 pa_tagstruct
*reply
;
1844 reply
= pa_tagstruct_new(NULL
, 0);
1845 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1846 pa_tagstruct_putu32(reply
, tag
);
1850 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1851 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1853 uint32_t sink_index
, syncid
, missing
;
1854 pa_buffer_attr attr
;
1855 const char *name
= NULL
, *sink_name
;
1858 pa_tagstruct
*reply
;
1859 pa_sink
*sink
= NULL
;
1867 fix_channels
= FALSE
,
1869 variable_rate
= FALSE
,
1871 adjust_latency
= FALSE
,
1872 early_requests
= FALSE
,
1873 dont_inhibit_auto_suspend
= FALSE
,
1875 fail_on_suspend
= FALSE
,
1876 relative_volume
= FALSE
,
1877 passthrough
= FALSE
;
1879 pa_sink_input_flags_t flags
= 0;
1881 pa_bool_t volume_set
= TRUE
;
1882 int ret
= PA_ERR_INVALID
;
1884 pa_native_connection_assert_ref(c
);
1886 memset(&attr
, 0, sizeof(attr
));
1888 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
1891 PA_TAG_SAMPLE_SPEC
, &ss
,
1892 PA_TAG_CHANNEL_MAP
, &map
,
1893 PA_TAG_U32
, &sink_index
,
1894 PA_TAG_STRING
, &sink_name
,
1895 PA_TAG_U32
, &attr
.maxlength
,
1896 PA_TAG_BOOLEAN
, &corked
,
1897 PA_TAG_U32
, &attr
.tlength
,
1898 PA_TAG_U32
, &attr
.prebuf
,
1899 PA_TAG_U32
, &attr
.minreq
,
1900 PA_TAG_U32
, &syncid
,
1901 PA_TAG_CVOLUME
, &volume
,
1902 PA_TAG_INVALID
) < 0) {
1908 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
1909 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
1910 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
1911 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
1912 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
1913 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
1914 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
1915 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
1917 p
= pa_proplist_new();
1920 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
1922 if (c
->version
>= 12) {
1923 /* Since 0.9.8 the user can ask for a couple of additional flags */
1925 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
1926 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
1927 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
1928 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
1929 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
1930 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
1931 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
1934 pa_proplist_free(p
);
1939 if (c
->version
>= 13) {
1941 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
1942 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
1943 pa_tagstruct_get_proplist(t
, p
) < 0) {
1945 pa_proplist_free(p
);
1950 if (c
->version
>= 14) {
1952 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
1953 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
1955 pa_proplist_free(p
);
1960 if (c
->version
>= 15) {
1962 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
1963 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
1964 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
1966 pa_proplist_free(p
);
1971 if (c
->version
>= 17) {
1973 if (pa_tagstruct_get_boolean(t
, &relative_volume
) < 0) {
1975 pa_proplist_free(p
);
1980 if (c
->version
>= 18) {
1982 if (pa_tagstruct_get_boolean(t
, &passthrough
) < 0 ) {
1984 pa_proplist_free(p
);
1989 if (!pa_tagstruct_eof(t
)) {
1991 pa_proplist_free(p
);
1995 if (sink_index
!= PA_INVALID_INDEX
) {
1997 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
1998 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
1999 pa_proplist_free(p
);
2003 } else if (sink_name
) {
2005 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
2006 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2007 pa_proplist_free(p
);
2013 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
2014 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
2015 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
2016 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
2017 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
2018 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
2019 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
2020 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
2021 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2022 (fail_on_suspend
? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND
|PA_SINK_INPUT_KILL_ON_SUSPEND
: 0) |
2023 (passthrough
? PA_SINK_INPUT_PASSTHROUGH
: 0);
2025 /* Only since protocol version 15 there's a seperate muted_set
2026 * flag. For older versions we synthesize it here */
2027 muted_set
= muted_set
|| muted
;
2029 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
);
2030 pa_proplist_free(p
);
2032 CHECK_VALIDITY(c
->pstream
, s
, tag
, ret
);
2034 reply
= reply_new(tag
);
2035 pa_tagstruct_putu32(reply
, s
->index
);
2036 pa_assert(s
->sink_input
);
2037 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
2038 pa_tagstruct_putu32(reply
, missing
);
2040 /* pa_log("initial request is %u", missing); */
2042 if (c
->version
>= 9) {
2043 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2045 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2046 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
2047 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
2048 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
2051 if (c
->version
>= 12) {
2052 /* Since 0.9.8 we support sending the chosen sample
2053 * spec/channel map/device/suspend status back to the
2056 pa_tagstruct_put_sample_spec(reply
, &ss
);
2057 pa_tagstruct_put_channel_map(reply
, &map
);
2059 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
2060 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
2062 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
2065 if (c
->version
>= 13)
2066 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
2068 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2071 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2072 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2075 pa_native_connection_assert_ref(c
);
2078 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2079 !pa_tagstruct_eof(t
)) {
2084 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2088 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2090 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2091 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2095 playback_stream_unlink(s
);
2099 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2101 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2102 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2106 record_stream_unlink(s
);
2110 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2113 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2114 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2118 upload_stream_unlink(s
);
2123 pa_assert_not_reached();
2126 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2129 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2130 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2132 pa_buffer_attr attr
;
2133 uint32_t source_index
;
2134 const char *name
= NULL
, *source_name
;
2137 pa_tagstruct
*reply
;
2138 pa_source
*source
= NULL
;
2145 fix_channels
= FALSE
,
2147 variable_rate
= FALSE
,
2148 adjust_latency
= FALSE
,
2149 peak_detect
= FALSE
,
2150 early_requests
= FALSE
,
2151 dont_inhibit_auto_suspend
= FALSE
,
2152 fail_on_suspend
= FALSE
;
2153 pa_source_output_flags_t flags
= 0;
2155 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2156 pa_sink_input
*direct_on_input
= NULL
;
2157 int ret
= PA_ERR_INVALID
;
2159 pa_native_connection_assert_ref(c
);
2162 memset(&attr
, 0, sizeof(attr
));
2164 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2165 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2166 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2167 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2168 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2169 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2170 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2171 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2176 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2177 CHECK_VALIDITY(c
->pstream
, !source_name
|| pa_namereg_is_valid_name_or_wildcard(source_name
, PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
);
2178 CHECK_VALIDITY(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
);
2179 CHECK_VALIDITY(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2180 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2181 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2182 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2184 p
= pa_proplist_new();
2187 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2189 if (c
->version
>= 12) {
2190 /* Since 0.9.8 the user can ask for a couple of additional flags */
2192 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2193 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2194 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2195 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2196 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2197 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2198 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2201 pa_proplist_free(p
);
2206 if (c
->version
>= 13) {
2208 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2209 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2210 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2211 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2213 pa_proplist_free(p
);
2218 if (c
->version
>= 14) {
2220 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2222 pa_proplist_free(p
);
2227 if (c
->version
>= 15) {
2229 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2230 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2232 pa_proplist_free(p
);
2237 if (!pa_tagstruct_eof(t
)) {
2239 pa_proplist_free(p
);
2243 if (source_index
!= PA_INVALID_INDEX
) {
2245 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2246 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2247 pa_proplist_free(p
);
2251 } else if (source_name
) {
2253 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2254 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2255 pa_proplist_free(p
);
2260 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2262 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2263 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2264 pa_proplist_free(p
);
2270 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2271 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2272 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2273 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2274 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2275 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2276 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2277 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2278 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2279 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0);
2281 s
= record_stream_new(c
, source
, &ss
, &map
, peak_detect
, &attr
, flags
, p
, adjust_latency
, direct_on_input
, early_requests
, &ret
);
2282 pa_proplist_free(p
);
2284 CHECK_VALIDITY(c
->pstream
, s
, tag
, ret
);
2286 reply
= reply_new(tag
);
2287 pa_tagstruct_putu32(reply
, s
->index
);
2288 pa_assert(s
->source_output
);
2289 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2291 if (c
->version
>= 9) {
2292 /* Since 0.9 we support sending the buffer metrics back to the client */
2294 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2295 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2298 if (c
->version
>= 12) {
2299 /* Since 0.9.8 we support sending the chosen sample
2300 * spec/channel map/device/suspend status back to the
2303 pa_tagstruct_put_sample_spec(reply
, &ss
);
2304 pa_tagstruct_put_channel_map(reply
, &map
);
2306 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2307 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2309 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2312 if (c
->version
>= 13)
2313 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2315 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2318 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2319 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2322 pa_native_connection_assert_ref(c
);
2325 if (!pa_tagstruct_eof(t
)) {
2330 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2331 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2332 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2334 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2336 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2339 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2340 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2342 pa_tagstruct
*reply
;
2343 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2345 pa_native_connection_assert_ref(c
);
2348 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2349 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2350 !pa_tagstruct_eof(t
)) {
2355 /* Minimum supported version */
2356 if (c
->version
< 8) {
2357 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2361 /* Starting with protocol version 13 the MSB of the version tag
2362 reflects if shm is available for this pa_native_connection or
2364 if (c
->version
>= 13) {
2365 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2366 c
->version
&= 0x7FFFFFFFU
;
2369 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2371 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2373 if (!c
->authorized
) {
2374 pa_bool_t success
= FALSE
;
2377 const pa_creds
*creds
;
2379 if ((creds
= pa_pdispatch_creds(pd
))) {
2380 if (creds
->uid
== getuid())
2382 else if (c
->options
->auth_group
) {
2386 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2387 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2388 else if (gid
== creds
->gid
)
2392 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2393 pa_log_warn("Failed to check group membership.");
2399 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2400 (unsigned long) creds
->uid
,
2401 (unsigned long) creds
->gid
,
2406 if (!success
&& c
->options
->auth_cookie
) {
2409 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2410 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2415 pa_log_warn("Denied access to client with invalid authorization data.");
2416 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2420 c
->authorized
= TRUE
;
2421 if (c
->auth_timeout_event
) {
2422 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2423 c
->auth_timeout_event
= NULL
;
2427 /* Enable shared memory support if possible */
2429 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2432 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2435 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2440 /* Only enable SHM if both sides are owned by the same
2441 * user. This is a security measure because otherwise data
2442 * private to the user might leak. */
2444 const pa_creds
*creds
;
2445 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2450 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2451 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2453 reply
= reply_new(tag
);
2454 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2458 /* SHM support is only enabled after both sides made sure they are the same user. */
2462 ucred
.uid
= getuid();
2463 ucred
.gid
= getgid();
2465 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2468 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2472 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2473 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2474 const char *name
= NULL
;
2476 pa_tagstruct
*reply
;
2478 pa_native_connection_assert_ref(c
);
2481 p
= pa_proplist_new();
2483 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2484 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2485 !pa_tagstruct_eof(t
)) {
2488 pa_proplist_free(p
);
2493 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2494 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2495 pa_proplist_free(p
);
2499 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2500 pa_proplist_free(p
);
2502 reply
= reply_new(tag
);
2504 if (c
->version
>= 13)
2505 pa_tagstruct_putu32(reply
, c
->client
->index
);
2507 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2510 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2511 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2513 uint32_t idx
= PA_IDXSET_INVALID
;
2515 pa_native_connection_assert_ref(c
);
2518 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2519 !pa_tagstruct_eof(t
)) {
2524 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2525 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
);
2527 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2529 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2533 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2534 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2535 idx
= source
->index
;
2538 if (idx
== PA_IDXSET_INVALID
)
2539 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2541 pa_tagstruct
*reply
;
2542 reply
= reply_new(tag
);
2543 pa_tagstruct_putu32(reply
, idx
);
2544 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2548 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2549 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2553 pa_native_connection_assert_ref(c
);
2556 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2557 !pa_tagstruct_eof(t
)) {
2562 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2563 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2564 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2565 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2567 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
);
2570 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2571 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2572 pa_tagstruct
*reply
;
2573 const pa_mempool_stat
*stat
;
2575 pa_native_connection_assert_ref(c
);
2578 if (!pa_tagstruct_eof(t
)) {
2583 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2585 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2587 reply
= reply_new(tag
);
2588 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2589 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2590 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2591 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2592 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2593 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2596 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2597 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2598 pa_tagstruct
*reply
;
2600 struct timeval tv
, now
;
2603 pa_native_connection_assert_ref(c
);
2606 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2607 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2608 !pa_tagstruct_eof(t
)) {
2613 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2614 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2615 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2616 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2618 /* Get an atomic snapshot of all timing parameters */
2619 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);
2621 reply
= reply_new(tag
);
2622 pa_tagstruct_put_usec(reply
,
2623 s
->current_sink_latency
+
2624 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2625 pa_tagstruct_put_usec(reply
, 0);
2626 pa_tagstruct_put_boolean(reply
,
2627 s
->playing_for
> 0 &&
2628 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2629 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2630 pa_tagstruct_put_timeval(reply
, &tv
);
2631 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2632 pa_tagstruct_puts64(reply
, s
->write_index
);
2633 pa_tagstruct_puts64(reply
, s
->read_index
);
2635 if (c
->version
>= 13) {
2636 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2637 pa_tagstruct_putu64(reply
, s
->playing_for
);
2640 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2643 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2644 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2645 pa_tagstruct
*reply
;
2647 struct timeval tv
, now
;
2650 pa_native_connection_assert_ref(c
);
2653 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2654 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2655 !pa_tagstruct_eof(t
)) {
2660 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2661 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2662 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2664 /* Get an atomic snapshot of all timing parameters */
2665 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);
2667 reply
= reply_new(tag
);
2668 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2669 pa_tagstruct_put_usec(reply
,
2670 s
->current_source_latency
+
2671 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2672 pa_tagstruct_put_boolean(reply
,
2673 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2674 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2675 pa_tagstruct_put_timeval(reply
, &tv
);
2676 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2677 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2678 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2679 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2682 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2683 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2686 const char *name
= NULL
;
2689 pa_tagstruct
*reply
;
2692 pa_native_connection_assert_ref(c
);
2695 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2696 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2697 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2698 pa_tagstruct_getu32(t
, &length
) < 0) {
2703 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2704 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2705 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2706 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2707 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2708 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2710 p
= pa_proplist_new();
2712 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2713 !pa_tagstruct_eof(t
)) {
2716 pa_proplist_free(p
);
2720 if (c
->version
< 13)
2721 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2723 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2724 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2726 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2727 pa_proplist_free(p
);
2728 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2731 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2732 pa_proplist_free(p
);
2734 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2736 reply
= reply_new(tag
);
2737 pa_tagstruct_putu32(reply
, s
->index
);
2738 pa_tagstruct_putu32(reply
, length
);
2739 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2742 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2743 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2748 pa_native_connection_assert_ref(c
);
2751 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2752 !pa_tagstruct_eof(t
)) {
2757 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2759 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2760 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2761 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2763 if (!s
->memchunk
.memblock
)
2764 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
2765 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2766 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2768 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2770 upload_stream_unlink(s
);
2773 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2774 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2775 uint32_t sink_index
;
2778 const char *name
, *sink_name
;
2781 pa_tagstruct
*reply
;
2783 pa_native_connection_assert_ref(c
);
2786 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2788 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
2789 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
2790 pa_tagstruct_getu32(t
, &volume
) < 0 ||
2791 pa_tagstruct_gets(t
, &name
) < 0) {
2796 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
2797 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
2798 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2799 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2801 if (sink_index
!= PA_INVALID_INDEX
)
2802 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
2804 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
2806 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
2808 p
= pa_proplist_new();
2810 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2811 !pa_tagstruct_eof(t
)) {
2813 pa_proplist_free(p
);
2817 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
2819 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
2820 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2821 pa_proplist_free(p
);
2825 pa_proplist_free(p
);
2827 reply
= reply_new(tag
);
2829 if (c
->version
>= 13)
2830 pa_tagstruct_putu32(reply
, idx
);
2832 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2835 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2836 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2839 pa_native_connection_assert_ref(c
);
2842 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2843 !pa_tagstruct_eof(t
)) {
2848 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2849 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2851 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
2852 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2856 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2859 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
2862 pa_assert(original
);
2866 if (c
->version
< 12) {
2867 /* Before protocol version 12 we didn't support S32 samples,
2868 * so we need to lie about this to the client */
2870 if (fixed
->format
== PA_SAMPLE_S32LE
)
2871 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
2872 if (fixed
->format
== PA_SAMPLE_S32BE
)
2873 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
2876 if (c
->version
< 15) {
2877 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
2878 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
2879 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
2880 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
2884 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
2885 pa_sample_spec fixed_ss
;
2888 pa_sink_assert_ref(sink
);
2890 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
2894 PA_TAG_U32
, sink
->index
,
2895 PA_TAG_STRING
, sink
->name
,
2896 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
2897 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
2898 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
2899 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
2900 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
2901 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
2902 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
2903 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
2904 PA_TAG_USEC
, pa_sink_get_latency(sink
),
2905 PA_TAG_STRING
, sink
->driver
,
2906 PA_TAG_U32
, sink
->flags
,
2909 if (c
->version
>= 13) {
2910 pa_tagstruct_put_proplist(t
, sink
->proplist
);
2911 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
2914 if (c
->version
>= 15) {
2915 pa_tagstruct_put_volume(t
, sink
->base_volume
);
2916 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
2917 pa_log_error("Internal sink state is invalid.");
2918 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
2919 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
2920 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
2923 if (c
->version
>= 16) {
2924 pa_tagstruct_putu32(t
, sink
->ports
? pa_hashmap_size(sink
->ports
) : 0);
2930 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
2931 pa_tagstruct_puts(t
, p
->name
);
2932 pa_tagstruct_puts(t
, p
->description
);
2933 pa_tagstruct_putu32(t
, p
->priority
);
2937 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
2941 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
2942 pa_sample_spec fixed_ss
;
2945 pa_source_assert_ref(source
);
2947 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
2951 PA_TAG_U32
, source
->index
,
2952 PA_TAG_STRING
, source
->name
,
2953 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
2954 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
2955 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
2956 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
2957 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
2958 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
2959 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
2960 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
2961 PA_TAG_USEC
, pa_source_get_latency(source
),
2962 PA_TAG_STRING
, source
->driver
,
2963 PA_TAG_U32
, source
->flags
,
2966 if (c
->version
>= 13) {
2967 pa_tagstruct_put_proplist(t
, source
->proplist
);
2968 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
2971 if (c
->version
>= 15) {
2972 pa_tagstruct_put_volume(t
, source
->base_volume
);
2973 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
2974 pa_log_error("Internal source state is invalid.");
2975 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
2976 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
2977 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
2980 if (c
->version
>= 16) {
2982 pa_tagstruct_putu32(t
, source
->ports
? pa_hashmap_size(source
->ports
) : 0);
2984 if (source
->ports
) {
2988 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
2989 pa_tagstruct_puts(t
, p
->name
);
2990 pa_tagstruct_puts(t
, p
->description
);
2991 pa_tagstruct_putu32(t
, p
->priority
);
2995 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
2999 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
3003 pa_tagstruct_putu32(t
, client
->index
);
3004 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
3005 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
3006 pa_tagstruct_puts(t
, client
->driver
);
3008 if (c
->version
>= 13)
3009 pa_tagstruct_put_proplist(t
, client
->proplist
);
3012 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
3019 pa_tagstruct_putu32(t
, card
->index
);
3020 pa_tagstruct_puts(t
, card
->name
);
3021 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
3022 pa_tagstruct_puts(t
, card
->driver
);
3024 pa_tagstruct_putu32(t
, card
->profiles
? pa_hashmap_size(card
->profiles
) : 0);
3026 if (card
->profiles
) {
3027 while ((p
= pa_hashmap_iterate(card
->profiles
, &state
, NULL
))) {
3028 pa_tagstruct_puts(t
, p
->name
);
3029 pa_tagstruct_puts(t
, p
->description
);
3030 pa_tagstruct_putu32(t
, p
->n_sinks
);
3031 pa_tagstruct_putu32(t
, p
->n_sources
);
3032 pa_tagstruct_putu32(t
, p
->priority
);
3036 pa_tagstruct_puts(t
, card
->active_profile
? card
->active_profile
->name
: NULL
);
3037 pa_tagstruct_put_proplist(t
, card
->proplist
);
3040 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3044 pa_tagstruct_putu32(t
, module
->index
);
3045 pa_tagstruct_puts(t
, module
->name
);
3046 pa_tagstruct_puts(t
, module
->argument
);
3047 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3049 if (c
->version
< 15)
3050 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
3052 if (c
->version
>= 15)
3053 pa_tagstruct_put_proplist(t
, module
->proplist
);
3056 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3057 pa_sample_spec fixed_ss
;
3058 pa_usec_t sink_latency
;
3062 pa_sink_input_assert_ref(s
);
3064 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3066 pa_tagstruct_putu32(t
, s
->index
);
3067 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3068 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3069 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3070 pa_tagstruct_putu32(t
, s
->sink
->index
);
3071 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3072 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3073 pa_tagstruct_put_cvolume(t
, pa_sink_input_get_volume(s
, &v
, TRUE
));
3074 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3075 pa_tagstruct_put_usec(t
, sink_latency
);
3076 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3077 pa_tagstruct_puts(t
, s
->driver
);
3078 if (c
->version
>= 11)
3079 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
3080 if (c
->version
>= 13)
3081 pa_tagstruct_put_proplist(t
, s
->proplist
);
3084 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3085 pa_sample_spec fixed_ss
;
3086 pa_usec_t source_latency
;
3089 pa_source_output_assert_ref(s
);
3091 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3093 pa_tagstruct_putu32(t
, s
->index
);
3094 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3095 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3096 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3097 pa_tagstruct_putu32(t
, s
->source
->index
);
3098 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3099 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3100 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3101 pa_tagstruct_put_usec(t
, source_latency
);
3102 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3103 pa_tagstruct_puts(t
, s
->driver
);
3105 if (c
->version
>= 13)
3106 pa_tagstruct_put_proplist(t
, s
->proplist
);
3109 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3110 pa_sample_spec fixed_ss
;
3116 if (e
->memchunk
.memblock
)
3117 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3119 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3121 pa_tagstruct_putu32(t
, e
->index
);
3122 pa_tagstruct_puts(t
, e
->name
);
3124 if (e
->volume_is_set
)
3127 pa_cvolume_init(&v
);
3129 pa_tagstruct_put_cvolume(t
, &v
);
3130 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3131 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3132 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3133 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3134 pa_tagstruct_put_boolean(t
, e
->lazy
);
3135 pa_tagstruct_puts(t
, e
->filename
);
3137 if (c
->version
>= 13)
3138 pa_tagstruct_put_proplist(t
, e
->proplist
);
3141 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3142 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3144 pa_sink
*sink
= NULL
;
3145 pa_source
*source
= NULL
;
3146 pa_client
*client
= NULL
;
3147 pa_card
*card
= NULL
;
3148 pa_module
*module
= NULL
;
3149 pa_sink_input
*si
= NULL
;
3150 pa_source_output
*so
= NULL
;
3151 pa_scache_entry
*sce
= NULL
;
3152 const char *name
= NULL
;
3153 pa_tagstruct
*reply
;
3155 pa_native_connection_assert_ref(c
);
3158 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3159 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3160 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3161 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3162 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3163 pa_tagstruct_gets(t
, &name
) < 0) ||
3164 !pa_tagstruct_eof(t
)) {
3169 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3170 CHECK_VALIDITY(c
->pstream
, !name
||
3171 (command
== PA_COMMAND_GET_SINK_INFO
&&
3172 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3173 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3174 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3175 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3176 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3177 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3178 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3180 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3181 if (idx
!= PA_INVALID_INDEX
)
3182 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3184 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3185 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3186 if (idx
!= PA_INVALID_INDEX
)
3187 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3189 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3190 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3191 if (idx
!= PA_INVALID_INDEX
)
3192 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3194 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3195 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3196 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3197 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3198 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3199 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3200 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3201 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3202 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3204 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3205 if (idx
!= PA_INVALID_INDEX
)
3206 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3208 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3211 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3212 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3216 reply
= reply_new(tag
);
3218 sink_fill_tagstruct(c
, reply
, sink
);
3220 source_fill_tagstruct(c
, reply
, source
);
3222 client_fill_tagstruct(c
, reply
, client
);
3224 card_fill_tagstruct(c
, reply
, card
);
3226 module_fill_tagstruct(c
, reply
, module
);
3228 sink_input_fill_tagstruct(c
, reply
, si
);
3230 source_output_fill_tagstruct(c
, reply
, so
);
3232 scache_fill_tagstruct(c
, reply
, sce
);
3233 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3236 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3237 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3241 pa_tagstruct
*reply
;
3243 pa_native_connection_assert_ref(c
);
3246 if (!pa_tagstruct_eof(t
)) {
3251 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3253 reply
= reply_new(tag
);
3255 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3256 i
= c
->protocol
->core
->sinks
;
3257 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3258 i
= c
->protocol
->core
->sources
;
3259 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3260 i
= c
->protocol
->core
->clients
;
3261 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3262 i
= c
->protocol
->core
->cards
;
3263 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3264 i
= c
->protocol
->core
->modules
;
3265 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3266 i
= c
->protocol
->core
->sink_inputs
;
3267 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3268 i
= c
->protocol
->core
->source_outputs
;
3270 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3271 i
= c
->protocol
->core
->scache
;
3275 for (p
= pa_idxset_first(i
, &idx
); p
; p
= pa_idxset_next(i
, &idx
)) {
3276 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3277 sink_fill_tagstruct(c
, reply
, p
);
3278 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3279 source_fill_tagstruct(c
, reply
, p
);
3280 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3281 client_fill_tagstruct(c
, reply
, p
);
3282 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3283 card_fill_tagstruct(c
, reply
, p
);
3284 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3285 module_fill_tagstruct(c
, reply
, p
);
3286 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3287 sink_input_fill_tagstruct(c
, reply
, p
);
3288 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3289 source_output_fill_tagstruct(c
, reply
, p
);
3291 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3292 scache_fill_tagstruct(c
, reply
, p
);
3297 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3300 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3301 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3302 pa_tagstruct
*reply
;
3304 pa_source
*def_source
;
3305 pa_sample_spec fixed_ss
;
3308 pa_native_connection_assert_ref(c
);
3311 if (!pa_tagstruct_eof(t
)) {
3316 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3318 reply
= reply_new(tag
);
3319 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3320 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3322 u
= pa_get_user_name_malloc();
3323 pa_tagstruct_puts(reply
, u
);
3326 h
= pa_get_host_name_malloc();
3327 pa_tagstruct_puts(reply
, h
);
3330 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3331 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3333 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3334 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3335 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3336 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3338 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3340 if (c
->version
>= 15)
3341 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3343 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3346 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3348 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3350 pa_native_connection_assert_ref(c
);
3352 t
= pa_tagstruct_new(NULL
, 0);
3353 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3354 pa_tagstruct_putu32(t
, (uint32_t) -1);
3355 pa_tagstruct_putu32(t
, e
);
3356 pa_tagstruct_putu32(t
, idx
);
3357 pa_pstream_send_tagstruct(c
->pstream
, t
);
3360 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3361 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3362 pa_subscription_mask_t m
;
3364 pa_native_connection_assert_ref(c
);
3367 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3368 !pa_tagstruct_eof(t
)) {
3373 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3374 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3376 if (c
->subscription
)
3377 pa_subscription_free(c
->subscription
);
3380 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3381 pa_assert(c
->subscription
);
3383 c
->subscription
= NULL
;
3385 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3388 static void command_set_volume(
3395 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3398 pa_sink
*sink
= NULL
;
3399 pa_source
*source
= NULL
;
3400 pa_sink_input
*si
= NULL
;
3401 const char *name
= NULL
;
3402 const char *client_name
;
3404 pa_native_connection_assert_ref(c
);
3407 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3408 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3409 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3410 pa_tagstruct_get_cvolume(t
, &volume
) ||
3411 !pa_tagstruct_eof(t
)) {
3416 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3417 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
);
3418 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3419 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3420 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3421 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3425 case PA_COMMAND_SET_SINK_VOLUME
:
3426 if (idx
!= PA_INVALID_INDEX
)
3427 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3429 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3432 case PA_COMMAND_SET_SOURCE_VOLUME
:
3433 if (idx
!= PA_INVALID_INDEX
)
3434 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3436 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3439 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3440 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3444 pa_assert_not_reached();
3447 CHECK_VALIDITY(c
->pstream
, si
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3449 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3452 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3454 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3455 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3456 } else if (source
) {
3457 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3459 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3460 pa_source_set_volume(source
, &volume
, TRUE
);
3462 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3464 pa_log_debug("Client %s changes volume of sink input %s.",
3466 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3467 pa_sink_input_set_volume(si
, &volume
, TRUE
, TRUE
);
3470 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3473 static void command_set_mute(
3480 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3483 pa_sink
*sink
= NULL
;
3484 pa_source
*source
= NULL
;
3485 pa_sink_input
*si
= NULL
;
3486 const char *name
= NULL
, *client_name
;
3488 pa_native_connection_assert_ref(c
);
3491 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3492 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3493 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3494 pa_tagstruct_get_boolean(t
, &mute
) ||
3495 !pa_tagstruct_eof(t
)) {
3500 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3501 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
);
3502 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3503 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3504 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3508 case PA_COMMAND_SET_SINK_MUTE
:
3509 if (idx
!= PA_INVALID_INDEX
)
3510 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3512 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3516 case PA_COMMAND_SET_SOURCE_MUTE
:
3517 if (idx
!= PA_INVALID_INDEX
)
3518 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3520 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3524 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3525 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3529 pa_assert_not_reached();
3532 CHECK_VALIDITY(c
->pstream
, si
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3534 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3537 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3538 pa_sink_set_mute(sink
, mute
, TRUE
);
3539 } else if (source
) {
3540 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3541 pa_source_set_mute(source
, mute
, TRUE
);
3543 pa_log_debug("Client %s changes mute of sink input %s.",
3545 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3546 pa_sink_input_set_mute(si
, mute
, TRUE
);
3549 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3552 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3553 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3558 pa_native_connection_assert_ref(c
);
3561 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3562 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3563 !pa_tagstruct_eof(t
)) {
3568 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3569 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3570 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3571 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3572 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3574 pa_sink_input_cork(s
->sink_input
, b
);
3577 s
->is_underrun
= TRUE
;
3579 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3582 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3583 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3587 pa_native_connection_assert_ref(c
);
3590 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3591 !pa_tagstruct_eof(t
)) {
3596 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3597 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3598 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3599 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3600 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3603 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3604 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3607 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3608 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3611 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3612 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3616 pa_assert_not_reached();
3619 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3622 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3623 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3628 pa_native_connection_assert_ref(c
);
3631 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3632 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3633 !pa_tagstruct_eof(t
)) {
3638 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3639 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3640 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3642 pa_source_output_cork(s
->source_output
, b
);
3643 pa_memblockq_prebuf_force(s
->memblockq
);
3644 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3647 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3648 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3652 pa_native_connection_assert_ref(c
);
3655 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3656 !pa_tagstruct_eof(t
)) {
3661 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3662 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3663 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3665 pa_memblockq_flush_read(s
->memblockq
);
3666 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3669 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3670 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3673 pa_tagstruct
*reply
;
3675 pa_native_connection_assert_ref(c
);
3678 memset(&a
, 0, sizeof(a
));
3680 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3685 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3687 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
3689 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3691 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3692 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3693 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3695 if (pa_tagstruct_get(
3697 PA_TAG_U32
, &a
.maxlength
,
3698 PA_TAG_U32
, &a
.tlength
,
3699 PA_TAG_U32
, &a
.prebuf
,
3700 PA_TAG_U32
, &a
.minreq
,
3701 PA_TAG_INVALID
) < 0 ||
3702 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3703 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3704 !pa_tagstruct_eof(t
)) {
3709 s
->adjust_latency
= adjust_latency
;
3710 s
->early_requests
= early_requests
;
3713 fix_playback_buffer_attr(s
);
3714 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);
3716 reply
= reply_new(tag
);
3717 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3718 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
3719 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
3720 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
3722 if (c
->version
>= 13)
3723 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
3727 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3728 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
3730 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3731 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3733 if (pa_tagstruct_get(
3735 PA_TAG_U32
, &a
.maxlength
,
3736 PA_TAG_U32
, &a
.fragsize
,
3737 PA_TAG_INVALID
) < 0 ||
3738 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3739 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3740 !pa_tagstruct_eof(t
)) {
3745 s
->adjust_latency
= adjust_latency
;
3746 s
->early_requests
= early_requests
;
3749 fix_record_buffer_attr_pre(s
);
3750 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
3751 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
3752 fix_record_buffer_attr_post(s
);
3754 reply
= reply_new(tag
);
3755 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3756 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
3758 if (c
->version
>= 13)
3759 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
3762 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3765 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3766 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3770 pa_native_connection_assert_ref(c
);
3773 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3774 pa_tagstruct_getu32(t
, &rate
) < 0 ||
3775 !pa_tagstruct_eof(t
)) {
3780 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3781 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
3783 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
3786 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3787 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3788 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3790 pa_sink_input_set_rate(s
->sink_input
, rate
);
3794 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
3796 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3797 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3799 pa_source_output_set_rate(s
->source_output
, rate
);
3802 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3805 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3806 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3811 pa_native_connection_assert_ref(c
);
3814 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3816 p
= pa_proplist_new();
3818 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
3820 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
3821 pa_tagstruct_get_proplist(t
, p
) < 0 ||
3822 !pa_tagstruct_eof(t
)) {
3824 pa_proplist_free(p
);
3830 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3831 pa_tagstruct_getu32(t
, &mode
) < 0 ||
3832 pa_tagstruct_get_proplist(t
, p
) < 0 ||
3833 !pa_tagstruct_eof(t
)) {
3835 pa_proplist_free(p
);
3840 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
3841 pa_proplist_free(p
);
3842 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
3845 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
3848 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3849 if (!s
|| !playback_stream_isinstance(s
)) {
3850 pa_proplist_free(p
);
3851 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
3853 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
3855 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
3858 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
3859 pa_proplist_free(p
);
3860 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
3862 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
3865 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
3867 pa_client_update_proplist(c
->client
, mode
, p
);
3870 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3871 pa_proplist_free(p
);
3874 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3875 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3877 unsigned changed
= 0;
3879 pa_strlist
*l
= NULL
;
3881 pa_native_connection_assert_ref(c
);
3884 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3886 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
3888 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3894 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
3897 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3898 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3899 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3901 p
= s
->sink_input
->proplist
;
3903 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
3906 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3907 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3909 p
= s
->source_output
->proplist
;
3911 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
3913 p
= c
->client
->proplist
;
3919 if (pa_tagstruct_gets(t
, &k
) < 0) {
3928 l
= pa_strlist_prepend(l
, k
);
3931 if (!pa_tagstruct_eof(t
)) {
3940 l
= pa_strlist_pop(l
, &z
);
3945 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
3949 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3952 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
3955 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3956 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
3958 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
3961 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3962 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
3965 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
3966 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
3971 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3972 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3975 pa_native_connection_assert_ref(c
);
3978 if (pa_tagstruct_gets(t
, &s
) < 0 ||
3979 !pa_tagstruct_eof(t
)) {
3984 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3985 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
3987 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
3990 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
3991 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
3993 pa_namereg_set_default_source(c
->protocol
->core
, source
);
3996 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
3998 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
3999 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4001 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
4004 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4007 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4008 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4012 pa_native_connection_assert_ref(c
);
4015 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4016 pa_tagstruct_gets(t
, &name
) < 0 ||
4017 !pa_tagstruct_eof(t
)) {
4022 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4023 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4025 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
4028 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4029 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4030 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4032 pa_sink_input_set_name(s
->sink_input
, name
);
4036 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4038 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4039 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4041 pa_source_output_set_name(s
->source_output
, name
);
4044 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4047 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4048 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4051 pa_native_connection_assert_ref(c
);
4054 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4055 !pa_tagstruct_eof(t
)) {
4060 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4062 if (command
== PA_COMMAND_KILL_CLIENT
) {
4065 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4066 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4068 pa_native_connection_ref(c
);
4069 pa_client_kill(client
);
4071 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4074 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4075 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4077 pa_native_connection_ref(c
);
4078 pa_sink_input_kill(s
);
4080 pa_source_output
*s
;
4082 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4084 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4085 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4087 pa_native_connection_ref(c
);
4088 pa_source_output_kill(s
);
4091 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4092 pa_native_connection_unref(c
);
4095 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4096 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4098 const char *name
, *argument
;
4099 pa_tagstruct
*reply
;
4101 pa_native_connection_assert_ref(c
);
4104 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4105 pa_tagstruct_gets(t
, &argument
) < 0 ||
4106 !pa_tagstruct_eof(t
)) {
4111 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4112 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4113 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4115 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4116 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4120 reply
= reply_new(tag
);
4121 pa_tagstruct_putu32(reply
, m
->index
);
4122 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4125 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4126 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4130 pa_native_connection_assert_ref(c
);
4133 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4134 !pa_tagstruct_eof(t
)) {
4139 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4140 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4141 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4143 pa_module_unload_request(m
, FALSE
);
4144 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4147 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4148 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4149 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4150 const char *name_device
= NULL
;
4152 pa_native_connection_assert_ref(c
);
4155 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4156 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4157 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4158 !pa_tagstruct_eof(t
)) {
4163 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4164 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4166 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
);
4167 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4168 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4169 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4171 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4172 pa_sink_input
*si
= NULL
;
4173 pa_sink
*sink
= NULL
;
4175 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4177 if (idx_device
!= PA_INVALID_INDEX
)
4178 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4180 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4182 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4184 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4185 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4189 pa_source_output
*so
= NULL
;
4192 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4194 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4196 if (idx_device
!= PA_INVALID_INDEX
)
4197 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4199 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4201 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4203 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4204 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4209 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4212 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4213 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4214 uint32_t idx
= PA_INVALID_INDEX
;
4215 const char *name
= NULL
;
4218 pa_native_connection_assert_ref(c
);
4221 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4222 pa_tagstruct_gets(t
, &name
) < 0 ||
4223 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4224 !pa_tagstruct_eof(t
)) {
4229 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4230 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
);
4231 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4232 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4233 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4235 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4237 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4239 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4241 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4242 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4246 pa_sink
*sink
= NULL
;
4248 if (idx
!= PA_INVALID_INDEX
)
4249 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4251 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4253 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4255 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4256 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4262 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4264 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4266 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4268 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4269 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4276 if (idx
!= PA_INVALID_INDEX
)
4277 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4279 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4281 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4283 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4284 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4290 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4293 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4294 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4295 uint32_t idx
= PA_INVALID_INDEX
;
4296 const char *name
= NULL
;
4298 pa_native_protocol_ext_cb_t cb
;
4300 pa_native_connection_assert_ref(c
);
4303 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4304 pa_tagstruct_gets(t
, &name
) < 0) {
4309 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4310 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4311 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4312 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4313 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4315 if (idx
!= PA_INVALID_INDEX
)
4316 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4318 for (m
= pa_idxset_first(c
->protocol
->core
->modules
, &idx
); m
; m
= pa_idxset_next(c
->protocol
->core
->modules
, &idx
))
4319 if (strcmp(name
, m
->name
) == 0)
4323 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4324 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4326 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4327 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4329 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4333 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4334 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4335 uint32_t idx
= PA_INVALID_INDEX
;
4336 const char *name
= NULL
, *profile
= NULL
;
4337 pa_card
*card
= NULL
;
4340 pa_native_connection_assert_ref(c
);
4343 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4344 pa_tagstruct_gets(t
, &name
) < 0 ||
4345 pa_tagstruct_gets(t
, &profile
) < 0 ||
4346 !pa_tagstruct_eof(t
)) {
4351 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4352 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4353 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4354 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4355 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4357 if (idx
!= PA_INVALID_INDEX
)
4358 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4360 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4362 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4364 if ((ret
= pa_card_set_profile(card
, profile
, TRUE
)) < 0) {
4365 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4369 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4372 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4373 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4374 uint32_t idx
= PA_INVALID_INDEX
;
4375 const char *name
= NULL
, *port
= NULL
;
4378 pa_native_connection_assert_ref(c
);
4381 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4382 pa_tagstruct_gets(t
, &name
) < 0 ||
4383 pa_tagstruct_gets(t
, &port
) < 0 ||
4384 !pa_tagstruct_eof(t
)) {
4389 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4390 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
);
4391 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4392 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4393 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4395 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4398 if (idx
!= PA_INVALID_INDEX
)
4399 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4401 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4403 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4405 if ((ret
= pa_sink_set_port(sink
, port
, TRUE
)) < 0) {
4406 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4412 pa_assert(command
= PA_COMMAND_SET_SOURCE_PORT
);
4414 if (idx
!= PA_INVALID_INDEX
)
4415 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4417 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4419 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4421 if ((ret
= pa_source_set_port(source
, port
, TRUE
)) < 0) {
4422 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4427 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4430 /*** pstream callbacks ***/
4432 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4433 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4437 pa_native_connection_assert_ref(c
);
4439 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4440 pa_log("invalid packet.");
4441 native_connection_unlink(c
);
4445 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
) {
4446 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4447 output_stream
*stream
;
4451 pa_native_connection_assert_ref(c
);
4453 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4454 pa_log_debug("Client sent block for invalid stream.");
4459 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4461 if (playback_stream_isinstance(stream
)) {
4462 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4464 if (chunk
->memblock
) {
4465 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4466 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
);
4468 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4470 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
);
4473 upload_stream
*u
= UPLOAD_STREAM(stream
);
4476 if (!u
->memchunk
.memblock
) {
4477 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4478 u
->memchunk
= *chunk
;
4479 pa_memblock_ref(u
->memchunk
.memblock
);
4482 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4483 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4487 pa_assert(u
->memchunk
.memblock
);
4490 if (l
> chunk
->length
)
4495 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4497 if (chunk
->memblock
) {
4499 src
= pa_memblock_acquire(chunk
->memblock
);
4501 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4502 (uint8_t*) src
+ chunk
->index
, l
);
4504 pa_memblock_release(chunk
->memblock
);
4506 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4508 pa_memblock_release(u
->memchunk
.memblock
);
4510 u
->memchunk
.length
+= l
;
4516 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4517 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4520 pa_native_connection_assert_ref(c
);
4522 native_connection_unlink(c
);
4523 pa_log_info("Connection died.");
4526 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4527 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4530 pa_native_connection_assert_ref(c
);
4532 native_connection_send_memblock(c
);
4535 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4538 if (!(q
= pa_thread_mq_get()))
4539 pa_pstream_send_revoke(p
, block_id
);
4541 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4544 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4547 if (!(q
= pa_thread_mq_get()))
4548 pa_pstream_send_release(p
, block_id
);
4550 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4553 /*** client callbacks ***/
4555 static void client_kill_cb(pa_client
*c
) {
4558 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4559 pa_log_info("Connection killed.");
4562 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4564 pa_native_connection
*c
;
4567 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4568 pa_native_connection_assert_ref(c
);
4570 if (c
->version
< 15)
4573 t
= pa_tagstruct_new(NULL
, 0);
4574 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4575 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4576 pa_tagstruct_puts(t
, event
);
4577 pa_tagstruct_put_proplist(t
, pl
);
4578 pa_pstream_send_tagstruct(c
->pstream
, t
);
4581 /*** module entry points ***/
4583 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4584 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4587 pa_native_connection_assert_ref(c
);
4588 pa_assert(c
->auth_timeout_event
== e
);
4590 if (!c
->authorized
) {
4591 native_connection_unlink(c
);
4592 pa_log_info("Connection terminated due to authentication timeout.");
4596 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4597 pa_native_connection
*c
;
4600 pa_client_new_data data
;
4606 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4607 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4608 pa_iochannel_free(io
);
4612 pa_client_new_data_init(&data
);
4613 data
.module
= o
->module
;
4614 data
.driver
= __FILE__
;
4615 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4616 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4617 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4618 client
= pa_client_new(p
->core
, &data
);
4619 pa_client_new_data_done(&data
);
4624 c
= pa_msgobject_new(pa_native_connection
);
4625 c
->parent
.parent
.free
= native_connection_free
;
4626 c
->parent
.process_msg
= native_connection_process_msg
;
4628 c
->options
= pa_native_options_ref(o
);
4629 c
->authorized
= FALSE
;
4631 if (o
->auth_anonymous
) {
4632 pa_log_info("Client authenticated anonymously.");
4633 c
->authorized
= TRUE
;
4636 if (!c
->authorized
&&
4638 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
4640 pa_log_info("Client authenticated by IP ACL.");
4641 c
->authorized
= TRUE
;
4645 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
4647 c
->auth_timeout_event
= NULL
;
4649 c
->is_local
= pa_iochannel_socket_is_local(io
);
4653 c
->client
->kill
= client_kill_cb
;
4654 c
->client
->send_event
= client_send_event_cb
;
4655 c
->client
->userdata
= c
;
4657 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
4658 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
4659 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
4660 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
4661 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
4662 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
4663 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
4665 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, TRUE
, command_table
, PA_COMMAND_MAX
);
4667 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
4668 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
4670 c
->rrobin_index
= PA_IDXSET_INVALID
;
4671 c
->subscription
= NULL
;
4673 pa_idxset_put(p
->connections
, c
, NULL
);
4676 if (pa_iochannel_creds_supported(io
))
4677 pa_iochannel_creds_enable(io
);
4680 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
4683 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
4684 pa_native_connection
*c
;
4690 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
4691 if (c
->options
->module
== m
)
4692 native_connection_unlink(c
);
4695 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
4696 pa_native_protocol
*p
;
4701 p
= pa_xnew(pa_native_protocol
, 1);
4704 p
->connections
= pa_idxset_new(NULL
, NULL
);
4708 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
4710 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4711 pa_hook_init(&p
->hooks
[h
], p
);
4713 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
4718 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
4719 pa_native_protocol
*p
;
4721 if ((p
= pa_shared_get(c
, "native-protocol")))
4722 return pa_native_protocol_ref(p
);
4724 return native_protocol_new(c
);
4727 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
4729 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4736 void pa_native_protocol_unref(pa_native_protocol
*p
) {
4737 pa_native_connection
*c
;
4741 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4743 if (PA_REFCNT_DEC(p
) > 0)
4746 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
4747 native_connection_unlink(c
);
4749 pa_idxset_free(p
->connections
, NULL
, NULL
);
4751 pa_strlist_free(p
->servers
);
4753 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4754 pa_hook_done(&p
->hooks
[h
]);
4756 pa_hashmap_free(p
->extensions
, NULL
, NULL
);
4758 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
4763 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
4765 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4768 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
4770 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
4773 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
4775 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4778 p
->servers
= pa_strlist_remove(p
->servers
, name
);
4780 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
4783 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
4785 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4790 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
4792 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4797 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
4799 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4802 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
4804 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
4808 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
4810 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4813 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
4816 pa_native_options
* pa_native_options_new(void) {
4817 pa_native_options
*o
;
4819 o
= pa_xnew0(pa_native_options
, 1);
4825 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
4827 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4834 void pa_native_options_unref(pa_native_options
*o
) {
4836 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4838 if (PA_REFCNT_DEC(o
) > 0)
4841 pa_xfree(o
->auth_group
);
4844 pa_ip_acl_free(o
->auth_ip_acl
);
4847 pa_auth_cookie_unref(o
->auth_cookie
);
4852 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
4857 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4860 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
4861 pa_log("auth-anonymous= expects a boolean argument.");
4866 if (pa_modargs_get_value_boolean(ma
, "auth-group-enabled", &enabled
) < 0) {
4867 pa_log("auth-group-enabled= expects a boolean argument.");
4871 pa_xfree(o
->auth_group
);
4872 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
4876 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4879 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
4882 if (!(ipa
= pa_ip_acl_new(acl
))) {
4883 pa_log("Failed to parse IP ACL '%s'", acl
);
4888 pa_ip_acl_free(o
->auth_ip_acl
);
4890 o
->auth_ip_acl
= ipa
;
4894 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
4895 pa_log("auth-cookie-enabled= expects a boolean argument.");
4900 pa_auth_cookie_unref(o
->auth_cookie
);
4905 /* The new name for this is 'auth-cookie', for compat reasons
4906 * we check the old name too */
4907 if (!(cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
)))
4908 if (!(cn
= pa_modargs_get_value(ma
, "cookie", NULL
)))
4909 cn
= PA_NATIVE_COOKIE_FILE
;
4911 if (!(o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, PA_NATIVE_COOKIE_LENGTH
)))
4915 o
->auth_cookie
= NULL
;
4920 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
4921 pa_native_connection_assert_ref(c
);
4926 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
4927 pa_native_connection_assert_ref(c
);