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
;
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) {
2338 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2344 formats
= pa_idxset_new(NULL
, NULL
);
2346 for (i
= 0; i
< n_formats
; i
++) {
2347 format
= pa_format_info_new();
2348 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2352 pa_idxset_put(formats
, format
, NULL
);
2355 if (pa_tagstruct_get_cvolume(t
, &volume
) < 0 ||
2356 pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2357 pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2358 pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2359 pa_tagstruct_get_boolean(t
, &relative_volume
) < 0 ||
2360 pa_tagstruct_get_boolean(t
, &passthrough
) < 0) {
2366 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
2369 if (n_formats
== 0) {
2370 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2371 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2372 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2374 PA_IDXSET_FOREACH(format
, formats
, i
) {
2375 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2380 if (!pa_tagstruct_eof(t
)) {
2385 if (source_index
!= PA_INVALID_INDEX
) {
2387 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2388 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2392 } else if (source_name
) {
2394 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2395 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2400 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2402 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2403 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2409 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2410 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2411 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2412 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2413 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2414 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2415 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2416 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2417 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2418 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0) |
2419 (passthrough
? PA_SOURCE_OUTPUT_PASSTHROUGH
: 0);
2421 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
);
2423 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2425 reply
= reply_new(tag
);
2426 pa_tagstruct_putu32(reply
, s
->index
);
2427 pa_assert(s
->source_output
);
2428 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2430 if (c
->version
>= 9) {
2431 /* Since 0.9 we support sending the buffer metrics back to the client */
2433 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2434 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2437 if (c
->version
>= 12) {
2438 /* Since 0.9.8 we support sending the chosen sample
2439 * spec/channel map/device/suspend status back to the
2442 pa_tagstruct_put_sample_spec(reply
, &ss
);
2443 pa_tagstruct_put_channel_map(reply
, &map
);
2445 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2446 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2448 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2451 if (c
->version
>= 13)
2452 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2454 if (c
->version
>= 22) {
2455 /* Send back the format we negotiated */
2456 if (s
->source_output
->format
)
2457 pa_tagstruct_put_format_info(reply
, s
->source_output
->format
);
2459 pa_format_info
*f
= pa_format_info_new();
2460 pa_tagstruct_put_format_info(reply
, f
);
2461 pa_format_info_free(f
);
2465 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2469 pa_proplist_free(p
);
2471 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
2474 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2475 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2478 pa_native_connection_assert_ref(c
);
2481 if (!pa_tagstruct_eof(t
)) {
2486 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2487 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2488 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2490 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2492 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2495 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2496 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2498 pa_tagstruct
*reply
;
2499 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2501 pa_native_connection_assert_ref(c
);
2504 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2505 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2506 !pa_tagstruct_eof(t
)) {
2511 /* Minimum supported version */
2512 if (c
->version
< 8) {
2513 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2517 /* Starting with protocol version 13 the MSB of the version tag
2518 reflects if shm is available for this pa_native_connection or
2520 if (c
->version
>= 13) {
2521 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2522 c
->version
&= 0x7FFFFFFFU
;
2525 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2527 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2529 if (!c
->authorized
) {
2530 pa_bool_t success
= FALSE
;
2533 const pa_creds
*creds
;
2535 if ((creds
= pa_pdispatch_creds(pd
))) {
2536 if (creds
->uid
== getuid())
2538 else if (c
->options
->auth_group
) {
2542 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2543 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2544 else if (gid
== creds
->gid
)
2548 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2549 pa_log_warn("Failed to check group membership.");
2555 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2556 (unsigned long) creds
->uid
,
2557 (unsigned long) creds
->gid
,
2562 if (!success
&& c
->options
->auth_cookie
) {
2565 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2566 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2571 pa_log_warn("Denied access to client with invalid authorization data.");
2572 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2576 c
->authorized
= TRUE
;
2577 if (c
->auth_timeout_event
) {
2578 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2579 c
->auth_timeout_event
= NULL
;
2583 /* Enable shared memory support if possible */
2585 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2588 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2591 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2596 /* Only enable SHM if both sides are owned by the same
2597 * user. This is a security measure because otherwise data
2598 * private to the user might leak. */
2600 const pa_creds
*creds
;
2601 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2606 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2607 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2609 reply
= reply_new(tag
);
2610 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2614 /* SHM support is only enabled after both sides made sure they are the same user. */
2618 ucred
.uid
= getuid();
2619 ucred
.gid
= getgid();
2621 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2624 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2628 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2629 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2630 const char *name
= NULL
;
2632 pa_tagstruct
*reply
;
2634 pa_native_connection_assert_ref(c
);
2637 p
= pa_proplist_new();
2639 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2640 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2641 !pa_tagstruct_eof(t
)) {
2644 pa_proplist_free(p
);
2649 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2650 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2651 pa_proplist_free(p
);
2655 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2656 pa_proplist_free(p
);
2658 reply
= reply_new(tag
);
2660 if (c
->version
>= 13)
2661 pa_tagstruct_putu32(reply
, c
->client
->index
);
2663 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2666 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2667 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2669 uint32_t idx
= PA_IDXSET_INVALID
;
2671 pa_native_connection_assert_ref(c
);
2674 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2675 !pa_tagstruct_eof(t
)) {
2680 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2681 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
);
2683 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2685 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2689 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2690 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2691 idx
= source
->index
;
2694 if (idx
== PA_IDXSET_INVALID
)
2695 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2697 pa_tagstruct
*reply
;
2698 reply
= reply_new(tag
);
2699 pa_tagstruct_putu32(reply
, idx
);
2700 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2704 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2705 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2709 pa_native_connection_assert_ref(c
);
2712 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2713 !pa_tagstruct_eof(t
)) {
2718 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2719 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2720 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2721 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2723 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
);
2726 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2727 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2728 pa_tagstruct
*reply
;
2729 const pa_mempool_stat
*stat
;
2731 pa_native_connection_assert_ref(c
);
2734 if (!pa_tagstruct_eof(t
)) {
2739 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2741 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2743 reply
= reply_new(tag
);
2744 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2745 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2746 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2747 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2748 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2749 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2752 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2753 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2754 pa_tagstruct
*reply
;
2756 struct timeval tv
, now
;
2759 pa_native_connection_assert_ref(c
);
2762 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2763 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2764 !pa_tagstruct_eof(t
)) {
2769 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2770 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2771 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2772 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2774 /* Get an atomic snapshot of all timing parameters */
2775 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);
2777 reply
= reply_new(tag
);
2778 pa_tagstruct_put_usec(reply
,
2779 s
->current_sink_latency
+
2780 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2781 pa_tagstruct_put_usec(reply
, 0);
2782 pa_tagstruct_put_boolean(reply
,
2783 s
->playing_for
> 0 &&
2784 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2785 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2786 pa_tagstruct_put_timeval(reply
, &tv
);
2787 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2788 pa_tagstruct_puts64(reply
, s
->write_index
);
2789 pa_tagstruct_puts64(reply
, s
->read_index
);
2791 if (c
->version
>= 13) {
2792 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2793 pa_tagstruct_putu64(reply
, s
->playing_for
);
2796 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2799 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2800 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2801 pa_tagstruct
*reply
;
2803 struct timeval tv
, now
;
2806 pa_native_connection_assert_ref(c
);
2809 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2810 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2811 !pa_tagstruct_eof(t
)) {
2816 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2817 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2818 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2820 /* Get an atomic snapshot of all timing parameters */
2821 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);
2823 reply
= reply_new(tag
);
2824 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2825 pa_tagstruct_put_usec(reply
,
2826 s
->current_source_latency
+
2827 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2828 pa_tagstruct_put_boolean(reply
,
2829 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2830 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2831 pa_tagstruct_put_timeval(reply
, &tv
);
2832 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2833 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2834 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2835 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2838 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2839 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2842 const char *name
= NULL
;
2845 pa_tagstruct
*reply
;
2848 pa_native_connection_assert_ref(c
);
2851 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2852 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2853 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2854 pa_tagstruct_getu32(t
, &length
) < 0) {
2859 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2860 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2861 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2862 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2863 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2864 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2866 p
= pa_proplist_new();
2868 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2869 !pa_tagstruct_eof(t
)) {
2872 pa_proplist_free(p
);
2876 if (c
->version
< 13)
2877 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2879 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2880 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2882 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2883 pa_proplist_free(p
);
2884 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2887 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2888 pa_proplist_free(p
);
2890 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2892 reply
= reply_new(tag
);
2893 pa_tagstruct_putu32(reply
, s
->index
);
2894 pa_tagstruct_putu32(reply
, length
);
2895 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2898 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2899 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2904 pa_native_connection_assert_ref(c
);
2907 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2908 !pa_tagstruct_eof(t
)) {
2913 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2915 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2916 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2917 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2919 if (!s
->memchunk
.memblock
)
2920 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
2921 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2922 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2924 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2926 upload_stream_unlink(s
);
2929 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2930 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2931 uint32_t sink_index
;
2934 const char *name
, *sink_name
;
2937 pa_tagstruct
*reply
;
2939 pa_native_connection_assert_ref(c
);
2942 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2944 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
2945 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
2946 pa_tagstruct_getu32(t
, &volume
) < 0 ||
2947 pa_tagstruct_gets(t
, &name
) < 0) {
2952 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
2953 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
2954 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2955 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2957 if (sink_index
!= PA_INVALID_INDEX
)
2958 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
2960 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
2962 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
2964 p
= pa_proplist_new();
2966 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2967 !pa_tagstruct_eof(t
)) {
2969 pa_proplist_free(p
);
2973 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
2975 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
2976 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2977 pa_proplist_free(p
);
2981 pa_proplist_free(p
);
2983 reply
= reply_new(tag
);
2985 if (c
->version
>= 13)
2986 pa_tagstruct_putu32(reply
, idx
);
2988 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2991 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2992 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2995 pa_native_connection_assert_ref(c
);
2998 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2999 !pa_tagstruct_eof(t
)) {
3004 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3005 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3007 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
3008 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3012 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3015 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
3018 pa_assert(original
);
3022 if (c
->version
< 12) {
3023 /* Before protocol version 12 we didn't support S32 samples,
3024 * so we need to lie about this to the client */
3026 if (fixed
->format
== PA_SAMPLE_S32LE
)
3027 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3028 if (fixed
->format
== PA_SAMPLE_S32BE
)
3029 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3032 if (c
->version
< 15) {
3033 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
3034 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3035 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
3036 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3040 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
3041 pa_sample_spec fixed_ss
;
3044 pa_sink_assert_ref(sink
);
3046 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
3050 PA_TAG_U32
, sink
->index
,
3051 PA_TAG_STRING
, sink
->name
,
3052 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3053 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3054 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
3055 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
3056 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
3057 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
3058 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
3059 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
3060 PA_TAG_USEC
, pa_sink_get_latency(sink
),
3061 PA_TAG_STRING
, sink
->driver
,
3062 PA_TAG_U32
, sink
->flags
& ~PA_SINK_SHARE_VOLUME_WITH_MASTER
,
3065 if (c
->version
>= 13) {
3066 pa_tagstruct_put_proplist(t
, sink
->proplist
);
3067 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
3070 if (c
->version
>= 15) {
3071 pa_tagstruct_put_volume(t
, sink
->base_volume
);
3072 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
3073 pa_log_error("Internal sink state is invalid.");
3074 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
3075 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
3076 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
3079 if (c
->version
>= 16) {
3080 pa_tagstruct_putu32(t
, sink
->ports
? pa_hashmap_size(sink
->ports
) : 0);
3086 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
3087 pa_tagstruct_puts(t
, p
->name
);
3088 pa_tagstruct_puts(t
, p
->description
);
3089 pa_tagstruct_putu32(t
, p
->priority
);
3093 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
3096 if (c
->version
>= 21) {
3099 pa_idxset
*formats
= pa_sink_get_formats(sink
);
3101 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3102 PA_IDXSET_FOREACH(f
, formats
, i
) {
3103 pa_tagstruct_put_format_info(t
, f
);
3106 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3110 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
3111 pa_sample_spec fixed_ss
;
3114 pa_source_assert_ref(source
);
3116 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
3120 PA_TAG_U32
, source
->index
,
3121 PA_TAG_STRING
, source
->name
,
3122 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3123 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3124 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
3125 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
3126 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
3127 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
3128 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
3129 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
3130 PA_TAG_USEC
, pa_source_get_latency(source
),
3131 PA_TAG_STRING
, source
->driver
,
3132 PA_TAG_U32
, source
->flags
,
3135 if (c
->version
>= 13) {
3136 pa_tagstruct_put_proplist(t
, source
->proplist
);
3137 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
3140 if (c
->version
>= 15) {
3141 pa_tagstruct_put_volume(t
, source
->base_volume
);
3142 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
3143 pa_log_error("Internal source state is invalid.");
3144 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
3145 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
3146 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
3149 if (c
->version
>= 16) {
3151 pa_tagstruct_putu32(t
, source
->ports
? pa_hashmap_size(source
->ports
) : 0);
3153 if (source
->ports
) {
3157 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
3158 pa_tagstruct_puts(t
, p
->name
);
3159 pa_tagstruct_puts(t
, p
->description
);
3160 pa_tagstruct_putu32(t
, p
->priority
);
3164 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
3167 if (c
->version
>= 22) {
3170 pa_idxset
*formats
= pa_source_get_formats(source
);
3172 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3173 PA_IDXSET_FOREACH(f
, formats
, i
) {
3174 pa_tagstruct_put_format_info(t
, f
);
3177 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3181 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
3185 pa_tagstruct_putu32(t
, client
->index
);
3186 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
3187 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
3188 pa_tagstruct_puts(t
, client
->driver
);
3190 if (c
->version
>= 13)
3191 pa_tagstruct_put_proplist(t
, client
->proplist
);
3194 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
3201 pa_tagstruct_putu32(t
, card
->index
);
3202 pa_tagstruct_puts(t
, card
->name
);
3203 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
3204 pa_tagstruct_puts(t
, card
->driver
);
3206 pa_tagstruct_putu32(t
, card
->profiles
? pa_hashmap_size(card
->profiles
) : 0);
3208 if (card
->profiles
) {
3209 while ((p
= pa_hashmap_iterate(card
->profiles
, &state
, NULL
))) {
3210 pa_tagstruct_puts(t
, p
->name
);
3211 pa_tagstruct_puts(t
, p
->description
);
3212 pa_tagstruct_putu32(t
, p
->n_sinks
);
3213 pa_tagstruct_putu32(t
, p
->n_sources
);
3214 pa_tagstruct_putu32(t
, p
->priority
);
3218 pa_tagstruct_puts(t
, card
->active_profile
? card
->active_profile
->name
: NULL
);
3219 pa_tagstruct_put_proplist(t
, card
->proplist
);
3222 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3226 pa_tagstruct_putu32(t
, module
->index
);
3227 pa_tagstruct_puts(t
, module
->name
);
3228 pa_tagstruct_puts(t
, module
->argument
);
3229 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3231 if (c
->version
< 15)
3232 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
3234 if (c
->version
>= 15)
3235 pa_tagstruct_put_proplist(t
, module
->proplist
);
3238 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3239 pa_sample_spec fixed_ss
;
3240 pa_usec_t sink_latency
;
3242 pa_bool_t has_volume
= FALSE
;
3245 pa_sink_input_assert_ref(s
);
3247 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3249 has_volume
= pa_sink_input_is_volume_readable(s
);
3251 pa_sink_input_get_volume(s
, &v
, TRUE
);
3253 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3255 pa_tagstruct_putu32(t
, s
->index
);
3256 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3257 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3258 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3259 pa_tagstruct_putu32(t
, s
->sink
->index
);
3260 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3261 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3262 pa_tagstruct_put_cvolume(t
, &v
);
3263 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3264 pa_tagstruct_put_usec(t
, sink_latency
);
3265 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3266 pa_tagstruct_puts(t
, s
->driver
);
3267 if (c
->version
>= 11)
3268 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
3269 if (c
->version
>= 13)
3270 pa_tagstruct_put_proplist(t
, s
->proplist
);
3271 if (c
->version
>= 19)
3272 pa_tagstruct_put_boolean(t
, (pa_sink_input_get_state(s
) == PA_SINK_INPUT_CORKED
));
3273 if (c
->version
>= 20) {
3274 pa_tagstruct_put_boolean(t
, has_volume
);
3275 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3277 if (c
->version
>= 21)
3278 pa_tagstruct_put_format_info(t
, s
->format
);
3281 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3282 pa_sample_spec fixed_ss
;
3283 pa_usec_t source_latency
;
3285 pa_bool_t has_volume
= FALSE
;
3288 pa_source_output_assert_ref(s
);
3290 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3292 has_volume
= pa_source_output_is_volume_readable(s
);
3294 pa_source_output_get_volume(s
, &v
, TRUE
);
3296 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3298 pa_tagstruct_putu32(t
, s
->index
);
3299 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3300 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3301 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3302 pa_tagstruct_putu32(t
, s
->source
->index
);
3303 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3304 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3305 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3306 pa_tagstruct_put_usec(t
, source_latency
);
3307 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3308 pa_tagstruct_puts(t
, s
->driver
);
3309 if (c
->version
>= 13)
3310 pa_tagstruct_put_proplist(t
, s
->proplist
);
3311 if (c
->version
>= 19)
3312 pa_tagstruct_put_boolean(t
, (pa_source_output_get_state(s
) == PA_SOURCE_OUTPUT_CORKED
));
3313 if (c
->version
>= 22) {
3314 pa_tagstruct_put_cvolume(t
, &v
);
3315 pa_tagstruct_put_boolean(t
, pa_source_output_get_mute(s
));
3316 pa_tagstruct_put_boolean(t
, has_volume
);
3317 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3318 pa_tagstruct_put_format_info(t
, s
->format
);
3322 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3323 pa_sample_spec fixed_ss
;
3329 if (e
->memchunk
.memblock
)
3330 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3332 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3334 pa_tagstruct_putu32(t
, e
->index
);
3335 pa_tagstruct_puts(t
, e
->name
);
3337 if (e
->volume_is_set
)
3340 pa_cvolume_init(&v
);
3342 pa_tagstruct_put_cvolume(t
, &v
);
3343 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3344 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3345 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3346 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3347 pa_tagstruct_put_boolean(t
, e
->lazy
);
3348 pa_tagstruct_puts(t
, e
->filename
);
3350 if (c
->version
>= 13)
3351 pa_tagstruct_put_proplist(t
, e
->proplist
);
3354 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3355 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3357 pa_sink
*sink
= NULL
;
3358 pa_source
*source
= NULL
;
3359 pa_client
*client
= NULL
;
3360 pa_card
*card
= NULL
;
3361 pa_module
*module
= NULL
;
3362 pa_sink_input
*si
= NULL
;
3363 pa_source_output
*so
= NULL
;
3364 pa_scache_entry
*sce
= NULL
;
3365 const char *name
= NULL
;
3366 pa_tagstruct
*reply
;
3368 pa_native_connection_assert_ref(c
);
3371 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3372 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3373 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3374 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3375 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3376 pa_tagstruct_gets(t
, &name
) < 0) ||
3377 !pa_tagstruct_eof(t
)) {
3382 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3383 CHECK_VALIDITY(c
->pstream
, !name
||
3384 (command
== PA_COMMAND_GET_SINK_INFO
&&
3385 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3386 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3387 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3388 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3389 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3390 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3391 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3393 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3394 if (idx
!= PA_INVALID_INDEX
)
3395 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3397 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3398 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3399 if (idx
!= PA_INVALID_INDEX
)
3400 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3402 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3403 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3404 if (idx
!= PA_INVALID_INDEX
)
3405 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3407 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3408 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3409 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3410 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3411 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3412 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3413 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3414 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3415 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3417 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3418 if (idx
!= PA_INVALID_INDEX
)
3419 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3421 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3424 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3425 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3429 reply
= reply_new(tag
);
3431 sink_fill_tagstruct(c
, reply
, sink
);
3433 source_fill_tagstruct(c
, reply
, source
);
3435 client_fill_tagstruct(c
, reply
, client
);
3437 card_fill_tagstruct(c
, reply
, card
);
3439 module_fill_tagstruct(c
, reply
, module
);
3441 sink_input_fill_tagstruct(c
, reply
, si
);
3443 source_output_fill_tagstruct(c
, reply
, so
);
3445 scache_fill_tagstruct(c
, reply
, sce
);
3446 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3449 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3450 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3454 pa_tagstruct
*reply
;
3456 pa_native_connection_assert_ref(c
);
3459 if (!pa_tagstruct_eof(t
)) {
3464 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3466 reply
= reply_new(tag
);
3468 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3469 i
= c
->protocol
->core
->sinks
;
3470 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3471 i
= c
->protocol
->core
->sources
;
3472 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3473 i
= c
->protocol
->core
->clients
;
3474 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3475 i
= c
->protocol
->core
->cards
;
3476 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3477 i
= c
->protocol
->core
->modules
;
3478 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3479 i
= c
->protocol
->core
->sink_inputs
;
3480 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3481 i
= c
->protocol
->core
->source_outputs
;
3483 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3484 i
= c
->protocol
->core
->scache
;
3488 for (p
= pa_idxset_first(i
, &idx
); p
; p
= pa_idxset_next(i
, &idx
)) {
3489 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3490 sink_fill_tagstruct(c
, reply
, p
);
3491 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3492 source_fill_tagstruct(c
, reply
, p
);
3493 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3494 client_fill_tagstruct(c
, reply
, p
);
3495 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3496 card_fill_tagstruct(c
, reply
, p
);
3497 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3498 module_fill_tagstruct(c
, reply
, p
);
3499 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3500 sink_input_fill_tagstruct(c
, reply
, p
);
3501 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3502 source_output_fill_tagstruct(c
, reply
, p
);
3504 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3505 scache_fill_tagstruct(c
, reply
, p
);
3510 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3513 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3514 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3515 pa_tagstruct
*reply
;
3517 pa_source
*def_source
;
3518 pa_sample_spec fixed_ss
;
3521 pa_native_connection_assert_ref(c
);
3524 if (!pa_tagstruct_eof(t
)) {
3529 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3531 reply
= reply_new(tag
);
3532 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3533 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3535 u
= pa_get_user_name_malloc();
3536 pa_tagstruct_puts(reply
, u
);
3539 h
= pa_get_host_name_malloc();
3540 pa_tagstruct_puts(reply
, h
);
3543 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3544 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3546 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3547 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3548 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3549 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3551 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3553 if (c
->version
>= 15)
3554 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3556 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3559 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3561 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3563 pa_native_connection_assert_ref(c
);
3565 t
= pa_tagstruct_new(NULL
, 0);
3566 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3567 pa_tagstruct_putu32(t
, (uint32_t) -1);
3568 pa_tagstruct_putu32(t
, e
);
3569 pa_tagstruct_putu32(t
, idx
);
3570 pa_pstream_send_tagstruct(c
->pstream
, t
);
3573 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3574 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3575 pa_subscription_mask_t m
;
3577 pa_native_connection_assert_ref(c
);
3580 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3581 !pa_tagstruct_eof(t
)) {
3586 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3587 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3589 if (c
->subscription
)
3590 pa_subscription_free(c
->subscription
);
3593 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3594 pa_assert(c
->subscription
);
3596 c
->subscription
= NULL
;
3598 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3601 static void command_set_volume(
3608 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3611 pa_sink
*sink
= NULL
;
3612 pa_source
*source
= NULL
;
3613 pa_sink_input
*si
= NULL
;
3614 pa_source_output
*so
= NULL
;
3615 const char *name
= NULL
;
3616 const char *client_name
;
3618 pa_native_connection_assert_ref(c
);
3621 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3622 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3623 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3624 pa_tagstruct_get_cvolume(t
, &volume
) ||
3625 !pa_tagstruct_eof(t
)) {
3630 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3631 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
);
3632 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3633 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3634 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3635 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3639 case PA_COMMAND_SET_SINK_VOLUME
:
3640 if (idx
!= PA_INVALID_INDEX
)
3641 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3643 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3646 case PA_COMMAND_SET_SOURCE_VOLUME
:
3647 if (idx
!= PA_INVALID_INDEX
)
3648 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3650 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3653 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3654 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3657 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
:
3658 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3662 pa_assert_not_reached();
3665 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3667 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3670 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3672 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3673 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3674 } else if (source
) {
3675 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3677 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3678 pa_source_set_volume(source
, &volume
, TRUE
, TRUE
);
3680 CHECK_VALIDITY(c
->pstream
, si
->volume_writable
, tag
, PA_ERR_BADSTATE
);
3681 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3683 pa_log_debug("Client %s changes volume of sink input %s.",
3685 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3686 pa_sink_input_set_volume(si
, &volume
, TRUE
, TRUE
);
3688 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &so
->sample_spec
), tag
, PA_ERR_INVALID
);
3690 pa_log_debug("Client %s changes volume of source output %s.",
3692 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3693 pa_source_output_set_volume(so
, &volume
, TRUE
, TRUE
);
3696 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3699 static void command_set_mute(
3706 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3709 pa_sink
*sink
= NULL
;
3710 pa_source
*source
= NULL
;
3711 pa_sink_input
*si
= NULL
;
3712 pa_source_output
*so
= NULL
;
3713 const char *name
= NULL
, *client_name
;
3715 pa_native_connection_assert_ref(c
);
3718 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3719 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3720 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3721 pa_tagstruct_get_boolean(t
, &mute
) ||
3722 !pa_tagstruct_eof(t
)) {
3727 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3728 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
);
3729 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3730 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3731 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3735 case PA_COMMAND_SET_SINK_MUTE
:
3736 if (idx
!= PA_INVALID_INDEX
)
3737 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3739 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3743 case PA_COMMAND_SET_SOURCE_MUTE
:
3744 if (idx
!= PA_INVALID_INDEX
)
3745 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3747 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3751 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3752 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3755 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
:
3756 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3760 pa_assert_not_reached();
3763 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3765 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3768 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3769 pa_sink_set_mute(sink
, mute
, TRUE
);
3770 } else if (source
) {
3771 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3772 pa_source_set_mute(source
, mute
, TRUE
);
3774 pa_log_debug("Client %s changes mute of sink input %s.",
3776 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3777 pa_sink_input_set_mute(si
, mute
, TRUE
);
3779 pa_log_debug("Client %s changes mute of source output %s.",
3781 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3782 pa_source_output_set_mute(so
, mute
, TRUE
);
3785 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3788 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3789 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3794 pa_native_connection_assert_ref(c
);
3797 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3798 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3799 !pa_tagstruct_eof(t
)) {
3804 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3805 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3806 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3807 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3808 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3810 pa_sink_input_cork(s
->sink_input
, b
);
3813 s
->is_underrun
= TRUE
;
3815 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3818 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3819 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3823 pa_native_connection_assert_ref(c
);
3826 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3827 !pa_tagstruct_eof(t
)) {
3832 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3833 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3834 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3835 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3836 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3839 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3840 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3843 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3844 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3847 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3848 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3852 pa_assert_not_reached();
3855 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3858 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3859 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3864 pa_native_connection_assert_ref(c
);
3867 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3868 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3869 !pa_tagstruct_eof(t
)) {
3874 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3875 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3876 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3878 pa_source_output_cork(s
->source_output
, b
);
3879 pa_memblockq_prebuf_force(s
->memblockq
);
3880 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3883 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3884 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3888 pa_native_connection_assert_ref(c
);
3891 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3892 !pa_tagstruct_eof(t
)) {
3897 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3898 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3899 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3901 pa_memblockq_flush_read(s
->memblockq
);
3902 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3905 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3906 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3909 pa_tagstruct
*reply
;
3911 pa_native_connection_assert_ref(c
);
3914 memset(&a
, 0, sizeof(a
));
3916 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3921 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3923 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
3925 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3927 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3928 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3929 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3931 if (pa_tagstruct_get(
3933 PA_TAG_U32
, &a
.maxlength
,
3934 PA_TAG_U32
, &a
.tlength
,
3935 PA_TAG_U32
, &a
.prebuf
,
3936 PA_TAG_U32
, &a
.minreq
,
3937 PA_TAG_INVALID
) < 0 ||
3938 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3939 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3940 !pa_tagstruct_eof(t
)) {
3945 s
->adjust_latency
= adjust_latency
;
3946 s
->early_requests
= early_requests
;
3947 s
->buffer_attr_req
= a
;
3949 fix_playback_buffer_attr(s
);
3950 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);
3952 reply
= reply_new(tag
);
3953 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3954 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
3955 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
3956 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
3958 if (c
->version
>= 13)
3959 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
3963 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3964 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
3966 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3967 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3969 if (pa_tagstruct_get(
3971 PA_TAG_U32
, &a
.maxlength
,
3972 PA_TAG_U32
, &a
.fragsize
,
3973 PA_TAG_INVALID
) < 0 ||
3974 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3975 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3976 !pa_tagstruct_eof(t
)) {
3981 s
->adjust_latency
= adjust_latency
;
3982 s
->early_requests
= early_requests
;
3983 s
->buffer_attr_req
= a
;
3985 fix_record_buffer_attr_pre(s
);
3986 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
3987 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
3988 fix_record_buffer_attr_post(s
);
3990 reply
= reply_new(tag
);
3991 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3992 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
3994 if (c
->version
>= 13)
3995 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
3998 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4001 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4002 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4006 pa_native_connection_assert_ref(c
);
4009 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4010 pa_tagstruct_getu32(t
, &rate
) < 0 ||
4011 !pa_tagstruct_eof(t
)) {
4016 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4017 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
4019 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
4022 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4023 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4024 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4026 pa_sink_input_set_rate(s
->sink_input
, rate
);
4030 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
4032 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4033 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4035 pa_source_output_set_rate(s
->source_output
, rate
);
4038 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4041 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4042 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4047 pa_native_connection_assert_ref(c
);
4050 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4052 p
= pa_proplist_new();
4054 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
4056 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
4057 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4058 !pa_tagstruct_eof(t
)) {
4060 pa_proplist_free(p
);
4066 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4067 pa_tagstruct_getu32(t
, &mode
) < 0 ||
4068 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4069 !pa_tagstruct_eof(t
)) {
4071 pa_proplist_free(p
);
4076 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
4077 pa_proplist_free(p
);
4078 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
4081 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
4084 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4085 if (!s
|| !playback_stream_isinstance(s
)) {
4086 pa_proplist_free(p
);
4087 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4089 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
4091 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
4094 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
4095 pa_proplist_free(p
);
4096 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4098 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
4101 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
4103 pa_client_update_proplist(c
->client
, mode
, p
);
4106 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4107 pa_proplist_free(p
);
4110 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4111 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4113 unsigned changed
= 0;
4115 pa_strlist
*l
= NULL
;
4117 pa_native_connection_assert_ref(c
);
4120 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4122 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
4124 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
4130 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4133 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4134 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4135 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4137 p
= s
->sink_input
->proplist
;
4139 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4142 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4143 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4145 p
= s
->source_output
->proplist
;
4147 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4149 p
= c
->client
->proplist
;
4155 if (pa_tagstruct_gets(t
, &k
) < 0) {
4164 l
= pa_strlist_prepend(l
, k
);
4167 if (!pa_tagstruct_eof(t
)) {
4176 l
= pa_strlist_pop(l
, &z
);
4181 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
4185 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4188 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4191 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4192 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
4194 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4197 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4198 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
4201 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4202 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
4207 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4208 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4211 pa_native_connection_assert_ref(c
);
4214 if (pa_tagstruct_gets(t
, &s
) < 0 ||
4215 !pa_tagstruct_eof(t
)) {
4220 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4221 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
4223 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
4226 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
4227 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4229 pa_namereg_set_default_source(c
->protocol
->core
, source
);
4232 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
4234 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
4235 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4237 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
4240 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4243 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4244 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4248 pa_native_connection_assert_ref(c
);
4251 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4252 pa_tagstruct_gets(t
, &name
) < 0 ||
4253 !pa_tagstruct_eof(t
)) {
4258 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4259 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4261 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
4264 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4265 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4266 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4268 pa_sink_input_set_name(s
->sink_input
, name
);
4272 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4274 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4275 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4277 pa_source_output_set_name(s
->source_output
, name
);
4280 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4283 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4284 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4287 pa_native_connection_assert_ref(c
);
4290 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4291 !pa_tagstruct_eof(t
)) {
4296 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4298 if (command
== PA_COMMAND_KILL_CLIENT
) {
4301 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4302 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4304 pa_native_connection_ref(c
);
4305 pa_client_kill(client
);
4307 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4310 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4311 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4313 pa_native_connection_ref(c
);
4314 pa_sink_input_kill(s
);
4316 pa_source_output
*s
;
4318 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4320 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4321 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4323 pa_native_connection_ref(c
);
4324 pa_source_output_kill(s
);
4327 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4328 pa_native_connection_unref(c
);
4331 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4332 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4334 const char *name
, *argument
;
4335 pa_tagstruct
*reply
;
4337 pa_native_connection_assert_ref(c
);
4340 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4341 pa_tagstruct_gets(t
, &argument
) < 0 ||
4342 !pa_tagstruct_eof(t
)) {
4347 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4348 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4349 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4351 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4352 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4356 reply
= reply_new(tag
);
4357 pa_tagstruct_putu32(reply
, m
->index
);
4358 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4361 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4362 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4366 pa_native_connection_assert_ref(c
);
4369 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4370 !pa_tagstruct_eof(t
)) {
4375 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4376 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4377 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4379 pa_module_unload_request(m
, FALSE
);
4380 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4383 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4384 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4385 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4386 const char *name_device
= NULL
;
4388 pa_native_connection_assert_ref(c
);
4391 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4392 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4393 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4394 !pa_tagstruct_eof(t
)) {
4399 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4400 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4402 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
);
4403 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4404 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4405 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4407 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4408 pa_sink_input
*si
= NULL
;
4409 pa_sink
*sink
= NULL
;
4411 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4413 if (idx_device
!= PA_INVALID_INDEX
)
4414 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4416 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4418 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4420 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4421 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4425 pa_source_output
*so
= NULL
;
4428 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4430 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4432 if (idx_device
!= PA_INVALID_INDEX
)
4433 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4435 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4437 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4439 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4440 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4445 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4448 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4449 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4450 uint32_t idx
= PA_INVALID_INDEX
;
4451 const char *name
= NULL
;
4454 pa_native_connection_assert_ref(c
);
4457 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4458 pa_tagstruct_gets(t
, &name
) < 0 ||
4459 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4460 !pa_tagstruct_eof(t
)) {
4465 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4466 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
);
4467 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4468 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4469 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4471 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4473 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4475 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4477 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4478 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4482 pa_sink
*sink
= NULL
;
4484 if (idx
!= PA_INVALID_INDEX
)
4485 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4487 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4489 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4491 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4492 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4498 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4500 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4502 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4504 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4505 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4512 if (idx
!= PA_INVALID_INDEX
)
4513 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4515 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4517 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4519 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4520 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4526 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4529 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4530 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4531 uint32_t idx
= PA_INVALID_INDEX
;
4532 const char *name
= NULL
;
4534 pa_native_protocol_ext_cb_t cb
;
4536 pa_native_connection_assert_ref(c
);
4539 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4540 pa_tagstruct_gets(t
, &name
) < 0) {
4545 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4546 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4547 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4548 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4549 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4551 if (idx
!= PA_INVALID_INDEX
)
4552 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4554 for (m
= pa_idxset_first(c
->protocol
->core
->modules
, &idx
); m
; m
= pa_idxset_next(c
->protocol
->core
->modules
, &idx
))
4555 if (strcmp(name
, m
->name
) == 0)
4559 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4560 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4562 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4563 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4565 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4569 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4570 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4571 uint32_t idx
= PA_INVALID_INDEX
;
4572 const char *name
= NULL
, *profile
= NULL
;
4573 pa_card
*card
= NULL
;
4576 pa_native_connection_assert_ref(c
);
4579 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4580 pa_tagstruct_gets(t
, &name
) < 0 ||
4581 pa_tagstruct_gets(t
, &profile
) < 0 ||
4582 !pa_tagstruct_eof(t
)) {
4587 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4588 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4589 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4590 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4591 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4593 if (idx
!= PA_INVALID_INDEX
)
4594 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4596 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4598 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4600 if ((ret
= pa_card_set_profile(card
, profile
, TRUE
)) < 0) {
4601 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4605 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4608 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4609 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4610 uint32_t idx
= PA_INVALID_INDEX
;
4611 const char *name
= NULL
, *port
= NULL
;
4614 pa_native_connection_assert_ref(c
);
4617 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4618 pa_tagstruct_gets(t
, &name
) < 0 ||
4619 pa_tagstruct_gets(t
, &port
) < 0 ||
4620 !pa_tagstruct_eof(t
)) {
4625 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4626 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
);
4627 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4628 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4629 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4631 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4634 if (idx
!= PA_INVALID_INDEX
)
4635 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4637 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4639 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4641 if ((ret
= pa_sink_set_port(sink
, port
, TRUE
)) < 0) {
4642 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4648 pa_assert(command
= PA_COMMAND_SET_SOURCE_PORT
);
4650 if (idx
!= PA_INVALID_INDEX
)
4651 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4653 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4655 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4657 if ((ret
= pa_source_set_port(source
, port
, TRUE
)) < 0) {
4658 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4663 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4666 /*** pstream callbacks ***/
4668 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4669 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4673 pa_native_connection_assert_ref(c
);
4675 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4676 pa_log("invalid packet.");
4677 native_connection_unlink(c
);
4681 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
) {
4682 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4683 output_stream
*stream
;
4687 pa_native_connection_assert_ref(c
);
4689 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4690 pa_log_debug("Client sent block for invalid stream.");
4695 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4697 if (playback_stream_isinstance(stream
)) {
4698 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4700 pa_atomic_inc(&ps
->seek_or_post_in_queue
);
4701 if (chunk
->memblock
) {
4702 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4703 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
);
4705 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4707 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
);
4710 upload_stream
*u
= UPLOAD_STREAM(stream
);
4713 if (!u
->memchunk
.memblock
) {
4714 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4715 u
->memchunk
= *chunk
;
4716 pa_memblock_ref(u
->memchunk
.memblock
);
4719 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4720 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4724 pa_assert(u
->memchunk
.memblock
);
4727 if (l
> chunk
->length
)
4732 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4734 if (chunk
->memblock
) {
4736 src
= pa_memblock_acquire(chunk
->memblock
);
4738 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4739 (uint8_t*) src
+ chunk
->index
, l
);
4741 pa_memblock_release(chunk
->memblock
);
4743 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4745 pa_memblock_release(u
->memchunk
.memblock
);
4747 u
->memchunk
.length
+= l
;
4753 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4754 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4757 pa_native_connection_assert_ref(c
);
4759 native_connection_unlink(c
);
4760 pa_log_info("Connection died.");
4763 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4764 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4767 pa_native_connection_assert_ref(c
);
4769 native_connection_send_memblock(c
);
4772 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4775 if (!(q
= pa_thread_mq_get()))
4776 pa_pstream_send_revoke(p
, block_id
);
4778 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4781 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4784 if (!(q
= pa_thread_mq_get()))
4785 pa_pstream_send_release(p
, block_id
);
4787 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4790 /*** client callbacks ***/
4792 static void client_kill_cb(pa_client
*c
) {
4795 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4796 pa_log_info("Connection killed.");
4799 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4801 pa_native_connection
*c
;
4804 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4805 pa_native_connection_assert_ref(c
);
4807 if (c
->version
< 15)
4810 t
= pa_tagstruct_new(NULL
, 0);
4811 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4812 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4813 pa_tagstruct_puts(t
, event
);
4814 pa_tagstruct_put_proplist(t
, pl
);
4815 pa_pstream_send_tagstruct(c
->pstream
, t
);
4818 /*** module entry points ***/
4820 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4821 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4824 pa_native_connection_assert_ref(c
);
4825 pa_assert(c
->auth_timeout_event
== e
);
4827 if (!c
->authorized
) {
4828 native_connection_unlink(c
);
4829 pa_log_info("Connection terminated due to authentication timeout.");
4833 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4834 pa_native_connection
*c
;
4837 pa_client_new_data data
;
4843 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4844 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4845 pa_iochannel_free(io
);
4849 pa_client_new_data_init(&data
);
4850 data
.module
= o
->module
;
4851 data
.driver
= __FILE__
;
4852 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4853 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4854 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4855 client
= pa_client_new(p
->core
, &data
);
4856 pa_client_new_data_done(&data
);
4861 c
= pa_msgobject_new(pa_native_connection
);
4862 c
->parent
.parent
.free
= native_connection_free
;
4863 c
->parent
.process_msg
= native_connection_process_msg
;
4865 c
->options
= pa_native_options_ref(o
);
4866 c
->authorized
= FALSE
;
4868 if (o
->auth_anonymous
) {
4869 pa_log_info("Client authenticated anonymously.");
4870 c
->authorized
= TRUE
;
4873 if (!c
->authorized
&&
4875 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
4877 pa_log_info("Client authenticated by IP ACL.");
4878 c
->authorized
= TRUE
;
4882 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
4884 c
->auth_timeout_event
= NULL
;
4886 c
->is_local
= pa_iochannel_socket_is_local(io
);
4890 c
->client
->kill
= client_kill_cb
;
4891 c
->client
->send_event
= client_send_event_cb
;
4892 c
->client
->userdata
= c
;
4894 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
4895 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
4896 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
4897 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
4898 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
4899 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
4900 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
4902 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, TRUE
, command_table
, PA_COMMAND_MAX
);
4904 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
4905 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
4907 c
->rrobin_index
= PA_IDXSET_INVALID
;
4908 c
->subscription
= NULL
;
4910 pa_idxset_put(p
->connections
, c
, NULL
);
4913 if (pa_iochannel_creds_supported(io
))
4914 pa_iochannel_creds_enable(io
);
4917 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
4920 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
4921 pa_native_connection
*c
;
4927 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
4928 if (c
->options
->module
== m
)
4929 native_connection_unlink(c
);
4932 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
4933 pa_native_protocol
*p
;
4938 p
= pa_xnew(pa_native_protocol
, 1);
4941 p
->connections
= pa_idxset_new(NULL
, NULL
);
4945 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
4947 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4948 pa_hook_init(&p
->hooks
[h
], p
);
4950 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
4955 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
4956 pa_native_protocol
*p
;
4958 if ((p
= pa_shared_get(c
, "native-protocol")))
4959 return pa_native_protocol_ref(p
);
4961 return native_protocol_new(c
);
4964 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
4966 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4973 void pa_native_protocol_unref(pa_native_protocol
*p
) {
4974 pa_native_connection
*c
;
4978 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4980 if (PA_REFCNT_DEC(p
) > 0)
4983 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
4984 native_connection_unlink(c
);
4986 pa_idxset_free(p
->connections
, NULL
, NULL
);
4988 pa_strlist_free(p
->servers
);
4990 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4991 pa_hook_done(&p
->hooks
[h
]);
4993 pa_hashmap_free(p
->extensions
, NULL
, NULL
);
4995 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
5000 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
5002 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5005 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
5007 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5010 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
5012 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5015 p
->servers
= pa_strlist_remove(p
->servers
, name
);
5017 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5020 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
5022 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5027 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
5029 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5034 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
5036 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5039 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
5041 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
5045 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
5047 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5050 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
5053 pa_native_options
* pa_native_options_new(void) {
5054 pa_native_options
*o
;
5056 o
= pa_xnew0(pa_native_options
, 1);
5062 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
5064 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5071 void pa_native_options_unref(pa_native_options
*o
) {
5073 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5075 if (PA_REFCNT_DEC(o
) > 0)
5078 pa_xfree(o
->auth_group
);
5081 pa_ip_acl_free(o
->auth_ip_acl
);
5084 pa_auth_cookie_unref(o
->auth_cookie
);
5089 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
5094 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5097 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
5098 pa_log("auth-anonymous= expects a boolean argument.");
5103 if (pa_modargs_get_value_boolean(ma
, "auth-group-enabled", &enabled
) < 0) {
5104 pa_log("auth-group-enabled= expects a boolean argument.");
5108 pa_xfree(o
->auth_group
);
5109 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
5113 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5116 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
5119 if (!(ipa
= pa_ip_acl_new(acl
))) {
5120 pa_log("Failed to parse IP ACL '%s'", acl
);
5125 pa_ip_acl_free(o
->auth_ip_acl
);
5127 o
->auth_ip_acl
= ipa
;
5131 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
5132 pa_log("auth-cookie-enabled= expects a boolean argument.");
5137 pa_auth_cookie_unref(o
->auth_cookie
);
5142 /* The new name for this is 'auth-cookie', for compat reasons
5143 * we check the old name too */
5144 if (!(cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
)))
5145 if (!(cn
= pa_modargs_get_value(ma
, "cookie", NULL
)))
5146 cn
= PA_NATIVE_COOKIE_FILE
;
5148 if (!(o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, PA_NATIVE_COOKIE_LENGTH
)))
5152 o
->auth_cookie
= NULL
;
5157 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
5158 pa_native_connection_assert_ref(c
);
5163 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
5164 pa_native_connection_assert_ref(c
);