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>
38 #include <pulse/internal.h>
40 #include <pulsecore/native-common.h>
41 #include <pulsecore/packet.h>
42 #include <pulsecore/client.h>
43 #include <pulsecore/source-output.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/pstream.h>
46 #include <pulsecore/tagstruct.h>
47 #include <pulsecore/pdispatch.h>
48 #include <pulsecore/pstream-util.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/core-subscribe.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/creds.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/ipacl.h>
59 #include <pulsecore/thread-mq.h>
61 #include "protocol-native.h"
63 /* #define PROTOCOL_NATIVE_DEBUG */
65 /* Kick a client if it doesn't authenticate within this time */
66 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
68 /* Don't accept more connection than this */
69 #define MAX_CONNECTIONS 64
71 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
72 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
73 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
74 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
76 struct pa_native_protocol
;
78 typedef struct record_stream
{
81 pa_native_connection
*connection
;
84 pa_source_output
*source_output
;
85 pa_memblockq
*memblockq
;
87 bool adjust_latency
:1;
88 bool early_requests
:1;
90 /* Requested buffer attributes */
91 pa_buffer_attr buffer_attr_req
;
92 /* Fixed-up and adjusted buffer attributes */
93 pa_buffer_attr buffer_attr
;
95 pa_atomic_t on_the_fly
;
96 pa_usec_t configured_source_latency
;
99 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
100 size_t on_the_fly_snapshot
;
101 pa_usec_t current_monitor_latency
;
102 pa_usec_t current_source_latency
;
105 #define RECORD_STREAM(o) (record_stream_cast(o))
106 PA_DEFINE_PRIVATE_CLASS(record_stream
, pa_msgobject
);
108 typedef struct output_stream
{
112 #define OUTPUT_STREAM(o) (output_stream_cast(o))
113 PA_DEFINE_PRIVATE_CLASS(output_stream
, pa_msgobject
);
115 typedef struct playback_stream
{
116 output_stream parent
;
118 pa_native_connection
*connection
;
121 pa_sink_input
*sink_input
;
122 pa_memblockq
*memblockq
;
124 bool adjust_latency
:1;
125 bool early_requests
:1;
128 bool drain_request
:1;
132 /* Optimization to avoid too many rewinds with a lot of small blocks */
133 pa_atomic_t seek_or_post_in_queue
;
137 pa_usec_t configured_sink_latency
;
138 /* Requested buffer attributes */
139 pa_buffer_attr buffer_attr_req
;
140 /* Fixed-up and adjusted buffer attributes */
141 pa_buffer_attr buffer_attr
;
143 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
144 int64_t read_index
, write_index
;
145 size_t render_memblockq_length
;
146 pa_usec_t current_sink_latency
;
147 uint64_t playing_for
, underrun_for
;
150 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
151 PA_DEFINE_PRIVATE_CLASS(playback_stream
, output_stream
);
153 typedef struct upload_stream
{
154 output_stream parent
;
156 pa_native_connection
*connection
;
159 pa_memchunk memchunk
;
162 pa_sample_spec sample_spec
;
163 pa_channel_map channel_map
;
164 pa_proplist
*proplist
;
167 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
168 PA_DEFINE_PRIVATE_CLASS(upload_stream
, output_stream
);
170 struct pa_native_connection
{
172 pa_native_protocol
*protocol
;
173 pa_native_options
*options
;
179 pa_pdispatch
*pdispatch
;
180 pa_idxset
*record_streams
, *output_streams
;
181 uint32_t rrobin_index
;
182 pa_subscription
*subscription
;
183 pa_time_event
*auth_timeout_event
;
186 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
187 PA_DEFINE_PRIVATE_CLASS(pa_native_connection
, pa_msgobject
);
189 struct pa_native_protocol
{
193 pa_idxset
*connections
;
196 pa_hook hooks
[PA_NATIVE_HOOK_MAX
];
198 pa_hashmap
*extensions
;
202 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
= PA_SOURCE_OUTPUT_MESSAGE_MAX
206 SINK_INPUT_MESSAGE_POST_DATA
= PA_SINK_INPUT_MESSAGE_MAX
, /* data from main loop to sink input */
207 SINK_INPUT_MESSAGE_DRAIN
, /* disabled prebuf, get playback started. */
208 SINK_INPUT_MESSAGE_FLUSH
,
209 SINK_INPUT_MESSAGE_TRIGGER
,
210 SINK_INPUT_MESSAGE_SEEK
,
211 SINK_INPUT_MESSAGE_PREBUF_FORCE
,
212 SINK_INPUT_MESSAGE_UPDATE_LATENCY
,
213 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
217 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, /* data requested from sink input from the main loop */
218 PLAYBACK_STREAM_MESSAGE_UNDERFLOW
,
219 PLAYBACK_STREAM_MESSAGE_OVERFLOW
,
220 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
,
221 PLAYBACK_STREAM_MESSAGE_STARTED
,
222 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
226 RECORD_STREAM_MESSAGE_POST_DATA
/* data from source output to main loop */
230 CONNECTION_MESSAGE_RELEASE
,
231 CONNECTION_MESSAGE_REVOKE
234 static bool sink_input_process_underrun_cb(pa_sink_input
*i
);
235 static int sink_input_pop_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
);
236 static void sink_input_kill_cb(pa_sink_input
*i
);
237 static void sink_input_suspend_cb(pa_sink_input
*i
, bool suspend
);
238 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
);
239 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
240 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
241 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
);
242 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
);
244 static void native_connection_send_memblock(pa_native_connection
*c
);
245 static void playback_stream_request_bytes(struct playback_stream
*s
);
247 static void source_output_kill_cb(pa_source_output
*o
);
248 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
);
249 static void source_output_suspend_cb(pa_source_output
*o
, bool suspend
);
250 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
);
251 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
);
252 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
);
254 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
255 static int source_output_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
257 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
258 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
259 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
260 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
261 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
262 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
263 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
264 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
265 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
266 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
267 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
268 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
269 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
270 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
271 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
272 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
273 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
274 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
275 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
276 static void command_set_volume(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
277 static void command_set_mute(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
278 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
279 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
280 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
281 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
282 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
283 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
284 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
285 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
286 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
287 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
288 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
289 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
290 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
291 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
292 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
293 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
294 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
295 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
296 static void command_set_port_latency_offset(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
298 static const pa_pdispatch_cb_t command_table
[PA_COMMAND_MAX
] = {
299 [PA_COMMAND_ERROR
] = NULL
,
300 [PA_COMMAND_TIMEOUT
] = NULL
,
301 [PA_COMMAND_REPLY
] = NULL
,
302 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = command_create_playback_stream
,
303 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = command_delete_stream
,
304 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = command_drain_playback_stream
,
305 [PA_COMMAND_CREATE_RECORD_STREAM
] = command_create_record_stream
,
306 [PA_COMMAND_DELETE_RECORD_STREAM
] = command_delete_stream
,
307 [PA_COMMAND_AUTH
] = command_auth
,
308 [PA_COMMAND_REQUEST
] = NULL
,
309 [PA_COMMAND_EXIT
] = command_exit
,
310 [PA_COMMAND_SET_CLIENT_NAME
] = command_set_client_name
,
311 [PA_COMMAND_LOOKUP_SINK
] = command_lookup
,
312 [PA_COMMAND_LOOKUP_SOURCE
] = command_lookup
,
313 [PA_COMMAND_STAT
] = command_stat
,
314 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = command_get_playback_latency
,
315 [PA_COMMAND_GET_RECORD_LATENCY
] = command_get_record_latency
,
316 [PA_COMMAND_CREATE_UPLOAD_STREAM
] = command_create_upload_stream
,
317 [PA_COMMAND_DELETE_UPLOAD_STREAM
] = command_delete_stream
,
318 [PA_COMMAND_FINISH_UPLOAD_STREAM
] = command_finish_upload_stream
,
319 [PA_COMMAND_PLAY_SAMPLE
] = command_play_sample
,
320 [PA_COMMAND_REMOVE_SAMPLE
] = command_remove_sample
,
321 [PA_COMMAND_GET_SINK_INFO
] = command_get_info
,
322 [PA_COMMAND_GET_SOURCE_INFO
] = command_get_info
,
323 [PA_COMMAND_GET_CLIENT_INFO
] = command_get_info
,
324 [PA_COMMAND_GET_CARD_INFO
] = command_get_info
,
325 [PA_COMMAND_GET_MODULE_INFO
] = command_get_info
,
326 [PA_COMMAND_GET_SINK_INPUT_INFO
] = command_get_info
,
327 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO
] = command_get_info
,
328 [PA_COMMAND_GET_SAMPLE_INFO
] = command_get_info
,
329 [PA_COMMAND_GET_SINK_INFO_LIST
] = command_get_info_list
,
330 [PA_COMMAND_GET_SOURCE_INFO_LIST
] = command_get_info_list
,
331 [PA_COMMAND_GET_MODULE_INFO_LIST
] = command_get_info_list
,
332 [PA_COMMAND_GET_CLIENT_INFO_LIST
] = command_get_info_list
,
333 [PA_COMMAND_GET_CARD_INFO_LIST
] = command_get_info_list
,
334 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST
] = command_get_info_list
,
335 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
] = command_get_info_list
,
336 [PA_COMMAND_GET_SAMPLE_INFO_LIST
] = command_get_info_list
,
337 [PA_COMMAND_GET_SERVER_INFO
] = command_get_server_info
,
338 [PA_COMMAND_SUBSCRIBE
] = command_subscribe
,
340 [PA_COMMAND_SET_SINK_VOLUME
] = command_set_volume
,
341 [PA_COMMAND_SET_SINK_INPUT_VOLUME
] = command_set_volume
,
342 [PA_COMMAND_SET_SOURCE_VOLUME
] = command_set_volume
,
343 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
] = command_set_volume
,
345 [PA_COMMAND_SET_SINK_MUTE
] = command_set_mute
,
346 [PA_COMMAND_SET_SINK_INPUT_MUTE
] = command_set_mute
,
347 [PA_COMMAND_SET_SOURCE_MUTE
] = command_set_mute
,
348 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
] = command_set_mute
,
350 [PA_COMMAND_SUSPEND_SINK
] = command_suspend
,
351 [PA_COMMAND_SUSPEND_SOURCE
] = command_suspend
,
353 [PA_COMMAND_CORK_PLAYBACK_STREAM
] = command_cork_playback_stream
,
354 [PA_COMMAND_FLUSH_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
355 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
356 [PA_COMMAND_PREBUF_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
358 [PA_COMMAND_CORK_RECORD_STREAM
] = command_cork_record_stream
,
359 [PA_COMMAND_FLUSH_RECORD_STREAM
] = command_flush_record_stream
,
361 [PA_COMMAND_SET_DEFAULT_SINK
] = command_set_default_sink_or_source
,
362 [PA_COMMAND_SET_DEFAULT_SOURCE
] = command_set_default_sink_or_source
,
363 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME
] = command_set_stream_name
,
364 [PA_COMMAND_SET_RECORD_STREAM_NAME
] = command_set_stream_name
,
365 [PA_COMMAND_KILL_CLIENT
] = command_kill
,
366 [PA_COMMAND_KILL_SINK_INPUT
] = command_kill
,
367 [PA_COMMAND_KILL_SOURCE_OUTPUT
] = command_kill
,
368 [PA_COMMAND_LOAD_MODULE
] = command_load_module
,
369 [PA_COMMAND_UNLOAD_MODULE
] = command_unload_module
,
371 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE
] = NULL
,
372 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE
] = NULL
,
373 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE
] = NULL
,
374 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE
] = NULL
,
376 [PA_COMMAND_MOVE_SINK_INPUT
] = command_move_stream
,
377 [PA_COMMAND_MOVE_SOURCE_OUTPUT
] = command_move_stream
,
379 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
380 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
382 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
383 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
385 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
] = command_update_proplist
,
386 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
] = command_update_proplist
,
387 [PA_COMMAND_UPDATE_CLIENT_PROPLIST
] = command_update_proplist
,
389 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
] = command_remove_proplist
,
390 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
] = command_remove_proplist
,
391 [PA_COMMAND_REMOVE_CLIENT_PROPLIST
] = command_remove_proplist
,
393 [PA_COMMAND_SET_CARD_PROFILE
] = command_set_card_profile
,
395 [PA_COMMAND_SET_SINK_PORT
] = command_set_sink_or_source_port
,
396 [PA_COMMAND_SET_SOURCE_PORT
] = command_set_sink_or_source_port
,
398 [PA_COMMAND_SET_PORT_LATENCY_OFFSET
] = command_set_port_latency_offset
,
400 [PA_COMMAND_EXTENSION
] = command_extension
403 /* structure management */
405 /* Called from main context */
406 static void upload_stream_unlink(upload_stream
*s
) {
412 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
413 s
->connection
= NULL
;
414 upload_stream_unref(s
);
417 /* Called from main context */
418 static void upload_stream_free(pa_object
*o
) {
419 upload_stream
*s
= UPLOAD_STREAM(o
);
422 upload_stream_unlink(s
);
427 pa_proplist_free(s
->proplist
);
429 if (s
->memchunk
.memblock
)
430 pa_memblock_unref(s
->memchunk
.memblock
);
435 /* Called from main context */
436 static upload_stream
* upload_stream_new(
437 pa_native_connection
*c
,
438 const pa_sample_spec
*ss
,
439 const pa_channel_map
*map
,
449 pa_assert(length
> 0);
452 s
= pa_msgobject_new(upload_stream
);
453 s
->parent
.parent
.parent
.free
= upload_stream_free
;
455 s
->sample_spec
= *ss
;
456 s
->channel_map
= *map
;
457 s
->name
= pa_xstrdup(name
);
458 pa_memchunk_reset(&s
->memchunk
);
460 s
->proplist
= pa_proplist_copy(p
);
461 pa_proplist_update(s
->proplist
, PA_UPDATE_MERGE
, c
->client
->proplist
);
463 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
468 /* Called from main context */
469 static void record_stream_unlink(record_stream
*s
) {
475 if (s
->source_output
) {
476 pa_source_output_unlink(s
->source_output
);
477 pa_source_output_unref(s
->source_output
);
478 s
->source_output
= NULL
;
481 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->record_streams
, s
, NULL
) == s
);
482 s
->connection
= NULL
;
483 record_stream_unref(s
);
486 /* Called from main context */
487 static void record_stream_free(pa_object
*o
) {
488 record_stream
*s
= RECORD_STREAM(o
);
491 record_stream_unlink(s
);
493 pa_memblockq_free(s
->memblockq
);
497 /* Called from main context */
498 static int record_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
499 record_stream
*s
= RECORD_STREAM(o
);
500 record_stream_assert_ref(s
);
507 case RECORD_STREAM_MESSAGE_POST_DATA
:
509 /* We try to keep up to date with how many bytes are
510 * currently on the fly */
511 pa_atomic_sub(&s
->on_the_fly
, chunk
->length
);
513 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
514 /* pa_log_warn("Failed to push data into output queue."); */
518 if (!pa_pstream_is_pending(s
->connection
->pstream
))
519 native_connection_send_memblock(s
->connection
);
527 /* Called from main context */
528 static void fix_record_buffer_attr_pre(record_stream
*s
) {
531 pa_usec_t orig_fragsize_usec
, fragsize_usec
, source_usec
;
535 /* This function will be called from the main thread, before as
536 * well as after the source output has been activated using
537 * pa_source_output_put()! That means it may not touch any
538 * ->thread_info data! */
540 frame_size
= pa_frame_size(&s
->source_output
->sample_spec
);
541 s
->buffer_attr
= s
->buffer_attr_req
;
543 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
544 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
545 if (s
->buffer_attr
.maxlength
<= 0)
546 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
548 if (s
->buffer_attr
.fragsize
== (uint32_t) -1)
549 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC
*PA_USEC_PER_MSEC
, &s
->source_output
->sample_spec
);
550 if (s
->buffer_attr
.fragsize
<= 0)
551 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
553 orig_fragsize_usec
= fragsize_usec
= pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &s
->source_output
->sample_spec
);
555 if (s
->early_requests
) {
557 /* In early request mode we need to emulate the classic
558 * fragment-based playback model. Unfortunately we have no
559 * mechanism to tell the source how often we want it to send us
560 * data. The next best thing we can do is to set the source's
561 * total buffer (i.e. its latency) to the fragment size. That
562 * way it will have to send data at least that often. */
564 source_usec
= fragsize_usec
;
566 } else if (s
->adjust_latency
) {
568 /* So, the user asked us to adjust the latency according to
569 * what the source can provide. Half the latency will be
570 * spent on the hw buffer, half of it in the async buffer
571 * queue we maintain for each client. */
573 source_usec
= fragsize_usec
/2;
577 /* Ok, the user didn't ask us to adjust the latency, hence we
580 source_usec
= (pa_usec_t
) -1;
583 if (source_usec
!= (pa_usec_t
) -1)
584 s
->configured_source_latency
= pa_source_output_set_requested_latency(s
->source_output
, source_usec
);
586 s
->configured_source_latency
= 0;
588 if (s
->early_requests
) {
590 /* Ok, we didn't necessarily get what we were asking for. We
591 * might still get the proper fragment interval, we just can't
594 if (fragsize_usec
!= s
->configured_source_latency
)
595 pa_log_debug("Could not configure a sufficiently low latency. Early requests might not be satisifed.");
597 } else if (s
->adjust_latency
) {
599 /* Now subtract what we actually got */
601 if (fragsize_usec
>= s
->configured_source_latency
*2)
602 fragsize_usec
-= s
->configured_source_latency
;
604 fragsize_usec
= s
->configured_source_latency
;
607 if (pa_usec_to_bytes(orig_fragsize_usec
, &s
->source_output
->sample_spec
) !=
608 pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
))
610 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
);
612 if (s
->buffer_attr
.fragsize
<= 0)
613 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
616 /* Called from main context */
617 static void fix_record_buffer_attr_post(record_stream
*s
) {
622 /* This function will be called from the main thread, before as
623 * well as after the source output has been activated using
624 * pa_source_output_put()! That means it may not touch and
625 * ->thread_info data! */
627 base
= pa_frame_size(&s
->source_output
->sample_spec
);
629 s
->buffer_attr
.fragsize
= (s
->buffer_attr
.fragsize
/base
)*base
;
630 if (s
->buffer_attr
.fragsize
<= 0)
631 s
->buffer_attr
.fragsize
= base
;
633 if (s
->buffer_attr
.fragsize
> s
->buffer_attr
.maxlength
)
634 s
->buffer_attr
.fragsize
= s
->buffer_attr
.maxlength
;
637 /* Called from main context */
638 static record_stream
* record_stream_new(
639 pa_native_connection
*c
,
644 pa_buffer_attr
*attr
,
648 pa_source_output_flags_t flags
,
652 bool relative_volume
,
654 pa_sink_input
*direct_on_input
,
658 pa_source_output
*source_output
= NULL
;
659 pa_source_output_new_data data
;
660 char *memblockq_name
;
667 pa_source_output_new_data_init(&data
);
669 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
670 data
.driver
= __FILE__
;
671 data
.module
= c
->options
->module
;
672 data
.client
= c
->client
;
674 pa_source_output_new_data_set_source(&data
, source
, false);
675 if (pa_sample_spec_valid(ss
))
676 pa_source_output_new_data_set_sample_spec(&data
, ss
);
677 if (pa_channel_map_valid(map
))
678 pa_source_output_new_data_set_channel_map(&data
, map
);
680 pa_source_output_new_data_set_formats(&data
, formats
);
681 data
.direct_on_input
= direct_on_input
;
683 pa_source_output_new_data_set_volume(&data
, volume
);
684 data
.volume_is_absolute
= !relative_volume
;
685 data
.save_volume
= false;
688 pa_source_output_new_data_set_muted(&data
, muted
);
689 data
.save_muted
= false;
692 data
.resample_method
= PA_RESAMPLER_PEAKS
;
695 *ret
= -pa_source_output_new(&source_output
, c
->protocol
->core
, &data
);
697 pa_source_output_new_data_done(&data
);
702 s
= pa_msgobject_new(record_stream
);
703 s
->parent
.parent
.free
= record_stream_free
;
704 s
->parent
.process_msg
= record_stream_process_msg
;
706 s
->source_output
= source_output
;
707 s
->buffer_attr_req
= *attr
;
708 s
->adjust_latency
= adjust_latency
;
709 s
->early_requests
= early_requests
;
710 pa_atomic_store(&s
->on_the_fly
, 0);
712 s
->source_output
->parent
.process_msg
= source_output_process_msg
;
713 s
->source_output
->push
= source_output_push_cb
;
714 s
->source_output
->kill
= source_output_kill_cb
;
715 s
->source_output
->get_latency
= source_output_get_latency_cb
;
716 s
->source_output
->moving
= source_output_moving_cb
;
717 s
->source_output
->suspend
= source_output_suspend_cb
;
718 s
->source_output
->send_event
= source_output_send_event_cb
;
719 s
->source_output
->userdata
= s
;
721 fix_record_buffer_attr_pre(s
);
723 memblockq_name
= pa_sprintf_malloc("native protocol record stream memblockq [%u]", s
->source_output
->index
);
724 s
->memblockq
= pa_memblockq_new(
727 s
->buffer_attr
.maxlength
,
729 &source_output
->sample_spec
,
734 pa_xfree(memblockq_name
);
736 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
737 fix_record_buffer_attr_post(s
);
739 *ss
= s
->source_output
->sample_spec
;
740 *map
= s
->source_output
->channel_map
;
742 pa_idxset_put(c
->record_streams
, s
, &s
->index
);
744 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
745 ((double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) + (double) s
->configured_source_latency
) / PA_USEC_PER_MSEC
,
746 (double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) / PA_USEC_PER_MSEC
,
747 (double) s
->configured_source_latency
/ PA_USEC_PER_MSEC
);
749 pa_source_output_put(s
->source_output
);
753 /* Called from main context */
754 static void record_stream_send_killed(record_stream
*r
) {
756 record_stream_assert_ref(r
);
758 t
= pa_tagstruct_new(NULL
, 0);
759 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_KILLED
);
760 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
761 pa_tagstruct_putu32(t
, r
->index
);
762 pa_pstream_send_tagstruct(r
->connection
->pstream
, t
);
765 /* Called from main context */
766 static void playback_stream_unlink(playback_stream
*s
) {
773 pa_sink_input_unlink(s
->sink_input
);
774 pa_sink_input_unref(s
->sink_input
);
775 s
->sink_input
= NULL
;
778 if (s
->drain_request
)
779 pa_pstream_send_error(s
->connection
->pstream
, s
->drain_tag
, PA_ERR_NOENTITY
);
781 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
782 s
->connection
= NULL
;
783 playback_stream_unref(s
);
786 /* Called from main context */
787 static void playback_stream_free(pa_object
* o
) {
788 playback_stream
*s
= PLAYBACK_STREAM(o
);
791 playback_stream_unlink(s
);
793 pa_memblockq_free(s
->memblockq
);
797 /* Called from main context */
798 static int playback_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
799 playback_stream
*s
= PLAYBACK_STREAM(o
);
800 playback_stream_assert_ref(s
);
807 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
: {
812 if ((l
= pa_atomic_load(&s
->missing
)) <= 0)
815 if (pa_atomic_cmpxchg(&s
->missing
, l
, 0))
819 t
= pa_tagstruct_new(NULL
, 0);
820 pa_tagstruct_putu32(t
, PA_COMMAND_REQUEST
);
821 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
822 pa_tagstruct_putu32(t
, s
->index
);
823 pa_tagstruct_putu32(t
, (uint32_t) l
);
824 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
826 #ifdef PROTOCOL_NATIVE_DEBUG
827 pa_log("Requesting %lu bytes", (unsigned long) l
);
832 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW
: {
835 #ifdef PROTOCOL_NATIVE_DEBUG
836 pa_log("signalling underflow");
839 /* Report that we're empty */
840 t
= pa_tagstruct_new(NULL
, 0);
841 pa_tagstruct_putu32(t
, PA_COMMAND_UNDERFLOW
);
842 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
843 pa_tagstruct_putu32(t
, s
->index
);
844 if (s
->connection
->version
>= 23)
845 pa_tagstruct_puts64(t
, offset
);
846 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
850 case PLAYBACK_STREAM_MESSAGE_OVERFLOW
: {
853 /* Notify the user we're overflowed*/
854 t
= pa_tagstruct_new(NULL
, 0);
855 pa_tagstruct_putu32(t
, PA_COMMAND_OVERFLOW
);
856 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
857 pa_tagstruct_putu32(t
, s
->index
);
858 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
862 case PLAYBACK_STREAM_MESSAGE_STARTED
:
864 if (s
->connection
->version
>= 13) {
867 /* Notify the user we started playback */
868 t
= pa_tagstruct_new(NULL
, 0);
869 pa_tagstruct_putu32(t
, PA_COMMAND_STARTED
);
870 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
871 pa_tagstruct_putu32(t
, s
->index
);
872 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
877 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
:
878 pa_pstream_send_simple_ack(s
->connection
->pstream
, PA_PTR_TO_UINT(userdata
));
881 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
:
883 s
->buffer_attr
.tlength
= (uint32_t) offset
;
885 if (s
->connection
->version
>= 15) {
888 t
= pa_tagstruct_new(NULL
, 0);
889 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
);
890 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
891 pa_tagstruct_putu32(t
, s
->index
);
892 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
893 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
894 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
895 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
896 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
897 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
906 /* Called from main context */
907 static void fix_playback_buffer_attr(playback_stream
*s
) {
908 size_t frame_size
, max_prebuf
;
909 pa_usec_t orig_tlength_usec
, tlength_usec
, orig_minreq_usec
, minreq_usec
, sink_usec
;
913 #ifdef PROTOCOL_NATIVE_DEBUG
914 pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes",
915 (long) s
->buffer_attr_req
.maxlength
,
916 (long) s
->buffer_attr_req
.tlength
,
917 (long) s
->buffer_attr_req
.minreq
,
918 (long) s
->buffer_attr_req
.prebuf
);
920 pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
921 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr_req
.maxlength
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
922 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr_req
.tlength
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
923 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr_req
.minreq
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
924 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr_req
.prebuf
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
));
927 /* This function will be called from the main thread, before as
928 * well as after the sink input has been activated using
929 * pa_sink_input_put()! That means it may not touch any
930 * ->thread_info data, such as the memblockq! */
932 frame_size
= pa_frame_size(&s
->sink_input
->sample_spec
);
933 s
->buffer_attr
= s
->buffer_attr_req
;
935 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
936 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
937 if (s
->buffer_attr
.maxlength
<= 0)
938 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
940 if (s
->buffer_attr
.tlength
== (uint32_t) -1)
941 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
942 if (s
->buffer_attr
.tlength
<= 0)
943 s
->buffer_attr
.tlength
= (uint32_t) frame_size
;
944 if (s
->buffer_attr
.tlength
> s
->buffer_attr
.maxlength
)
945 s
->buffer_attr
.tlength
= s
->buffer_attr
.maxlength
;
947 if (s
->buffer_attr
.minreq
== (uint32_t) -1) {
948 uint32_t process
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
949 /* With low-latency, tlength/4 gives a decent default in all of traditional, adjust latency and early request modes. */
950 uint32_t m
= s
->buffer_attr
.tlength
/ 4;
953 s
->buffer_attr
.minreq
= PA_MIN(process
, m
);
955 if (s
->buffer_attr
.minreq
<= 0)
956 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
958 if (s
->buffer_attr
.tlength
< s
->buffer_attr
.minreq
+frame_size
)
959 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
+(uint32_t) frame_size
;
961 orig_tlength_usec
= tlength_usec
= pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
);
962 orig_minreq_usec
= minreq_usec
= pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
);
964 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
965 (double) tlength_usec
/ PA_USEC_PER_MSEC
,
966 (double) minreq_usec
/ PA_USEC_PER_MSEC
);
968 if (s
->early_requests
) {
970 /* In early request mode we need to emulate the classic
971 * fragment-based playback model. Unfortunately we have no
972 * mechanism to tell the sink how often we want to be queried
973 * for data. The next best thing we can do is to set the sink's
974 * total buffer (i.e. its latency) to the fragment size. That
975 * way it will have to query us at least that often. */
977 sink_usec
= minreq_usec
;
978 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
980 } else if (s
->adjust_latency
) {
982 /* So, the user asked us to adjust the latency of the stream
983 * buffer according to the what the sink can provide. The
984 * tlength passed in shall be the overall latency. Roughly
985 * half the latency will be spent on the hw buffer, the other
986 * half of it in the async buffer queue we maintain for each
987 * client. In between we'll have a safety space of size
988 * 2*minreq. Why the 2*minreq? When the hw buffer is completely
989 * empty and needs to be filled, then our buffer must have
990 * enough data to fulfill this request immediately and thus
991 * have at least the same tlength as the size of the hw
992 * buffer. It additionally needs space for 2 times minreq
993 * because if the buffer ran empty and a partial fillup
994 * happens immediately on the next iteration we need to be
995 * able to fulfill it and give the application also minreq
996 * time to fill it up again for the next request Makes 2 times
997 * minreq in plus.. */
999 if (tlength_usec
> minreq_usec
*2)
1000 sink_usec
= (tlength_usec
- minreq_usec
*2)/2;
1004 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
1008 /* Ok, the user didn't ask us to adjust the latency, but we
1009 * still need to make sure that the parameters from the user
1012 if (tlength_usec
> minreq_usec
*2)
1013 sink_usec
= (tlength_usec
- minreq_usec
*2);
1017 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
1020 s
->configured_sink_latency
= pa_sink_input_set_requested_latency(s
->sink_input
, sink_usec
);
1022 if (s
->early_requests
) {
1024 /* Ok, we didn't necessarily get what we were asking for. We
1025 * might still get the proper fragment interval, we just can't
1028 if (minreq_usec
!= s
->configured_sink_latency
)
1029 pa_log_debug("Could not configure a sufficiently low latency. Early requests might not be satisifed.");
1031 } else if (s
->adjust_latency
) {
1033 /* Ok, we didn't necessarily get what we were asking for, so
1034 * let's subtract from what we asked for for the remaining
1037 if (tlength_usec
>= s
->configured_sink_latency
)
1038 tlength_usec
-= s
->configured_sink_latency
;
1041 pa_log_debug("Requested latency=%0.2f ms, Received latency=%0.2f ms",
1042 (double) sink_usec
/ PA_USEC_PER_MSEC
,
1043 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1045 /* FIXME: This is actually larger than necessary, since not all of
1046 * the sink latency is actually rewritable. */
1047 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
1048 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
1050 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
1051 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
1052 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
1054 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
1055 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
1056 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
1058 if (s
->buffer_attr
.minreq
<= 0) {
1059 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
1060 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
1063 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
1064 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
1066 max_prebuf
= s
->buffer_attr
.tlength
+ (uint32_t)frame_size
- s
->buffer_attr
.minreq
;
1068 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 ||
1069 s
->buffer_attr
.prebuf
> max_prebuf
)
1070 s
->buffer_attr
.prebuf
= max_prebuf
;
1072 #ifdef PROTOCOL_NATIVE_DEBUG
1073 pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
1074 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr
.maxlength
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
1075 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
1076 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
1077 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr
.prebuf
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
));
1081 /* Called from main context */
1082 static playback_stream
* playback_stream_new(
1083 pa_native_connection
*c
,
1086 pa_channel_map
*map
,
1092 pa_sink_input_flags_t flags
,
1094 bool adjust_latency
,
1095 bool early_requests
,
1096 bool relative_volume
,
1101 /* Note: This function takes ownership of the 'formats' param, so we need
1102 * to take extra care to not leak it */
1104 playback_stream
*ssync
;
1105 playback_stream
*s
= NULL
;
1106 pa_sink_input
*sink_input
= NULL
;
1107 pa_memchunk silence
;
1109 int64_t start_index
;
1110 pa_sink_input_new_data data
;
1111 char *memblockq_name
;
1119 /* Find syncid group */
1120 PA_IDXSET_FOREACH(ssync
, c
->output_streams
, idx
) {
1122 if (!playback_stream_isinstance(ssync
))
1125 if (ssync
->syncid
== syncid
)
1129 /* Synced streams must connect to the same sink */
1133 sink
= ssync
->sink_input
->sink
;
1134 else if (sink
!= ssync
->sink_input
->sink
) {
1135 *ret
= PA_ERR_INVALID
;
1140 pa_sink_input_new_data_init(&data
);
1142 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1143 data
.driver
= __FILE__
;
1144 data
.module
= c
->options
->module
;
1145 data
.client
= c
->client
;
1147 pa_sink_input_new_data_set_sink(&data
, sink
, false);
1148 if (pa_sample_spec_valid(ss
))
1149 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1150 if (pa_channel_map_valid(map
))
1151 pa_sink_input_new_data_set_channel_map(&data
, map
);
1153 pa_sink_input_new_data_set_formats(&data
, formats
);
1154 /* Ownership transferred to new_data, so we don't free it ourselves */
1158 pa_sink_input_new_data_set_volume(&data
, volume
);
1159 data
.volume_is_absolute
= !relative_volume
;
1160 data
.save_volume
= false;
1163 pa_sink_input_new_data_set_muted(&data
, muted
);
1164 data
.save_muted
= false;
1166 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1169 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
);
1171 pa_sink_input_new_data_done(&data
);
1176 s
= pa_msgobject_new(playback_stream
);
1177 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1178 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1181 s
->sink_input
= sink_input
;
1182 s
->is_underrun
= true;
1183 s
->drain_request
= false;
1184 pa_atomic_store(&s
->missing
, 0);
1185 s
->buffer_attr_req
= *a
;
1186 s
->adjust_latency
= adjust_latency
;
1187 s
->early_requests
= early_requests
;
1188 pa_atomic_store(&s
->seek_or_post_in_queue
, 0);
1189 s
->seek_windex
= -1;
1191 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1192 s
->sink_input
->pop
= sink_input_pop_cb
;
1193 s
->sink_input
->process_underrun
= sink_input_process_underrun_cb
;
1194 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1195 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1196 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1197 s
->sink_input
->kill
= sink_input_kill_cb
;
1198 s
->sink_input
->moving
= sink_input_moving_cb
;
1199 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1200 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1201 s
->sink_input
->userdata
= s
;
1203 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1205 fix_playback_buffer_attr(s
);
1207 pa_sink_input_get_silence(sink_input
, &silence
);
1208 memblockq_name
= pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s
->sink_input
->index
);
1209 s
->memblockq
= pa_memblockq_new(
1212 s
->buffer_attr
.maxlength
,
1213 s
->buffer_attr
.tlength
,
1214 &sink_input
->sample_spec
,
1215 s
->buffer_attr
.prebuf
,
1216 s
->buffer_attr
.minreq
,
1219 pa_xfree(memblockq_name
);
1220 pa_memblock_unref(silence
.memblock
);
1222 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1224 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1226 #ifdef PROTOCOL_NATIVE_DEBUG
1227 pa_log("missing original: %li", (long int) *missing
);
1230 *ss
= s
->sink_input
->sample_spec
;
1231 *map
= s
->sink_input
->channel_map
;
1233 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1235 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1236 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1237 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1238 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1239 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1241 pa_sink_input_put(s
->sink_input
);
1245 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
1250 /* Called from IO context */
1251 static void playback_stream_request_bytes(playback_stream
*s
) {
1253 int previous_missing
;
1255 playback_stream_assert_ref(s
);
1257 m
= pa_memblockq_pop_missing(s
->memblockq
);
1259 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1260 /* (unsigned long) m, */
1261 /* pa_memblockq_get_tlength(s->memblockq), */
1262 /* pa_memblockq_get_minreq(s->memblockq), */
1263 /* pa_memblockq_get_length(s->memblockq), */
1264 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1269 #ifdef PROTOCOL_NATIVE_DEBUG
1270 pa_log("request_bytes(%lu)", (unsigned long) m
);
1273 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1274 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1276 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1277 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1278 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1281 /* Called from main context */
1282 static void playback_stream_send_killed(playback_stream
*p
) {
1284 playback_stream_assert_ref(p
);
1286 t
= pa_tagstruct_new(NULL
, 0);
1287 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1288 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1289 pa_tagstruct_putu32(t
, p
->index
);
1290 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1293 /* Called from main context */
1294 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1295 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1296 pa_native_connection_assert_ref(c
);
1303 case CONNECTION_MESSAGE_REVOKE
:
1304 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1307 case CONNECTION_MESSAGE_RELEASE
:
1308 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1315 /* Called from main context */
1316 static void native_connection_unlink(pa_native_connection
*c
) {
1325 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1328 pa_native_options_unref(c
->options
);
1330 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1331 record_stream_unlink(r
);
1333 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1334 if (playback_stream_isinstance(o
))
1335 playback_stream_unlink(PLAYBACK_STREAM(o
));
1337 upload_stream_unlink(UPLOAD_STREAM(o
));
1339 if (c
->subscription
)
1340 pa_subscription_free(c
->subscription
);
1343 pa_pstream_unlink(c
->pstream
);
1345 if (c
->auth_timeout_event
) {
1346 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1347 c
->auth_timeout_event
= NULL
;
1350 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1352 pa_native_connection_unref(c
);
1355 /* Called from main context */
1356 static void native_connection_free(pa_object
*o
) {
1357 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1361 native_connection_unlink(c
);
1363 pa_idxset_free(c
->record_streams
, NULL
);
1364 pa_idxset_free(c
->output_streams
, NULL
);
1366 pa_pdispatch_unref(c
->pdispatch
);
1367 pa_pstream_unref(c
->pstream
);
1368 pa_client_free(c
->client
);
1373 /* Called from main context */
1374 static void native_connection_send_memblock(pa_native_connection
*c
) {
1378 start
= PA_IDXSET_INVALID
;
1382 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1385 if (start
== PA_IDXSET_INVALID
)
1386 start
= c
->rrobin_index
;
1387 else if (start
== c
->rrobin_index
)
1390 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1391 pa_memchunk schunk
= chunk
;
1393 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1394 schunk
.length
= r
->buffer_attr
.fragsize
;
1396 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1398 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1399 pa_memblock_unref(schunk
.memblock
);
1406 /*** sink input callbacks ***/
1408 /* Called from thread context */
1409 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1410 playback_stream_assert_ref(s
);
1412 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1414 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1416 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1418 if (pa_memblockq_is_readable(s
->memblockq
)) {
1420 /* We just ended an underrun, let's ask the sink
1421 * for a complete rewind rewrite */
1423 pa_log_debug("Requesting rewind due to end of underrun.");
1424 pa_sink_input_request_rewind(s
->sink_input
,
1425 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (uint64_t) -1 ? 0 :
1426 s
->sink_input
->thread_info
.underrun_for
),
1427 false, true, false);
1433 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1435 if (indexw
< indexr
) {
1436 /* OK, the sink already asked for this data, so
1437 * let's have it ask us again */
1439 pa_log_debug("Requesting rewind due to rewrite.");
1440 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), true, false, false);
1444 playback_stream_request_bytes(s
);
1447 static void flush_write_no_account(pa_memblockq
*q
) {
1448 pa_memblockq_flush_write(q
, false);
1451 /* Called from thread context */
1452 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1453 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1456 pa_sink_input_assert_ref(i
);
1457 s
= PLAYBACK_STREAM(i
->userdata
);
1458 playback_stream_assert_ref(s
);
1462 case SINK_INPUT_MESSAGE_SEEK
:
1463 case SINK_INPUT_MESSAGE_POST_DATA
: {
1464 int64_t windex
= pa_memblockq_get_write_index(s
->memblockq
);
1466 if (code
== SINK_INPUT_MESSAGE_SEEK
) {
1467 /* The client side is incapable of accounting correctly
1468 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1469 * able to deal with that. */
1471 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1472 windex
= PA_MIN(windex
, pa_memblockq_get_write_index(s
->memblockq
));
1475 if (chunk
&& pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1476 if (pa_log_ratelimit(PA_LOG_WARN
))
1477 pa_log_warn("Failed to push data into queue");
1478 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1479 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, true);
1482 /* If more data is in queue, we rewind later instead. */
1483 if (s
->seek_windex
!= -1)
1484 windex
= PA_MIN(windex
, s
->seek_windex
);
1485 if (pa_atomic_dec(&s
->seek_or_post_in_queue
) > 1)
1486 s
->seek_windex
= windex
;
1488 s
->seek_windex
= -1;
1489 handle_seek(s
, windex
);
1494 case SINK_INPUT_MESSAGE_DRAIN
:
1495 case SINK_INPUT_MESSAGE_FLUSH
:
1496 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1497 case SINK_INPUT_MESSAGE_TRIGGER
: {
1500 pa_sink_input
*isync
;
1501 void (*func
)(pa_memblockq
*bq
);
1504 case SINK_INPUT_MESSAGE_FLUSH
:
1505 func
= flush_write_no_account
;
1508 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1509 func
= pa_memblockq_prebuf_force
;
1512 case SINK_INPUT_MESSAGE_DRAIN
:
1513 case SINK_INPUT_MESSAGE_TRIGGER
:
1514 func
= pa_memblockq_prebuf_disable
;
1518 pa_assert_not_reached();
1521 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1523 handle_seek(s
, windex
);
1525 /* Do the same for all other members in the sync group */
1526 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1527 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1528 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1529 func(ssync
->memblockq
);
1530 handle_seek(ssync
, windex
);
1533 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1534 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1535 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1536 func(ssync
->memblockq
);
1537 handle_seek(ssync
, windex
);
1540 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1541 if (!pa_memblockq_is_readable(s
->memblockq
))
1542 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1544 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1545 s
->drain_request
= true;
1552 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1553 /* Atomically get a snapshot of all timing parameters... */
1554 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1555 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1556 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1557 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1558 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1559 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1563 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1566 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1568 /* We enable prebuffering so that after CORKED -> RUNNING
1569 * transitions we don't have trouble with underruns in case the
1570 * buffer has too little data. This must not be done when draining
1571 * has been requested, however, otherwise the buffered audio would
1573 if (!s
->drain_request
)
1574 pa_memblockq_prebuf_force(s
->memblockq
);
1576 handle_seek(s
, windex
);
1578 /* Fall through to the default handler */
1582 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1583 pa_usec_t
*r
= userdata
;
1585 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1587 /* Fall through, the default handler will add in the extra
1588 * latency added by the resampler */
1592 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1593 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1594 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1599 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1602 static bool handle_input_underrun(playback_stream
*s
, bool force
) {
1605 if (pa_memblockq_is_readable(s
->memblockq
))
1608 if (!s
->is_underrun
)
1609 pa_log_debug("%s %s of '%s'", force
? "Actual" : "Implicit",
1610 s
->drain_request
? "drain" : "underrun", pa_strnull(pa_proplist_gets(s
->sink_input
->proplist
, PA_PROP_MEDIA_NAME
)));
1612 send_drain
= s
->drain_request
&& (force
|| pa_sink_input_safe_to_remove(s
->sink_input
));
1615 s
->drain_request
= false;
1616 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
);
1617 pa_log_debug("Drain acknowledged of '%s'", pa_strnull(pa_proplist_gets(s
->sink_input
->proplist
, PA_PROP_MEDIA_NAME
)));
1618 } else if (!s
->is_underrun
) {
1619 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UNDERFLOW
, NULL
, pa_memblockq_get_read_index(s
->memblockq
), NULL
, NULL
);
1621 s
->is_underrun
= true;
1622 playback_stream_request_bytes(s
);
1626 /* Called from thread context */
1627 static bool sink_input_process_underrun_cb(pa_sink_input
*i
) {
1630 pa_sink_input_assert_ref(i
);
1631 s
= PLAYBACK_STREAM(i
->userdata
);
1632 playback_stream_assert_ref(s
);
1634 return handle_input_underrun(s
, true);
1637 /* Called from thread context */
1638 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1641 pa_sink_input_assert_ref(i
);
1642 s
= PLAYBACK_STREAM(i
->userdata
);
1643 playback_stream_assert_ref(s
);
1646 #ifdef PROTOCOL_NATIVE_DEBUG
1647 pa_log("%s, pop(): %lu", pa_proplist_gets(i
->proplist
, PA_PROP_MEDIA_NAME
), (unsigned long) pa_memblockq_get_length(s
->memblockq
));
1650 if (!handle_input_underrun(s
, false))
1651 s
->is_underrun
= false;
1653 /* This call will not fail with prebuf=0, hence we check for
1654 underrun explicitly in handle_input_underrun */
1655 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1658 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1660 if (i
->thread_info
.underrun_for
> 0)
1661 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1663 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1664 playback_stream_request_bytes(s
);
1669 /* Called from thread context */
1670 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1673 pa_sink_input_assert_ref(i
);
1674 s
= PLAYBACK_STREAM(i
->userdata
);
1675 playback_stream_assert_ref(s
);
1677 /* If we are in an underrun, then we don't rewind */
1678 if (i
->thread_info
.underrun_for
> 0)
1681 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1684 /* Called from thread context */
1685 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1688 pa_sink_input_assert_ref(i
);
1689 s
= PLAYBACK_STREAM(i
->userdata
);
1690 playback_stream_assert_ref(s
);
1692 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1695 /* Called from thread context */
1696 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1698 size_t new_tlength
, old_tlength
;
1700 pa_sink_input_assert_ref(i
);
1701 s
= PLAYBACK_STREAM(i
->userdata
);
1702 playback_stream_assert_ref(s
);
1704 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1705 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1707 if (old_tlength
< new_tlength
) {
1708 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1709 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1710 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1712 if (new_tlength
== old_tlength
)
1713 pa_log_debug("Failed to increase tlength");
1715 pa_log_debug("Notifying client about increased tlength");
1716 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
);
1721 /* Called from main context */
1722 static void sink_input_kill_cb(pa_sink_input
*i
) {
1725 pa_sink_input_assert_ref(i
);
1726 s
= PLAYBACK_STREAM(i
->userdata
);
1727 playback_stream_assert_ref(s
);
1729 playback_stream_send_killed(s
);
1730 playback_stream_unlink(s
);
1733 /* Called from main context */
1734 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1738 pa_sink_input_assert_ref(i
);
1739 s
= PLAYBACK_STREAM(i
->userdata
);
1740 playback_stream_assert_ref(s
);
1742 if (s
->connection
->version
< 15)
1745 t
= pa_tagstruct_new(NULL
, 0);
1746 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1747 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1748 pa_tagstruct_putu32(t
, s
->index
);
1749 pa_tagstruct_puts(t
, event
);
1750 pa_tagstruct_put_proplist(t
, pl
);
1751 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1754 /* Called from main context */
1755 static void sink_input_suspend_cb(pa_sink_input
*i
, bool suspend
) {
1759 pa_sink_input_assert_ref(i
);
1760 s
= PLAYBACK_STREAM(i
->userdata
);
1761 playback_stream_assert_ref(s
);
1763 if (s
->connection
->version
< 12)
1766 t
= pa_tagstruct_new(NULL
, 0);
1767 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1768 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1769 pa_tagstruct_putu32(t
, s
->index
);
1770 pa_tagstruct_put_boolean(t
, suspend
);
1771 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1774 /* Called from main context */
1775 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1779 pa_sink_input_assert_ref(i
);
1780 s
= PLAYBACK_STREAM(i
->userdata
);
1781 playback_stream_assert_ref(s
);
1786 fix_playback_buffer_attr(s
);
1787 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1788 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1790 if (s
->connection
->version
< 12)
1793 t
= pa_tagstruct_new(NULL
, 0);
1794 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1795 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1796 pa_tagstruct_putu32(t
, s
->index
);
1797 pa_tagstruct_putu32(t
, dest
->index
);
1798 pa_tagstruct_puts(t
, dest
->name
);
1799 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1801 if (s
->connection
->version
>= 13) {
1802 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1803 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1804 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1805 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1806 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1809 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1812 /*** source_output callbacks ***/
1814 /* Called from thread context */
1815 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1816 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1819 pa_source_output_assert_ref(o
);
1820 s
= RECORD_STREAM(o
->userdata
);
1821 record_stream_assert_ref(s
);
1824 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1825 /* Atomically get a snapshot of all timing parameters... */
1826 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1827 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1828 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1832 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1835 /* Called from thread context */
1836 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1839 pa_source_output_assert_ref(o
);
1840 s
= RECORD_STREAM(o
->userdata
);
1841 record_stream_assert_ref(s
);
1844 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1845 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1848 static void source_output_kill_cb(pa_source_output
*o
) {
1851 pa_source_output_assert_ref(o
);
1852 s
= RECORD_STREAM(o
->userdata
);
1853 record_stream_assert_ref(s
);
1855 record_stream_send_killed(s
);
1856 record_stream_unlink(s
);
1859 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1862 pa_source_output_assert_ref(o
);
1863 s
= RECORD_STREAM(o
->userdata
);
1864 record_stream_assert_ref(s
);
1866 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1868 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1871 /* Called from main context */
1872 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1876 pa_source_output_assert_ref(o
);
1877 s
= RECORD_STREAM(o
->userdata
);
1878 record_stream_assert_ref(s
);
1880 if (s
->connection
->version
< 15)
1883 t
= pa_tagstruct_new(NULL
, 0);
1884 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1885 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1886 pa_tagstruct_putu32(t
, s
->index
);
1887 pa_tagstruct_puts(t
, event
);
1888 pa_tagstruct_put_proplist(t
, pl
);
1889 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1892 /* Called from main context */
1893 static void source_output_suspend_cb(pa_source_output
*o
, bool suspend
) {
1897 pa_source_output_assert_ref(o
);
1898 s
= RECORD_STREAM(o
->userdata
);
1899 record_stream_assert_ref(s
);
1901 if (s
->connection
->version
< 12)
1904 t
= pa_tagstruct_new(NULL
, 0);
1905 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1906 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1907 pa_tagstruct_putu32(t
, s
->index
);
1908 pa_tagstruct_put_boolean(t
, suspend
);
1909 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1912 /* Called from main context */
1913 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1917 pa_source_output_assert_ref(o
);
1918 s
= RECORD_STREAM(o
->userdata
);
1919 record_stream_assert_ref(s
);
1924 fix_record_buffer_attr_pre(s
);
1925 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1926 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1927 fix_record_buffer_attr_post(s
);
1929 if (s
->connection
->version
< 12)
1932 t
= pa_tagstruct_new(NULL
, 0);
1933 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1934 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1935 pa_tagstruct_putu32(t
, s
->index
);
1936 pa_tagstruct_putu32(t
, dest
->index
);
1937 pa_tagstruct_puts(t
, dest
->name
);
1938 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1940 if (s
->connection
->version
>= 13) {
1941 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1942 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1943 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1946 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1949 /*** pdispatch callbacks ***/
1951 static void protocol_error(pa_native_connection
*c
) {
1952 pa_log("protocol error, kicking client");
1953 native_connection_unlink(c
);
1956 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1957 if (!(expression)) { \
1958 pa_pstream_send_error((pstream), (tag), (error)); \
1963 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1964 if (!(expression)) { \
1965 pa_pstream_send_error((pstream), (tag), (error)); \
1970 static pa_tagstruct
*reply_new(uint32_t tag
) {
1971 pa_tagstruct
*reply
;
1973 reply
= pa_tagstruct_new(NULL
, 0);
1974 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1975 pa_tagstruct_putu32(reply
, tag
);
1979 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1980 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1982 uint32_t sink_index
, syncid
, missing
= 0;
1983 pa_buffer_attr attr
;
1984 const char *name
= NULL
, *sink_name
;
1987 pa_tagstruct
*reply
;
1988 pa_sink
*sink
= NULL
;
1996 fix_channels
= false,
1998 variable_rate
= false,
2000 adjust_latency
= false,
2001 early_requests
= false,
2002 dont_inhibit_auto_suspend
= false,
2005 fail_on_suspend
= false,
2006 relative_volume
= false,
2007 passthrough
= false;
2009 pa_sink_input_flags_t flags
= 0;
2010 pa_proplist
*p
= NULL
;
2011 int ret
= PA_ERR_INVALID
;
2012 uint8_t n_formats
= 0;
2013 pa_format_info
*format
;
2014 pa_idxset
*formats
= NULL
;
2017 pa_native_connection_assert_ref(c
);
2019 memset(&attr
, 0, sizeof(attr
));
2021 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2024 PA_TAG_SAMPLE_SPEC
, &ss
,
2025 PA_TAG_CHANNEL_MAP
, &map
,
2026 PA_TAG_U32
, &sink_index
,
2027 PA_TAG_STRING
, &sink_name
,
2028 PA_TAG_U32
, &attr
.maxlength
,
2029 PA_TAG_BOOLEAN
, &corked
,
2030 PA_TAG_U32
, &attr
.tlength
,
2031 PA_TAG_U32
, &attr
.prebuf
,
2032 PA_TAG_U32
, &attr
.minreq
,
2033 PA_TAG_U32
, &syncid
,
2034 PA_TAG_CVOLUME
, &volume
,
2035 PA_TAG_INVALID
) < 0) {
2041 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
2042 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
, finish
);
2043 CHECK_VALIDITY_GOTO(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
, finish
);
2044 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
2045 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
2047 p
= pa_proplist_new();
2050 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2052 if (c
->version
>= 12) {
2053 /* Since 0.9.8 the user can ask for a couple of additional flags */
2055 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2056 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2057 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2058 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2059 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2060 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2061 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2068 if (c
->version
>= 13) {
2070 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2071 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2072 pa_tagstruct_get_proplist(t
, p
) < 0) {
2079 if (c
->version
>= 14) {
2081 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2082 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2089 if (c
->version
>= 15) {
2091 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2092 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2093 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2100 if (c
->version
>= 17) {
2102 if (pa_tagstruct_get_boolean(t
, &relative_volume
) < 0) {
2109 if (c
->version
>= 18) {
2111 if (pa_tagstruct_get_boolean(t
, &passthrough
) < 0 ) {
2117 if (c
->version
>= 21) {
2119 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2125 formats
= pa_idxset_new(NULL
, NULL
);
2127 for (i
= 0; i
< n_formats
; i
++) {
2128 format
= pa_format_info_new();
2129 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2133 pa_idxset_put(formats
, format
, NULL
);
2137 if (n_formats
== 0) {
2138 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2139 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2140 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2142 PA_IDXSET_FOREACH(format
, formats
, i
) {
2143 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2147 if (!pa_tagstruct_eof(t
)) {
2152 if (sink_index
!= PA_INVALID_INDEX
) {
2154 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
2155 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2159 } else if (sink_name
) {
2161 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
2162 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2168 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
2169 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
2170 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
2171 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
2172 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
2173 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
2174 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
2175 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
2176 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2177 (fail_on_suspend
? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND
|PA_SINK_INPUT_KILL_ON_SUSPEND
: 0) |
2178 (passthrough
? PA_SINK_INPUT_PASSTHROUGH
: 0);
2180 /* Only since protocol version 15 there's a separate muted_set
2181 * flag. For older versions we synthesize it here */
2182 muted_set
= muted_set
|| muted
;
2184 s
= playback_stream_new(c
, sink
, &ss
, &map
, formats
, &attr
, volume_set
? &volume
: NULL
, muted
, muted_set
, flags
, p
, adjust_latency
, early_requests
, relative_volume
, syncid
, &missing
, &ret
);
2185 /* We no longer own the formats idxset */
2188 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2190 reply
= reply_new(tag
);
2191 pa_tagstruct_putu32(reply
, s
->index
);
2192 pa_assert(s
->sink_input
);
2193 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
2194 pa_tagstruct_putu32(reply
, missing
);
2196 #ifdef PROTOCOL_NATIVE_DEBUG
2197 pa_log("initial request is %u", missing
);
2200 if (c
->version
>= 9) {
2201 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2203 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2204 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
2205 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
2206 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
2209 if (c
->version
>= 12) {
2210 /* Since 0.9.8 we support sending the chosen sample
2211 * spec/channel map/device/suspend status back to the
2214 pa_tagstruct_put_sample_spec(reply
, &ss
);
2215 pa_tagstruct_put_channel_map(reply
, &map
);
2217 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
2218 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
2220 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
2223 if (c
->version
>= 13)
2224 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
2226 if (c
->version
>= 21) {
2227 /* Send back the format we negotiated */
2228 if (s
->sink_input
->format
)
2229 pa_tagstruct_put_format_info(reply
, s
->sink_input
->format
);
2231 pa_format_info
*f
= pa_format_info_new();
2232 pa_tagstruct_put_format_info(reply
, f
);
2233 pa_format_info_free(f
);
2237 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2241 pa_proplist_free(p
);
2243 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
2246 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2247 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2250 pa_native_connection_assert_ref(c
);
2253 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2254 !pa_tagstruct_eof(t
)) {
2259 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2263 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2265 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2266 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2270 playback_stream_unlink(s
);
2274 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2276 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2277 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2281 record_stream_unlink(s
);
2285 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2288 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2289 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2293 upload_stream_unlink(s
);
2298 pa_assert_not_reached();
2301 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2304 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2305 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2307 pa_buffer_attr attr
;
2308 uint32_t source_index
;
2309 const char *name
= NULL
, *source_name
;
2312 pa_tagstruct
*reply
;
2313 pa_source
*source
= NULL
;
2321 fix_channels
= false,
2323 variable_rate
= false,
2325 adjust_latency
= false,
2326 peak_detect
= false,
2327 early_requests
= false,
2328 dont_inhibit_auto_suspend
= false,
2331 fail_on_suspend
= false,
2332 relative_volume
= false,
2333 passthrough
= false;
2335 pa_source_output_flags_t flags
= 0;
2336 pa_proplist
*p
= NULL
;
2337 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2338 pa_sink_input
*direct_on_input
= NULL
;
2339 int ret
= PA_ERR_INVALID
;
2340 uint8_t n_formats
= 0;
2341 pa_format_info
*format
;
2342 pa_idxset
*formats
= NULL
;
2345 pa_native_connection_assert_ref(c
);
2348 memset(&attr
, 0, sizeof(attr
));
2350 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2351 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2352 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2353 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2354 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2355 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2356 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2357 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2363 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
2364 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| pa_namereg_is_valid_name_or_wildcard(source_name
, PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
, finish
);
2365 CHECK_VALIDITY_GOTO(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
, finish
);
2366 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
2368 p
= pa_proplist_new();
2371 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2373 if (c
->version
>= 12) {
2374 /* Since 0.9.8 the user can ask for a couple of additional flags */
2376 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2377 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2378 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2379 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2380 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2381 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2382 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2389 if (c
->version
>= 13) {
2391 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2392 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2393 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2394 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2401 if (c
->version
>= 14) {
2403 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2409 if (c
->version
>= 15) {
2411 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2412 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2419 if (c
->version
>= 22) {
2420 /* For newer client versions (with per-source-output volumes), we try
2421 * to make the behaviour for playback and record streams the same. */
2424 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2430 formats
= pa_idxset_new(NULL
, NULL
);
2432 for (i
= 0; i
< n_formats
; i
++) {
2433 format
= pa_format_info_new();
2434 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2438 pa_idxset_put(formats
, format
, NULL
);
2441 if (pa_tagstruct_get_cvolume(t
, &volume
) < 0 ||
2442 pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2443 pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2444 pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2445 pa_tagstruct_get_boolean(t
, &relative_volume
) < 0 ||
2446 pa_tagstruct_get_boolean(t
, &passthrough
) < 0) {
2452 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
2455 if (n_formats
== 0) {
2456 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2457 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2458 CHECK_VALIDITY_GOTO(c
->pstream
, c
->version
< 22 || (volume
.channels
== ss
.channels
), tag
, PA_ERR_INVALID
, finish
);
2459 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2461 PA_IDXSET_FOREACH(format
, formats
, i
) {
2462 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2466 if (!pa_tagstruct_eof(t
)) {
2471 if (source_index
!= PA_INVALID_INDEX
) {
2473 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2474 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2478 } else if (source_name
) {
2480 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2481 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2486 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2488 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2489 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2495 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2496 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2497 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2498 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2499 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2500 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2501 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2502 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2503 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2504 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0) |
2505 (passthrough
? PA_SOURCE_OUTPUT_PASSTHROUGH
: 0);
2507 s
= record_stream_new(c
, source
, &ss
, &map
, formats
, &attr
, volume_set
? &volume
: NULL
, muted
, muted_set
, flags
, p
, adjust_latency
, early_requests
, relative_volume
, peak_detect
, direct_on_input
, &ret
);
2509 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2511 reply
= reply_new(tag
);
2512 pa_tagstruct_putu32(reply
, s
->index
);
2513 pa_assert(s
->source_output
);
2514 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2516 if (c
->version
>= 9) {
2517 /* Since 0.9 we support sending the buffer metrics back to the client */
2519 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2520 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2523 if (c
->version
>= 12) {
2524 /* Since 0.9.8 we support sending the chosen sample
2525 * spec/channel map/device/suspend status back to the
2528 pa_tagstruct_put_sample_spec(reply
, &ss
);
2529 pa_tagstruct_put_channel_map(reply
, &map
);
2531 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2532 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2534 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2537 if (c
->version
>= 13)
2538 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2540 if (c
->version
>= 22) {
2541 /* Send back the format we negotiated */
2542 if (s
->source_output
->format
)
2543 pa_tagstruct_put_format_info(reply
, s
->source_output
->format
);
2545 pa_format_info
*f
= pa_format_info_new();
2546 pa_tagstruct_put_format_info(reply
, f
);
2547 pa_format_info_free(f
);
2551 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2555 pa_proplist_free(p
);
2557 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
2560 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2561 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2564 pa_native_connection_assert_ref(c
);
2567 if (!pa_tagstruct_eof(t
)) {
2572 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2573 ret
= pa_core_exit(c
->protocol
->core
, false, 0);
2574 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2576 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2578 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2581 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2582 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2584 pa_tagstruct
*reply
;
2585 bool shm_on_remote
= false, do_shm
;
2587 pa_native_connection_assert_ref(c
);
2590 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2591 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2592 !pa_tagstruct_eof(t
)) {
2597 /* Minimum supported version */
2598 if (c
->version
< 8) {
2599 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2603 /* Starting with protocol version 13 the MSB of the version tag
2604 reflects if shm is available for this pa_native_connection or
2606 if (c
->version
>= 13) {
2607 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2608 c
->version
&= 0x7FFFFFFFU
;
2611 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2613 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2615 if (!c
->authorized
) {
2616 bool success
= false;
2619 const pa_creds
*creds
;
2621 if ((creds
= pa_pdispatch_creds(pd
))) {
2622 if (creds
->uid
== getuid())
2624 else if (c
->options
->auth_group
) {
2628 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2629 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2630 else if (gid
== creds
->gid
)
2634 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2635 pa_log_warn("Failed to check group membership.");
2641 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2642 (unsigned long) creds
->uid
,
2643 (unsigned long) creds
->gid
,
2648 if (!success
&& c
->options
->auth_cookie
) {
2651 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2652 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2657 pa_log_warn("Denied access to client with invalid authorization data.");
2658 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2662 c
->authorized
= true;
2663 if (c
->auth_timeout_event
) {
2664 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2665 c
->auth_timeout_event
= NULL
;
2669 /* Enable shared memory support if possible */
2671 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2674 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2677 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2682 /* Only enable SHM if both sides are owned by the same
2683 * user. This is a security measure because otherwise data
2684 * private to the user might leak. */
2686 const pa_creds
*creds
;
2687 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2692 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2693 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2695 reply
= reply_new(tag
);
2696 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2700 /* SHM support is only enabled after both sides made sure they are the same user. */
2704 ucred
.uid
= getuid();
2705 ucred
.gid
= getgid();
2707 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2710 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2714 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2715 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2716 const char *name
= NULL
;
2718 pa_tagstruct
*reply
;
2720 pa_native_connection_assert_ref(c
);
2723 p
= pa_proplist_new();
2725 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2726 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2727 !pa_tagstruct_eof(t
)) {
2730 pa_proplist_free(p
);
2735 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2736 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2737 pa_proplist_free(p
);
2741 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2742 pa_proplist_free(p
);
2744 reply
= reply_new(tag
);
2746 if (c
->version
>= 13)
2747 pa_tagstruct_putu32(reply
, c
->client
->index
);
2749 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2752 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2753 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2755 uint32_t idx
= PA_IDXSET_INVALID
;
2757 pa_native_connection_assert_ref(c
);
2760 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2761 !pa_tagstruct_eof(t
)) {
2766 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2767 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
);
2769 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2771 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2775 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2776 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2777 idx
= source
->index
;
2780 if (idx
== PA_IDXSET_INVALID
)
2781 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2783 pa_tagstruct
*reply
;
2784 reply
= reply_new(tag
);
2785 pa_tagstruct_putu32(reply
, idx
);
2786 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2790 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2791 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2795 pa_native_connection_assert_ref(c
);
2798 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2799 !pa_tagstruct_eof(t
)) {
2804 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2805 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2806 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2807 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2809 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
);
2812 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2813 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2814 pa_tagstruct
*reply
;
2815 const pa_mempool_stat
*stat
;
2817 pa_native_connection_assert_ref(c
);
2820 if (!pa_tagstruct_eof(t
)) {
2825 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2827 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2829 reply
= reply_new(tag
);
2830 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2831 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2832 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2833 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2834 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2835 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2838 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2839 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2840 pa_tagstruct
*reply
;
2842 struct timeval tv
, now
;
2845 pa_native_connection_assert_ref(c
);
2848 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2849 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2850 !pa_tagstruct_eof(t
)) {
2855 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2856 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2857 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2858 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2860 /* Get an atomic snapshot of all timing parameters */
2861 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);
2863 reply
= reply_new(tag
);
2864 pa_tagstruct_put_usec(reply
,
2865 s
->current_sink_latency
+
2866 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2867 pa_tagstruct_put_usec(reply
, 0);
2868 pa_tagstruct_put_boolean(reply
,
2869 s
->playing_for
> 0 &&
2870 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2871 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2872 pa_tagstruct_put_timeval(reply
, &tv
);
2873 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2874 pa_tagstruct_puts64(reply
, s
->write_index
);
2875 pa_tagstruct_puts64(reply
, s
->read_index
);
2877 if (c
->version
>= 13) {
2878 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2879 pa_tagstruct_putu64(reply
, s
->playing_for
);
2882 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2885 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2886 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2887 pa_tagstruct
*reply
;
2889 struct timeval tv
, now
;
2892 pa_native_connection_assert_ref(c
);
2895 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2896 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2897 !pa_tagstruct_eof(t
)) {
2902 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2903 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2904 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2906 /* Get an atomic snapshot of all timing parameters */
2907 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);
2909 reply
= reply_new(tag
);
2910 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2911 pa_tagstruct_put_usec(reply
,
2912 s
->current_source_latency
+
2913 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2914 pa_tagstruct_put_boolean(reply
,
2915 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2916 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2917 pa_tagstruct_put_timeval(reply
, &tv
);
2918 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2919 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2920 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2921 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2924 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2925 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2928 const char *name
= NULL
;
2931 pa_tagstruct
*reply
;
2934 pa_native_connection_assert_ref(c
);
2937 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2938 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2939 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2940 pa_tagstruct_getu32(t
, &length
) < 0) {
2945 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2946 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2947 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2948 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2949 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2950 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2952 p
= pa_proplist_new();
2954 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2955 !pa_tagstruct_eof(t
)) {
2958 pa_proplist_free(p
);
2962 if (c
->version
< 13)
2963 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2965 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2966 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2968 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2969 pa_proplist_free(p
);
2970 CHECK_VALIDITY(c
->pstream
, false, tag
, PA_ERR_INVALID
);
2973 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2974 pa_proplist_free(p
);
2976 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2978 reply
= reply_new(tag
);
2979 pa_tagstruct_putu32(reply
, s
->index
);
2980 pa_tagstruct_putu32(reply
, length
);
2981 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2984 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2985 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2990 pa_native_connection_assert_ref(c
);
2993 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2994 !pa_tagstruct_eof(t
)) {
2999 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3001 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
3002 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3003 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3005 if (!s
->memchunk
.memblock
)
3006 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
3007 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
3008 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
3010 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3012 upload_stream_unlink(s
);
3015 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3016 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3017 uint32_t sink_index
;
3020 const char *name
, *sink_name
;
3023 pa_tagstruct
*reply
;
3025 pa_native_connection_assert_ref(c
);
3028 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3030 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
3031 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
3032 pa_tagstruct_getu32(t
, &volume
) < 0 ||
3033 pa_tagstruct_gets(t
, &name
) < 0) {
3038 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
3039 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
3040 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3041 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3043 if (sink_index
!= PA_INVALID_INDEX
)
3044 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
3046 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
3048 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
3050 p
= pa_proplist_new();
3052 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
3053 !pa_tagstruct_eof(t
)) {
3055 pa_proplist_free(p
);
3059 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
3061 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
3062 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3063 pa_proplist_free(p
);
3067 pa_proplist_free(p
);
3069 reply
= reply_new(tag
);
3071 if (c
->version
>= 13)
3072 pa_tagstruct_putu32(reply
, idx
);
3074 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3077 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3078 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3081 pa_native_connection_assert_ref(c
);
3084 if (pa_tagstruct_gets(t
, &name
) < 0 ||
3085 !pa_tagstruct_eof(t
)) {
3090 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3091 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3093 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
3094 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3098 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3101 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
3104 pa_assert(original
);
3108 if (c
->version
< 12) {
3109 /* Before protocol version 12 we didn't support S32 samples,
3110 * so we need to lie about this to the client */
3112 if (fixed
->format
== PA_SAMPLE_S32LE
)
3113 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3114 if (fixed
->format
== PA_SAMPLE_S32BE
)
3115 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3118 if (c
->version
< 15) {
3119 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
3120 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3121 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
3122 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3126 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
3127 pa_sample_spec fixed_ss
;
3130 pa_sink_assert_ref(sink
);
3132 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
3136 PA_TAG_U32
, sink
->index
,
3137 PA_TAG_STRING
, sink
->name
,
3138 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3139 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3140 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
3141 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
3142 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, false),
3143 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, false),
3144 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
3145 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
3146 PA_TAG_USEC
, pa_sink_get_latency(sink
),
3147 PA_TAG_STRING
, sink
->driver
,
3148 PA_TAG_U32
, sink
->flags
& PA_SINK_CLIENT_FLAGS_MASK
,
3151 if (c
->version
>= 13) {
3152 pa_tagstruct_put_proplist(t
, sink
->proplist
);
3153 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
3156 if (c
->version
>= 15) {
3157 pa_tagstruct_put_volume(t
, sink
->base_volume
);
3158 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
3159 pa_log_error("Internal sink state is invalid.");
3160 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
3161 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
3162 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
3165 if (c
->version
>= 16) {
3169 pa_tagstruct_putu32(t
, pa_hashmap_size(sink
->ports
));
3171 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
3172 pa_tagstruct_puts(t
, p
->name
);
3173 pa_tagstruct_puts(t
, p
->description
);
3174 pa_tagstruct_putu32(t
, p
->priority
);
3175 if (c
->version
>= 24)
3176 pa_tagstruct_putu32(t
, p
->available
);
3179 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
3182 if (c
->version
>= 21) {
3185 pa_idxset
*formats
= pa_sink_get_formats(sink
);
3187 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3188 PA_IDXSET_FOREACH(f
, formats
, i
) {
3189 pa_tagstruct_put_format_info(t
, f
);
3192 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
3196 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
3197 pa_sample_spec fixed_ss
;
3200 pa_source_assert_ref(source
);
3202 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
3206 PA_TAG_U32
, source
->index
,
3207 PA_TAG_STRING
, source
->name
,
3208 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3209 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3210 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
3211 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
3212 PA_TAG_CVOLUME
, pa_source_get_volume(source
, false),
3213 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, false),
3214 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
3215 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
3216 PA_TAG_USEC
, pa_source_get_latency(source
),
3217 PA_TAG_STRING
, source
->driver
,
3218 PA_TAG_U32
, source
->flags
& PA_SOURCE_CLIENT_FLAGS_MASK
,
3221 if (c
->version
>= 13) {
3222 pa_tagstruct_put_proplist(t
, source
->proplist
);
3223 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
3226 if (c
->version
>= 15) {
3227 pa_tagstruct_put_volume(t
, source
->base_volume
);
3228 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
3229 pa_log_error("Internal source state is invalid.");
3230 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
3231 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
3232 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
3235 if (c
->version
>= 16) {
3239 pa_tagstruct_putu32(t
, pa_hashmap_size(source
->ports
));
3241 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
3242 pa_tagstruct_puts(t
, p
->name
);
3243 pa_tagstruct_puts(t
, p
->description
);
3244 pa_tagstruct_putu32(t
, p
->priority
);
3245 if (c
->version
>= 24)
3246 pa_tagstruct_putu32(t
, p
->available
);
3249 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
3252 if (c
->version
>= 22) {
3255 pa_idxset
*formats
= pa_source_get_formats(source
);
3257 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3258 PA_IDXSET_FOREACH(f
, formats
, i
) {
3259 pa_tagstruct_put_format_info(t
, f
);
3262 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
3266 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
3270 pa_tagstruct_putu32(t
, client
->index
);
3271 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
3272 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
3273 pa_tagstruct_puts(t
, client
->driver
);
3275 if (c
->version
>= 13)
3276 pa_tagstruct_put_proplist(t
, client
->proplist
);
3279 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
3282 pa_device_port
*port
;
3287 pa_tagstruct_putu32(t
, card
->index
);
3288 pa_tagstruct_puts(t
, card
->name
);
3289 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
3290 pa_tagstruct_puts(t
, card
->driver
);
3292 pa_tagstruct_putu32(t
, pa_hashmap_size(card
->profiles
));
3294 PA_HASHMAP_FOREACH(p
, card
->profiles
, state
) {
3295 pa_tagstruct_puts(t
, p
->name
);
3296 pa_tagstruct_puts(t
, p
->description
);
3297 pa_tagstruct_putu32(t
, p
->n_sinks
);
3298 pa_tagstruct_putu32(t
, p
->n_sources
);
3299 pa_tagstruct_putu32(t
, p
->priority
);
3301 if (c
->version
>= 29)
3302 pa_tagstruct_putu32(t
, (p
->available
!= PA_AVAILABLE_NO
));
3305 pa_tagstruct_puts(t
, card
->active_profile
->name
);
3306 pa_tagstruct_put_proplist(t
, card
->proplist
);
3308 if (c
->version
< 26)
3311 pa_tagstruct_putu32(t
, pa_hashmap_size(card
->ports
));
3313 PA_HASHMAP_FOREACH(port
, card
->ports
, state
) {
3316 pa_tagstruct_puts(t
, port
->name
);
3317 pa_tagstruct_puts(t
, port
->description
);
3318 pa_tagstruct_putu32(t
, port
->priority
);
3319 pa_tagstruct_putu32(t
, port
->available
);
3320 pa_tagstruct_putu8(t
, port
->direction
);
3321 pa_tagstruct_put_proplist(t
, port
->proplist
);
3323 pa_tagstruct_putu32(t
, pa_hashmap_size(port
->profiles
));
3325 PA_HASHMAP_FOREACH(p
, port
->profiles
, state2
)
3326 pa_tagstruct_puts(t
, p
->name
);
3328 if (c
->version
>= 27)
3329 pa_tagstruct_puts64(t
, port
->latency_offset
);
3333 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3337 pa_tagstruct_putu32(t
, module
->index
);
3338 pa_tagstruct_puts(t
, module
->name
);
3339 pa_tagstruct_puts(t
, module
->argument
);
3340 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3342 if (c
->version
< 15)
3343 pa_tagstruct_put_boolean(t
, false); /* autoload is obsolete */
3345 if (c
->version
>= 15)
3346 pa_tagstruct_put_proplist(t
, module
->proplist
);
3349 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3350 pa_sample_spec fixed_ss
;
3351 pa_usec_t sink_latency
;
3353 bool has_volume
= false;
3356 pa_sink_input_assert_ref(s
);
3358 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3360 has_volume
= pa_sink_input_is_volume_readable(s
);
3362 pa_sink_input_get_volume(s
, &v
, true);
3364 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3366 pa_tagstruct_putu32(t
, s
->index
);
3367 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3368 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3369 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3370 pa_tagstruct_putu32(t
, s
->sink
->index
);
3371 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3372 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3373 pa_tagstruct_put_cvolume(t
, &v
);
3374 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3375 pa_tagstruct_put_usec(t
, sink_latency
);
3376 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3377 pa_tagstruct_puts(t
, s
->driver
);
3378 if (c
->version
>= 11)
3379 pa_tagstruct_put_boolean(t
, s
->muted
);
3380 if (c
->version
>= 13)
3381 pa_tagstruct_put_proplist(t
, s
->proplist
);
3382 if (c
->version
>= 19)
3383 pa_tagstruct_put_boolean(t
, (pa_sink_input_get_state(s
) == PA_SINK_INPUT_CORKED
));
3384 if (c
->version
>= 20) {
3385 pa_tagstruct_put_boolean(t
, has_volume
);
3386 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3388 if (c
->version
>= 21)
3389 pa_tagstruct_put_format_info(t
, s
->format
);
3392 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3393 pa_sample_spec fixed_ss
;
3394 pa_usec_t source_latency
;
3396 bool has_volume
= false;
3399 pa_source_output_assert_ref(s
);
3401 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3403 has_volume
= pa_source_output_is_volume_readable(s
);
3405 pa_source_output_get_volume(s
, &v
, true);
3407 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3409 pa_tagstruct_putu32(t
, s
->index
);
3410 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3411 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3412 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3413 pa_tagstruct_putu32(t
, s
->source
->index
);
3414 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3415 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3416 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3417 pa_tagstruct_put_usec(t
, source_latency
);
3418 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3419 pa_tagstruct_puts(t
, s
->driver
);
3420 if (c
->version
>= 13)
3421 pa_tagstruct_put_proplist(t
, s
->proplist
);
3422 if (c
->version
>= 19)
3423 pa_tagstruct_put_boolean(t
, (pa_source_output_get_state(s
) == PA_SOURCE_OUTPUT_CORKED
));
3424 if (c
->version
>= 22) {
3425 pa_tagstruct_put_cvolume(t
, &v
);
3426 pa_tagstruct_put_boolean(t
, s
->muted
);
3427 pa_tagstruct_put_boolean(t
, has_volume
);
3428 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3429 pa_tagstruct_put_format_info(t
, s
->format
);
3433 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3434 pa_sample_spec fixed_ss
;
3440 if (e
->memchunk
.memblock
)
3441 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3443 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3445 pa_tagstruct_putu32(t
, e
->index
);
3446 pa_tagstruct_puts(t
, e
->name
);
3448 if (e
->volume_is_set
)
3451 pa_cvolume_init(&v
);
3453 pa_tagstruct_put_cvolume(t
, &v
);
3454 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3455 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3456 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3457 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3458 pa_tagstruct_put_boolean(t
, e
->lazy
);
3459 pa_tagstruct_puts(t
, e
->filename
);
3461 if (c
->version
>= 13)
3462 pa_tagstruct_put_proplist(t
, e
->proplist
);
3465 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3466 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3468 pa_sink
*sink
= NULL
;
3469 pa_source
*source
= NULL
;
3470 pa_client
*client
= NULL
;
3471 pa_card
*card
= NULL
;
3472 pa_module
*module
= NULL
;
3473 pa_sink_input
*si
= NULL
;
3474 pa_source_output
*so
= NULL
;
3475 pa_scache_entry
*sce
= NULL
;
3476 const char *name
= NULL
;
3477 pa_tagstruct
*reply
;
3479 pa_native_connection_assert_ref(c
);
3482 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3483 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3484 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3485 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3486 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3487 pa_tagstruct_gets(t
, &name
) < 0) ||
3488 !pa_tagstruct_eof(t
)) {
3493 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3494 CHECK_VALIDITY(c
->pstream
, !name
||
3495 (command
== PA_COMMAND_GET_SINK_INFO
&&
3496 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3497 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3498 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3499 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3500 CHECK_VALIDITY(c
->pstream
, command
== PA_COMMAND_GET_SINK_INFO
||
3501 command
== PA_COMMAND_GET_SOURCE_INFO
||
3502 (idx
!= PA_INVALID_INDEX
|| name
), tag
, PA_ERR_INVALID
);
3503 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3505 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3506 if (idx
!= PA_INVALID_INDEX
)
3507 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3509 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3510 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3511 if (idx
!= PA_INVALID_INDEX
)
3512 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3514 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3515 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3516 if (idx
!= PA_INVALID_INDEX
)
3517 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3519 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3520 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3521 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3522 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3523 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3524 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3525 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3526 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3527 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3529 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3530 if (idx
!= PA_INVALID_INDEX
)
3531 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3533 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3536 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3537 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3541 reply
= reply_new(tag
);
3543 sink_fill_tagstruct(c
, reply
, sink
);
3545 source_fill_tagstruct(c
, reply
, source
);
3547 client_fill_tagstruct(c
, reply
, client
);
3549 card_fill_tagstruct(c
, reply
, card
);
3551 module_fill_tagstruct(c
, reply
, module
);
3553 sink_input_fill_tagstruct(c
, reply
, si
);
3555 source_output_fill_tagstruct(c
, reply
, so
);
3557 scache_fill_tagstruct(c
, reply
, sce
);
3558 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3561 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3562 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3566 pa_tagstruct
*reply
;
3568 pa_native_connection_assert_ref(c
);
3571 if (!pa_tagstruct_eof(t
)) {
3576 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3578 reply
= reply_new(tag
);
3580 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3581 i
= c
->protocol
->core
->sinks
;
3582 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3583 i
= c
->protocol
->core
->sources
;
3584 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3585 i
= c
->protocol
->core
->clients
;
3586 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3587 i
= c
->protocol
->core
->cards
;
3588 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3589 i
= c
->protocol
->core
->modules
;
3590 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3591 i
= c
->protocol
->core
->sink_inputs
;
3592 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3593 i
= c
->protocol
->core
->source_outputs
;
3595 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3596 i
= c
->protocol
->core
->scache
;
3600 PA_IDXSET_FOREACH(p
, i
, idx
) {
3601 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3602 sink_fill_tagstruct(c
, reply
, p
);
3603 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3604 source_fill_tagstruct(c
, reply
, p
);
3605 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3606 client_fill_tagstruct(c
, reply
, p
);
3607 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3608 card_fill_tagstruct(c
, reply
, p
);
3609 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3610 module_fill_tagstruct(c
, reply
, p
);
3611 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3612 sink_input_fill_tagstruct(c
, reply
, p
);
3613 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3614 source_output_fill_tagstruct(c
, reply
, p
);
3616 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3617 scache_fill_tagstruct(c
, reply
, p
);
3622 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3625 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3626 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3627 pa_tagstruct
*reply
;
3629 pa_source
*def_source
;
3630 pa_sample_spec fixed_ss
;
3633 pa_native_connection_assert_ref(c
);
3636 if (!pa_tagstruct_eof(t
)) {
3641 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3643 reply
= reply_new(tag
);
3644 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3645 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3647 u
= pa_get_user_name_malloc();
3648 pa_tagstruct_puts(reply
, u
);
3651 h
= pa_get_host_name_malloc();
3652 pa_tagstruct_puts(reply
, h
);
3655 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3656 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3658 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3659 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3660 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3661 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3663 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3665 if (c
->version
>= 15)
3666 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3668 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3671 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3673 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3675 pa_native_connection_assert_ref(c
);
3677 t
= pa_tagstruct_new(NULL
, 0);
3678 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3679 pa_tagstruct_putu32(t
, (uint32_t) -1);
3680 pa_tagstruct_putu32(t
, e
);
3681 pa_tagstruct_putu32(t
, idx
);
3682 pa_pstream_send_tagstruct(c
->pstream
, t
);
3685 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3686 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3687 pa_subscription_mask_t m
;
3689 pa_native_connection_assert_ref(c
);
3692 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3693 !pa_tagstruct_eof(t
)) {
3698 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3699 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3701 if (c
->subscription
)
3702 pa_subscription_free(c
->subscription
);
3705 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3706 pa_assert(c
->subscription
);
3708 c
->subscription
= NULL
;
3710 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3713 static void command_set_volume(
3720 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3723 pa_sink
*sink
= NULL
;
3724 pa_source
*source
= NULL
;
3725 pa_sink_input
*si
= NULL
;
3726 pa_source_output
*so
= NULL
;
3727 const char *name
= NULL
;
3728 const char *client_name
;
3730 pa_native_connection_assert_ref(c
);
3733 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3734 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3735 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3736 pa_tagstruct_get_cvolume(t
, &volume
) ||
3737 !pa_tagstruct_eof(t
)) {
3742 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3743 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
);
3744 CHECK_VALIDITY(c
->pstream
, (idx
!= PA_INVALID_INDEX
) ^ (name
!= NULL
), tag
, PA_ERR_INVALID
);
3745 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3749 case PA_COMMAND_SET_SINK_VOLUME
:
3750 if (idx
!= PA_INVALID_INDEX
)
3751 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3753 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3756 case PA_COMMAND_SET_SOURCE_VOLUME
:
3757 if (idx
!= PA_INVALID_INDEX
)
3758 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3760 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3763 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3764 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3767 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
:
3768 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3772 pa_assert_not_reached();
3775 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3777 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3780 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3782 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3783 pa_sink_set_volume(sink
, &volume
, true, true);
3784 } else if (source
) {
3785 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3787 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3788 pa_source_set_volume(source
, &volume
, true, true);
3790 CHECK_VALIDITY(c
->pstream
, si
->volume_writable
, tag
, PA_ERR_BADSTATE
);
3791 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3793 pa_log_debug("Client %s changes volume of sink input %s.",
3795 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3796 pa_sink_input_set_volume(si
, &volume
, true, true);
3798 CHECK_VALIDITY(c
->pstream
, so
->volume_writable
, tag
, PA_ERR_BADSTATE
);
3799 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &so
->sample_spec
), tag
, PA_ERR_INVALID
);
3801 pa_log_debug("Client %s changes volume of source output %s.",
3803 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3804 pa_source_output_set_volume(so
, &volume
, true, true);
3807 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3810 static void command_set_mute(
3817 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3820 pa_sink
*sink
= NULL
;
3821 pa_source
*source
= NULL
;
3822 pa_sink_input
*si
= NULL
;
3823 pa_source_output
*so
= NULL
;
3824 const char *name
= NULL
, *client_name
;
3826 pa_native_connection_assert_ref(c
);
3829 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3830 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3831 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3832 pa_tagstruct_get_boolean(t
, &mute
) ||
3833 !pa_tagstruct_eof(t
)) {
3838 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3839 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
);
3840 CHECK_VALIDITY(c
->pstream
, (idx
!= PA_INVALID_INDEX
) ^ (name
!= NULL
), tag
, PA_ERR_INVALID
);
3844 case PA_COMMAND_SET_SINK_MUTE
:
3845 if (idx
!= PA_INVALID_INDEX
)
3846 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3848 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3852 case PA_COMMAND_SET_SOURCE_MUTE
:
3853 if (idx
!= PA_INVALID_INDEX
)
3854 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3856 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3860 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3861 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3864 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
:
3865 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3869 pa_assert_not_reached();
3872 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3874 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3877 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3878 pa_sink_set_mute(sink
, mute
, true);
3879 } else if (source
) {
3880 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3881 pa_source_set_mute(source
, mute
, true);
3883 pa_log_debug("Client %s changes mute of sink input %s.",
3885 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3886 pa_sink_input_set_mute(si
, mute
, true);
3888 pa_log_debug("Client %s changes mute of source output %s.",
3890 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3891 pa_source_output_set_mute(so
, mute
, true);
3894 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3897 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3898 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3903 pa_native_connection_assert_ref(c
);
3906 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3907 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3908 !pa_tagstruct_eof(t
)) {
3913 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3914 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3915 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3916 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3917 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3919 pa_sink_input_cork(s
->sink_input
, b
);
3922 s
->is_underrun
= true;
3924 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3927 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3928 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3932 pa_native_connection_assert_ref(c
);
3935 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3936 !pa_tagstruct_eof(t
)) {
3941 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3942 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3943 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3944 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3945 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3948 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3949 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3952 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3953 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3956 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3957 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3961 pa_assert_not_reached();
3964 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3967 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3968 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3973 pa_native_connection_assert_ref(c
);
3976 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3977 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3978 !pa_tagstruct_eof(t
)) {
3983 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3984 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3985 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3987 pa_source_output_cork(s
->source_output
, b
);
3988 pa_memblockq_prebuf_force(s
->memblockq
);
3989 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3992 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3993 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3997 pa_native_connection_assert_ref(c
);
4000 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4001 !pa_tagstruct_eof(t
)) {
4006 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4007 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4008 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4010 pa_memblockq_flush_read(s
->memblockq
);
4011 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4014 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4015 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4018 pa_tagstruct
*reply
;
4020 pa_native_connection_assert_ref(c
);
4023 memset(&a
, 0, sizeof(a
));
4025 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
4030 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4032 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
4034 bool adjust_latency
= false, early_requests
= false;
4036 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4037 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4038 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4040 if (pa_tagstruct_get(
4042 PA_TAG_U32
, &a
.maxlength
,
4043 PA_TAG_U32
, &a
.tlength
,
4044 PA_TAG_U32
, &a
.prebuf
,
4045 PA_TAG_U32
, &a
.minreq
,
4046 PA_TAG_INVALID
) < 0 ||
4047 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
4048 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
4049 !pa_tagstruct_eof(t
)) {
4054 s
->adjust_latency
= adjust_latency
;
4055 s
->early_requests
= early_requests
;
4056 s
->buffer_attr_req
= a
;
4058 fix_playback_buffer_attr(s
);
4059 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);
4061 reply
= reply_new(tag
);
4062 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
4063 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
4064 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
4065 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
4067 if (c
->version
>= 13)
4068 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
4072 bool adjust_latency
= false, early_requests
= false;
4073 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
4075 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4076 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4078 if (pa_tagstruct_get(
4080 PA_TAG_U32
, &a
.maxlength
,
4081 PA_TAG_U32
, &a
.fragsize
,
4082 PA_TAG_INVALID
) < 0 ||
4083 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
4084 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
4085 !pa_tagstruct_eof(t
)) {
4090 s
->adjust_latency
= adjust_latency
;
4091 s
->early_requests
= early_requests
;
4092 s
->buffer_attr_req
= a
;
4094 fix_record_buffer_attr_pre(s
);
4095 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
4096 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
4097 fix_record_buffer_attr_post(s
);
4099 reply
= reply_new(tag
);
4100 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
4101 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
4103 if (c
->version
>= 13)
4104 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
4107 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4110 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4111 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4115 pa_native_connection_assert_ref(c
);
4118 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4119 pa_tagstruct_getu32(t
, &rate
) < 0 ||
4120 !pa_tagstruct_eof(t
)) {
4125 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4126 CHECK_VALIDITY(c
->pstream
, pa_sample_rate_valid(rate
), tag
, PA_ERR_INVALID
);
4128 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
4131 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4132 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4133 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4135 pa_sink_input_set_rate(s
->sink_input
, rate
);
4139 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
4141 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4142 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4144 pa_source_output_set_rate(s
->source_output
, rate
);
4147 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4150 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4151 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4156 pa_native_connection_assert_ref(c
);
4159 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4161 p
= pa_proplist_new();
4163 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
4165 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
4166 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4167 !pa_tagstruct_eof(t
)) {
4169 pa_proplist_free(p
);
4175 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4176 pa_tagstruct_getu32(t
, &mode
) < 0 ||
4177 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4178 !pa_tagstruct_eof(t
)) {
4180 pa_proplist_free(p
);
4185 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
4186 pa_proplist_free(p
);
4187 CHECK_VALIDITY(c
->pstream
, false, tag
, PA_ERR_INVALID
);
4190 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
4193 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4194 if (!s
|| !playback_stream_isinstance(s
)) {
4195 pa_proplist_free(p
);
4196 CHECK_VALIDITY(c
->pstream
, false, tag
, PA_ERR_NOENTITY
);
4198 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
4200 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
4203 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
4204 pa_proplist_free(p
);
4205 CHECK_VALIDITY(c
->pstream
, false, tag
, PA_ERR_NOENTITY
);
4207 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
4210 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
4212 pa_client_update_proplist(c
->client
, mode
, p
);
4215 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4216 pa_proplist_free(p
);
4219 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4220 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4222 unsigned changed
= 0;
4224 pa_strlist
*l
= NULL
;
4226 pa_native_connection_assert_ref(c
);
4229 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4231 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
4233 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
4239 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4242 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4243 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4244 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4246 p
= s
->sink_input
->proplist
;
4248 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4251 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4252 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4254 p
= s
->source_output
->proplist
;
4256 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4258 p
= c
->client
->proplist
;
4264 if (pa_tagstruct_gets(t
, &k
) < 0) {
4273 l
= pa_strlist_prepend(l
, k
);
4276 if (!pa_tagstruct_eof(t
)) {
4285 l
= pa_strlist_pop(l
, &z
);
4290 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
4294 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4297 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4300 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4301 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
4303 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4306 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4307 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
4310 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4311 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
4316 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4317 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4320 pa_native_connection_assert_ref(c
);
4323 if (pa_tagstruct_gets(t
, &s
) < 0 ||
4324 !pa_tagstruct_eof(t
)) {
4329 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4330 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
4332 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
4335 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
4336 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4338 pa_namereg_set_default_source(c
->protocol
->core
, source
);
4341 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
4343 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
4344 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4346 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
4349 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4352 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4353 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4357 pa_native_connection_assert_ref(c
);
4360 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4361 pa_tagstruct_gets(t
, &name
) < 0 ||
4362 !pa_tagstruct_eof(t
)) {
4367 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4368 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4370 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
4373 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4374 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4375 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4377 pa_sink_input_set_name(s
->sink_input
, name
);
4381 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4383 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4384 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4386 pa_source_output_set_name(s
->source_output
, name
);
4389 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4392 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4393 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4396 pa_native_connection_assert_ref(c
);
4399 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4400 !pa_tagstruct_eof(t
)) {
4405 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4407 if (command
== PA_COMMAND_KILL_CLIENT
) {
4410 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4411 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4413 pa_native_connection_ref(c
);
4414 pa_client_kill(client
);
4416 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4419 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4420 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4422 pa_native_connection_ref(c
);
4423 pa_sink_input_kill(s
);
4425 pa_source_output
*s
;
4427 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4429 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4430 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4432 pa_native_connection_ref(c
);
4433 pa_source_output_kill(s
);
4436 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4437 pa_native_connection_unref(c
);
4440 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4441 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4443 const char *name
, *argument
;
4444 pa_tagstruct
*reply
;
4446 pa_native_connection_assert_ref(c
);
4449 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4450 pa_tagstruct_gets(t
, &argument
) < 0 ||
4451 !pa_tagstruct_eof(t
)) {
4456 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4457 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4458 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4460 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4461 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4465 reply
= reply_new(tag
);
4466 pa_tagstruct_putu32(reply
, m
->index
);
4467 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4470 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4471 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4475 pa_native_connection_assert_ref(c
);
4478 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4479 !pa_tagstruct_eof(t
)) {
4484 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4485 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4486 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4488 pa_module_unload_request(m
, false);
4489 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4492 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4493 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4494 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4495 const char *name_device
= NULL
;
4497 pa_native_connection_assert_ref(c
);
4500 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4501 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4502 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4503 !pa_tagstruct_eof(t
)) {
4508 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4509 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4511 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
);
4512 CHECK_VALIDITY(c
->pstream
, (idx_device
!= PA_INVALID_INDEX
) ^ (name_device
!= NULL
), tag
, PA_ERR_INVALID
);
4514 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4515 pa_sink_input
*si
= NULL
;
4516 pa_sink
*sink
= NULL
;
4518 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4520 if (idx_device
!= PA_INVALID_INDEX
)
4521 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4523 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4525 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4527 if (pa_sink_input_move_to(si
, sink
, true) < 0) {
4528 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4532 pa_source_output
*so
= NULL
;
4535 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4537 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4539 if (idx_device
!= PA_INVALID_INDEX
)
4540 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4542 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4544 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4546 if (pa_source_output_move_to(so
, source
, true) < 0) {
4547 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4552 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4555 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4556 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4557 uint32_t idx
= PA_INVALID_INDEX
;
4558 const char *name
= NULL
;
4561 pa_native_connection_assert_ref(c
);
4564 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4565 pa_tagstruct_gets(t
, &name
) < 0 ||
4566 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4567 !pa_tagstruct_eof(t
)) {
4572 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4573 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
);
4574 CHECK_VALIDITY(c
->pstream
, (idx
!= PA_INVALID_INDEX
) ^ (name
!= NULL
), tag
, PA_ERR_INVALID
);
4576 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4578 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4580 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4582 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4583 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4587 pa_sink
*sink
= NULL
;
4589 if (idx
!= PA_INVALID_INDEX
)
4590 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4592 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4594 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4596 pa_log_debug("%s of sink %s requested by client %" PRIu32
".",
4597 b
? "Suspending" : "Resuming", sink
->name
, c
->client
->index
);
4599 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4600 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4606 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4608 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4610 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4612 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4613 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4620 if (idx
!= PA_INVALID_INDEX
)
4621 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4623 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4625 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4627 pa_log_debug("%s of source %s requested by client %" PRIu32
".",
4628 b
? "Suspending" : "Resuming", source
->name
, c
->client
->index
);
4630 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4631 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4637 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4640 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4641 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4642 uint32_t idx
= PA_INVALID_INDEX
;
4643 const char *name
= NULL
;
4645 pa_native_protocol_ext_cb_t cb
;
4647 pa_native_connection_assert_ref(c
);
4650 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4651 pa_tagstruct_gets(t
, &name
) < 0) {
4656 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4657 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4658 CHECK_VALIDITY(c
->pstream
, (idx
!= PA_INVALID_INDEX
) ^ (name
!= NULL
), tag
, PA_ERR_INVALID
);
4660 if (idx
!= PA_INVALID_INDEX
)
4661 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4663 PA_IDXSET_FOREACH(m
, c
->protocol
->core
->modules
, idx
)
4664 if (pa_streq(name
, m
->name
))
4667 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4668 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4670 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4671 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4673 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4677 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4678 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4679 uint32_t idx
= PA_INVALID_INDEX
;
4680 const char *name
= NULL
, *profile_name
= NULL
;
4681 pa_card
*card
= NULL
;
4682 pa_card_profile
*profile
;
4685 pa_native_connection_assert_ref(c
);
4688 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4689 pa_tagstruct_gets(t
, &name
) < 0 ||
4690 pa_tagstruct_gets(t
, &profile_name
) < 0 ||
4691 !pa_tagstruct_eof(t
)) {
4696 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4697 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4698 CHECK_VALIDITY(c
->pstream
, (idx
!= PA_INVALID_INDEX
) ^ (name
!= NULL
), tag
, PA_ERR_INVALID
);
4699 CHECK_VALIDITY(c
->pstream
, profile_name
, tag
, PA_ERR_INVALID
);
4701 if (idx
!= PA_INVALID_INDEX
)
4702 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4704 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4706 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4708 profile
= pa_hashmap_get(card
->profiles
, profile_name
);
4710 CHECK_VALIDITY(c
->pstream
, profile
, tag
, PA_ERR_NOENTITY
);
4712 if ((ret
= pa_card_set_profile(card
, profile
, true)) < 0) {
4713 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4717 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4720 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4721 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4722 uint32_t idx
= PA_INVALID_INDEX
;
4723 const char *name
= NULL
, *port
= NULL
;
4726 pa_native_connection_assert_ref(c
);
4729 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4730 pa_tagstruct_gets(t
, &name
) < 0 ||
4731 pa_tagstruct_gets(t
, &port
) < 0 ||
4732 !pa_tagstruct_eof(t
)) {
4737 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4738 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
);
4739 CHECK_VALIDITY(c
->pstream
, (idx
!= PA_INVALID_INDEX
) ^ (name
!= NULL
), tag
, PA_ERR_INVALID
);
4740 CHECK_VALIDITY(c
->pstream
, port
, tag
, PA_ERR_INVALID
);
4742 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4745 if (idx
!= PA_INVALID_INDEX
)
4746 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4748 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4750 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4752 if ((ret
= pa_sink_set_port(sink
, port
, true)) < 0) {
4753 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4759 pa_assert(command
== PA_COMMAND_SET_SOURCE_PORT
);
4761 if (idx
!= PA_INVALID_INDEX
)
4762 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4764 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4766 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4768 if ((ret
= pa_source_set_port(source
, port
, true)) < 0) {
4769 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4774 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4777 static void command_set_port_latency_offset(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4778 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4779 const char *port_name
, *card_name
;
4780 uint32_t idx
= PA_INVALID_INDEX
;
4782 pa_card
*card
= NULL
;
4783 pa_device_port
*port
= NULL
;
4785 pa_native_connection_assert_ref(c
);
4788 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4789 pa_tagstruct_gets(t
, &card_name
) < 0 ||
4790 pa_tagstruct_gets(t
, &port_name
) < 0 ||
4791 pa_tagstruct_gets64(t
, &offset
) < 0 ||
4792 !pa_tagstruct_eof(t
)) {
4797 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4798 CHECK_VALIDITY(c
->pstream
, !card_name
|| pa_namereg_is_valid_name(card_name
), tag
, PA_ERR_INVALID
);
4799 CHECK_VALIDITY(c
->pstream
, (idx
!= PA_INVALID_INDEX
) ^ (card_name
!= NULL
), tag
, PA_ERR_INVALID
);
4800 CHECK_VALIDITY(c
->pstream
, port_name
, tag
, PA_ERR_INVALID
);
4802 if (idx
!= PA_INVALID_INDEX
)
4803 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4805 card
= pa_namereg_get(c
->protocol
->core
, card_name
, PA_NAMEREG_CARD
);
4807 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4809 port
= pa_hashmap_get(card
->ports
, port_name
);
4810 CHECK_VALIDITY(c
->pstream
, port
, tag
, PA_ERR_NOENTITY
);
4812 pa_device_port_set_latency_offset(port
, offset
);
4814 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4817 /*** pstream callbacks ***/
4819 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4820 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4824 pa_native_connection_assert_ref(c
);
4826 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4827 pa_log("invalid packet.");
4828 native_connection_unlink(c
);
4832 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
) {
4833 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4834 output_stream
*stream
;
4838 pa_native_connection_assert_ref(c
);
4840 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4841 pa_log_debug("Client sent block for invalid stream.");
4846 #ifdef PROTOCOL_NATIVE_DEBUG
4847 pa_log("got %lu bytes from client", (unsigned long) chunk
->length
);
4850 if (playback_stream_isinstance(stream
)) {
4851 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4853 pa_atomic_inc(&ps
->seek_or_post_in_queue
);
4854 if (chunk
->memblock
) {
4855 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4856 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_SEEK
, PA_UINT_TO_PTR(seek
), offset
, chunk
, NULL
);
4858 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4860 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
);
4863 upload_stream
*u
= UPLOAD_STREAM(stream
);
4866 if (!u
->memchunk
.memblock
) {
4867 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4868 u
->memchunk
= *chunk
;
4869 pa_memblock_ref(u
->memchunk
.memblock
);
4872 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4873 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4877 pa_assert(u
->memchunk
.memblock
);
4880 if (l
> chunk
->length
)
4885 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4887 if (chunk
->memblock
) {
4889 src
= pa_memblock_acquire(chunk
->memblock
);
4891 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4892 (uint8_t*) src
+ chunk
->index
, l
);
4894 pa_memblock_release(chunk
->memblock
);
4896 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4898 pa_memblock_release(u
->memchunk
.memblock
);
4900 u
->memchunk
.length
+= l
;
4906 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4907 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4910 pa_native_connection_assert_ref(c
);
4912 native_connection_unlink(c
);
4913 pa_log_info("Connection died.");
4916 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4917 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4920 pa_native_connection_assert_ref(c
);
4922 native_connection_send_memblock(c
);
4925 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4928 if (!(q
= pa_thread_mq_get()))
4929 pa_pstream_send_revoke(p
, block_id
);
4931 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4934 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4937 if (!(q
= pa_thread_mq_get()))
4938 pa_pstream_send_release(p
, block_id
);
4940 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4943 /*** client callbacks ***/
4945 static void client_kill_cb(pa_client
*c
) {
4948 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4949 pa_log_info("Connection killed.");
4952 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4954 pa_native_connection
*c
;
4957 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4958 pa_native_connection_assert_ref(c
);
4960 if (c
->version
< 15)
4963 t
= pa_tagstruct_new(NULL
, 0);
4964 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4965 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4966 pa_tagstruct_puts(t
, event
);
4967 pa_tagstruct_put_proplist(t
, pl
);
4968 pa_pstream_send_tagstruct(c
->pstream
, t
);
4971 /*** module entry points ***/
4973 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4974 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4977 pa_native_connection_assert_ref(c
);
4978 pa_assert(c
->auth_timeout_event
== e
);
4980 if (!c
->authorized
) {
4981 native_connection_unlink(c
);
4982 pa_log_info("Connection terminated due to authentication timeout.");
4986 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4987 pa_native_connection
*c
;
4990 pa_client_new_data data
;
4996 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4997 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4998 pa_iochannel_free(io
);
5002 pa_client_new_data_init(&data
);
5003 data
.module
= o
->module
;
5004 data
.driver
= __FILE__
;
5005 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
5006 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
5007 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
5008 client
= pa_client_new(p
->core
, &data
);
5009 pa_client_new_data_done(&data
);
5014 c
= pa_msgobject_new(pa_native_connection
);
5015 c
->parent
.parent
.free
= native_connection_free
;
5016 c
->parent
.process_msg
= native_connection_process_msg
;
5018 c
->options
= pa_native_options_ref(o
);
5019 c
->authorized
= false;
5021 if (o
->auth_anonymous
) {
5022 pa_log_info("Client authenticated anonymously.");
5023 c
->authorized
= true;
5026 if (!c
->authorized
&&
5028 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
5030 pa_log_info("Client authenticated by IP ACL.");
5031 c
->authorized
= true;
5035 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
5037 c
->auth_timeout_event
= NULL
;
5039 c
->is_local
= pa_iochannel_socket_is_local(io
);
5043 c
->client
->kill
= client_kill_cb
;
5044 c
->client
->send_event
= client_send_event_cb
;
5045 c
->client
->userdata
= c
;
5047 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
5048 pa_pstream_set_receive_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
5049 pa_pstream_set_receive_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
5050 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
5051 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
5052 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
5053 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
5055 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, true, command_table
, PA_COMMAND_MAX
);
5057 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
5058 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
5060 c
->rrobin_index
= PA_IDXSET_INVALID
;
5061 c
->subscription
= NULL
;
5063 pa_idxset_put(p
->connections
, c
, NULL
);
5066 if (pa_iochannel_creds_supported(io
))
5067 pa_iochannel_creds_enable(io
);
5070 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
5073 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
5074 pa_native_connection
*c
;
5080 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
5081 if (c
->options
->module
== m
)
5082 native_connection_unlink(c
);
5085 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
5086 pa_native_protocol
*p
;
5091 p
= pa_xnew(pa_native_protocol
, 1);
5094 p
->connections
= pa_idxset_new(NULL
, NULL
);
5098 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
5100 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
5101 pa_hook_init(&p
->hooks
[h
], p
);
5103 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
5108 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
5109 pa_native_protocol
*p
;
5111 if ((p
= pa_shared_get(c
, "native-protocol")))
5112 return pa_native_protocol_ref(p
);
5114 return native_protocol_new(c
);
5117 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
5119 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5126 void pa_native_protocol_unref(pa_native_protocol
*p
) {
5127 pa_native_connection
*c
;
5131 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5133 if (PA_REFCNT_DEC(p
) > 0)
5136 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
5137 native_connection_unlink(c
);
5139 pa_idxset_free(p
->connections
, NULL
);
5141 pa_strlist_free(p
->servers
);
5143 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
5144 pa_hook_done(&p
->hooks
[h
]);
5146 pa_hashmap_free(p
->extensions
);
5148 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
5153 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
5155 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5158 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
5160 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5163 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
5165 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5168 p
->servers
= pa_strlist_remove(p
->servers
, name
);
5170 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5173 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
5175 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5180 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
5182 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5187 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
5189 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5192 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
5194 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
5198 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
5200 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5203 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
5206 pa_native_options
* pa_native_options_new(void) {
5207 pa_native_options
*o
;
5209 o
= pa_xnew0(pa_native_options
, 1);
5215 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
5217 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5224 void pa_native_options_unref(pa_native_options
*o
) {
5226 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5228 if (PA_REFCNT_DEC(o
) > 0)
5231 pa_xfree(o
->auth_group
);
5234 pa_ip_acl_free(o
->auth_ip_acl
);
5237 pa_auth_cookie_unref(o
->auth_cookie
);
5242 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
5247 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5250 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
5251 pa_log("auth-anonymous= expects a boolean argument.");
5256 if (pa_modargs_get_value_boolean(ma
, "auth-group-enable", &enabled
) < 0) {
5257 pa_log("auth-group-enable= expects a boolean argument.");
5261 pa_xfree(o
->auth_group
);
5262 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
5266 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5269 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
5272 if (!(ipa
= pa_ip_acl_new(acl
))) {
5273 pa_log("Failed to parse IP ACL '%s'", acl
);
5278 pa_ip_acl_free(o
->auth_ip_acl
);
5280 o
->auth_ip_acl
= ipa
;
5284 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
5285 pa_log("auth-cookie-enabled= expects a boolean argument.");
5290 pa_auth_cookie_unref(o
->auth_cookie
);
5295 /* The new name for this is 'auth-cookie', for compat reasons
5296 * we check the old name too */
5297 cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
);
5299 cn
= pa_modargs_get_value(ma
, "cookie", NULL
);
5302 o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, true, PA_NATIVE_COOKIE_LENGTH
);
5304 o
->auth_cookie
= pa_auth_cookie_get(c
, PA_NATIVE_COOKIE_FILE
, false, PA_NATIVE_COOKIE_LENGTH
);
5305 if (!o
->auth_cookie
) {
5306 o
->auth_cookie
= pa_auth_cookie_get(c
, PA_NATIVE_COOKIE_FILE_FALLBACK
, false, PA_NATIVE_COOKIE_LENGTH
);
5308 if (!o
->auth_cookie
)
5309 o
->auth_cookie
= pa_auth_cookie_get(c
, PA_NATIVE_COOKIE_FILE
, true, PA_NATIVE_COOKIE_LENGTH
);
5313 if (!o
->auth_cookie
)
5317 o
->auth_cookie
= NULL
;
5322 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
5323 pa_native_connection_assert_ref(c
);
5328 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
5329 pa_native_connection_assert_ref(c
);