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 /* Kick a client if it doesn't authenticate within this time */
64 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
66 /* Don't accept more connection than this */
67 #define MAX_CONNECTIONS 64
69 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
70 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
71 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
72 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
74 struct pa_native_protocol
;
76 typedef struct record_stream
{
79 pa_native_connection
*connection
;
82 pa_source_output
*source_output
;
83 pa_memblockq
*memblockq
;
85 pa_bool_t adjust_latency
:1;
86 pa_bool_t early_requests
:1;
88 /* Requested buffer attributes */
89 pa_buffer_attr buffer_attr_req
;
90 /* Fixed-up and adjusted buffer attributes */
91 pa_buffer_attr buffer_attr
;
93 pa_atomic_t on_the_fly
;
94 pa_usec_t configured_source_latency
;
97 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
98 size_t on_the_fly_snapshot
;
99 pa_usec_t current_monitor_latency
;
100 pa_usec_t current_source_latency
;
103 #define RECORD_STREAM(o) (record_stream_cast(o))
104 PA_DEFINE_PRIVATE_CLASS(record_stream
, pa_msgobject
);
106 typedef struct output_stream
{
110 #define OUTPUT_STREAM(o) (output_stream_cast(o))
111 PA_DEFINE_PRIVATE_CLASS(output_stream
, pa_msgobject
);
113 typedef struct playback_stream
{
114 output_stream parent
;
116 pa_native_connection
*connection
;
119 pa_sink_input
*sink_input
;
120 pa_memblockq
*memblockq
;
122 pa_bool_t adjust_latency
:1;
123 pa_bool_t early_requests
:1;
125 pa_bool_t is_underrun
:1;
126 pa_bool_t drain_request
:1;
130 /* Optimization to avoid too many rewinds with a lot of small blocks */
131 pa_atomic_t seek_or_post_in_queue
;
135 pa_usec_t configured_sink_latency
;
136 /* Requested buffer attributes */
137 pa_buffer_attr buffer_attr_req
;
138 /* Fixed-up and adjusted buffer attributes */
139 pa_buffer_attr buffer_attr
;
141 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
142 int64_t read_index
, write_index
;
143 size_t render_memblockq_length
;
144 pa_usec_t current_sink_latency
;
145 uint64_t playing_for
, underrun_for
;
148 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
149 PA_DEFINE_PRIVATE_CLASS(playback_stream
, output_stream
);
151 typedef struct upload_stream
{
152 output_stream parent
;
154 pa_native_connection
*connection
;
157 pa_memchunk memchunk
;
160 pa_sample_spec sample_spec
;
161 pa_channel_map channel_map
;
162 pa_proplist
*proplist
;
165 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
166 PA_DEFINE_PRIVATE_CLASS(upload_stream
, output_stream
);
168 struct pa_native_connection
{
170 pa_native_protocol
*protocol
;
171 pa_native_options
*options
;
172 pa_bool_t authorized
:1;
173 pa_bool_t is_local
:1;
177 pa_pdispatch
*pdispatch
;
178 pa_idxset
*record_streams
, *output_streams
;
179 uint32_t rrobin_index
;
180 pa_subscription
*subscription
;
181 pa_time_event
*auth_timeout_event
;
184 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
185 PA_DEFINE_PRIVATE_CLASS(pa_native_connection
, pa_msgobject
);
187 struct pa_native_protocol
{
191 pa_idxset
*connections
;
194 pa_hook hooks
[PA_NATIVE_HOOK_MAX
];
196 pa_hashmap
*extensions
;
200 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
= PA_SOURCE_OUTPUT_MESSAGE_MAX
204 SINK_INPUT_MESSAGE_POST_DATA
= PA_SINK_INPUT_MESSAGE_MAX
, /* data from main loop to sink input */
205 SINK_INPUT_MESSAGE_DRAIN
, /* disabled prebuf, get playback started. */
206 SINK_INPUT_MESSAGE_FLUSH
,
207 SINK_INPUT_MESSAGE_TRIGGER
,
208 SINK_INPUT_MESSAGE_SEEK
,
209 SINK_INPUT_MESSAGE_PREBUF_FORCE
,
210 SINK_INPUT_MESSAGE_UPDATE_LATENCY
,
211 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
215 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, /* data requested from sink input from the main loop */
216 PLAYBACK_STREAM_MESSAGE_UNDERFLOW
,
217 PLAYBACK_STREAM_MESSAGE_OVERFLOW
,
218 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
,
219 PLAYBACK_STREAM_MESSAGE_STARTED
,
220 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
224 RECORD_STREAM_MESSAGE_POST_DATA
/* data from source output to main loop */
228 CONNECTION_MESSAGE_RELEASE
,
229 CONNECTION_MESSAGE_REVOKE
232 static int sink_input_pop_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
);
233 static void sink_input_kill_cb(pa_sink_input
*i
);
234 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
);
235 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
);
236 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
237 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
238 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
);
239 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
);
241 static void native_connection_send_memblock(pa_native_connection
*c
);
242 static void playback_stream_request_bytes(struct playback_stream
*s
);
244 static void source_output_kill_cb(pa_source_output
*o
);
245 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
);
246 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
);
247 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
);
248 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
);
249 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
);
251 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
252 static int source_output_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
254 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
255 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
256 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
257 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
258 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
259 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
260 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
261 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
262 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
263 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
264 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
265 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
266 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
267 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
268 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
269 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
270 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
271 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
272 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
273 static void command_set_volume(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
274 static void command_set_mute(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
275 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
276 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
277 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
278 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
279 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
280 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
281 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
282 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
283 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
284 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
285 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
286 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
287 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
288 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
289 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
290 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
291 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
292 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
294 static const pa_pdispatch_cb_t command_table
[PA_COMMAND_MAX
] = {
295 [PA_COMMAND_ERROR
] = NULL
,
296 [PA_COMMAND_TIMEOUT
] = NULL
,
297 [PA_COMMAND_REPLY
] = NULL
,
298 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = command_create_playback_stream
,
299 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = command_delete_stream
,
300 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = command_drain_playback_stream
,
301 [PA_COMMAND_CREATE_RECORD_STREAM
] = command_create_record_stream
,
302 [PA_COMMAND_DELETE_RECORD_STREAM
] = command_delete_stream
,
303 [PA_COMMAND_AUTH
] = command_auth
,
304 [PA_COMMAND_REQUEST
] = NULL
,
305 [PA_COMMAND_EXIT
] = command_exit
,
306 [PA_COMMAND_SET_CLIENT_NAME
] = command_set_client_name
,
307 [PA_COMMAND_LOOKUP_SINK
] = command_lookup
,
308 [PA_COMMAND_LOOKUP_SOURCE
] = command_lookup
,
309 [PA_COMMAND_STAT
] = command_stat
,
310 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = command_get_playback_latency
,
311 [PA_COMMAND_GET_RECORD_LATENCY
] = command_get_record_latency
,
312 [PA_COMMAND_CREATE_UPLOAD_STREAM
] = command_create_upload_stream
,
313 [PA_COMMAND_DELETE_UPLOAD_STREAM
] = command_delete_stream
,
314 [PA_COMMAND_FINISH_UPLOAD_STREAM
] = command_finish_upload_stream
,
315 [PA_COMMAND_PLAY_SAMPLE
] = command_play_sample
,
316 [PA_COMMAND_REMOVE_SAMPLE
] = command_remove_sample
,
317 [PA_COMMAND_GET_SINK_INFO
] = command_get_info
,
318 [PA_COMMAND_GET_SOURCE_INFO
] = command_get_info
,
319 [PA_COMMAND_GET_CLIENT_INFO
] = command_get_info
,
320 [PA_COMMAND_GET_CARD_INFO
] = command_get_info
,
321 [PA_COMMAND_GET_MODULE_INFO
] = command_get_info
,
322 [PA_COMMAND_GET_SINK_INPUT_INFO
] = command_get_info
,
323 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO
] = command_get_info
,
324 [PA_COMMAND_GET_SAMPLE_INFO
] = command_get_info
,
325 [PA_COMMAND_GET_SINK_INFO_LIST
] = command_get_info_list
,
326 [PA_COMMAND_GET_SOURCE_INFO_LIST
] = command_get_info_list
,
327 [PA_COMMAND_GET_MODULE_INFO_LIST
] = command_get_info_list
,
328 [PA_COMMAND_GET_CLIENT_INFO_LIST
] = command_get_info_list
,
329 [PA_COMMAND_GET_CARD_INFO_LIST
] = command_get_info_list
,
330 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST
] = command_get_info_list
,
331 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
] = command_get_info_list
,
332 [PA_COMMAND_GET_SAMPLE_INFO_LIST
] = command_get_info_list
,
333 [PA_COMMAND_GET_SERVER_INFO
] = command_get_server_info
,
334 [PA_COMMAND_SUBSCRIBE
] = command_subscribe
,
336 [PA_COMMAND_SET_SINK_VOLUME
] = command_set_volume
,
337 [PA_COMMAND_SET_SINK_INPUT_VOLUME
] = command_set_volume
,
338 [PA_COMMAND_SET_SOURCE_VOLUME
] = command_set_volume
,
339 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
] = command_set_volume
,
341 [PA_COMMAND_SET_SINK_MUTE
] = command_set_mute
,
342 [PA_COMMAND_SET_SINK_INPUT_MUTE
] = command_set_mute
,
343 [PA_COMMAND_SET_SOURCE_MUTE
] = command_set_mute
,
344 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
] = command_set_mute
,
346 [PA_COMMAND_SUSPEND_SINK
] = command_suspend
,
347 [PA_COMMAND_SUSPEND_SOURCE
] = command_suspend
,
349 [PA_COMMAND_CORK_PLAYBACK_STREAM
] = command_cork_playback_stream
,
350 [PA_COMMAND_FLUSH_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
351 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
352 [PA_COMMAND_PREBUF_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
354 [PA_COMMAND_CORK_RECORD_STREAM
] = command_cork_record_stream
,
355 [PA_COMMAND_FLUSH_RECORD_STREAM
] = command_flush_record_stream
,
357 [PA_COMMAND_SET_DEFAULT_SINK
] = command_set_default_sink_or_source
,
358 [PA_COMMAND_SET_DEFAULT_SOURCE
] = command_set_default_sink_or_source
,
359 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME
] = command_set_stream_name
,
360 [PA_COMMAND_SET_RECORD_STREAM_NAME
] = command_set_stream_name
,
361 [PA_COMMAND_KILL_CLIENT
] = command_kill
,
362 [PA_COMMAND_KILL_SINK_INPUT
] = command_kill
,
363 [PA_COMMAND_KILL_SOURCE_OUTPUT
] = command_kill
,
364 [PA_COMMAND_LOAD_MODULE
] = command_load_module
,
365 [PA_COMMAND_UNLOAD_MODULE
] = command_unload_module
,
367 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE
] = NULL
,
368 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE
] = NULL
,
369 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE
] = NULL
,
370 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE
] = NULL
,
372 [PA_COMMAND_MOVE_SINK_INPUT
] = command_move_stream
,
373 [PA_COMMAND_MOVE_SOURCE_OUTPUT
] = command_move_stream
,
375 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
376 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
378 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
379 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
381 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
] = command_update_proplist
,
382 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
] = command_update_proplist
,
383 [PA_COMMAND_UPDATE_CLIENT_PROPLIST
] = command_update_proplist
,
385 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
] = command_remove_proplist
,
386 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
] = command_remove_proplist
,
387 [PA_COMMAND_REMOVE_CLIENT_PROPLIST
] = command_remove_proplist
,
389 [PA_COMMAND_SET_CARD_PROFILE
] = command_set_card_profile
,
391 [PA_COMMAND_SET_SINK_PORT
] = command_set_sink_or_source_port
,
392 [PA_COMMAND_SET_SOURCE_PORT
] = command_set_sink_or_source_port
,
394 [PA_COMMAND_EXTENSION
] = command_extension
397 /* structure management */
399 /* Called from main context */
400 static void upload_stream_unlink(upload_stream
*s
) {
406 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
407 s
->connection
= NULL
;
408 upload_stream_unref(s
);
411 /* Called from main context */
412 static void upload_stream_free(pa_object
*o
) {
413 upload_stream
*s
= UPLOAD_STREAM(o
);
416 upload_stream_unlink(s
);
421 pa_proplist_free(s
->proplist
);
423 if (s
->memchunk
.memblock
)
424 pa_memblock_unref(s
->memchunk
.memblock
);
429 /* Called from main context */
430 static upload_stream
* upload_stream_new(
431 pa_native_connection
*c
,
432 const pa_sample_spec
*ss
,
433 const pa_channel_map
*map
,
443 pa_assert(length
> 0);
446 s
= pa_msgobject_new(upload_stream
);
447 s
->parent
.parent
.parent
.free
= upload_stream_free
;
449 s
->sample_spec
= *ss
;
450 s
->channel_map
= *map
;
451 s
->name
= pa_xstrdup(name
);
452 pa_memchunk_reset(&s
->memchunk
);
454 s
->proplist
= pa_proplist_copy(p
);
455 pa_proplist_update(s
->proplist
, PA_UPDATE_MERGE
, c
->client
->proplist
);
457 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
462 /* Called from main context */
463 static void record_stream_unlink(record_stream
*s
) {
469 if (s
->source_output
) {
470 pa_source_output_unlink(s
->source_output
);
471 pa_source_output_unref(s
->source_output
);
472 s
->source_output
= NULL
;
475 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->record_streams
, s
, NULL
) == s
);
476 s
->connection
= NULL
;
477 record_stream_unref(s
);
480 /* Called from main context */
481 static void record_stream_free(pa_object
*o
) {
482 record_stream
*s
= RECORD_STREAM(o
);
485 record_stream_unlink(s
);
487 pa_memblockq_free(s
->memblockq
);
491 /* Called from main context */
492 static int record_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
493 record_stream
*s
= RECORD_STREAM(o
);
494 record_stream_assert_ref(s
);
501 case RECORD_STREAM_MESSAGE_POST_DATA
:
503 /* We try to keep up to date with how many bytes are
504 * currently on the fly */
505 pa_atomic_sub(&s
->on_the_fly
, chunk
->length
);
507 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
508 /* pa_log_warn("Failed to push data into output queue."); */
512 if (!pa_pstream_is_pending(s
->connection
->pstream
))
513 native_connection_send_memblock(s
->connection
);
521 /* Called from main context */
522 static void fix_record_buffer_attr_pre(record_stream
*s
) {
525 pa_usec_t orig_fragsize_usec
, fragsize_usec
, source_usec
;
529 /* This function will be called from the main thread, before as
530 * well as after the source output has been activated using
531 * pa_source_output_put()! That means it may not touch any
532 * ->thread_info data! */
534 frame_size
= pa_frame_size(&s
->source_output
->sample_spec
);
535 s
->buffer_attr
= s
->buffer_attr_req
;
537 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
538 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
539 if (s
->buffer_attr
.maxlength
<= 0)
540 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
542 if (s
->buffer_attr
.fragsize
== (uint32_t) -1)
543 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC
*PA_USEC_PER_MSEC
, &s
->source_output
->sample_spec
);
544 if (s
->buffer_attr
.fragsize
<= 0)
545 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
547 orig_fragsize_usec
= fragsize_usec
= pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &s
->source_output
->sample_spec
);
549 if (s
->early_requests
) {
551 /* In early request mode we need to emulate the classic
552 * fragment-based playback model. We do this setting the source
553 * latency to the fragment size. */
555 source_usec
= fragsize_usec
;
557 } else if (s
->adjust_latency
) {
559 /* So, the user asked us to adjust the latency according to
560 * what the source can provide. Half the latency will be
561 * spent on the hw buffer, half of it in the async buffer
562 * queue we maintain for each client. */
564 source_usec
= fragsize_usec
/2;
568 /* Ok, the user didn't ask us to adjust the latency, hence we
571 source_usec
= (pa_usec_t
) -1;
574 if (source_usec
!= (pa_usec_t
) -1)
575 s
->configured_source_latency
= pa_source_output_set_requested_latency(s
->source_output
, source_usec
);
577 s
->configured_source_latency
= 0;
579 if (s
->early_requests
) {
581 /* Ok, we didn't necessarily get what we were asking for, so
582 * let's tell the user */
584 fragsize_usec
= s
->configured_source_latency
;
586 } else if (s
->adjust_latency
) {
588 /* Now subtract what we actually got */
590 if (fragsize_usec
>= s
->configured_source_latency
*2)
591 fragsize_usec
-= s
->configured_source_latency
;
593 fragsize_usec
= s
->configured_source_latency
;
596 if (pa_usec_to_bytes(orig_fragsize_usec
, &s
->source_output
->sample_spec
) !=
597 pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
))
599 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
);
601 if (s
->buffer_attr
.fragsize
<= 0)
602 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
605 /* Called from main context */
606 static void fix_record_buffer_attr_post(record_stream
*s
) {
611 /* This function will be called from the main thread, before as
612 * well as after the source output has been activated using
613 * pa_source_output_put()! That means it may not touch and
614 * ->thread_info data! */
616 base
= pa_frame_size(&s
->source_output
->sample_spec
);
618 s
->buffer_attr
.fragsize
= (s
->buffer_attr
.fragsize
/base
)*base
;
619 if (s
->buffer_attr
.fragsize
<= 0)
620 s
->buffer_attr
.fragsize
= base
;
622 if (s
->buffer_attr
.fragsize
> s
->buffer_attr
.maxlength
)
623 s
->buffer_attr
.fragsize
= s
->buffer_attr
.maxlength
;
626 /* Called from main context */
627 static record_stream
* record_stream_new(
628 pa_native_connection
*c
,
633 pa_buffer_attr
*attr
,
637 pa_source_output_flags_t flags
,
639 pa_bool_t adjust_latency
,
640 pa_bool_t early_requests
,
641 pa_bool_t relative_volume
,
642 pa_bool_t peak_detect
,
643 pa_sink_input
*direct_on_input
,
647 pa_source_output
*source_output
= NULL
;
648 pa_source_output_new_data data
;
655 pa_source_output_new_data_init(&data
);
657 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
658 data
.driver
= __FILE__
;
659 data
.module
= c
->options
->module
;
660 data
.client
= c
->client
;
662 pa_source_output_new_data_set_source(&data
, source
, TRUE
);
663 if (pa_sample_spec_valid(ss
))
664 pa_source_output_new_data_set_sample_spec(&data
, ss
);
665 if (pa_channel_map_valid(map
))
666 pa_source_output_new_data_set_channel_map(&data
, map
);
668 pa_source_output_new_data_set_formats(&data
, formats
);
669 data
.direct_on_input
= direct_on_input
;
671 pa_source_output_new_data_set_volume(&data
, volume
);
672 data
.volume_is_absolute
= !relative_volume
;
673 data
.save_volume
= TRUE
;
676 pa_source_output_new_data_set_muted(&data
, muted
);
677 data
.save_muted
= TRUE
;
680 data
.resample_method
= PA_RESAMPLER_PEAKS
;
683 *ret
= -pa_source_output_new(&source_output
, c
->protocol
->core
, &data
);
685 pa_source_output_new_data_done(&data
);
690 s
= pa_msgobject_new(record_stream
);
691 s
->parent
.parent
.free
= record_stream_free
;
692 s
->parent
.process_msg
= record_stream_process_msg
;
694 s
->source_output
= source_output
;
695 s
->buffer_attr_req
= *attr
;
696 s
->adjust_latency
= adjust_latency
;
697 s
->early_requests
= early_requests
;
698 pa_atomic_store(&s
->on_the_fly
, 0);
700 s
->source_output
->parent
.process_msg
= source_output_process_msg
;
701 s
->source_output
->push
= source_output_push_cb
;
702 s
->source_output
->kill
= source_output_kill_cb
;
703 s
->source_output
->get_latency
= source_output_get_latency_cb
;
704 s
->source_output
->moving
= source_output_moving_cb
;
705 s
->source_output
->suspend
= source_output_suspend_cb
;
706 s
->source_output
->send_event
= source_output_send_event_cb
;
707 s
->source_output
->userdata
= s
;
709 fix_record_buffer_attr_pre(s
);
711 s
->memblockq
= pa_memblockq_new(
713 s
->buffer_attr
.maxlength
,
715 pa_frame_size(&source_output
->sample_spec
),
721 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
722 fix_record_buffer_attr_post(s
);
724 *ss
= s
->source_output
->sample_spec
;
725 *map
= s
->source_output
->channel_map
;
727 pa_idxset_put(c
->record_streams
, s
, &s
->index
);
729 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
730 ((double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) + (double) s
->configured_source_latency
) / PA_USEC_PER_MSEC
,
731 (double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) / PA_USEC_PER_MSEC
,
732 (double) s
->configured_source_latency
/ PA_USEC_PER_MSEC
);
734 pa_source_output_put(s
->source_output
);
738 /* Called from main context */
739 static void record_stream_send_killed(record_stream
*r
) {
741 record_stream_assert_ref(r
);
743 t
= pa_tagstruct_new(NULL
, 0);
744 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_KILLED
);
745 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
746 pa_tagstruct_putu32(t
, r
->index
);
747 pa_pstream_send_tagstruct(r
->connection
->pstream
, t
);
750 /* Called from main context */
751 static void playback_stream_unlink(playback_stream
*s
) {
758 pa_sink_input_unlink(s
->sink_input
);
759 pa_sink_input_unref(s
->sink_input
);
760 s
->sink_input
= NULL
;
763 if (s
->drain_request
)
764 pa_pstream_send_error(s
->connection
->pstream
, s
->drain_tag
, PA_ERR_NOENTITY
);
766 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
767 s
->connection
= NULL
;
768 playback_stream_unref(s
);
771 /* Called from main context */
772 static void playback_stream_free(pa_object
* o
) {
773 playback_stream
*s
= PLAYBACK_STREAM(o
);
776 playback_stream_unlink(s
);
778 pa_memblockq_free(s
->memblockq
);
782 /* Called from main context */
783 static int playback_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
784 playback_stream
*s
= PLAYBACK_STREAM(o
);
785 playback_stream_assert_ref(s
);
792 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
: {
797 if ((l
= pa_atomic_load(&s
->missing
)) <= 0)
800 if (pa_atomic_cmpxchg(&s
->missing
, l
, 0))
804 t
= pa_tagstruct_new(NULL
, 0);
805 pa_tagstruct_putu32(t
, PA_COMMAND_REQUEST
);
806 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
807 pa_tagstruct_putu32(t
, s
->index
);
808 pa_tagstruct_putu32(t
, (uint32_t) l
);
809 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
811 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
815 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW
: {
818 /* pa_log("signalling underflow"); */
820 /* Report that we're empty */
821 t
= pa_tagstruct_new(NULL
, 0);
822 pa_tagstruct_putu32(t
, PA_COMMAND_UNDERFLOW
);
823 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
824 pa_tagstruct_putu32(t
, s
->index
);
825 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
829 case PLAYBACK_STREAM_MESSAGE_OVERFLOW
: {
832 /* Notify the user we're overflowed*/
833 t
= pa_tagstruct_new(NULL
, 0);
834 pa_tagstruct_putu32(t
, PA_COMMAND_OVERFLOW
);
835 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
836 pa_tagstruct_putu32(t
, s
->index
);
837 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
841 case PLAYBACK_STREAM_MESSAGE_STARTED
:
843 if (s
->connection
->version
>= 13) {
846 /* Notify the user we started playback */
847 t
= pa_tagstruct_new(NULL
, 0);
848 pa_tagstruct_putu32(t
, PA_COMMAND_STARTED
);
849 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
850 pa_tagstruct_putu32(t
, s
->index
);
851 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
856 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
:
857 pa_pstream_send_simple_ack(s
->connection
->pstream
, PA_PTR_TO_UINT(userdata
));
860 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
:
862 s
->buffer_attr
.tlength
= (uint32_t) offset
;
864 if (s
->connection
->version
>= 15) {
867 t
= pa_tagstruct_new(NULL
, 0);
868 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
);
869 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
870 pa_tagstruct_putu32(t
, s
->index
);
871 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
872 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
873 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
874 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
875 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
876 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
885 /* Called from main context */
886 static void fix_playback_buffer_attr(playback_stream
*s
) {
887 size_t frame_size
, max_prebuf
;
888 pa_usec_t orig_tlength_usec
, tlength_usec
, orig_minreq_usec
, minreq_usec
, sink_usec
;
892 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
893 /* (long) s->buffer_attr.maxlength, */
894 /* (long) s->buffer_attr.tlength, */
895 /* (long) s->buffer_attr.minreq, */
896 /* (long) s->buffer_attr.prebuf); */
898 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
899 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
900 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
901 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
902 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
904 /* This function will be called from the main thread, before as
905 * well as after the sink input has been activated using
906 * pa_sink_input_put()! That means it may not touch any
907 * ->thread_info data, such as the memblockq! */
909 frame_size
= pa_frame_size(&s
->sink_input
->sample_spec
);
910 s
->buffer_attr
= s
->buffer_attr_req
;
912 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
913 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
914 if (s
->buffer_attr
.maxlength
<= 0)
915 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
917 if (s
->buffer_attr
.tlength
== (uint32_t) -1)
918 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
919 if (s
->buffer_attr
.tlength
<= 0)
920 s
->buffer_attr
.tlength
= (uint32_t) frame_size
;
922 if (s
->buffer_attr
.minreq
== (uint32_t) -1)
923 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
924 if (s
->buffer_attr
.minreq
<= 0)
925 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
927 if (s
->buffer_attr
.tlength
< s
->buffer_attr
.minreq
+frame_size
)
928 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
+(uint32_t) frame_size
;
930 orig_tlength_usec
= tlength_usec
= pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
);
931 orig_minreq_usec
= minreq_usec
= pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
);
933 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
934 (double) tlength_usec
/ PA_USEC_PER_MSEC
,
935 (double) minreq_usec
/ PA_USEC_PER_MSEC
);
937 if (s
->early_requests
) {
939 /* In early request mode we need to emulate the classic
940 * fragment-based playback model. We do this setting the sink
941 * latency to the fragment size. */
943 sink_usec
= minreq_usec
;
944 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
946 } else if (s
->adjust_latency
) {
948 /* So, the user asked us to adjust the latency of the stream
949 * buffer according to the what the sink can provide. The
950 * tlength passed in shall be the overall latency. Roughly
951 * half the latency will be spent on the hw buffer, the other
952 * half of it in the async buffer queue we maintain for each
953 * client. In between we'll have a safety space of size
954 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
955 * empty and needs to be filled, then our buffer must have
956 * enough data to fulfill this request immediatly and thus
957 * have at least the same tlength as the size of the hw
958 * buffer. It additionally needs space for 2 times minreq
959 * because if the buffer ran empty and a partial fillup
960 * happens immediately on the next iteration we need to be
961 * able to fulfill it and give the application also minreq
962 * time to fill it up again for the next request Makes 2 times
963 * minreq in plus.. */
965 if (tlength_usec
> minreq_usec
*2)
966 sink_usec
= (tlength_usec
- minreq_usec
*2)/2;
970 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
974 /* Ok, the user didn't ask us to adjust the latency, but we
975 * still need to make sure that the parameters from the user
978 if (tlength_usec
> minreq_usec
*2)
979 sink_usec
= (tlength_usec
- minreq_usec
*2);
983 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
986 s
->configured_sink_latency
= pa_sink_input_set_requested_latency(s
->sink_input
, sink_usec
);
988 if (s
->early_requests
) {
990 /* Ok, we didn't necessarily get what we were asking for, so
991 * let's tell the user */
993 minreq_usec
= s
->configured_sink_latency
;
995 } else if (s
->adjust_latency
) {
997 /* Ok, we didn't necessarily get what we were asking for, so
998 * let's subtract from what we asked for for the remaining
1001 if (tlength_usec
>= s
->configured_sink_latency
)
1002 tlength_usec
-= s
->configured_sink_latency
;
1005 /* FIXME: This is actually larger than necessary, since not all of
1006 * the sink latency is actually rewritable. */
1007 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
1008 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
1010 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
1011 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
1012 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
1014 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
1015 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
1016 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
1018 if (s
->buffer_attr
.minreq
<= 0) {
1019 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
1020 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
1023 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
1024 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
1026 max_prebuf
= s
->buffer_attr
.tlength
+ (uint32_t)frame_size
- s
->buffer_attr
.minreq
;
1028 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 ||
1029 s
->buffer_attr
.prebuf
> max_prebuf
)
1030 s
->buffer_attr
.prebuf
= max_prebuf
;
1032 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1033 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1034 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1035 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1036 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1039 /* Called from main context */
1040 static playback_stream
* playback_stream_new(
1041 pa_native_connection
*c
,
1044 pa_channel_map
*map
,
1049 pa_bool_t muted_set
,
1050 pa_sink_input_flags_t flags
,
1052 pa_bool_t adjust_latency
,
1053 pa_bool_t early_requests
,
1054 pa_bool_t relative_volume
,
1059 /* Note: This function takes ownership of the 'formats' param, so we need
1060 * to take extra care to not leak it */
1062 playback_stream
*s
, *ssync
;
1063 pa_sink_input
*sink_input
= NULL
;
1064 pa_memchunk silence
;
1066 int64_t start_index
;
1067 pa_sink_input_new_data data
;
1075 /* Find syncid group */
1076 PA_IDXSET_FOREACH(ssync
, c
->output_streams
, idx
) {
1078 if (!playback_stream_isinstance(ssync
))
1081 if (ssync
->syncid
== syncid
)
1085 /* Synced streams must connect to the same sink */
1089 sink
= ssync
->sink_input
->sink
;
1090 else if (sink
!= ssync
->sink_input
->sink
) {
1091 *ret
= PA_ERR_INVALID
;
1096 pa_sink_input_new_data_init(&data
);
1098 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1099 data
.driver
= __FILE__
;
1100 data
.module
= c
->options
->module
;
1101 data
.client
= c
->client
;
1103 pa_sink_input_new_data_set_sink(&data
, sink
, TRUE
);
1104 if (pa_sample_spec_valid(ss
))
1105 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1106 if (pa_channel_map_valid(map
))
1107 pa_sink_input_new_data_set_channel_map(&data
, map
);
1109 pa_sink_input_new_data_set_formats(&data
, formats
);
1110 /* Ownership transferred to new_data, so we don't free it ourseleves */
1114 pa_sink_input_new_data_set_volume(&data
, volume
);
1115 data
.volume_is_absolute
= !relative_volume
;
1116 data
.save_volume
= TRUE
;
1119 pa_sink_input_new_data_set_muted(&data
, muted
);
1120 data
.save_muted
= TRUE
;
1122 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1125 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
);
1127 pa_sink_input_new_data_done(&data
);
1132 s
= pa_msgobject_new(playback_stream
);
1133 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1134 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1137 s
->sink_input
= sink_input
;
1138 s
->is_underrun
= TRUE
;
1139 s
->drain_request
= FALSE
;
1140 pa_atomic_store(&s
->missing
, 0);
1141 s
->buffer_attr_req
= *a
;
1142 s
->adjust_latency
= adjust_latency
;
1143 s
->early_requests
= early_requests
;
1144 pa_atomic_store(&s
->seek_or_post_in_queue
, 0);
1145 s
->seek_windex
= -1;
1147 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1148 s
->sink_input
->pop
= sink_input_pop_cb
;
1149 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1150 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1151 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1152 s
->sink_input
->kill
= sink_input_kill_cb
;
1153 s
->sink_input
->moving
= sink_input_moving_cb
;
1154 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1155 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1156 s
->sink_input
->userdata
= s
;
1158 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1160 fix_playback_buffer_attr(s
);
1162 pa_sink_input_get_silence(sink_input
, &silence
);
1163 s
->memblockq
= pa_memblockq_new(
1165 s
->buffer_attr
.maxlength
,
1166 s
->buffer_attr
.tlength
,
1167 pa_frame_size(&sink_input
->sample_spec
),
1168 s
->buffer_attr
.prebuf
,
1169 s
->buffer_attr
.minreq
,
1172 pa_memblock_unref(silence
.memblock
);
1174 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1176 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1178 /* pa_log("missing original: %li", (long int) *missing); */
1180 *ss
= s
->sink_input
->sample_spec
;
1181 *map
= s
->sink_input
->channel_map
;
1183 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1185 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1186 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1187 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1188 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1189 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1191 pa_sink_input_put(s
->sink_input
);
1195 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
1200 /* Called from IO context */
1201 static void playback_stream_request_bytes(playback_stream
*s
) {
1203 int previous_missing
;
1205 playback_stream_assert_ref(s
);
1207 m
= pa_memblockq_pop_missing(s
->memblockq
);
1209 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1210 /* (unsigned long) m, */
1211 /* pa_memblockq_get_tlength(s->memblockq), */
1212 /* pa_memblockq_get_minreq(s->memblockq), */
1213 /* pa_memblockq_get_length(s->memblockq), */
1214 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1219 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1221 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1222 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1224 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1225 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1226 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1229 /* Called from main context */
1230 static void playback_stream_send_killed(playback_stream
*p
) {
1232 playback_stream_assert_ref(p
);
1234 t
= pa_tagstruct_new(NULL
, 0);
1235 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1236 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1237 pa_tagstruct_putu32(t
, p
->index
);
1238 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1241 /* Called from main context */
1242 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1243 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1244 pa_native_connection_assert_ref(c
);
1251 case CONNECTION_MESSAGE_REVOKE
:
1252 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1255 case CONNECTION_MESSAGE_RELEASE
:
1256 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1263 /* Called from main context */
1264 static void native_connection_unlink(pa_native_connection
*c
) {
1273 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1276 pa_native_options_unref(c
->options
);
1278 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1279 record_stream_unlink(r
);
1281 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1282 if (playback_stream_isinstance(o
))
1283 playback_stream_unlink(PLAYBACK_STREAM(o
));
1285 upload_stream_unlink(UPLOAD_STREAM(o
));
1287 if (c
->subscription
)
1288 pa_subscription_free(c
->subscription
);
1291 pa_pstream_unlink(c
->pstream
);
1293 if (c
->auth_timeout_event
) {
1294 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1295 c
->auth_timeout_event
= NULL
;
1298 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1300 pa_native_connection_unref(c
);
1303 /* Called from main context */
1304 static void native_connection_free(pa_object
*o
) {
1305 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1309 native_connection_unlink(c
);
1311 pa_idxset_free(c
->record_streams
, NULL
, NULL
);
1312 pa_idxset_free(c
->output_streams
, NULL
, NULL
);
1314 pa_pdispatch_unref(c
->pdispatch
);
1315 pa_pstream_unref(c
->pstream
);
1316 pa_client_free(c
->client
);
1321 /* Called from main context */
1322 static void native_connection_send_memblock(pa_native_connection
*c
) {
1326 start
= PA_IDXSET_INVALID
;
1330 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1333 if (start
== PA_IDXSET_INVALID
)
1334 start
= c
->rrobin_index
;
1335 else if (start
== c
->rrobin_index
)
1338 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1339 pa_memchunk schunk
= chunk
;
1341 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1342 schunk
.length
= r
->buffer_attr
.fragsize
;
1344 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1346 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1347 pa_memblock_unref(schunk
.memblock
);
1354 /*** sink input callbacks ***/
1356 /* Called from thread context */
1357 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1358 playback_stream_assert_ref(s
);
1360 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1362 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1364 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1366 if (pa_memblockq_is_readable(s
->memblockq
)) {
1368 /* We just ended an underrun, let's ask the sink
1369 * for a complete rewind rewrite */
1371 pa_log_debug("Requesting rewind due to end of underrun.");
1372 pa_sink_input_request_rewind(s
->sink_input
,
1373 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (uint64_t) -1 ? 0 :
1374 s
->sink_input
->thread_info
.underrun_for
),
1375 FALSE
, TRUE
, FALSE
);
1381 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1383 if (indexw
< indexr
) {
1384 /* OK, the sink already asked for this data, so
1385 * let's have it usk us again */
1387 pa_log_debug("Requesting rewind due to rewrite.");
1388 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), TRUE
, FALSE
, FALSE
);
1392 playback_stream_request_bytes(s
);
1395 static void flush_write_no_account(pa_memblockq
*q
) {
1396 pa_memblockq_flush_write(q
, FALSE
);
1399 /* Called from thread context */
1400 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1401 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1404 pa_sink_input_assert_ref(i
);
1405 s
= PLAYBACK_STREAM(i
->userdata
);
1406 playback_stream_assert_ref(s
);
1410 case SINK_INPUT_MESSAGE_SEEK
:
1411 case SINK_INPUT_MESSAGE_POST_DATA
: {
1412 int64_t windex
= pa_memblockq_get_write_index(s
->memblockq
);
1414 if (code
== SINK_INPUT_MESSAGE_SEEK
) {
1415 /* The client side is incapable of accounting correctly
1416 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1417 * able to deal with that. */
1419 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1420 windex
= PA_MIN(windex
, pa_memblockq_get_write_index(s
->memblockq
));
1423 if (chunk
&& pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1424 if (pa_log_ratelimit(PA_LOG_WARN
))
1425 pa_log_warn("Failed to push data into queue");
1426 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1427 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, TRUE
);
1430 /* If more data is in queue, we rewind later instead. */
1431 if (s
->seek_windex
!= -1)
1432 windex
= PA_MIN(windex
, s
->seek_windex
);
1433 if (pa_atomic_dec(&s
->seek_or_post_in_queue
) > 1)
1434 s
->seek_windex
= windex
;
1436 s
->seek_windex
= -1;
1437 handle_seek(s
, windex
);
1442 case SINK_INPUT_MESSAGE_DRAIN
:
1443 case SINK_INPUT_MESSAGE_FLUSH
:
1444 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1445 case SINK_INPUT_MESSAGE_TRIGGER
: {
1448 pa_sink_input
*isync
;
1449 void (*func
)(pa_memblockq
*bq
);
1452 case SINK_INPUT_MESSAGE_FLUSH
:
1453 func
= flush_write_no_account
;
1456 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1457 func
= pa_memblockq_prebuf_force
;
1460 case SINK_INPUT_MESSAGE_DRAIN
:
1461 case SINK_INPUT_MESSAGE_TRIGGER
:
1462 func
= pa_memblockq_prebuf_disable
;
1466 pa_assert_not_reached();
1469 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1471 handle_seek(s
, windex
);
1473 /* Do the same for all other members in the sync group */
1474 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1475 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1476 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1477 func(ssync
->memblockq
);
1478 handle_seek(ssync
, windex
);
1481 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1482 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1483 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1484 func(ssync
->memblockq
);
1485 handle_seek(ssync
, windex
);
1488 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1489 if (!pa_memblockq_is_readable(s
->memblockq
))
1490 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1492 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1493 s
->drain_request
= TRUE
;
1500 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1501 /* Atomically get a snapshot of all timing parameters... */
1502 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1503 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1504 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1505 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1506 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1507 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1511 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1514 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1516 pa_memblockq_prebuf_force(s
->memblockq
);
1518 handle_seek(s
, windex
);
1520 /* Fall through to the default handler */
1524 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1525 pa_usec_t
*r
= userdata
;
1527 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1529 /* Fall through, the default handler will add in the extra
1530 * latency added by the resampler */
1534 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1535 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1536 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1541 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1544 /* Called from thread context */
1545 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1548 pa_sink_input_assert_ref(i
);
1549 s
= PLAYBACK_STREAM(i
->userdata
);
1550 playback_stream_assert_ref(s
);
1553 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1555 if (pa_memblockq_is_readable(s
->memblockq
))
1556 s
->is_underrun
= FALSE
;
1558 if (!s
->is_underrun
)
1559 pa_log_debug("Underrun on '%s', %lu bytes in queue.", pa_strnull(pa_proplist_gets(i
->proplist
, PA_PROP_MEDIA_NAME
)), (unsigned long) pa_memblockq_get_length(s
->memblockq
));
1561 if (s
->drain_request
&& pa_sink_input_safe_to_remove(i
)) {
1562 s
->drain_request
= FALSE
;
1563 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
);
1564 } else if (!s
->is_underrun
)
1565 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UNDERFLOW
, NULL
, 0, NULL
, NULL
);
1567 s
->is_underrun
= TRUE
;
1569 playback_stream_request_bytes(s
);
1572 /* This call will not fail with prebuf=0, hence we check for
1573 underrun explicitly above */
1574 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1577 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1579 if (i
->thread_info
.underrun_for
> 0)
1580 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1582 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1583 playback_stream_request_bytes(s
);
1588 /* Called from thread context */
1589 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1592 pa_sink_input_assert_ref(i
);
1593 s
= PLAYBACK_STREAM(i
->userdata
);
1594 playback_stream_assert_ref(s
);
1596 /* If we are in an underrun, then we don't rewind */
1597 if (i
->thread_info
.underrun_for
> 0)
1600 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1603 /* Called from thread context */
1604 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1607 pa_sink_input_assert_ref(i
);
1608 s
= PLAYBACK_STREAM(i
->userdata
);
1609 playback_stream_assert_ref(s
);
1611 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1614 /* Called from thread context */
1615 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1617 size_t new_tlength
, old_tlength
;
1619 pa_sink_input_assert_ref(i
);
1620 s
= PLAYBACK_STREAM(i
->userdata
);
1621 playback_stream_assert_ref(s
);
1623 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1624 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1626 if (old_tlength
< new_tlength
) {
1627 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1628 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1629 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1631 if (new_tlength
== old_tlength
)
1632 pa_log_debug("Failed to increase tlength");
1634 pa_log_debug("Notifying client about increased tlength");
1635 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
);
1640 /* Called from main context */
1641 static void sink_input_kill_cb(pa_sink_input
*i
) {
1644 pa_sink_input_assert_ref(i
);
1645 s
= PLAYBACK_STREAM(i
->userdata
);
1646 playback_stream_assert_ref(s
);
1648 playback_stream_send_killed(s
);
1649 playback_stream_unlink(s
);
1652 /* Called from main context */
1653 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1657 pa_sink_input_assert_ref(i
);
1658 s
= PLAYBACK_STREAM(i
->userdata
);
1659 playback_stream_assert_ref(s
);
1661 if (s
->connection
->version
< 15)
1664 t
= pa_tagstruct_new(NULL
, 0);
1665 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1666 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1667 pa_tagstruct_putu32(t
, s
->index
);
1668 pa_tagstruct_puts(t
, event
);
1669 pa_tagstruct_put_proplist(t
, pl
);
1670 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1673 /* Called from main context */
1674 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
) {
1678 pa_sink_input_assert_ref(i
);
1679 s
= PLAYBACK_STREAM(i
->userdata
);
1680 playback_stream_assert_ref(s
);
1682 if (s
->connection
->version
< 12)
1685 t
= pa_tagstruct_new(NULL
, 0);
1686 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1687 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1688 pa_tagstruct_putu32(t
, s
->index
);
1689 pa_tagstruct_put_boolean(t
, suspend
);
1690 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1693 /* Called from main context */
1694 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1698 pa_sink_input_assert_ref(i
);
1699 s
= PLAYBACK_STREAM(i
->userdata
);
1700 playback_stream_assert_ref(s
);
1705 fix_playback_buffer_attr(s
);
1706 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1707 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1709 if (s
->connection
->version
< 12)
1712 t
= pa_tagstruct_new(NULL
, 0);
1713 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1714 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1715 pa_tagstruct_putu32(t
, s
->index
);
1716 pa_tagstruct_putu32(t
, dest
->index
);
1717 pa_tagstruct_puts(t
, dest
->name
);
1718 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1720 if (s
->connection
->version
>= 13) {
1721 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1722 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1723 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1724 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1725 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1728 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1731 /*** source_output callbacks ***/
1733 /* Called from thread context */
1734 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1735 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1738 pa_source_output_assert_ref(o
);
1739 s
= RECORD_STREAM(o
->userdata
);
1740 record_stream_assert_ref(s
);
1743 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1744 /* Atomically get a snapshot of all timing parameters... */
1745 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1746 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1747 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1751 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1754 /* Called from thread context */
1755 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1758 pa_source_output_assert_ref(o
);
1759 s
= RECORD_STREAM(o
->userdata
);
1760 record_stream_assert_ref(s
);
1763 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1764 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1767 static void source_output_kill_cb(pa_source_output
*o
) {
1770 pa_source_output_assert_ref(o
);
1771 s
= RECORD_STREAM(o
->userdata
);
1772 record_stream_assert_ref(s
);
1774 record_stream_send_killed(s
);
1775 record_stream_unlink(s
);
1778 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1781 pa_source_output_assert_ref(o
);
1782 s
= RECORD_STREAM(o
->userdata
);
1783 record_stream_assert_ref(s
);
1785 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1787 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1790 /* Called from main context */
1791 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1795 pa_source_output_assert_ref(o
);
1796 s
= RECORD_STREAM(o
->userdata
);
1797 record_stream_assert_ref(s
);
1799 if (s
->connection
->version
< 15)
1802 t
= pa_tagstruct_new(NULL
, 0);
1803 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1804 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1805 pa_tagstruct_putu32(t
, s
->index
);
1806 pa_tagstruct_puts(t
, event
);
1807 pa_tagstruct_put_proplist(t
, pl
);
1808 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1811 /* Called from main context */
1812 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
) {
1816 pa_source_output_assert_ref(o
);
1817 s
= RECORD_STREAM(o
->userdata
);
1818 record_stream_assert_ref(s
);
1820 if (s
->connection
->version
< 12)
1823 t
= pa_tagstruct_new(NULL
, 0);
1824 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1825 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1826 pa_tagstruct_putu32(t
, s
->index
);
1827 pa_tagstruct_put_boolean(t
, suspend
);
1828 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1831 /* Called from main context */
1832 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1836 pa_source_output_assert_ref(o
);
1837 s
= RECORD_STREAM(o
->userdata
);
1838 record_stream_assert_ref(s
);
1843 fix_record_buffer_attr_pre(s
);
1844 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1845 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1846 fix_record_buffer_attr_post(s
);
1848 if (s
->connection
->version
< 12)
1851 t
= pa_tagstruct_new(NULL
, 0);
1852 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1853 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1854 pa_tagstruct_putu32(t
, s
->index
);
1855 pa_tagstruct_putu32(t
, dest
->index
);
1856 pa_tagstruct_puts(t
, dest
->name
);
1857 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1859 if (s
->connection
->version
>= 13) {
1860 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1861 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1862 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1865 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1868 /*** pdispatch callbacks ***/
1870 static void protocol_error(pa_native_connection
*c
) {
1871 pa_log("protocol error, kicking client");
1872 native_connection_unlink(c
);
1875 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1876 if (!(expression)) { \
1877 pa_pstream_send_error((pstream), (tag), (error)); \
1882 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1883 if (!(expression)) { \
1884 pa_pstream_send_error((pstream), (tag), (error)); \
1889 static pa_tagstruct
*reply_new(uint32_t tag
) {
1890 pa_tagstruct
*reply
;
1892 reply
= pa_tagstruct_new(NULL
, 0);
1893 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1894 pa_tagstruct_putu32(reply
, tag
);
1898 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1899 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1901 uint32_t sink_index
, syncid
, missing
= 0;
1902 pa_buffer_attr attr
;
1903 const char *name
= NULL
, *sink_name
;
1906 pa_tagstruct
*reply
;
1907 pa_sink
*sink
= NULL
;
1915 fix_channels
= FALSE
,
1917 variable_rate
= FALSE
,
1919 adjust_latency
= FALSE
,
1920 early_requests
= FALSE
,
1921 dont_inhibit_auto_suspend
= FALSE
,
1924 fail_on_suspend
= FALSE
,
1925 relative_volume
= FALSE
,
1926 passthrough
= FALSE
;
1928 pa_sink_input_flags_t flags
= 0;
1929 pa_proplist
*p
= NULL
;
1930 int ret
= PA_ERR_INVALID
;
1931 uint8_t n_formats
= 0;
1932 pa_format_info
*format
;
1933 pa_idxset
*formats
= NULL
;
1936 pa_native_connection_assert_ref(c
);
1938 memset(&attr
, 0, sizeof(attr
));
1940 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
1943 PA_TAG_SAMPLE_SPEC
, &ss
,
1944 PA_TAG_CHANNEL_MAP
, &map
,
1945 PA_TAG_U32
, &sink_index
,
1946 PA_TAG_STRING
, &sink_name
,
1947 PA_TAG_U32
, &attr
.maxlength
,
1948 PA_TAG_BOOLEAN
, &corked
,
1949 PA_TAG_U32
, &attr
.tlength
,
1950 PA_TAG_U32
, &attr
.prebuf
,
1951 PA_TAG_U32
, &attr
.minreq
,
1952 PA_TAG_U32
, &syncid
,
1953 PA_TAG_CVOLUME
, &volume
,
1954 PA_TAG_INVALID
) < 0) {
1960 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
1961 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
, finish
);
1962 CHECK_VALIDITY_GOTO(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
, finish
);
1963 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
1964 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
1966 p
= pa_proplist_new();
1969 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
1971 if (c
->version
>= 12) {
1972 /* Since 0.9.8 the user can ask for a couple of additional flags */
1974 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
1975 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
1976 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
1977 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
1978 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
1979 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
1980 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
1987 if (c
->version
>= 13) {
1989 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
1990 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
1991 pa_tagstruct_get_proplist(t
, p
) < 0) {
1998 if (c
->version
>= 14) {
2000 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2001 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2008 if (c
->version
>= 15) {
2010 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2011 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2012 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2019 if (c
->version
>= 17) {
2021 if (pa_tagstruct_get_boolean(t
, &relative_volume
) < 0) {
2028 if (c
->version
>= 18) {
2030 if (pa_tagstruct_get_boolean(t
, &passthrough
) < 0 ) {
2036 if (c
->version
>= 21) {
2038 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2044 formats
= pa_idxset_new(NULL
, NULL
);
2046 for (i
= 0; i
< n_formats
; i
++) {
2047 format
= pa_format_info_new();
2048 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2052 pa_idxset_put(formats
, format
, NULL
);
2056 if (n_formats
== 0) {
2057 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2058 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2059 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2061 PA_IDXSET_FOREACH(format
, formats
, i
) {
2062 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2066 if (!pa_tagstruct_eof(t
)) {
2071 if (sink_index
!= PA_INVALID_INDEX
) {
2073 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
2074 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2078 } else if (sink_name
) {
2080 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
2081 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2087 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
2088 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
2089 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
2090 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
2091 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
2092 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
2093 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
2094 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
2095 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2096 (fail_on_suspend
? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND
|PA_SINK_INPUT_KILL_ON_SUSPEND
: 0) |
2097 (passthrough
? PA_SINK_INPUT_PASSTHROUGH
: 0);
2099 /* Only since protocol version 15 there's a seperate muted_set
2100 * flag. For older versions we synthesize it here */
2101 muted_set
= muted_set
|| muted
;
2103 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
);
2104 /* We no longer own the formats idxset */
2107 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2109 reply
= reply_new(tag
);
2110 pa_tagstruct_putu32(reply
, s
->index
);
2111 pa_assert(s
->sink_input
);
2112 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
2113 pa_tagstruct_putu32(reply
, missing
);
2115 /* pa_log("initial request is %u", missing); */
2117 if (c
->version
>= 9) {
2118 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2120 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2121 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
2122 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
2123 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
2126 if (c
->version
>= 12) {
2127 /* Since 0.9.8 we support sending the chosen sample
2128 * spec/channel map/device/suspend status back to the
2131 pa_tagstruct_put_sample_spec(reply
, &ss
);
2132 pa_tagstruct_put_channel_map(reply
, &map
);
2134 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
2135 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
2137 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
2140 if (c
->version
>= 13)
2141 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
2143 if (c
->version
>= 21) {
2144 /* Send back the format we negotiated */
2145 if (s
->sink_input
->format
)
2146 pa_tagstruct_put_format_info(reply
, s
->sink_input
->format
);
2148 pa_format_info
*f
= pa_format_info_new();
2149 pa_tagstruct_put_format_info(reply
, f
);
2150 pa_format_info_free(f
);
2154 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2158 pa_proplist_free(p
);
2160 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
2163 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2164 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2167 pa_native_connection_assert_ref(c
);
2170 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2171 !pa_tagstruct_eof(t
)) {
2176 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2180 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2182 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2183 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2187 playback_stream_unlink(s
);
2191 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2193 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2194 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2198 record_stream_unlink(s
);
2202 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2205 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2206 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2210 upload_stream_unlink(s
);
2215 pa_assert_not_reached();
2218 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2221 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2222 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2224 pa_buffer_attr attr
;
2225 uint32_t source_index
;
2226 const char *name
= NULL
, *source_name
;
2229 pa_tagstruct
*reply
;
2230 pa_source
*source
= NULL
;
2238 fix_channels
= FALSE
,
2240 variable_rate
= FALSE
,
2242 adjust_latency
= FALSE
,
2243 peak_detect
= FALSE
,
2244 early_requests
= FALSE
,
2245 dont_inhibit_auto_suspend
= FALSE
,
2248 fail_on_suspend
= FALSE
,
2249 relative_volume
= FALSE
,
2250 passthrough
= FALSE
;
2252 pa_source_output_flags_t flags
= 0;
2253 pa_proplist
*p
= NULL
;
2254 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2255 pa_sink_input
*direct_on_input
= NULL
;
2256 int ret
= PA_ERR_INVALID
;
2257 uint8_t n_formats
= 0;
2258 pa_format_info
*format
;
2259 pa_idxset
*formats
= NULL
;
2262 pa_native_connection_assert_ref(c
);
2265 memset(&attr
, 0, sizeof(attr
));
2267 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2268 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2269 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2270 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2271 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2272 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2273 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2274 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2280 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
2281 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| pa_namereg_is_valid_name_or_wildcard(source_name
, PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
, finish
);
2282 CHECK_VALIDITY_GOTO(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
, finish
);
2283 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
2285 p
= pa_proplist_new();
2288 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2290 if (c
->version
>= 12) {
2291 /* Since 0.9.8 the user can ask for a couple of additional flags */
2293 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2294 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2295 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2296 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2297 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2298 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2299 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2306 if (c
->version
>= 13) {
2308 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2309 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2310 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2311 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2318 if (c
->version
>= 14) {
2320 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2326 if (c
->version
>= 15) {
2328 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2329 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2336 if (c
->version
>= 22) {
2337 /* For newer client versions (with per-source-output volumes), we try
2338 * to make the behaviour for playback and record streams the same. */
2341 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2347 formats
= pa_idxset_new(NULL
, NULL
);
2349 for (i
= 0; i
< n_formats
; i
++) {
2350 format
= pa_format_info_new();
2351 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2355 pa_idxset_put(formats
, format
, NULL
);
2358 if (pa_tagstruct_get_cvolume(t
, &volume
) < 0 ||
2359 pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2360 pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2361 pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2362 pa_tagstruct_get_boolean(t
, &relative_volume
) < 0 ||
2363 pa_tagstruct_get_boolean(t
, &passthrough
) < 0) {
2369 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
2372 if (n_formats
== 0) {
2373 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2374 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2375 CHECK_VALIDITY_GOTO(c
->pstream
, c
->version
< 22 || (volume
.channels
== ss
.channels
), tag
, PA_ERR_INVALID
, finish
);
2376 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2378 PA_IDXSET_FOREACH(format
, formats
, i
) {
2379 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2384 if (!pa_tagstruct_eof(t
)) {
2389 if (source_index
!= PA_INVALID_INDEX
) {
2391 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2392 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2396 } else if (source_name
) {
2398 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2399 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2404 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2406 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2407 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2413 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2414 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2415 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2416 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2417 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2418 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2419 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2420 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2421 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2422 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0) |
2423 (passthrough
? PA_SOURCE_OUTPUT_PASSTHROUGH
: 0);
2425 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
);
2427 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2429 reply
= reply_new(tag
);
2430 pa_tagstruct_putu32(reply
, s
->index
);
2431 pa_assert(s
->source_output
);
2432 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2434 if (c
->version
>= 9) {
2435 /* Since 0.9 we support sending the buffer metrics back to the client */
2437 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2438 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2441 if (c
->version
>= 12) {
2442 /* Since 0.9.8 we support sending the chosen sample
2443 * spec/channel map/device/suspend status back to the
2446 pa_tagstruct_put_sample_spec(reply
, &ss
);
2447 pa_tagstruct_put_channel_map(reply
, &map
);
2449 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2450 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2452 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2455 if (c
->version
>= 13)
2456 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2458 if (c
->version
>= 22) {
2459 /* Send back the format we negotiated */
2460 if (s
->source_output
->format
)
2461 pa_tagstruct_put_format_info(reply
, s
->source_output
->format
);
2463 pa_format_info
*f
= pa_format_info_new();
2464 pa_tagstruct_put_format_info(reply
, f
);
2465 pa_format_info_free(f
);
2469 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2473 pa_proplist_free(p
);
2475 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
2478 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2479 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2482 pa_native_connection_assert_ref(c
);
2485 if (!pa_tagstruct_eof(t
)) {
2490 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2491 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2492 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2494 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2496 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2499 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2500 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2502 pa_tagstruct
*reply
;
2503 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2505 pa_native_connection_assert_ref(c
);
2508 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2509 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2510 !pa_tagstruct_eof(t
)) {
2515 /* Minimum supported version */
2516 if (c
->version
< 8) {
2517 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2521 /* Starting with protocol version 13 the MSB of the version tag
2522 reflects if shm is available for this pa_native_connection or
2524 if (c
->version
>= 13) {
2525 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2526 c
->version
&= 0x7FFFFFFFU
;
2529 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2531 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2533 if (!c
->authorized
) {
2534 pa_bool_t success
= FALSE
;
2537 const pa_creds
*creds
;
2539 if ((creds
= pa_pdispatch_creds(pd
))) {
2540 if (creds
->uid
== getuid())
2542 else if (c
->options
->auth_group
) {
2546 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2547 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2548 else if (gid
== creds
->gid
)
2552 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2553 pa_log_warn("Failed to check group membership.");
2559 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2560 (unsigned long) creds
->uid
,
2561 (unsigned long) creds
->gid
,
2566 if (!success
&& c
->options
->auth_cookie
) {
2569 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2570 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2575 pa_log_warn("Denied access to client with invalid authorization data.");
2576 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2580 c
->authorized
= TRUE
;
2581 if (c
->auth_timeout_event
) {
2582 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2583 c
->auth_timeout_event
= NULL
;
2587 /* Enable shared memory support if possible */
2589 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2592 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2595 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2600 /* Only enable SHM if both sides are owned by the same
2601 * user. This is a security measure because otherwise data
2602 * private to the user might leak. */
2604 const pa_creds
*creds
;
2605 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2610 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2611 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2613 reply
= reply_new(tag
);
2614 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2618 /* SHM support is only enabled after both sides made sure they are the same user. */
2622 ucred
.uid
= getuid();
2623 ucred
.gid
= getgid();
2625 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2628 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2632 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2633 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2634 const char *name
= NULL
;
2636 pa_tagstruct
*reply
;
2638 pa_native_connection_assert_ref(c
);
2641 p
= pa_proplist_new();
2643 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2644 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2645 !pa_tagstruct_eof(t
)) {
2648 pa_proplist_free(p
);
2653 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2654 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2655 pa_proplist_free(p
);
2659 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2660 pa_proplist_free(p
);
2662 reply
= reply_new(tag
);
2664 if (c
->version
>= 13)
2665 pa_tagstruct_putu32(reply
, c
->client
->index
);
2667 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2670 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2671 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2673 uint32_t idx
= PA_IDXSET_INVALID
;
2675 pa_native_connection_assert_ref(c
);
2678 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2679 !pa_tagstruct_eof(t
)) {
2684 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2685 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
);
2687 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2689 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2693 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2694 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2695 idx
= source
->index
;
2698 if (idx
== PA_IDXSET_INVALID
)
2699 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2701 pa_tagstruct
*reply
;
2702 reply
= reply_new(tag
);
2703 pa_tagstruct_putu32(reply
, idx
);
2704 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2708 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2709 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2713 pa_native_connection_assert_ref(c
);
2716 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2717 !pa_tagstruct_eof(t
)) {
2722 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2723 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2724 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2725 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2727 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
);
2730 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2731 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2732 pa_tagstruct
*reply
;
2733 const pa_mempool_stat
*stat
;
2735 pa_native_connection_assert_ref(c
);
2738 if (!pa_tagstruct_eof(t
)) {
2743 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2745 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2747 reply
= reply_new(tag
);
2748 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2749 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2750 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2751 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2752 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2753 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2756 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2757 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2758 pa_tagstruct
*reply
;
2760 struct timeval tv
, now
;
2763 pa_native_connection_assert_ref(c
);
2766 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2767 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2768 !pa_tagstruct_eof(t
)) {
2773 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2774 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2775 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2776 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2778 /* Get an atomic snapshot of all timing parameters */
2779 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);
2781 reply
= reply_new(tag
);
2782 pa_tagstruct_put_usec(reply
,
2783 s
->current_sink_latency
+
2784 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2785 pa_tagstruct_put_usec(reply
, 0);
2786 pa_tagstruct_put_boolean(reply
,
2787 s
->playing_for
> 0 &&
2788 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2789 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2790 pa_tagstruct_put_timeval(reply
, &tv
);
2791 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2792 pa_tagstruct_puts64(reply
, s
->write_index
);
2793 pa_tagstruct_puts64(reply
, s
->read_index
);
2795 if (c
->version
>= 13) {
2796 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2797 pa_tagstruct_putu64(reply
, s
->playing_for
);
2800 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2803 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2804 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2805 pa_tagstruct
*reply
;
2807 struct timeval tv
, now
;
2810 pa_native_connection_assert_ref(c
);
2813 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2814 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2815 !pa_tagstruct_eof(t
)) {
2820 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2821 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2822 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2824 /* Get an atomic snapshot of all timing parameters */
2825 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);
2827 reply
= reply_new(tag
);
2828 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2829 pa_tagstruct_put_usec(reply
,
2830 s
->current_source_latency
+
2831 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2832 pa_tagstruct_put_boolean(reply
,
2833 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2834 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2835 pa_tagstruct_put_timeval(reply
, &tv
);
2836 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2837 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2838 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2839 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2842 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2843 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2846 const char *name
= NULL
;
2849 pa_tagstruct
*reply
;
2852 pa_native_connection_assert_ref(c
);
2855 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2856 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2857 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2858 pa_tagstruct_getu32(t
, &length
) < 0) {
2863 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2864 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2865 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2866 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2867 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2868 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2870 p
= pa_proplist_new();
2872 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2873 !pa_tagstruct_eof(t
)) {
2876 pa_proplist_free(p
);
2880 if (c
->version
< 13)
2881 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2883 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2884 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2886 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2887 pa_proplist_free(p
);
2888 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2891 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2892 pa_proplist_free(p
);
2894 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2896 reply
= reply_new(tag
);
2897 pa_tagstruct_putu32(reply
, s
->index
);
2898 pa_tagstruct_putu32(reply
, length
);
2899 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2902 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2903 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2908 pa_native_connection_assert_ref(c
);
2911 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2912 !pa_tagstruct_eof(t
)) {
2917 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2919 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2920 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2921 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2923 if (!s
->memchunk
.memblock
)
2924 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
2925 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2926 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2928 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2930 upload_stream_unlink(s
);
2933 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2934 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2935 uint32_t sink_index
;
2938 const char *name
, *sink_name
;
2941 pa_tagstruct
*reply
;
2943 pa_native_connection_assert_ref(c
);
2946 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2948 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
2949 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
2950 pa_tagstruct_getu32(t
, &volume
) < 0 ||
2951 pa_tagstruct_gets(t
, &name
) < 0) {
2956 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
2957 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
2958 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2959 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2961 if (sink_index
!= PA_INVALID_INDEX
)
2962 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
2964 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
2966 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
2968 p
= pa_proplist_new();
2970 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2971 !pa_tagstruct_eof(t
)) {
2973 pa_proplist_free(p
);
2977 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
2979 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
2980 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2981 pa_proplist_free(p
);
2985 pa_proplist_free(p
);
2987 reply
= reply_new(tag
);
2989 if (c
->version
>= 13)
2990 pa_tagstruct_putu32(reply
, idx
);
2992 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2995 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2996 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2999 pa_native_connection_assert_ref(c
);
3002 if (pa_tagstruct_gets(t
, &name
) < 0 ||
3003 !pa_tagstruct_eof(t
)) {
3008 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3009 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3011 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
3012 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3016 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3019 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
3022 pa_assert(original
);
3026 if (c
->version
< 12) {
3027 /* Before protocol version 12 we didn't support S32 samples,
3028 * so we need to lie about this to the client */
3030 if (fixed
->format
== PA_SAMPLE_S32LE
)
3031 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3032 if (fixed
->format
== PA_SAMPLE_S32BE
)
3033 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3036 if (c
->version
< 15) {
3037 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
3038 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3039 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
3040 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3044 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
3045 pa_sample_spec fixed_ss
;
3048 pa_sink_assert_ref(sink
);
3050 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
3054 PA_TAG_U32
, sink
->index
,
3055 PA_TAG_STRING
, sink
->name
,
3056 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3057 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3058 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
3059 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
3060 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
3061 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
3062 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
3063 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
3064 PA_TAG_USEC
, pa_sink_get_latency(sink
),
3065 PA_TAG_STRING
, sink
->driver
,
3066 PA_TAG_U32
, sink
->flags
& ~PA_SINK_SHARE_VOLUME_WITH_MASTER
,
3069 if (c
->version
>= 13) {
3070 pa_tagstruct_put_proplist(t
, sink
->proplist
);
3071 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
3074 if (c
->version
>= 15) {
3075 pa_tagstruct_put_volume(t
, sink
->base_volume
);
3076 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
3077 pa_log_error("Internal sink state is invalid.");
3078 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
3079 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
3080 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
3083 if (c
->version
>= 16) {
3084 pa_tagstruct_putu32(t
, sink
->ports
? pa_hashmap_size(sink
->ports
) : 0);
3090 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
3091 pa_tagstruct_puts(t
, p
->name
);
3092 pa_tagstruct_puts(t
, p
->description
);
3093 pa_tagstruct_putu32(t
, p
->priority
);
3097 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
3100 if (c
->version
>= 21) {
3103 pa_idxset
*formats
= pa_sink_get_formats(sink
);
3105 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3106 PA_IDXSET_FOREACH(f
, formats
, i
) {
3107 pa_tagstruct_put_format_info(t
, f
);
3110 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3114 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
3115 pa_sample_spec fixed_ss
;
3118 pa_source_assert_ref(source
);
3120 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
3124 PA_TAG_U32
, source
->index
,
3125 PA_TAG_STRING
, source
->name
,
3126 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3127 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3128 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
3129 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
3130 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
3131 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
3132 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
3133 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
3134 PA_TAG_USEC
, pa_source_get_latency(source
),
3135 PA_TAG_STRING
, source
->driver
,
3136 PA_TAG_U32
, source
->flags
,
3139 if (c
->version
>= 13) {
3140 pa_tagstruct_put_proplist(t
, source
->proplist
);
3141 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
3144 if (c
->version
>= 15) {
3145 pa_tagstruct_put_volume(t
, source
->base_volume
);
3146 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
3147 pa_log_error("Internal source state is invalid.");
3148 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
3149 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
3150 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
3153 if (c
->version
>= 16) {
3155 pa_tagstruct_putu32(t
, source
->ports
? pa_hashmap_size(source
->ports
) : 0);
3157 if (source
->ports
) {
3161 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
3162 pa_tagstruct_puts(t
, p
->name
);
3163 pa_tagstruct_puts(t
, p
->description
);
3164 pa_tagstruct_putu32(t
, p
->priority
);
3168 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
3171 if (c
->version
>= 22) {
3174 pa_idxset
*formats
= pa_source_get_formats(source
);
3176 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3177 PA_IDXSET_FOREACH(f
, formats
, i
) {
3178 pa_tagstruct_put_format_info(t
, f
);
3181 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3185 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
3189 pa_tagstruct_putu32(t
, client
->index
);
3190 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
3191 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
3192 pa_tagstruct_puts(t
, client
->driver
);
3194 if (c
->version
>= 13)
3195 pa_tagstruct_put_proplist(t
, client
->proplist
);
3198 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
3205 pa_tagstruct_putu32(t
, card
->index
);
3206 pa_tagstruct_puts(t
, card
->name
);
3207 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
3208 pa_tagstruct_puts(t
, card
->driver
);
3210 pa_tagstruct_putu32(t
, card
->profiles
? pa_hashmap_size(card
->profiles
) : 0);
3212 if (card
->profiles
) {
3213 while ((p
= pa_hashmap_iterate(card
->profiles
, &state
, NULL
))) {
3214 pa_tagstruct_puts(t
, p
->name
);
3215 pa_tagstruct_puts(t
, p
->description
);
3216 pa_tagstruct_putu32(t
, p
->n_sinks
);
3217 pa_tagstruct_putu32(t
, p
->n_sources
);
3218 pa_tagstruct_putu32(t
, p
->priority
);
3222 pa_tagstruct_puts(t
, card
->active_profile
? card
->active_profile
->name
: NULL
);
3223 pa_tagstruct_put_proplist(t
, card
->proplist
);
3226 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3230 pa_tagstruct_putu32(t
, module
->index
);
3231 pa_tagstruct_puts(t
, module
->name
);
3232 pa_tagstruct_puts(t
, module
->argument
);
3233 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3235 if (c
->version
< 15)
3236 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
3238 if (c
->version
>= 15)
3239 pa_tagstruct_put_proplist(t
, module
->proplist
);
3242 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3243 pa_sample_spec fixed_ss
;
3244 pa_usec_t sink_latency
;
3246 pa_bool_t has_volume
= FALSE
;
3249 pa_sink_input_assert_ref(s
);
3251 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3253 has_volume
= pa_sink_input_is_volume_readable(s
);
3255 pa_sink_input_get_volume(s
, &v
, TRUE
);
3257 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3259 pa_tagstruct_putu32(t
, s
->index
);
3260 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3261 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3262 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3263 pa_tagstruct_putu32(t
, s
->sink
->index
);
3264 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3265 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3266 pa_tagstruct_put_cvolume(t
, &v
);
3267 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3268 pa_tagstruct_put_usec(t
, sink_latency
);
3269 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3270 pa_tagstruct_puts(t
, s
->driver
);
3271 if (c
->version
>= 11)
3272 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
3273 if (c
->version
>= 13)
3274 pa_tagstruct_put_proplist(t
, s
->proplist
);
3275 if (c
->version
>= 19)
3276 pa_tagstruct_put_boolean(t
, (pa_sink_input_get_state(s
) == PA_SINK_INPUT_CORKED
));
3277 if (c
->version
>= 20) {
3278 pa_tagstruct_put_boolean(t
, has_volume
);
3279 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3281 if (c
->version
>= 21)
3282 pa_tagstruct_put_format_info(t
, s
->format
);
3285 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3286 pa_sample_spec fixed_ss
;
3287 pa_usec_t source_latency
;
3289 pa_bool_t has_volume
= FALSE
;
3292 pa_source_output_assert_ref(s
);
3294 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3296 has_volume
= pa_source_output_is_volume_readable(s
);
3298 pa_source_output_get_volume(s
, &v
, TRUE
);
3300 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3302 pa_tagstruct_putu32(t
, s
->index
);
3303 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3304 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3305 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3306 pa_tagstruct_putu32(t
, s
->source
->index
);
3307 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3308 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3309 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3310 pa_tagstruct_put_usec(t
, source_latency
);
3311 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3312 pa_tagstruct_puts(t
, s
->driver
);
3313 if (c
->version
>= 13)
3314 pa_tagstruct_put_proplist(t
, s
->proplist
);
3315 if (c
->version
>= 19)
3316 pa_tagstruct_put_boolean(t
, (pa_source_output_get_state(s
) == PA_SOURCE_OUTPUT_CORKED
));
3317 if (c
->version
>= 22) {
3318 pa_tagstruct_put_cvolume(t
, &v
);
3319 pa_tagstruct_put_boolean(t
, pa_source_output_get_mute(s
));
3320 pa_tagstruct_put_boolean(t
, has_volume
);
3321 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3322 pa_tagstruct_put_format_info(t
, s
->format
);
3326 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3327 pa_sample_spec fixed_ss
;
3333 if (e
->memchunk
.memblock
)
3334 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3336 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3338 pa_tagstruct_putu32(t
, e
->index
);
3339 pa_tagstruct_puts(t
, e
->name
);
3341 if (e
->volume_is_set
)
3344 pa_cvolume_init(&v
);
3346 pa_tagstruct_put_cvolume(t
, &v
);
3347 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3348 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3349 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3350 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3351 pa_tagstruct_put_boolean(t
, e
->lazy
);
3352 pa_tagstruct_puts(t
, e
->filename
);
3354 if (c
->version
>= 13)
3355 pa_tagstruct_put_proplist(t
, e
->proplist
);
3358 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3359 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3361 pa_sink
*sink
= NULL
;
3362 pa_source
*source
= NULL
;
3363 pa_client
*client
= NULL
;
3364 pa_card
*card
= NULL
;
3365 pa_module
*module
= NULL
;
3366 pa_sink_input
*si
= NULL
;
3367 pa_source_output
*so
= NULL
;
3368 pa_scache_entry
*sce
= NULL
;
3369 const char *name
= NULL
;
3370 pa_tagstruct
*reply
;
3372 pa_native_connection_assert_ref(c
);
3375 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3376 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3377 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3378 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3379 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3380 pa_tagstruct_gets(t
, &name
) < 0) ||
3381 !pa_tagstruct_eof(t
)) {
3386 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3387 CHECK_VALIDITY(c
->pstream
, !name
||
3388 (command
== PA_COMMAND_GET_SINK_INFO
&&
3389 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3390 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3391 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3392 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3393 CHECK_VALIDITY(c
->pstream
, command
== PA_COMMAND_GET_SINK_INFO
||
3394 command
== PA_COMMAND_GET_SOURCE_INFO
||
3395 (idx
!= PA_INVALID_INDEX
|| name
), tag
, PA_ERR_INVALID
);
3396 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3397 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3399 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3400 if (idx
!= PA_INVALID_INDEX
)
3401 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3403 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3404 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3405 if (idx
!= PA_INVALID_INDEX
)
3406 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3408 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3409 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3410 if (idx
!= PA_INVALID_INDEX
)
3411 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3413 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3414 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3415 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3416 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3417 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3418 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3419 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3420 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3421 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3423 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3424 if (idx
!= PA_INVALID_INDEX
)
3425 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3427 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3430 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3431 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3435 reply
= reply_new(tag
);
3437 sink_fill_tagstruct(c
, reply
, sink
);
3439 source_fill_tagstruct(c
, reply
, source
);
3441 client_fill_tagstruct(c
, reply
, client
);
3443 card_fill_tagstruct(c
, reply
, card
);
3445 module_fill_tagstruct(c
, reply
, module
);
3447 sink_input_fill_tagstruct(c
, reply
, si
);
3449 source_output_fill_tagstruct(c
, reply
, so
);
3451 scache_fill_tagstruct(c
, reply
, sce
);
3452 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3455 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3456 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3460 pa_tagstruct
*reply
;
3462 pa_native_connection_assert_ref(c
);
3465 if (!pa_tagstruct_eof(t
)) {
3470 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3472 reply
= reply_new(tag
);
3474 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3475 i
= c
->protocol
->core
->sinks
;
3476 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3477 i
= c
->protocol
->core
->sources
;
3478 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3479 i
= c
->protocol
->core
->clients
;
3480 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3481 i
= c
->protocol
->core
->cards
;
3482 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3483 i
= c
->protocol
->core
->modules
;
3484 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3485 i
= c
->protocol
->core
->sink_inputs
;
3486 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3487 i
= c
->protocol
->core
->source_outputs
;
3489 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3490 i
= c
->protocol
->core
->scache
;
3494 for (p
= pa_idxset_first(i
, &idx
); p
; p
= pa_idxset_next(i
, &idx
)) {
3495 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3496 sink_fill_tagstruct(c
, reply
, p
);
3497 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3498 source_fill_tagstruct(c
, reply
, p
);
3499 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3500 client_fill_tagstruct(c
, reply
, p
);
3501 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3502 card_fill_tagstruct(c
, reply
, p
);
3503 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3504 module_fill_tagstruct(c
, reply
, p
);
3505 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3506 sink_input_fill_tagstruct(c
, reply
, p
);
3507 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3508 source_output_fill_tagstruct(c
, reply
, p
);
3510 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3511 scache_fill_tagstruct(c
, reply
, p
);
3516 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3519 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3520 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3521 pa_tagstruct
*reply
;
3523 pa_source
*def_source
;
3524 pa_sample_spec fixed_ss
;
3527 pa_native_connection_assert_ref(c
);
3530 if (!pa_tagstruct_eof(t
)) {
3535 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3537 reply
= reply_new(tag
);
3538 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3539 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3541 u
= pa_get_user_name_malloc();
3542 pa_tagstruct_puts(reply
, u
);
3545 h
= pa_get_host_name_malloc();
3546 pa_tagstruct_puts(reply
, h
);
3549 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3550 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3552 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3553 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3554 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3555 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3557 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3559 if (c
->version
>= 15)
3560 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3562 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3565 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3567 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3569 pa_native_connection_assert_ref(c
);
3571 t
= pa_tagstruct_new(NULL
, 0);
3572 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3573 pa_tagstruct_putu32(t
, (uint32_t) -1);
3574 pa_tagstruct_putu32(t
, e
);
3575 pa_tagstruct_putu32(t
, idx
);
3576 pa_pstream_send_tagstruct(c
->pstream
, t
);
3579 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3580 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3581 pa_subscription_mask_t m
;
3583 pa_native_connection_assert_ref(c
);
3586 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3587 !pa_tagstruct_eof(t
)) {
3592 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3593 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3595 if (c
->subscription
)
3596 pa_subscription_free(c
->subscription
);
3599 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3600 pa_assert(c
->subscription
);
3602 c
->subscription
= NULL
;
3604 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3607 static void command_set_volume(
3614 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3617 pa_sink
*sink
= NULL
;
3618 pa_source
*source
= NULL
;
3619 pa_sink_input
*si
= NULL
;
3620 pa_source_output
*so
= NULL
;
3621 const char *name
= NULL
;
3622 const char *client_name
;
3624 pa_native_connection_assert_ref(c
);
3627 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3628 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3629 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3630 pa_tagstruct_get_cvolume(t
, &volume
) ||
3631 !pa_tagstruct_eof(t
)) {
3636 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3637 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
);
3638 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3639 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3640 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3641 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3645 case PA_COMMAND_SET_SINK_VOLUME
:
3646 if (idx
!= PA_INVALID_INDEX
)
3647 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3649 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3652 case PA_COMMAND_SET_SOURCE_VOLUME
:
3653 if (idx
!= PA_INVALID_INDEX
)
3654 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3656 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3659 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3660 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3663 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
:
3664 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3668 pa_assert_not_reached();
3671 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3673 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3676 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3678 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3679 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3680 } else if (source
) {
3681 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3683 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3684 pa_source_set_volume(source
, &volume
, TRUE
, TRUE
);
3686 CHECK_VALIDITY(c
->pstream
, si
->volume_writable
, tag
, PA_ERR_BADSTATE
);
3687 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3689 pa_log_debug("Client %s changes volume of sink input %s.",
3691 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3692 pa_sink_input_set_volume(si
, &volume
, TRUE
, TRUE
);
3694 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &so
->sample_spec
), tag
, PA_ERR_INVALID
);
3696 pa_log_debug("Client %s changes volume of source output %s.",
3698 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3699 pa_source_output_set_volume(so
, &volume
, TRUE
, TRUE
);
3702 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3705 static void command_set_mute(
3712 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3715 pa_sink
*sink
= NULL
;
3716 pa_source
*source
= NULL
;
3717 pa_sink_input
*si
= NULL
;
3718 pa_source_output
*so
= NULL
;
3719 const char *name
= NULL
, *client_name
;
3721 pa_native_connection_assert_ref(c
);
3724 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3725 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3726 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3727 pa_tagstruct_get_boolean(t
, &mute
) ||
3728 !pa_tagstruct_eof(t
)) {
3733 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3734 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
);
3735 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3736 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3737 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3741 case PA_COMMAND_SET_SINK_MUTE
:
3742 if (idx
!= PA_INVALID_INDEX
)
3743 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3745 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3749 case PA_COMMAND_SET_SOURCE_MUTE
:
3750 if (idx
!= PA_INVALID_INDEX
)
3751 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3753 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3757 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3758 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3761 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
:
3762 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3766 pa_assert_not_reached();
3769 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3771 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3774 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3775 pa_sink_set_mute(sink
, mute
, TRUE
);
3776 } else if (source
) {
3777 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3778 pa_source_set_mute(source
, mute
, TRUE
);
3780 pa_log_debug("Client %s changes mute of sink input %s.",
3782 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3783 pa_sink_input_set_mute(si
, mute
, TRUE
);
3785 pa_log_debug("Client %s changes mute of source output %s.",
3787 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3788 pa_source_output_set_mute(so
, mute
, TRUE
);
3791 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3794 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3795 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3800 pa_native_connection_assert_ref(c
);
3803 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3804 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3805 !pa_tagstruct_eof(t
)) {
3810 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3811 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3812 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3813 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3814 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3816 pa_sink_input_cork(s
->sink_input
, b
);
3819 s
->is_underrun
= TRUE
;
3821 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3824 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3825 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3829 pa_native_connection_assert_ref(c
);
3832 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3833 !pa_tagstruct_eof(t
)) {
3838 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3839 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3840 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3841 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3842 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3845 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3846 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3849 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3850 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3853 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3854 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3858 pa_assert_not_reached();
3861 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3864 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3865 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3870 pa_native_connection_assert_ref(c
);
3873 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3874 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3875 !pa_tagstruct_eof(t
)) {
3880 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3881 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3882 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3884 pa_source_output_cork(s
->source_output
, b
);
3885 pa_memblockq_prebuf_force(s
->memblockq
);
3886 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3889 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3890 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3894 pa_native_connection_assert_ref(c
);
3897 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3898 !pa_tagstruct_eof(t
)) {
3903 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3904 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3905 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3907 pa_memblockq_flush_read(s
->memblockq
);
3908 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3911 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3912 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3915 pa_tagstruct
*reply
;
3917 pa_native_connection_assert_ref(c
);
3920 memset(&a
, 0, sizeof(a
));
3922 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3927 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3929 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
3931 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3933 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3934 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3935 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3937 if (pa_tagstruct_get(
3939 PA_TAG_U32
, &a
.maxlength
,
3940 PA_TAG_U32
, &a
.tlength
,
3941 PA_TAG_U32
, &a
.prebuf
,
3942 PA_TAG_U32
, &a
.minreq
,
3943 PA_TAG_INVALID
) < 0 ||
3944 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3945 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3946 !pa_tagstruct_eof(t
)) {
3951 s
->adjust_latency
= adjust_latency
;
3952 s
->early_requests
= early_requests
;
3953 s
->buffer_attr_req
= a
;
3955 fix_playback_buffer_attr(s
);
3956 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);
3958 reply
= reply_new(tag
);
3959 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3960 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
3961 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
3962 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
3964 if (c
->version
>= 13)
3965 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
3969 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3970 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
3972 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3973 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3975 if (pa_tagstruct_get(
3977 PA_TAG_U32
, &a
.maxlength
,
3978 PA_TAG_U32
, &a
.fragsize
,
3979 PA_TAG_INVALID
) < 0 ||
3980 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3981 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3982 !pa_tagstruct_eof(t
)) {
3987 s
->adjust_latency
= adjust_latency
;
3988 s
->early_requests
= early_requests
;
3989 s
->buffer_attr_req
= a
;
3991 fix_record_buffer_attr_pre(s
);
3992 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
3993 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
3994 fix_record_buffer_attr_post(s
);
3996 reply
= reply_new(tag
);
3997 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3998 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
4000 if (c
->version
>= 13)
4001 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
4004 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4007 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4008 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4012 pa_native_connection_assert_ref(c
);
4015 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4016 pa_tagstruct_getu32(t
, &rate
) < 0 ||
4017 !pa_tagstruct_eof(t
)) {
4022 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4023 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
4025 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
4028 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4029 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4030 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4032 pa_sink_input_set_rate(s
->sink_input
, rate
);
4036 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
4038 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4039 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4041 pa_source_output_set_rate(s
->source_output
, rate
);
4044 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4047 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4048 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4053 pa_native_connection_assert_ref(c
);
4056 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4058 p
= pa_proplist_new();
4060 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
4062 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
4063 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4064 !pa_tagstruct_eof(t
)) {
4066 pa_proplist_free(p
);
4072 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4073 pa_tagstruct_getu32(t
, &mode
) < 0 ||
4074 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4075 !pa_tagstruct_eof(t
)) {
4077 pa_proplist_free(p
);
4082 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
4083 pa_proplist_free(p
);
4084 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
4087 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
4090 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4091 if (!s
|| !playback_stream_isinstance(s
)) {
4092 pa_proplist_free(p
);
4093 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4095 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
4097 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
4100 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
4101 pa_proplist_free(p
);
4102 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4104 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
4107 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
4109 pa_client_update_proplist(c
->client
, mode
, p
);
4112 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4113 pa_proplist_free(p
);
4116 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4117 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4119 unsigned changed
= 0;
4121 pa_strlist
*l
= NULL
;
4123 pa_native_connection_assert_ref(c
);
4126 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4128 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
4130 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
4136 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4139 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4140 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4141 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4143 p
= s
->sink_input
->proplist
;
4145 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4148 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4149 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4151 p
= s
->source_output
->proplist
;
4153 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4155 p
= c
->client
->proplist
;
4161 if (pa_tagstruct_gets(t
, &k
) < 0) {
4170 l
= pa_strlist_prepend(l
, k
);
4173 if (!pa_tagstruct_eof(t
)) {
4182 l
= pa_strlist_pop(l
, &z
);
4187 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
4191 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4194 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4197 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4198 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
4200 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4203 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4204 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
4207 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4208 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
4213 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4214 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4217 pa_native_connection_assert_ref(c
);
4220 if (pa_tagstruct_gets(t
, &s
) < 0 ||
4221 !pa_tagstruct_eof(t
)) {
4226 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4227 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
4229 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
4232 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
4233 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4235 pa_namereg_set_default_source(c
->protocol
->core
, source
);
4238 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
4240 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
4241 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4243 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
4246 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4249 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4250 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4254 pa_native_connection_assert_ref(c
);
4257 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4258 pa_tagstruct_gets(t
, &name
) < 0 ||
4259 !pa_tagstruct_eof(t
)) {
4264 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4265 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4267 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
4270 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4271 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4272 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4274 pa_sink_input_set_name(s
->sink_input
, name
);
4278 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4280 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4281 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4283 pa_source_output_set_name(s
->source_output
, name
);
4286 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4289 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4290 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4293 pa_native_connection_assert_ref(c
);
4296 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4297 !pa_tagstruct_eof(t
)) {
4302 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4304 if (command
== PA_COMMAND_KILL_CLIENT
) {
4307 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4308 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4310 pa_native_connection_ref(c
);
4311 pa_client_kill(client
);
4313 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4316 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4317 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4319 pa_native_connection_ref(c
);
4320 pa_sink_input_kill(s
);
4322 pa_source_output
*s
;
4324 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4326 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4327 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4329 pa_native_connection_ref(c
);
4330 pa_source_output_kill(s
);
4333 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4334 pa_native_connection_unref(c
);
4337 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4338 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4340 const char *name
, *argument
;
4341 pa_tagstruct
*reply
;
4343 pa_native_connection_assert_ref(c
);
4346 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4347 pa_tagstruct_gets(t
, &argument
) < 0 ||
4348 !pa_tagstruct_eof(t
)) {
4353 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4354 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4355 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4357 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4358 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4362 reply
= reply_new(tag
);
4363 pa_tagstruct_putu32(reply
, m
->index
);
4364 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4367 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4368 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4372 pa_native_connection_assert_ref(c
);
4375 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4376 !pa_tagstruct_eof(t
)) {
4381 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4382 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4383 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4385 pa_module_unload_request(m
, FALSE
);
4386 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4389 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4390 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4391 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4392 const char *name_device
= NULL
;
4394 pa_native_connection_assert_ref(c
);
4397 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4398 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4399 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4400 !pa_tagstruct_eof(t
)) {
4405 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4406 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4408 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
);
4409 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4410 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4411 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4413 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4414 pa_sink_input
*si
= NULL
;
4415 pa_sink
*sink
= NULL
;
4417 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4419 if (idx_device
!= PA_INVALID_INDEX
)
4420 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4422 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4424 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4426 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4427 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4431 pa_source_output
*so
= NULL
;
4434 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4436 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4438 if (idx_device
!= PA_INVALID_INDEX
)
4439 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4441 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4443 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4445 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4446 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4451 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4454 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4455 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4456 uint32_t idx
= PA_INVALID_INDEX
;
4457 const char *name
= NULL
;
4460 pa_native_connection_assert_ref(c
);
4463 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4464 pa_tagstruct_gets(t
, &name
) < 0 ||
4465 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4466 !pa_tagstruct_eof(t
)) {
4471 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4472 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
);
4473 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4474 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4475 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4477 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4479 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4481 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4483 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4484 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4488 pa_sink
*sink
= NULL
;
4490 if (idx
!= PA_INVALID_INDEX
)
4491 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4493 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4495 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4497 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4498 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4504 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4506 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4508 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4510 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4511 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4518 if (idx
!= PA_INVALID_INDEX
)
4519 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4521 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4523 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4525 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4526 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4532 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4535 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4536 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4537 uint32_t idx
= PA_INVALID_INDEX
;
4538 const char *name
= NULL
;
4540 pa_native_protocol_ext_cb_t cb
;
4542 pa_native_connection_assert_ref(c
);
4545 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4546 pa_tagstruct_gets(t
, &name
) < 0) {
4551 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4552 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4553 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4554 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4555 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4557 if (idx
!= PA_INVALID_INDEX
)
4558 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4560 for (m
= pa_idxset_first(c
->protocol
->core
->modules
, &idx
); m
; m
= pa_idxset_next(c
->protocol
->core
->modules
, &idx
))
4561 if (strcmp(name
, m
->name
) == 0)
4565 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4566 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4568 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4569 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4571 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4575 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4576 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4577 uint32_t idx
= PA_INVALID_INDEX
;
4578 const char *name
= NULL
, *profile
= NULL
;
4579 pa_card
*card
= NULL
;
4582 pa_native_connection_assert_ref(c
);
4585 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4586 pa_tagstruct_gets(t
, &name
) < 0 ||
4587 pa_tagstruct_gets(t
, &profile
) < 0 ||
4588 !pa_tagstruct_eof(t
)) {
4593 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4594 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4595 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4596 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4597 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4599 if (idx
!= PA_INVALID_INDEX
)
4600 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4602 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4604 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4606 if ((ret
= pa_card_set_profile(card
, profile
, TRUE
)) < 0) {
4607 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4611 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4614 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4615 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4616 uint32_t idx
= PA_INVALID_INDEX
;
4617 const char *name
= NULL
, *port
= NULL
;
4620 pa_native_connection_assert_ref(c
);
4623 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4624 pa_tagstruct_gets(t
, &name
) < 0 ||
4625 pa_tagstruct_gets(t
, &port
) < 0 ||
4626 !pa_tagstruct_eof(t
)) {
4631 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4632 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
);
4633 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4634 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4635 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4637 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4640 if (idx
!= PA_INVALID_INDEX
)
4641 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4643 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4645 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4647 if ((ret
= pa_sink_set_port(sink
, port
, TRUE
)) < 0) {
4648 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4654 pa_assert(command
= PA_COMMAND_SET_SOURCE_PORT
);
4656 if (idx
!= PA_INVALID_INDEX
)
4657 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4659 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4661 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4663 if ((ret
= pa_source_set_port(source
, port
, TRUE
)) < 0) {
4664 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4669 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4672 /*** pstream callbacks ***/
4674 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4675 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4679 pa_native_connection_assert_ref(c
);
4681 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4682 pa_log("invalid packet.");
4683 native_connection_unlink(c
);
4687 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
) {
4688 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4689 output_stream
*stream
;
4693 pa_native_connection_assert_ref(c
);
4695 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4696 pa_log_debug("Client sent block for invalid stream.");
4701 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4703 if (playback_stream_isinstance(stream
)) {
4704 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4706 pa_atomic_inc(&ps
->seek_or_post_in_queue
);
4707 if (chunk
->memblock
) {
4708 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4709 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
);
4711 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4713 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
);
4716 upload_stream
*u
= UPLOAD_STREAM(stream
);
4719 if (!u
->memchunk
.memblock
) {
4720 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4721 u
->memchunk
= *chunk
;
4722 pa_memblock_ref(u
->memchunk
.memblock
);
4725 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4726 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4730 pa_assert(u
->memchunk
.memblock
);
4733 if (l
> chunk
->length
)
4738 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4740 if (chunk
->memblock
) {
4742 src
= pa_memblock_acquire(chunk
->memblock
);
4744 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4745 (uint8_t*) src
+ chunk
->index
, l
);
4747 pa_memblock_release(chunk
->memblock
);
4749 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4751 pa_memblock_release(u
->memchunk
.memblock
);
4753 u
->memchunk
.length
+= l
;
4759 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4760 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4763 pa_native_connection_assert_ref(c
);
4765 native_connection_unlink(c
);
4766 pa_log_info("Connection died.");
4769 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4770 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4773 pa_native_connection_assert_ref(c
);
4775 native_connection_send_memblock(c
);
4778 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4781 if (!(q
= pa_thread_mq_get()))
4782 pa_pstream_send_revoke(p
, block_id
);
4784 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4787 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4790 if (!(q
= pa_thread_mq_get()))
4791 pa_pstream_send_release(p
, block_id
);
4793 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4796 /*** client callbacks ***/
4798 static void client_kill_cb(pa_client
*c
) {
4801 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4802 pa_log_info("Connection killed.");
4805 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4807 pa_native_connection
*c
;
4810 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4811 pa_native_connection_assert_ref(c
);
4813 if (c
->version
< 15)
4816 t
= pa_tagstruct_new(NULL
, 0);
4817 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4818 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4819 pa_tagstruct_puts(t
, event
);
4820 pa_tagstruct_put_proplist(t
, pl
);
4821 pa_pstream_send_tagstruct(c
->pstream
, t
);
4824 /*** module entry points ***/
4826 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4827 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4830 pa_native_connection_assert_ref(c
);
4831 pa_assert(c
->auth_timeout_event
== e
);
4833 if (!c
->authorized
) {
4834 native_connection_unlink(c
);
4835 pa_log_info("Connection terminated due to authentication timeout.");
4839 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4840 pa_native_connection
*c
;
4843 pa_client_new_data data
;
4849 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4850 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4851 pa_iochannel_free(io
);
4855 pa_client_new_data_init(&data
);
4856 data
.module
= o
->module
;
4857 data
.driver
= __FILE__
;
4858 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4859 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4860 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4861 client
= pa_client_new(p
->core
, &data
);
4862 pa_client_new_data_done(&data
);
4867 c
= pa_msgobject_new(pa_native_connection
);
4868 c
->parent
.parent
.free
= native_connection_free
;
4869 c
->parent
.process_msg
= native_connection_process_msg
;
4871 c
->options
= pa_native_options_ref(o
);
4872 c
->authorized
= FALSE
;
4874 if (o
->auth_anonymous
) {
4875 pa_log_info("Client authenticated anonymously.");
4876 c
->authorized
= TRUE
;
4879 if (!c
->authorized
&&
4881 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
4883 pa_log_info("Client authenticated by IP ACL.");
4884 c
->authorized
= TRUE
;
4888 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
4890 c
->auth_timeout_event
= NULL
;
4892 c
->is_local
= pa_iochannel_socket_is_local(io
);
4896 c
->client
->kill
= client_kill_cb
;
4897 c
->client
->send_event
= client_send_event_cb
;
4898 c
->client
->userdata
= c
;
4900 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
4901 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
4902 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
4903 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
4904 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
4905 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
4906 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
4908 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, TRUE
, command_table
, PA_COMMAND_MAX
);
4910 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
4911 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
4913 c
->rrobin_index
= PA_IDXSET_INVALID
;
4914 c
->subscription
= NULL
;
4916 pa_idxset_put(p
->connections
, c
, NULL
);
4919 if (pa_iochannel_creds_supported(io
))
4920 pa_iochannel_creds_enable(io
);
4923 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
4926 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
4927 pa_native_connection
*c
;
4933 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
4934 if (c
->options
->module
== m
)
4935 native_connection_unlink(c
);
4938 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
4939 pa_native_protocol
*p
;
4944 p
= pa_xnew(pa_native_protocol
, 1);
4947 p
->connections
= pa_idxset_new(NULL
, NULL
);
4951 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
4953 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4954 pa_hook_init(&p
->hooks
[h
], p
);
4956 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
4961 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
4962 pa_native_protocol
*p
;
4964 if ((p
= pa_shared_get(c
, "native-protocol")))
4965 return pa_native_protocol_ref(p
);
4967 return native_protocol_new(c
);
4970 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
4972 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4979 void pa_native_protocol_unref(pa_native_protocol
*p
) {
4980 pa_native_connection
*c
;
4984 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4986 if (PA_REFCNT_DEC(p
) > 0)
4989 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
4990 native_connection_unlink(c
);
4992 pa_idxset_free(p
->connections
, NULL
, NULL
);
4994 pa_strlist_free(p
->servers
);
4996 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4997 pa_hook_done(&p
->hooks
[h
]);
4999 pa_hashmap_free(p
->extensions
, NULL
, NULL
);
5001 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
5006 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
5008 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5011 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
5013 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5016 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
5018 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5021 p
->servers
= pa_strlist_remove(p
->servers
, name
);
5023 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5026 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
5028 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5033 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
5035 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5040 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
5042 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5045 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
5047 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
5051 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
5053 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5056 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
5059 pa_native_options
* pa_native_options_new(void) {
5060 pa_native_options
*o
;
5062 o
= pa_xnew0(pa_native_options
, 1);
5068 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
5070 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5077 void pa_native_options_unref(pa_native_options
*o
) {
5079 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5081 if (PA_REFCNT_DEC(o
) > 0)
5084 pa_xfree(o
->auth_group
);
5087 pa_ip_acl_free(o
->auth_ip_acl
);
5090 pa_auth_cookie_unref(o
->auth_cookie
);
5095 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
5100 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5103 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
5104 pa_log("auth-anonymous= expects a boolean argument.");
5109 if (pa_modargs_get_value_boolean(ma
, "auth-group-enabled", &enabled
) < 0) {
5110 pa_log("auth-group-enabled= expects a boolean argument.");
5114 pa_xfree(o
->auth_group
);
5115 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
5119 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5122 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
5125 if (!(ipa
= pa_ip_acl_new(acl
))) {
5126 pa_log("Failed to parse IP ACL '%s'", acl
);
5131 pa_ip_acl_free(o
->auth_ip_acl
);
5133 o
->auth_ip_acl
= ipa
;
5137 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
5138 pa_log("auth-cookie-enabled= expects a boolean argument.");
5143 pa_auth_cookie_unref(o
->auth_cookie
);
5148 /* The new name for this is 'auth-cookie', for compat reasons
5149 * we check the old name too */
5150 if (!(cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
)))
5151 if (!(cn
= pa_modargs_get_value(ma
, "cookie", NULL
)))
5152 cn
= PA_NATIVE_COOKIE_FILE
;
5154 if (!(o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, PA_NATIVE_COOKIE_LENGTH
)))
5158 o
->auth_cookie
= NULL
;
5163 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
5164 pa_native_connection_assert_ref(c
);
5169 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
5170 pa_native_connection_assert_ref(c
);