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
;
649 char *memblockq_name
;
656 pa_source_output_new_data_init(&data
);
658 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
659 data
.driver
= __FILE__
;
660 data
.module
= c
->options
->module
;
661 data
.client
= c
->client
;
663 pa_source_output_new_data_set_source(&data
, source
, TRUE
);
664 if (pa_sample_spec_valid(ss
))
665 pa_source_output_new_data_set_sample_spec(&data
, ss
);
666 if (pa_channel_map_valid(map
))
667 pa_source_output_new_data_set_channel_map(&data
, map
);
669 pa_source_output_new_data_set_formats(&data
, formats
);
670 data
.direct_on_input
= direct_on_input
;
672 pa_source_output_new_data_set_volume(&data
, volume
);
673 data
.volume_is_absolute
= !relative_volume
;
674 data
.save_volume
= TRUE
;
677 pa_source_output_new_data_set_muted(&data
, muted
);
678 data
.save_muted
= TRUE
;
681 data
.resample_method
= PA_RESAMPLER_PEAKS
;
684 *ret
= -pa_source_output_new(&source_output
, c
->protocol
->core
, &data
);
686 pa_source_output_new_data_done(&data
);
691 s
= pa_msgobject_new(record_stream
);
692 s
->parent
.parent
.free
= record_stream_free
;
693 s
->parent
.process_msg
= record_stream_process_msg
;
695 s
->source_output
= source_output
;
696 s
->buffer_attr_req
= *attr
;
697 s
->adjust_latency
= adjust_latency
;
698 s
->early_requests
= early_requests
;
699 pa_atomic_store(&s
->on_the_fly
, 0);
701 s
->source_output
->parent
.process_msg
= source_output_process_msg
;
702 s
->source_output
->push
= source_output_push_cb
;
703 s
->source_output
->kill
= source_output_kill_cb
;
704 s
->source_output
->get_latency
= source_output_get_latency_cb
;
705 s
->source_output
->moving
= source_output_moving_cb
;
706 s
->source_output
->suspend
= source_output_suspend_cb
;
707 s
->source_output
->send_event
= source_output_send_event_cb
;
708 s
->source_output
->userdata
= s
;
710 fix_record_buffer_attr_pre(s
);
712 memblockq_name
= pa_sprintf_malloc("native protocol record stream memblockq [%u]", s
->source_output
->index
);
713 s
->memblockq
= pa_memblockq_new(
716 s
->buffer_attr
.maxlength
,
718 &source_output
->sample_spec
,
723 pa_xfree(memblockq_name
);
725 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
726 fix_record_buffer_attr_post(s
);
728 *ss
= s
->source_output
->sample_spec
;
729 *map
= s
->source_output
->channel_map
;
731 pa_idxset_put(c
->record_streams
, s
, &s
->index
);
733 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
734 ((double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) + (double) s
->configured_source_latency
) / PA_USEC_PER_MSEC
,
735 (double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) / PA_USEC_PER_MSEC
,
736 (double) s
->configured_source_latency
/ PA_USEC_PER_MSEC
);
738 pa_source_output_put(s
->source_output
);
742 /* Called from main context */
743 static void record_stream_send_killed(record_stream
*r
) {
745 record_stream_assert_ref(r
);
747 t
= pa_tagstruct_new(NULL
, 0);
748 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_KILLED
);
749 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
750 pa_tagstruct_putu32(t
, r
->index
);
751 pa_pstream_send_tagstruct(r
->connection
->pstream
, t
);
754 /* Called from main context */
755 static void playback_stream_unlink(playback_stream
*s
) {
762 pa_sink_input_unlink(s
->sink_input
);
763 pa_sink_input_unref(s
->sink_input
);
764 s
->sink_input
= NULL
;
767 if (s
->drain_request
)
768 pa_pstream_send_error(s
->connection
->pstream
, s
->drain_tag
, PA_ERR_NOENTITY
);
770 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
771 s
->connection
= NULL
;
772 playback_stream_unref(s
);
775 /* Called from main context */
776 static void playback_stream_free(pa_object
* o
) {
777 playback_stream
*s
= PLAYBACK_STREAM(o
);
780 playback_stream_unlink(s
);
782 pa_memblockq_free(s
->memblockq
);
786 /* Called from main context */
787 static int playback_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
788 playback_stream
*s
= PLAYBACK_STREAM(o
);
789 playback_stream_assert_ref(s
);
796 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
: {
801 if ((l
= pa_atomic_load(&s
->missing
)) <= 0)
804 if (pa_atomic_cmpxchg(&s
->missing
, l
, 0))
808 t
= pa_tagstruct_new(NULL
, 0);
809 pa_tagstruct_putu32(t
, PA_COMMAND_REQUEST
);
810 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
811 pa_tagstruct_putu32(t
, s
->index
);
812 pa_tagstruct_putu32(t
, (uint32_t) l
);
813 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
815 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
819 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW
: {
822 /* pa_log("signalling underflow"); */
824 /* Report that we're empty */
825 t
= pa_tagstruct_new(NULL
, 0);
826 pa_tagstruct_putu32(t
, PA_COMMAND_UNDERFLOW
);
827 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
828 pa_tagstruct_putu32(t
, s
->index
);
829 if (s
->connection
->version
>= 23)
830 pa_tagstruct_puts64(t
, offset
);
831 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
835 case PLAYBACK_STREAM_MESSAGE_OVERFLOW
: {
838 /* Notify the user we're overflowed*/
839 t
= pa_tagstruct_new(NULL
, 0);
840 pa_tagstruct_putu32(t
, PA_COMMAND_OVERFLOW
);
841 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
842 pa_tagstruct_putu32(t
, s
->index
);
843 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
847 case PLAYBACK_STREAM_MESSAGE_STARTED
:
849 if (s
->connection
->version
>= 13) {
852 /* Notify the user we started playback */
853 t
= pa_tagstruct_new(NULL
, 0);
854 pa_tagstruct_putu32(t
, PA_COMMAND_STARTED
);
855 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
856 pa_tagstruct_putu32(t
, s
->index
);
857 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
862 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
:
863 pa_pstream_send_simple_ack(s
->connection
->pstream
, PA_PTR_TO_UINT(userdata
));
866 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
:
868 s
->buffer_attr
.tlength
= (uint32_t) offset
;
870 if (s
->connection
->version
>= 15) {
873 t
= pa_tagstruct_new(NULL
, 0);
874 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
);
875 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
876 pa_tagstruct_putu32(t
, s
->index
);
877 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
878 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
879 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
880 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
881 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
882 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
891 /* Called from main context */
892 static void fix_playback_buffer_attr(playback_stream
*s
) {
893 size_t frame_size
, max_prebuf
;
894 pa_usec_t orig_tlength_usec
, tlength_usec
, orig_minreq_usec
, minreq_usec
, sink_usec
;
898 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
899 /* (long) s->buffer_attr.maxlength, */
900 /* (long) s->buffer_attr.tlength, */
901 /* (long) s->buffer_attr.minreq, */
902 /* (long) s->buffer_attr.prebuf); */
904 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
905 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
906 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
907 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
908 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
910 /* This function will be called from the main thread, before as
911 * well as after the sink input has been activated using
912 * pa_sink_input_put()! That means it may not touch any
913 * ->thread_info data, such as the memblockq! */
915 frame_size
= pa_frame_size(&s
->sink_input
->sample_spec
);
916 s
->buffer_attr
= s
->buffer_attr_req
;
918 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
919 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
920 if (s
->buffer_attr
.maxlength
<= 0)
921 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
923 if (s
->buffer_attr
.tlength
== (uint32_t) -1)
924 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
925 if (s
->buffer_attr
.tlength
<= 0)
926 s
->buffer_attr
.tlength
= (uint32_t) frame_size
;
928 if (s
->buffer_attr
.minreq
== (uint32_t) -1)
929 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
930 if (s
->buffer_attr
.minreq
<= 0)
931 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
933 if (s
->buffer_attr
.tlength
< s
->buffer_attr
.minreq
+frame_size
)
934 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
+(uint32_t) frame_size
;
936 orig_tlength_usec
= tlength_usec
= pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
);
937 orig_minreq_usec
= minreq_usec
= pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
);
939 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
940 (double) tlength_usec
/ PA_USEC_PER_MSEC
,
941 (double) minreq_usec
/ PA_USEC_PER_MSEC
);
943 if (s
->early_requests
) {
945 /* In early request mode we need to emulate the classic
946 * fragment-based playback model. We do this setting the sink
947 * latency to the fragment size. */
949 sink_usec
= minreq_usec
;
950 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
952 } else if (s
->adjust_latency
) {
954 /* So, the user asked us to adjust the latency of the stream
955 * buffer according to the what the sink can provide. The
956 * tlength passed in shall be the overall latency. Roughly
957 * half the latency will be spent on the hw buffer, the other
958 * half of it in the async buffer queue we maintain for each
959 * client. In between we'll have a safety space of size
960 * 2*minreq. Why the 2*minreq? When the hw buffer is completely
961 * empty and needs to be filled, then our buffer must have
962 * enough data to fulfill this request immediately and thus
963 * have at least the same tlength as the size of the hw
964 * buffer. It additionally needs space for 2 times minreq
965 * because if the buffer ran empty and a partial fillup
966 * happens immediately on the next iteration we need to be
967 * able to fulfill it and give the application also minreq
968 * time to fill it up again for the next request Makes 2 times
969 * minreq in plus.. */
971 if (tlength_usec
> minreq_usec
*2)
972 sink_usec
= (tlength_usec
- minreq_usec
*2)/2;
976 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
980 /* Ok, the user didn't ask us to adjust the latency, but we
981 * still need to make sure that the parameters from the user
984 if (tlength_usec
> minreq_usec
*2)
985 sink_usec
= (tlength_usec
- minreq_usec
*2);
989 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
992 s
->configured_sink_latency
= pa_sink_input_set_requested_latency(s
->sink_input
, sink_usec
);
994 if (s
->early_requests
) {
996 /* Ok, we didn't necessarily get what we were asking for, so
997 * let's tell the user */
999 minreq_usec
= s
->configured_sink_latency
;
1001 } else if (s
->adjust_latency
) {
1003 /* Ok, we didn't necessarily get what we were asking for, so
1004 * let's subtract from what we asked for for the remaining
1007 if (tlength_usec
>= s
->configured_sink_latency
)
1008 tlength_usec
-= s
->configured_sink_latency
;
1011 pa_log_debug("Requested latency=%0.2f ms, Received latency=%0.2f ms",
1012 (double) sink_usec
/ PA_USEC_PER_MSEC
,
1013 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1015 /* FIXME: This is actually larger than necessary, since not all of
1016 * the sink latency is actually rewritable. */
1017 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
1018 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
1020 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
1021 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
1022 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
1024 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
1025 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
1026 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
1028 if (s
->buffer_attr
.minreq
<= 0) {
1029 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
1030 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
1033 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
1034 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
1036 max_prebuf
= s
->buffer_attr
.tlength
+ (uint32_t)frame_size
- s
->buffer_attr
.minreq
;
1038 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 ||
1039 s
->buffer_attr
.prebuf
> max_prebuf
)
1040 s
->buffer_attr
.prebuf
= max_prebuf
;
1042 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1043 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1044 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1045 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1046 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1049 /* Called from main context */
1050 static playback_stream
* playback_stream_new(
1051 pa_native_connection
*c
,
1054 pa_channel_map
*map
,
1059 pa_bool_t muted_set
,
1060 pa_sink_input_flags_t flags
,
1062 pa_bool_t adjust_latency
,
1063 pa_bool_t early_requests
,
1064 pa_bool_t relative_volume
,
1069 /* Note: This function takes ownership of the 'formats' param, so we need
1070 * to take extra care to not leak it */
1072 playback_stream
*ssync
;
1073 playback_stream
*s
= NULL
;
1074 pa_sink_input
*sink_input
= NULL
;
1075 pa_memchunk silence
;
1077 int64_t start_index
;
1078 pa_sink_input_new_data data
;
1079 char *memblockq_name
;
1087 /* Find syncid group */
1088 PA_IDXSET_FOREACH(ssync
, c
->output_streams
, idx
) {
1090 if (!playback_stream_isinstance(ssync
))
1093 if (ssync
->syncid
== syncid
)
1097 /* Synced streams must connect to the same sink */
1101 sink
= ssync
->sink_input
->sink
;
1102 else if (sink
!= ssync
->sink_input
->sink
) {
1103 *ret
= PA_ERR_INVALID
;
1108 pa_sink_input_new_data_init(&data
);
1110 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1111 data
.driver
= __FILE__
;
1112 data
.module
= c
->options
->module
;
1113 data
.client
= c
->client
;
1115 pa_sink_input_new_data_set_sink(&data
, sink
, TRUE
);
1116 if (pa_sample_spec_valid(ss
))
1117 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1118 if (pa_channel_map_valid(map
))
1119 pa_sink_input_new_data_set_channel_map(&data
, map
);
1121 pa_sink_input_new_data_set_formats(&data
, formats
);
1122 /* Ownership transferred to new_data, so we don't free it ourselves */
1126 pa_sink_input_new_data_set_volume(&data
, volume
);
1127 data
.volume_is_absolute
= !relative_volume
;
1128 data
.save_volume
= TRUE
;
1131 pa_sink_input_new_data_set_muted(&data
, muted
);
1132 data
.save_muted
= TRUE
;
1134 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1137 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
);
1139 pa_sink_input_new_data_done(&data
);
1144 s
= pa_msgobject_new(playback_stream
);
1145 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1146 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1149 s
->sink_input
= sink_input
;
1150 s
->is_underrun
= TRUE
;
1151 s
->drain_request
= FALSE
;
1152 pa_atomic_store(&s
->missing
, 0);
1153 s
->buffer_attr_req
= *a
;
1154 s
->adjust_latency
= adjust_latency
;
1155 s
->early_requests
= early_requests
;
1156 pa_atomic_store(&s
->seek_or_post_in_queue
, 0);
1157 s
->seek_windex
= -1;
1159 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1160 s
->sink_input
->pop
= sink_input_pop_cb
;
1161 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1162 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1163 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1164 s
->sink_input
->kill
= sink_input_kill_cb
;
1165 s
->sink_input
->moving
= sink_input_moving_cb
;
1166 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1167 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1168 s
->sink_input
->userdata
= s
;
1170 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1172 fix_playback_buffer_attr(s
);
1174 pa_sink_input_get_silence(sink_input
, &silence
);
1175 memblockq_name
= pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s
->sink_input
->index
);
1176 s
->memblockq
= pa_memblockq_new(
1179 s
->buffer_attr
.maxlength
,
1180 s
->buffer_attr
.tlength
,
1181 &sink_input
->sample_spec
,
1182 s
->buffer_attr
.prebuf
,
1183 s
->buffer_attr
.minreq
,
1186 pa_xfree(memblockq_name
);
1187 pa_memblock_unref(silence
.memblock
);
1189 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1191 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1193 /* pa_log("missing original: %li", (long int) *missing); */
1195 *ss
= s
->sink_input
->sample_spec
;
1196 *map
= s
->sink_input
->channel_map
;
1198 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1200 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1201 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1202 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1203 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1204 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1206 pa_sink_input_put(s
->sink_input
);
1210 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
1215 /* Called from IO context */
1216 static void playback_stream_request_bytes(playback_stream
*s
) {
1218 int previous_missing
;
1220 playback_stream_assert_ref(s
);
1222 m
= pa_memblockq_pop_missing(s
->memblockq
);
1224 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1225 /* (unsigned long) m, */
1226 /* pa_memblockq_get_tlength(s->memblockq), */
1227 /* pa_memblockq_get_minreq(s->memblockq), */
1228 /* pa_memblockq_get_length(s->memblockq), */
1229 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1234 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1236 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1237 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1239 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1240 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1241 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1244 /* Called from main context */
1245 static void playback_stream_send_killed(playback_stream
*p
) {
1247 playback_stream_assert_ref(p
);
1249 t
= pa_tagstruct_new(NULL
, 0);
1250 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1251 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1252 pa_tagstruct_putu32(t
, p
->index
);
1253 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1256 /* Called from main context */
1257 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1258 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1259 pa_native_connection_assert_ref(c
);
1266 case CONNECTION_MESSAGE_REVOKE
:
1267 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1270 case CONNECTION_MESSAGE_RELEASE
:
1271 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1278 /* Called from main context */
1279 static void native_connection_unlink(pa_native_connection
*c
) {
1288 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1291 pa_native_options_unref(c
->options
);
1293 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1294 record_stream_unlink(r
);
1296 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1297 if (playback_stream_isinstance(o
))
1298 playback_stream_unlink(PLAYBACK_STREAM(o
));
1300 upload_stream_unlink(UPLOAD_STREAM(o
));
1302 if (c
->subscription
)
1303 pa_subscription_free(c
->subscription
);
1306 pa_pstream_unlink(c
->pstream
);
1308 if (c
->auth_timeout_event
) {
1309 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1310 c
->auth_timeout_event
= NULL
;
1313 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1315 pa_native_connection_unref(c
);
1318 /* Called from main context */
1319 static void native_connection_free(pa_object
*o
) {
1320 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1324 native_connection_unlink(c
);
1326 pa_idxset_free(c
->record_streams
, NULL
, NULL
);
1327 pa_idxset_free(c
->output_streams
, NULL
, NULL
);
1329 pa_pdispatch_unref(c
->pdispatch
);
1330 pa_pstream_unref(c
->pstream
);
1331 pa_client_free(c
->client
);
1336 /* Called from main context */
1337 static void native_connection_send_memblock(pa_native_connection
*c
) {
1341 start
= PA_IDXSET_INVALID
;
1345 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1348 if (start
== PA_IDXSET_INVALID
)
1349 start
= c
->rrobin_index
;
1350 else if (start
== c
->rrobin_index
)
1353 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1354 pa_memchunk schunk
= chunk
;
1356 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1357 schunk
.length
= r
->buffer_attr
.fragsize
;
1359 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1361 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1362 pa_memblock_unref(schunk
.memblock
);
1369 /*** sink input callbacks ***/
1371 /* Called from thread context */
1372 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1373 playback_stream_assert_ref(s
);
1375 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1377 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1379 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1381 if (pa_memblockq_is_readable(s
->memblockq
)) {
1383 /* We just ended an underrun, let's ask the sink
1384 * for a complete rewind rewrite */
1386 pa_log_debug("Requesting rewind due to end of underrun.");
1387 pa_sink_input_request_rewind(s
->sink_input
,
1388 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (uint64_t) -1 ? 0 :
1389 s
->sink_input
->thread_info
.underrun_for
),
1390 FALSE
, TRUE
, FALSE
);
1396 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1398 if (indexw
< indexr
) {
1399 /* OK, the sink already asked for this data, so
1400 * let's have it ask us again */
1402 pa_log_debug("Requesting rewind due to rewrite.");
1403 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), TRUE
, FALSE
, FALSE
);
1407 playback_stream_request_bytes(s
);
1410 static void flush_write_no_account(pa_memblockq
*q
) {
1411 pa_memblockq_flush_write(q
, FALSE
);
1414 /* Called from thread context */
1415 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1416 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1419 pa_sink_input_assert_ref(i
);
1420 s
= PLAYBACK_STREAM(i
->userdata
);
1421 playback_stream_assert_ref(s
);
1425 case SINK_INPUT_MESSAGE_SEEK
:
1426 case SINK_INPUT_MESSAGE_POST_DATA
: {
1427 int64_t windex
= pa_memblockq_get_write_index(s
->memblockq
);
1429 if (code
== SINK_INPUT_MESSAGE_SEEK
) {
1430 /* The client side is incapable of accounting correctly
1431 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1432 * able to deal with that. */
1434 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1435 windex
= PA_MIN(windex
, pa_memblockq_get_write_index(s
->memblockq
));
1438 if (chunk
&& pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1439 if (pa_log_ratelimit(PA_LOG_WARN
))
1440 pa_log_warn("Failed to push data into queue");
1441 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1442 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, TRUE
);
1445 /* If more data is in queue, we rewind later instead. */
1446 if (s
->seek_windex
!= -1)
1447 windex
= PA_MIN(windex
, s
->seek_windex
);
1448 if (pa_atomic_dec(&s
->seek_or_post_in_queue
) > 1)
1449 s
->seek_windex
= windex
;
1451 s
->seek_windex
= -1;
1452 handle_seek(s
, windex
);
1457 case SINK_INPUT_MESSAGE_DRAIN
:
1458 case SINK_INPUT_MESSAGE_FLUSH
:
1459 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1460 case SINK_INPUT_MESSAGE_TRIGGER
: {
1463 pa_sink_input
*isync
;
1464 void (*func
)(pa_memblockq
*bq
);
1467 case SINK_INPUT_MESSAGE_FLUSH
:
1468 func
= flush_write_no_account
;
1471 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1472 func
= pa_memblockq_prebuf_force
;
1475 case SINK_INPUT_MESSAGE_DRAIN
:
1476 case SINK_INPUT_MESSAGE_TRIGGER
:
1477 func
= pa_memblockq_prebuf_disable
;
1481 pa_assert_not_reached();
1484 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1486 handle_seek(s
, windex
);
1488 /* Do the same for all other members in the sync group */
1489 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1490 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1491 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1492 func(ssync
->memblockq
);
1493 handle_seek(ssync
, windex
);
1496 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1497 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1498 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1499 func(ssync
->memblockq
);
1500 handle_seek(ssync
, windex
);
1503 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1504 if (!pa_memblockq_is_readable(s
->memblockq
))
1505 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1507 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1508 s
->drain_request
= TRUE
;
1515 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1516 /* Atomically get a snapshot of all timing parameters... */
1517 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1518 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1519 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1520 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1521 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1522 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1526 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1529 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1531 pa_memblockq_prebuf_force(s
->memblockq
);
1533 handle_seek(s
, windex
);
1535 /* Fall through to the default handler */
1539 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1540 pa_usec_t
*r
= userdata
;
1542 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1544 /* Fall through, the default handler will add in the extra
1545 * latency added by the resampler */
1549 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1550 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1551 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1556 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1559 /* Called from thread context */
1560 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1563 pa_sink_input_assert_ref(i
);
1564 s
= PLAYBACK_STREAM(i
->userdata
);
1565 playback_stream_assert_ref(s
);
1568 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1570 if (pa_memblockq_is_readable(s
->memblockq
))
1571 s
->is_underrun
= FALSE
;
1573 if (!s
->is_underrun
)
1574 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
));
1576 if (s
->drain_request
&& pa_sink_input_safe_to_remove(i
)) {
1577 s
->drain_request
= FALSE
;
1578 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
);
1579 } else if (!s
->is_underrun
)
1580 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UNDERFLOW
, NULL
, pa_memblockq_get_read_index(s
->memblockq
), NULL
, NULL
);
1582 s
->is_underrun
= TRUE
;
1584 playback_stream_request_bytes(s
);
1587 /* This call will not fail with prebuf=0, hence we check for
1588 underrun explicitly above */
1589 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1592 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1594 if (i
->thread_info
.underrun_for
> 0)
1595 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1597 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1598 playback_stream_request_bytes(s
);
1603 /* Called from thread context */
1604 static void sink_input_process_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 /* If we are in an underrun, then we don't rewind */
1612 if (i
->thread_info
.underrun_for
> 0)
1615 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1618 /* Called from thread context */
1619 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1622 pa_sink_input_assert_ref(i
);
1623 s
= PLAYBACK_STREAM(i
->userdata
);
1624 playback_stream_assert_ref(s
);
1626 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1629 /* Called from thread context */
1630 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1632 size_t new_tlength
, old_tlength
;
1634 pa_sink_input_assert_ref(i
);
1635 s
= PLAYBACK_STREAM(i
->userdata
);
1636 playback_stream_assert_ref(s
);
1638 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1639 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1641 if (old_tlength
< new_tlength
) {
1642 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1643 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1644 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1646 if (new_tlength
== old_tlength
)
1647 pa_log_debug("Failed to increase tlength");
1649 pa_log_debug("Notifying client about increased tlength");
1650 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
);
1655 /* Called from main context */
1656 static void sink_input_kill_cb(pa_sink_input
*i
) {
1659 pa_sink_input_assert_ref(i
);
1660 s
= PLAYBACK_STREAM(i
->userdata
);
1661 playback_stream_assert_ref(s
);
1663 playback_stream_send_killed(s
);
1664 playback_stream_unlink(s
);
1667 /* Called from main context */
1668 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1672 pa_sink_input_assert_ref(i
);
1673 s
= PLAYBACK_STREAM(i
->userdata
);
1674 playback_stream_assert_ref(s
);
1676 if (s
->connection
->version
< 15)
1679 t
= pa_tagstruct_new(NULL
, 0);
1680 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1681 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1682 pa_tagstruct_putu32(t
, s
->index
);
1683 pa_tagstruct_puts(t
, event
);
1684 pa_tagstruct_put_proplist(t
, pl
);
1685 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1688 /* Called from main context */
1689 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
) {
1693 pa_sink_input_assert_ref(i
);
1694 s
= PLAYBACK_STREAM(i
->userdata
);
1695 playback_stream_assert_ref(s
);
1697 if (s
->connection
->version
< 12)
1700 t
= pa_tagstruct_new(NULL
, 0);
1701 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1702 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1703 pa_tagstruct_putu32(t
, s
->index
);
1704 pa_tagstruct_put_boolean(t
, suspend
);
1705 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1708 /* Called from main context */
1709 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1713 pa_sink_input_assert_ref(i
);
1714 s
= PLAYBACK_STREAM(i
->userdata
);
1715 playback_stream_assert_ref(s
);
1720 fix_playback_buffer_attr(s
);
1721 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1722 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1724 if (s
->connection
->version
< 12)
1727 t
= pa_tagstruct_new(NULL
, 0);
1728 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1729 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1730 pa_tagstruct_putu32(t
, s
->index
);
1731 pa_tagstruct_putu32(t
, dest
->index
);
1732 pa_tagstruct_puts(t
, dest
->name
);
1733 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1735 if (s
->connection
->version
>= 13) {
1736 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1737 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1738 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1739 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1740 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1743 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1746 /*** source_output callbacks ***/
1748 /* Called from thread context */
1749 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1750 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1753 pa_source_output_assert_ref(o
);
1754 s
= RECORD_STREAM(o
->userdata
);
1755 record_stream_assert_ref(s
);
1758 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1759 /* Atomically get a snapshot of all timing parameters... */
1760 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1761 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1762 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1766 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1769 /* Called from thread context */
1770 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1773 pa_source_output_assert_ref(o
);
1774 s
= RECORD_STREAM(o
->userdata
);
1775 record_stream_assert_ref(s
);
1778 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1779 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1782 static void source_output_kill_cb(pa_source_output
*o
) {
1785 pa_source_output_assert_ref(o
);
1786 s
= RECORD_STREAM(o
->userdata
);
1787 record_stream_assert_ref(s
);
1789 record_stream_send_killed(s
);
1790 record_stream_unlink(s
);
1793 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1796 pa_source_output_assert_ref(o
);
1797 s
= RECORD_STREAM(o
->userdata
);
1798 record_stream_assert_ref(s
);
1800 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1802 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1805 /* Called from main context */
1806 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1810 pa_source_output_assert_ref(o
);
1811 s
= RECORD_STREAM(o
->userdata
);
1812 record_stream_assert_ref(s
);
1814 if (s
->connection
->version
< 15)
1817 t
= pa_tagstruct_new(NULL
, 0);
1818 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1819 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1820 pa_tagstruct_putu32(t
, s
->index
);
1821 pa_tagstruct_puts(t
, event
);
1822 pa_tagstruct_put_proplist(t
, pl
);
1823 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1826 /* Called from main context */
1827 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
) {
1831 pa_source_output_assert_ref(o
);
1832 s
= RECORD_STREAM(o
->userdata
);
1833 record_stream_assert_ref(s
);
1835 if (s
->connection
->version
< 12)
1838 t
= pa_tagstruct_new(NULL
, 0);
1839 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1840 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1841 pa_tagstruct_putu32(t
, s
->index
);
1842 pa_tagstruct_put_boolean(t
, suspend
);
1843 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1846 /* Called from main context */
1847 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1851 pa_source_output_assert_ref(o
);
1852 s
= RECORD_STREAM(o
->userdata
);
1853 record_stream_assert_ref(s
);
1858 fix_record_buffer_attr_pre(s
);
1859 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1860 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1861 fix_record_buffer_attr_post(s
);
1863 if (s
->connection
->version
< 12)
1866 t
= pa_tagstruct_new(NULL
, 0);
1867 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1868 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1869 pa_tagstruct_putu32(t
, s
->index
);
1870 pa_tagstruct_putu32(t
, dest
->index
);
1871 pa_tagstruct_puts(t
, dest
->name
);
1872 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1874 if (s
->connection
->version
>= 13) {
1875 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1876 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1877 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1880 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1883 /*** pdispatch callbacks ***/
1885 static void protocol_error(pa_native_connection
*c
) {
1886 pa_log("protocol error, kicking client");
1887 native_connection_unlink(c
);
1890 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1891 if (!(expression)) { \
1892 pa_pstream_send_error((pstream), (tag), (error)); \
1897 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1898 if (!(expression)) { \
1899 pa_pstream_send_error((pstream), (tag), (error)); \
1904 static pa_tagstruct
*reply_new(uint32_t tag
) {
1905 pa_tagstruct
*reply
;
1907 reply
= pa_tagstruct_new(NULL
, 0);
1908 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1909 pa_tagstruct_putu32(reply
, tag
);
1913 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1914 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1916 uint32_t sink_index
, syncid
, missing
= 0;
1917 pa_buffer_attr attr
;
1918 const char *name
= NULL
, *sink_name
;
1921 pa_tagstruct
*reply
;
1922 pa_sink
*sink
= NULL
;
1930 fix_channels
= FALSE
,
1932 variable_rate
= FALSE
,
1934 adjust_latency
= FALSE
,
1935 early_requests
= FALSE
,
1936 dont_inhibit_auto_suspend
= FALSE
,
1939 fail_on_suspend
= FALSE
,
1940 relative_volume
= FALSE
,
1941 passthrough
= FALSE
;
1943 pa_sink_input_flags_t flags
= 0;
1944 pa_proplist
*p
= NULL
;
1945 int ret
= PA_ERR_INVALID
;
1946 uint8_t n_formats
= 0;
1947 pa_format_info
*format
;
1948 pa_idxset
*formats
= NULL
;
1951 pa_native_connection_assert_ref(c
);
1953 memset(&attr
, 0, sizeof(attr
));
1955 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
1958 PA_TAG_SAMPLE_SPEC
, &ss
,
1959 PA_TAG_CHANNEL_MAP
, &map
,
1960 PA_TAG_U32
, &sink_index
,
1961 PA_TAG_STRING
, &sink_name
,
1962 PA_TAG_U32
, &attr
.maxlength
,
1963 PA_TAG_BOOLEAN
, &corked
,
1964 PA_TAG_U32
, &attr
.tlength
,
1965 PA_TAG_U32
, &attr
.prebuf
,
1966 PA_TAG_U32
, &attr
.minreq
,
1967 PA_TAG_U32
, &syncid
,
1968 PA_TAG_CVOLUME
, &volume
,
1969 PA_TAG_INVALID
) < 0) {
1975 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
1976 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
, finish
);
1977 CHECK_VALIDITY_GOTO(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
, finish
);
1978 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
1979 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
1981 p
= pa_proplist_new();
1984 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
1986 if (c
->version
>= 12) {
1987 /* Since 0.9.8 the user can ask for a couple of additional flags */
1989 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
1990 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
1991 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
1992 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
1993 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
1994 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
1995 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2002 if (c
->version
>= 13) {
2004 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2005 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2006 pa_tagstruct_get_proplist(t
, p
) < 0) {
2013 if (c
->version
>= 14) {
2015 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2016 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2023 if (c
->version
>= 15) {
2025 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2026 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2027 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2034 if (c
->version
>= 17) {
2036 if (pa_tagstruct_get_boolean(t
, &relative_volume
) < 0) {
2043 if (c
->version
>= 18) {
2045 if (pa_tagstruct_get_boolean(t
, &passthrough
) < 0 ) {
2051 if (c
->version
>= 21) {
2053 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2059 formats
= pa_idxset_new(NULL
, NULL
);
2061 for (i
= 0; i
< n_formats
; i
++) {
2062 format
= pa_format_info_new();
2063 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2067 pa_idxset_put(formats
, format
, NULL
);
2071 if (n_formats
== 0) {
2072 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2073 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2074 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2076 PA_IDXSET_FOREACH(format
, formats
, i
) {
2077 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2081 if (!pa_tagstruct_eof(t
)) {
2086 if (sink_index
!= PA_INVALID_INDEX
) {
2088 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
2089 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2093 } else if (sink_name
) {
2095 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
2096 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2102 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
2103 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
2104 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
2105 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
2106 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
2107 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
2108 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
2109 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
2110 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2111 (fail_on_suspend
? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND
|PA_SINK_INPUT_KILL_ON_SUSPEND
: 0) |
2112 (passthrough
? PA_SINK_INPUT_PASSTHROUGH
: 0);
2114 /* Only since protocol version 15 there's a separate muted_set
2115 * flag. For older versions we synthesize it here */
2116 muted_set
= muted_set
|| muted
;
2118 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
);
2119 /* We no longer own the formats idxset */
2122 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2124 reply
= reply_new(tag
);
2125 pa_tagstruct_putu32(reply
, s
->index
);
2126 pa_assert(s
->sink_input
);
2127 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
2128 pa_tagstruct_putu32(reply
, missing
);
2130 /* pa_log("initial request is %u", missing); */
2132 if (c
->version
>= 9) {
2133 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2135 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2136 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
2137 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
2138 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
2141 if (c
->version
>= 12) {
2142 /* Since 0.9.8 we support sending the chosen sample
2143 * spec/channel map/device/suspend status back to the
2146 pa_tagstruct_put_sample_spec(reply
, &ss
);
2147 pa_tagstruct_put_channel_map(reply
, &map
);
2149 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
2150 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
2152 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
2155 if (c
->version
>= 13)
2156 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
2158 if (c
->version
>= 21) {
2159 /* Send back the format we negotiated */
2160 if (s
->sink_input
->format
)
2161 pa_tagstruct_put_format_info(reply
, s
->sink_input
->format
);
2163 pa_format_info
*f
= pa_format_info_new();
2164 pa_tagstruct_put_format_info(reply
, f
);
2165 pa_format_info_free(f
);
2169 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2173 pa_proplist_free(p
);
2175 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
2178 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2179 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2182 pa_native_connection_assert_ref(c
);
2185 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2186 !pa_tagstruct_eof(t
)) {
2191 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2195 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2197 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2198 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2202 playback_stream_unlink(s
);
2206 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2208 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2209 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2213 record_stream_unlink(s
);
2217 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2220 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2221 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2225 upload_stream_unlink(s
);
2230 pa_assert_not_reached();
2233 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2236 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2237 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2239 pa_buffer_attr attr
;
2240 uint32_t source_index
;
2241 const char *name
= NULL
, *source_name
;
2244 pa_tagstruct
*reply
;
2245 pa_source
*source
= NULL
;
2253 fix_channels
= FALSE
,
2255 variable_rate
= FALSE
,
2257 adjust_latency
= FALSE
,
2258 peak_detect
= FALSE
,
2259 early_requests
= FALSE
,
2260 dont_inhibit_auto_suspend
= FALSE
,
2263 fail_on_suspend
= FALSE
,
2264 relative_volume
= FALSE
,
2265 passthrough
= FALSE
;
2267 pa_source_output_flags_t flags
= 0;
2268 pa_proplist
*p
= NULL
;
2269 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2270 pa_sink_input
*direct_on_input
= NULL
;
2271 int ret
= PA_ERR_INVALID
;
2272 uint8_t n_formats
= 0;
2273 pa_format_info
*format
;
2274 pa_idxset
*formats
= NULL
;
2277 pa_native_connection_assert_ref(c
);
2280 memset(&attr
, 0, sizeof(attr
));
2282 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2283 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2284 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2285 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2286 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2287 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2288 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2289 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2295 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
2296 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| pa_namereg_is_valid_name_or_wildcard(source_name
, PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
, finish
);
2297 CHECK_VALIDITY_GOTO(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
, finish
);
2298 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
2300 p
= pa_proplist_new();
2303 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2305 if (c
->version
>= 12) {
2306 /* Since 0.9.8 the user can ask for a couple of additional flags */
2308 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2309 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2310 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2311 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2312 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2313 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2314 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2321 if (c
->version
>= 13) {
2323 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2324 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2325 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2326 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2333 if (c
->version
>= 14) {
2335 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2341 if (c
->version
>= 15) {
2343 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2344 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2351 if (c
->version
>= 22) {
2352 /* For newer client versions (with per-source-output volumes), we try
2353 * to make the behaviour for playback and record streams the same. */
2356 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2362 formats
= pa_idxset_new(NULL
, NULL
);
2364 for (i
= 0; i
< n_formats
; i
++) {
2365 format
= pa_format_info_new();
2366 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2370 pa_idxset_put(formats
, format
, NULL
);
2373 if (pa_tagstruct_get_cvolume(t
, &volume
) < 0 ||
2374 pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2375 pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2376 pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2377 pa_tagstruct_get_boolean(t
, &relative_volume
) < 0 ||
2378 pa_tagstruct_get_boolean(t
, &passthrough
) < 0) {
2384 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
2387 if (n_formats
== 0) {
2388 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2389 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2390 CHECK_VALIDITY_GOTO(c
->pstream
, c
->version
< 22 || (volume
.channels
== ss
.channels
), tag
, PA_ERR_INVALID
, finish
);
2391 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2393 PA_IDXSET_FOREACH(format
, formats
, i
) {
2394 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2399 if (!pa_tagstruct_eof(t
)) {
2404 if (source_index
!= PA_INVALID_INDEX
) {
2406 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2407 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2411 } else if (source_name
) {
2413 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2414 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2419 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2421 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2422 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2428 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2429 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2430 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2431 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2432 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2433 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2434 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2435 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2436 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2437 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0) |
2438 (passthrough
? PA_SOURCE_OUTPUT_PASSTHROUGH
: 0);
2440 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
);
2442 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2444 reply
= reply_new(tag
);
2445 pa_tagstruct_putu32(reply
, s
->index
);
2446 pa_assert(s
->source_output
);
2447 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2449 if (c
->version
>= 9) {
2450 /* Since 0.9 we support sending the buffer metrics back to the client */
2452 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2453 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2456 if (c
->version
>= 12) {
2457 /* Since 0.9.8 we support sending the chosen sample
2458 * spec/channel map/device/suspend status back to the
2461 pa_tagstruct_put_sample_spec(reply
, &ss
);
2462 pa_tagstruct_put_channel_map(reply
, &map
);
2464 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2465 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2467 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2470 if (c
->version
>= 13)
2471 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2473 if (c
->version
>= 22) {
2474 /* Send back the format we negotiated */
2475 if (s
->source_output
->format
)
2476 pa_tagstruct_put_format_info(reply
, s
->source_output
->format
);
2478 pa_format_info
*f
= pa_format_info_new();
2479 pa_tagstruct_put_format_info(reply
, f
);
2480 pa_format_info_free(f
);
2484 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2488 pa_proplist_free(p
);
2490 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
2493 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2494 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2497 pa_native_connection_assert_ref(c
);
2500 if (!pa_tagstruct_eof(t
)) {
2505 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2506 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2507 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2509 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2511 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2514 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2515 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2517 pa_tagstruct
*reply
;
2518 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2520 pa_native_connection_assert_ref(c
);
2523 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2524 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2525 !pa_tagstruct_eof(t
)) {
2530 /* Minimum supported version */
2531 if (c
->version
< 8) {
2532 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2536 /* Starting with protocol version 13 the MSB of the version tag
2537 reflects if shm is available for this pa_native_connection or
2539 if (c
->version
>= 13) {
2540 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2541 c
->version
&= 0x7FFFFFFFU
;
2544 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2546 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2548 if (!c
->authorized
) {
2549 pa_bool_t success
= FALSE
;
2552 const pa_creds
*creds
;
2554 if ((creds
= pa_pdispatch_creds(pd
))) {
2555 if (creds
->uid
== getuid())
2557 else if (c
->options
->auth_group
) {
2561 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2562 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2563 else if (gid
== creds
->gid
)
2567 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2568 pa_log_warn("Failed to check group membership.");
2574 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2575 (unsigned long) creds
->uid
,
2576 (unsigned long) creds
->gid
,
2581 if (!success
&& c
->options
->auth_cookie
) {
2584 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2585 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2590 pa_log_warn("Denied access to client with invalid authorization data.");
2591 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2595 c
->authorized
= TRUE
;
2596 if (c
->auth_timeout_event
) {
2597 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2598 c
->auth_timeout_event
= NULL
;
2602 /* Enable shared memory support if possible */
2604 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2607 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2610 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2615 /* Only enable SHM if both sides are owned by the same
2616 * user. This is a security measure because otherwise data
2617 * private to the user might leak. */
2619 const pa_creds
*creds
;
2620 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2625 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2626 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2628 reply
= reply_new(tag
);
2629 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2633 /* SHM support is only enabled after both sides made sure they are the same user. */
2637 ucred
.uid
= getuid();
2638 ucred
.gid
= getgid();
2640 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2643 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2647 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2648 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2649 const char *name
= NULL
;
2651 pa_tagstruct
*reply
;
2653 pa_native_connection_assert_ref(c
);
2656 p
= pa_proplist_new();
2658 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2659 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2660 !pa_tagstruct_eof(t
)) {
2663 pa_proplist_free(p
);
2668 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2669 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2670 pa_proplist_free(p
);
2674 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2675 pa_proplist_free(p
);
2677 reply
= reply_new(tag
);
2679 if (c
->version
>= 13)
2680 pa_tagstruct_putu32(reply
, c
->client
->index
);
2682 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2685 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2686 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2688 uint32_t idx
= PA_IDXSET_INVALID
;
2690 pa_native_connection_assert_ref(c
);
2693 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2694 !pa_tagstruct_eof(t
)) {
2699 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2700 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
);
2702 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2704 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2708 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2709 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2710 idx
= source
->index
;
2713 if (idx
== PA_IDXSET_INVALID
)
2714 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2716 pa_tagstruct
*reply
;
2717 reply
= reply_new(tag
);
2718 pa_tagstruct_putu32(reply
, idx
);
2719 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2723 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2724 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2728 pa_native_connection_assert_ref(c
);
2731 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2732 !pa_tagstruct_eof(t
)) {
2737 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2738 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2739 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2740 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2742 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
);
2745 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2746 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2747 pa_tagstruct
*reply
;
2748 const pa_mempool_stat
*stat
;
2750 pa_native_connection_assert_ref(c
);
2753 if (!pa_tagstruct_eof(t
)) {
2758 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2760 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2762 reply
= reply_new(tag
);
2763 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2764 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2765 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2766 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2767 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2768 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2771 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2772 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2773 pa_tagstruct
*reply
;
2775 struct timeval tv
, now
;
2778 pa_native_connection_assert_ref(c
);
2781 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2782 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2783 !pa_tagstruct_eof(t
)) {
2788 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2789 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2790 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2791 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2793 /* Get an atomic snapshot of all timing parameters */
2794 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);
2796 reply
= reply_new(tag
);
2797 pa_tagstruct_put_usec(reply
,
2798 s
->current_sink_latency
+
2799 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2800 pa_tagstruct_put_usec(reply
, 0);
2801 pa_tagstruct_put_boolean(reply
,
2802 s
->playing_for
> 0 &&
2803 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2804 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2805 pa_tagstruct_put_timeval(reply
, &tv
);
2806 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2807 pa_tagstruct_puts64(reply
, s
->write_index
);
2808 pa_tagstruct_puts64(reply
, s
->read_index
);
2810 if (c
->version
>= 13) {
2811 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2812 pa_tagstruct_putu64(reply
, s
->playing_for
);
2815 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2818 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2819 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2820 pa_tagstruct
*reply
;
2822 struct timeval tv
, now
;
2825 pa_native_connection_assert_ref(c
);
2828 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2829 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2830 !pa_tagstruct_eof(t
)) {
2835 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2836 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2837 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2839 /* Get an atomic snapshot of all timing parameters */
2840 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);
2842 reply
= reply_new(tag
);
2843 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2844 pa_tagstruct_put_usec(reply
,
2845 s
->current_source_latency
+
2846 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2847 pa_tagstruct_put_boolean(reply
,
2848 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2849 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2850 pa_tagstruct_put_timeval(reply
, &tv
);
2851 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2852 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2853 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2854 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2857 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2858 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2861 const char *name
= NULL
;
2864 pa_tagstruct
*reply
;
2867 pa_native_connection_assert_ref(c
);
2870 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2871 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2872 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2873 pa_tagstruct_getu32(t
, &length
) < 0) {
2878 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2879 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2880 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2881 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2882 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2883 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2885 p
= pa_proplist_new();
2887 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2888 !pa_tagstruct_eof(t
)) {
2891 pa_proplist_free(p
);
2895 if (c
->version
< 13)
2896 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2898 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2899 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2901 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2902 pa_proplist_free(p
);
2903 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2906 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2907 pa_proplist_free(p
);
2909 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2911 reply
= reply_new(tag
);
2912 pa_tagstruct_putu32(reply
, s
->index
);
2913 pa_tagstruct_putu32(reply
, length
);
2914 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2917 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2918 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2923 pa_native_connection_assert_ref(c
);
2926 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2927 !pa_tagstruct_eof(t
)) {
2932 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2934 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2935 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2936 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2938 if (!s
->memchunk
.memblock
)
2939 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
2940 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2941 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2943 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2945 upload_stream_unlink(s
);
2948 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2949 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2950 uint32_t sink_index
;
2953 const char *name
, *sink_name
;
2956 pa_tagstruct
*reply
;
2958 pa_native_connection_assert_ref(c
);
2961 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2963 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
2964 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
2965 pa_tagstruct_getu32(t
, &volume
) < 0 ||
2966 pa_tagstruct_gets(t
, &name
) < 0) {
2971 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
2972 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
2973 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2974 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2976 if (sink_index
!= PA_INVALID_INDEX
)
2977 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
2979 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
2981 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
2983 p
= pa_proplist_new();
2985 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2986 !pa_tagstruct_eof(t
)) {
2988 pa_proplist_free(p
);
2992 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
2994 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
2995 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2996 pa_proplist_free(p
);
3000 pa_proplist_free(p
);
3002 reply
= reply_new(tag
);
3004 if (c
->version
>= 13)
3005 pa_tagstruct_putu32(reply
, idx
);
3007 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3010 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3011 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3014 pa_native_connection_assert_ref(c
);
3017 if (pa_tagstruct_gets(t
, &name
) < 0 ||
3018 !pa_tagstruct_eof(t
)) {
3023 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3024 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3026 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
3027 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3031 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3034 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
3037 pa_assert(original
);
3041 if (c
->version
< 12) {
3042 /* Before protocol version 12 we didn't support S32 samples,
3043 * so we need to lie about this to the client */
3045 if (fixed
->format
== PA_SAMPLE_S32LE
)
3046 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3047 if (fixed
->format
== PA_SAMPLE_S32BE
)
3048 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3051 if (c
->version
< 15) {
3052 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
3053 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3054 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
3055 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3059 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
3060 pa_sample_spec fixed_ss
;
3063 pa_sink_assert_ref(sink
);
3065 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
3069 PA_TAG_U32
, sink
->index
,
3070 PA_TAG_STRING
, sink
->name
,
3071 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3072 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3073 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
3074 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
3075 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
3076 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
3077 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
3078 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
3079 PA_TAG_USEC
, pa_sink_get_latency(sink
),
3080 PA_TAG_STRING
, sink
->driver
,
3081 PA_TAG_U32
, sink
->flags
& PA_SINK_CLIENT_FLAGS_MASK
,
3084 if (c
->version
>= 13) {
3085 pa_tagstruct_put_proplist(t
, sink
->proplist
);
3086 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
3089 if (c
->version
>= 15) {
3090 pa_tagstruct_put_volume(t
, sink
->base_volume
);
3091 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
3092 pa_log_error("Internal sink state is invalid.");
3093 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
3094 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
3095 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
3098 if (c
->version
>= 16) {
3099 pa_tagstruct_putu32(t
, sink
->ports
? pa_hashmap_size(sink
->ports
) : 0);
3105 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
3106 pa_tagstruct_puts(t
, p
->name
);
3107 pa_tagstruct_puts(t
, p
->description
);
3108 pa_tagstruct_putu32(t
, p
->priority
);
3112 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
3115 if (c
->version
>= 21) {
3118 pa_idxset
*formats
= pa_sink_get_formats(sink
);
3120 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3121 PA_IDXSET_FOREACH(f
, formats
, i
) {
3122 pa_tagstruct_put_format_info(t
, f
);
3125 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3129 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
3130 pa_sample_spec fixed_ss
;
3133 pa_source_assert_ref(source
);
3135 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
3139 PA_TAG_U32
, source
->index
,
3140 PA_TAG_STRING
, source
->name
,
3141 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3142 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3143 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
3144 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
3145 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
3146 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
3147 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
3148 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
3149 PA_TAG_USEC
, pa_source_get_latency(source
),
3150 PA_TAG_STRING
, source
->driver
,
3151 PA_TAG_U32
, source
->flags
& PA_SOURCE_CLIENT_FLAGS_MASK
,
3154 if (c
->version
>= 13) {
3155 pa_tagstruct_put_proplist(t
, source
->proplist
);
3156 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
3159 if (c
->version
>= 15) {
3160 pa_tagstruct_put_volume(t
, source
->base_volume
);
3161 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
3162 pa_log_error("Internal source state is invalid.");
3163 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
3164 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
3165 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
3168 if (c
->version
>= 16) {
3170 pa_tagstruct_putu32(t
, source
->ports
? pa_hashmap_size(source
->ports
) : 0);
3172 if (source
->ports
) {
3176 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
3177 pa_tagstruct_puts(t
, p
->name
);
3178 pa_tagstruct_puts(t
, p
->description
);
3179 pa_tagstruct_putu32(t
, p
->priority
);
3183 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
3186 if (c
->version
>= 22) {
3189 pa_idxset
*formats
= pa_source_get_formats(source
);
3191 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3192 PA_IDXSET_FOREACH(f
, formats
, i
) {
3193 pa_tagstruct_put_format_info(t
, f
);
3196 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3200 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
3204 pa_tagstruct_putu32(t
, client
->index
);
3205 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
3206 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
3207 pa_tagstruct_puts(t
, client
->driver
);
3209 if (c
->version
>= 13)
3210 pa_tagstruct_put_proplist(t
, client
->proplist
);
3213 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
3220 pa_tagstruct_putu32(t
, card
->index
);
3221 pa_tagstruct_puts(t
, card
->name
);
3222 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
3223 pa_tagstruct_puts(t
, card
->driver
);
3225 pa_tagstruct_putu32(t
, card
->profiles
? pa_hashmap_size(card
->profiles
) : 0);
3227 if (card
->profiles
) {
3228 while ((p
= pa_hashmap_iterate(card
->profiles
, &state
, NULL
))) {
3229 pa_tagstruct_puts(t
, p
->name
);
3230 pa_tagstruct_puts(t
, p
->description
);
3231 pa_tagstruct_putu32(t
, p
->n_sinks
);
3232 pa_tagstruct_putu32(t
, p
->n_sources
);
3233 pa_tagstruct_putu32(t
, p
->priority
);
3237 pa_tagstruct_puts(t
, card
->active_profile
? card
->active_profile
->name
: NULL
);
3238 pa_tagstruct_put_proplist(t
, card
->proplist
);
3241 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3245 pa_tagstruct_putu32(t
, module
->index
);
3246 pa_tagstruct_puts(t
, module
->name
);
3247 pa_tagstruct_puts(t
, module
->argument
);
3248 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3250 if (c
->version
< 15)
3251 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
3253 if (c
->version
>= 15)
3254 pa_tagstruct_put_proplist(t
, module
->proplist
);
3257 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3258 pa_sample_spec fixed_ss
;
3259 pa_usec_t sink_latency
;
3261 pa_bool_t has_volume
= FALSE
;
3264 pa_sink_input_assert_ref(s
);
3266 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3268 has_volume
= pa_sink_input_is_volume_readable(s
);
3270 pa_sink_input_get_volume(s
, &v
, TRUE
);
3272 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3274 pa_tagstruct_putu32(t
, s
->index
);
3275 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3276 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3277 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3278 pa_tagstruct_putu32(t
, s
->sink
->index
);
3279 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3280 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3281 pa_tagstruct_put_cvolume(t
, &v
);
3282 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3283 pa_tagstruct_put_usec(t
, sink_latency
);
3284 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3285 pa_tagstruct_puts(t
, s
->driver
);
3286 if (c
->version
>= 11)
3287 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
3288 if (c
->version
>= 13)
3289 pa_tagstruct_put_proplist(t
, s
->proplist
);
3290 if (c
->version
>= 19)
3291 pa_tagstruct_put_boolean(t
, (pa_sink_input_get_state(s
) == PA_SINK_INPUT_CORKED
));
3292 if (c
->version
>= 20) {
3293 pa_tagstruct_put_boolean(t
, has_volume
);
3294 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3296 if (c
->version
>= 21)
3297 pa_tagstruct_put_format_info(t
, s
->format
);
3300 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3301 pa_sample_spec fixed_ss
;
3302 pa_usec_t source_latency
;
3304 pa_bool_t has_volume
= FALSE
;
3307 pa_source_output_assert_ref(s
);
3309 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3311 has_volume
= pa_source_output_is_volume_readable(s
);
3313 pa_source_output_get_volume(s
, &v
, TRUE
);
3315 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3317 pa_tagstruct_putu32(t
, s
->index
);
3318 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3319 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3320 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3321 pa_tagstruct_putu32(t
, s
->source
->index
);
3322 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3323 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3324 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3325 pa_tagstruct_put_usec(t
, source_latency
);
3326 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3327 pa_tagstruct_puts(t
, s
->driver
);
3328 if (c
->version
>= 13)
3329 pa_tagstruct_put_proplist(t
, s
->proplist
);
3330 if (c
->version
>= 19)
3331 pa_tagstruct_put_boolean(t
, (pa_source_output_get_state(s
) == PA_SOURCE_OUTPUT_CORKED
));
3332 if (c
->version
>= 22) {
3333 pa_tagstruct_put_cvolume(t
, &v
);
3334 pa_tagstruct_put_boolean(t
, pa_source_output_get_mute(s
));
3335 pa_tagstruct_put_boolean(t
, has_volume
);
3336 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3337 pa_tagstruct_put_format_info(t
, s
->format
);
3341 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3342 pa_sample_spec fixed_ss
;
3348 if (e
->memchunk
.memblock
)
3349 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3351 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3353 pa_tagstruct_putu32(t
, e
->index
);
3354 pa_tagstruct_puts(t
, e
->name
);
3356 if (e
->volume_is_set
)
3359 pa_cvolume_init(&v
);
3361 pa_tagstruct_put_cvolume(t
, &v
);
3362 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3363 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3364 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3365 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3366 pa_tagstruct_put_boolean(t
, e
->lazy
);
3367 pa_tagstruct_puts(t
, e
->filename
);
3369 if (c
->version
>= 13)
3370 pa_tagstruct_put_proplist(t
, e
->proplist
);
3373 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3374 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3376 pa_sink
*sink
= NULL
;
3377 pa_source
*source
= NULL
;
3378 pa_client
*client
= NULL
;
3379 pa_card
*card
= NULL
;
3380 pa_module
*module
= NULL
;
3381 pa_sink_input
*si
= NULL
;
3382 pa_source_output
*so
= NULL
;
3383 pa_scache_entry
*sce
= NULL
;
3384 const char *name
= NULL
;
3385 pa_tagstruct
*reply
;
3387 pa_native_connection_assert_ref(c
);
3390 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3391 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3392 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3393 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3394 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3395 pa_tagstruct_gets(t
, &name
) < 0) ||
3396 !pa_tagstruct_eof(t
)) {
3401 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3402 CHECK_VALIDITY(c
->pstream
, !name
||
3403 (command
== PA_COMMAND_GET_SINK_INFO
&&
3404 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3405 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3406 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3407 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3408 CHECK_VALIDITY(c
->pstream
, command
== PA_COMMAND_GET_SINK_INFO
||
3409 command
== PA_COMMAND_GET_SOURCE_INFO
||
3410 (idx
!= PA_INVALID_INDEX
|| name
), tag
, PA_ERR_INVALID
);
3411 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3412 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3414 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3415 if (idx
!= PA_INVALID_INDEX
)
3416 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3418 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3419 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3420 if (idx
!= PA_INVALID_INDEX
)
3421 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3423 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3424 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3425 if (idx
!= PA_INVALID_INDEX
)
3426 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3428 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3429 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3430 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3431 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3432 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3433 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3434 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3435 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3436 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3438 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3439 if (idx
!= PA_INVALID_INDEX
)
3440 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3442 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3445 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3446 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3450 reply
= reply_new(tag
);
3452 sink_fill_tagstruct(c
, reply
, sink
);
3454 source_fill_tagstruct(c
, reply
, source
);
3456 client_fill_tagstruct(c
, reply
, client
);
3458 card_fill_tagstruct(c
, reply
, card
);
3460 module_fill_tagstruct(c
, reply
, module
);
3462 sink_input_fill_tagstruct(c
, reply
, si
);
3464 source_output_fill_tagstruct(c
, reply
, so
);
3466 scache_fill_tagstruct(c
, reply
, sce
);
3467 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3470 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3471 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3475 pa_tagstruct
*reply
;
3477 pa_native_connection_assert_ref(c
);
3480 if (!pa_tagstruct_eof(t
)) {
3485 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3487 reply
= reply_new(tag
);
3489 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3490 i
= c
->protocol
->core
->sinks
;
3491 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3492 i
= c
->protocol
->core
->sources
;
3493 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3494 i
= c
->protocol
->core
->clients
;
3495 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3496 i
= c
->protocol
->core
->cards
;
3497 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3498 i
= c
->protocol
->core
->modules
;
3499 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3500 i
= c
->protocol
->core
->sink_inputs
;
3501 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3502 i
= c
->protocol
->core
->source_outputs
;
3504 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3505 i
= c
->protocol
->core
->scache
;
3509 for (p
= pa_idxset_first(i
, &idx
); p
; p
= pa_idxset_next(i
, &idx
)) {
3510 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3511 sink_fill_tagstruct(c
, reply
, p
);
3512 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3513 source_fill_tagstruct(c
, reply
, p
);
3514 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3515 client_fill_tagstruct(c
, reply
, p
);
3516 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3517 card_fill_tagstruct(c
, reply
, p
);
3518 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3519 module_fill_tagstruct(c
, reply
, p
);
3520 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3521 sink_input_fill_tagstruct(c
, reply
, p
);
3522 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3523 source_output_fill_tagstruct(c
, reply
, p
);
3525 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3526 scache_fill_tagstruct(c
, reply
, p
);
3531 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3534 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3535 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3536 pa_tagstruct
*reply
;
3538 pa_source
*def_source
;
3539 pa_sample_spec fixed_ss
;
3542 pa_native_connection_assert_ref(c
);
3545 if (!pa_tagstruct_eof(t
)) {
3550 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3552 reply
= reply_new(tag
);
3553 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3554 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3556 u
= pa_get_user_name_malloc();
3557 pa_tagstruct_puts(reply
, u
);
3560 h
= pa_get_host_name_malloc();
3561 pa_tagstruct_puts(reply
, h
);
3564 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3565 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3567 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3568 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3569 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3570 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3572 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3574 if (c
->version
>= 15)
3575 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3577 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3580 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3582 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3584 pa_native_connection_assert_ref(c
);
3586 t
= pa_tagstruct_new(NULL
, 0);
3587 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3588 pa_tagstruct_putu32(t
, (uint32_t) -1);
3589 pa_tagstruct_putu32(t
, e
);
3590 pa_tagstruct_putu32(t
, idx
);
3591 pa_pstream_send_tagstruct(c
->pstream
, t
);
3594 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3595 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3596 pa_subscription_mask_t m
;
3598 pa_native_connection_assert_ref(c
);
3601 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3602 !pa_tagstruct_eof(t
)) {
3607 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3608 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3610 if (c
->subscription
)
3611 pa_subscription_free(c
->subscription
);
3614 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3615 pa_assert(c
->subscription
);
3617 c
->subscription
= NULL
;
3619 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3622 static void command_set_volume(
3629 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3632 pa_sink
*sink
= NULL
;
3633 pa_source
*source
= NULL
;
3634 pa_sink_input
*si
= NULL
;
3635 pa_source_output
*so
= NULL
;
3636 const char *name
= NULL
;
3637 const char *client_name
;
3639 pa_native_connection_assert_ref(c
);
3642 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3643 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3644 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3645 pa_tagstruct_get_cvolume(t
, &volume
) ||
3646 !pa_tagstruct_eof(t
)) {
3651 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3652 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
);
3653 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3654 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3655 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3656 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3660 case PA_COMMAND_SET_SINK_VOLUME
:
3661 if (idx
!= PA_INVALID_INDEX
)
3662 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3664 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3667 case PA_COMMAND_SET_SOURCE_VOLUME
:
3668 if (idx
!= PA_INVALID_INDEX
)
3669 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3671 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3674 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3675 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3678 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
:
3679 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3683 pa_assert_not_reached();
3686 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3688 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3691 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3693 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3694 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3695 } else if (source
) {
3696 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3698 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3699 pa_source_set_volume(source
, &volume
, TRUE
, TRUE
);
3701 CHECK_VALIDITY(c
->pstream
, si
->volume_writable
, tag
, PA_ERR_BADSTATE
);
3702 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3704 pa_log_debug("Client %s changes volume of sink input %s.",
3706 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3707 pa_sink_input_set_volume(si
, &volume
, TRUE
, TRUE
);
3709 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &so
->sample_spec
), tag
, PA_ERR_INVALID
);
3711 pa_log_debug("Client %s changes volume of source output %s.",
3713 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3714 pa_source_output_set_volume(so
, &volume
, TRUE
, TRUE
);
3717 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3720 static void command_set_mute(
3727 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3730 pa_sink
*sink
= NULL
;
3731 pa_source
*source
= NULL
;
3732 pa_sink_input
*si
= NULL
;
3733 pa_source_output
*so
= NULL
;
3734 const char *name
= NULL
, *client_name
;
3736 pa_native_connection_assert_ref(c
);
3739 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3740 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3741 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3742 pa_tagstruct_get_boolean(t
, &mute
) ||
3743 !pa_tagstruct_eof(t
)) {
3748 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3749 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
);
3750 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3751 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3752 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3756 case PA_COMMAND_SET_SINK_MUTE
:
3757 if (idx
!= PA_INVALID_INDEX
)
3758 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3760 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3764 case PA_COMMAND_SET_SOURCE_MUTE
:
3765 if (idx
!= PA_INVALID_INDEX
)
3766 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3768 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3772 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3773 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3776 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
:
3777 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3781 pa_assert_not_reached();
3784 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3786 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3789 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3790 pa_sink_set_mute(sink
, mute
, TRUE
);
3791 } else if (source
) {
3792 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3793 pa_source_set_mute(source
, mute
, TRUE
);
3795 pa_log_debug("Client %s changes mute of sink input %s.",
3797 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3798 pa_sink_input_set_mute(si
, mute
, TRUE
);
3800 pa_log_debug("Client %s changes mute of source output %s.",
3802 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3803 pa_source_output_set_mute(so
, mute
, TRUE
);
3806 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3809 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3810 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3815 pa_native_connection_assert_ref(c
);
3818 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3819 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3820 !pa_tagstruct_eof(t
)) {
3825 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3826 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3827 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3828 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3829 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3831 pa_sink_input_cork(s
->sink_input
, b
);
3834 s
->is_underrun
= TRUE
;
3836 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3839 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3840 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3844 pa_native_connection_assert_ref(c
);
3847 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3848 !pa_tagstruct_eof(t
)) {
3853 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3854 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3855 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3856 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3857 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3860 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3861 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3864 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3865 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3868 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3869 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3873 pa_assert_not_reached();
3876 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3879 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3880 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3885 pa_native_connection_assert_ref(c
);
3888 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3889 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3890 !pa_tagstruct_eof(t
)) {
3895 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3896 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3897 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3899 pa_source_output_cork(s
->source_output
, b
);
3900 pa_memblockq_prebuf_force(s
->memblockq
);
3901 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3904 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3905 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3909 pa_native_connection_assert_ref(c
);
3912 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3913 !pa_tagstruct_eof(t
)) {
3918 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3919 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3920 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3922 pa_memblockq_flush_read(s
->memblockq
);
3923 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3926 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3927 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3930 pa_tagstruct
*reply
;
3932 pa_native_connection_assert_ref(c
);
3935 memset(&a
, 0, sizeof(a
));
3937 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3942 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3944 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
3946 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3948 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3949 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3950 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3952 if (pa_tagstruct_get(
3954 PA_TAG_U32
, &a
.maxlength
,
3955 PA_TAG_U32
, &a
.tlength
,
3956 PA_TAG_U32
, &a
.prebuf
,
3957 PA_TAG_U32
, &a
.minreq
,
3958 PA_TAG_INVALID
) < 0 ||
3959 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3960 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3961 !pa_tagstruct_eof(t
)) {
3966 s
->adjust_latency
= adjust_latency
;
3967 s
->early_requests
= early_requests
;
3968 s
->buffer_attr_req
= a
;
3970 fix_playback_buffer_attr(s
);
3971 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);
3973 reply
= reply_new(tag
);
3974 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3975 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
3976 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
3977 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
3979 if (c
->version
>= 13)
3980 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
3984 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3985 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
3987 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3988 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3990 if (pa_tagstruct_get(
3992 PA_TAG_U32
, &a
.maxlength
,
3993 PA_TAG_U32
, &a
.fragsize
,
3994 PA_TAG_INVALID
) < 0 ||
3995 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3996 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3997 !pa_tagstruct_eof(t
)) {
4002 s
->adjust_latency
= adjust_latency
;
4003 s
->early_requests
= early_requests
;
4004 s
->buffer_attr_req
= a
;
4006 fix_record_buffer_attr_pre(s
);
4007 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
4008 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
4009 fix_record_buffer_attr_post(s
);
4011 reply
= reply_new(tag
);
4012 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
4013 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
4015 if (c
->version
>= 13)
4016 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
4019 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4022 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4023 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4027 pa_native_connection_assert_ref(c
);
4030 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4031 pa_tagstruct_getu32(t
, &rate
) < 0 ||
4032 !pa_tagstruct_eof(t
)) {
4037 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4038 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
4040 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
4043 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4044 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4045 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4047 pa_sink_input_set_rate(s
->sink_input
, rate
);
4051 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
4053 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4054 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4056 pa_source_output_set_rate(s
->source_output
, rate
);
4059 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4062 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4063 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4068 pa_native_connection_assert_ref(c
);
4071 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4073 p
= pa_proplist_new();
4075 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
4077 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
4078 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4079 !pa_tagstruct_eof(t
)) {
4081 pa_proplist_free(p
);
4087 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4088 pa_tagstruct_getu32(t
, &mode
) < 0 ||
4089 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4090 !pa_tagstruct_eof(t
)) {
4092 pa_proplist_free(p
);
4097 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
4098 pa_proplist_free(p
);
4099 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
4102 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
4105 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4106 if (!s
|| !playback_stream_isinstance(s
)) {
4107 pa_proplist_free(p
);
4108 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4110 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
4112 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
4115 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
4116 pa_proplist_free(p
);
4117 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4119 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
4122 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
4124 pa_client_update_proplist(c
->client
, mode
, p
);
4127 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4128 pa_proplist_free(p
);
4131 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4132 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4134 unsigned changed
= 0;
4136 pa_strlist
*l
= NULL
;
4138 pa_native_connection_assert_ref(c
);
4141 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4143 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
4145 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
4151 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4154 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4155 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4156 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4158 p
= s
->sink_input
->proplist
;
4160 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4163 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4164 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4166 p
= s
->source_output
->proplist
;
4168 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4170 p
= c
->client
->proplist
;
4176 if (pa_tagstruct_gets(t
, &k
) < 0) {
4185 l
= pa_strlist_prepend(l
, k
);
4188 if (!pa_tagstruct_eof(t
)) {
4197 l
= pa_strlist_pop(l
, &z
);
4202 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
4206 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4209 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4212 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4213 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
4215 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4218 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4219 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
4222 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4223 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
4228 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4229 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4232 pa_native_connection_assert_ref(c
);
4235 if (pa_tagstruct_gets(t
, &s
) < 0 ||
4236 !pa_tagstruct_eof(t
)) {
4241 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4242 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
4244 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
4247 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
4248 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4250 pa_namereg_set_default_source(c
->protocol
->core
, source
);
4253 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
4255 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
4256 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4258 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
4261 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4264 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4265 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4269 pa_native_connection_assert_ref(c
);
4272 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4273 pa_tagstruct_gets(t
, &name
) < 0 ||
4274 !pa_tagstruct_eof(t
)) {
4279 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4280 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4282 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
4285 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4286 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4287 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4289 pa_sink_input_set_name(s
->sink_input
, name
);
4293 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4295 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4296 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4298 pa_source_output_set_name(s
->source_output
, name
);
4301 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4304 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4305 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4308 pa_native_connection_assert_ref(c
);
4311 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4312 !pa_tagstruct_eof(t
)) {
4317 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4319 if (command
== PA_COMMAND_KILL_CLIENT
) {
4322 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4323 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4325 pa_native_connection_ref(c
);
4326 pa_client_kill(client
);
4328 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4331 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4332 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4334 pa_native_connection_ref(c
);
4335 pa_sink_input_kill(s
);
4337 pa_source_output
*s
;
4339 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4341 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4342 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4344 pa_native_connection_ref(c
);
4345 pa_source_output_kill(s
);
4348 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4349 pa_native_connection_unref(c
);
4352 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4353 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4355 const char *name
, *argument
;
4356 pa_tagstruct
*reply
;
4358 pa_native_connection_assert_ref(c
);
4361 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4362 pa_tagstruct_gets(t
, &argument
) < 0 ||
4363 !pa_tagstruct_eof(t
)) {
4368 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4369 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4370 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4372 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4373 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4377 reply
= reply_new(tag
);
4378 pa_tagstruct_putu32(reply
, m
->index
);
4379 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4382 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4383 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4387 pa_native_connection_assert_ref(c
);
4390 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4391 !pa_tagstruct_eof(t
)) {
4396 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4397 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4398 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4400 pa_module_unload_request(m
, FALSE
);
4401 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4404 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4405 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4406 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4407 const char *name_device
= NULL
;
4409 pa_native_connection_assert_ref(c
);
4412 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4413 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4414 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4415 !pa_tagstruct_eof(t
)) {
4420 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4421 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4423 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
);
4424 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4425 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4426 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4428 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4429 pa_sink_input
*si
= NULL
;
4430 pa_sink
*sink
= NULL
;
4432 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4434 if (idx_device
!= PA_INVALID_INDEX
)
4435 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4437 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4439 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4441 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4442 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4446 pa_source_output
*so
= NULL
;
4449 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4451 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4453 if (idx_device
!= PA_INVALID_INDEX
)
4454 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4456 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4458 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4460 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4461 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4466 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4469 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4470 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4471 uint32_t idx
= PA_INVALID_INDEX
;
4472 const char *name
= NULL
;
4475 pa_native_connection_assert_ref(c
);
4478 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4479 pa_tagstruct_gets(t
, &name
) < 0 ||
4480 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4481 !pa_tagstruct_eof(t
)) {
4486 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4487 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
);
4488 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4489 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4490 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4492 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4494 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4496 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4498 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4499 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4503 pa_sink
*sink
= NULL
;
4505 if (idx
!= PA_INVALID_INDEX
)
4506 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4508 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4510 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4512 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4513 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4519 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4521 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4523 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4525 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4526 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4533 if (idx
!= PA_INVALID_INDEX
)
4534 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4536 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4538 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4540 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4541 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4547 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4550 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4551 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4552 uint32_t idx
= PA_INVALID_INDEX
;
4553 const char *name
= NULL
;
4555 pa_native_protocol_ext_cb_t cb
;
4557 pa_native_connection_assert_ref(c
);
4560 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4561 pa_tagstruct_gets(t
, &name
) < 0) {
4566 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4567 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4568 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4569 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4570 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4572 if (idx
!= PA_INVALID_INDEX
)
4573 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4575 for (m
= pa_idxset_first(c
->protocol
->core
->modules
, &idx
); m
; m
= pa_idxset_next(c
->protocol
->core
->modules
, &idx
))
4576 if (strcmp(name
, m
->name
) == 0)
4580 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4581 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4583 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4584 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4586 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4590 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4591 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4592 uint32_t idx
= PA_INVALID_INDEX
;
4593 const char *name
= NULL
, *profile
= NULL
;
4594 pa_card
*card
= NULL
;
4597 pa_native_connection_assert_ref(c
);
4600 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4601 pa_tagstruct_gets(t
, &name
) < 0 ||
4602 pa_tagstruct_gets(t
, &profile
) < 0 ||
4603 !pa_tagstruct_eof(t
)) {
4608 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4609 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4610 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4611 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4612 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4614 if (idx
!= PA_INVALID_INDEX
)
4615 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4617 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4619 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4621 if ((ret
= pa_card_set_profile(card
, profile
, TRUE
)) < 0) {
4622 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4626 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4629 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4630 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4631 uint32_t idx
= PA_INVALID_INDEX
;
4632 const char *name
= NULL
, *port
= NULL
;
4635 pa_native_connection_assert_ref(c
);
4638 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4639 pa_tagstruct_gets(t
, &name
) < 0 ||
4640 pa_tagstruct_gets(t
, &port
) < 0 ||
4641 !pa_tagstruct_eof(t
)) {
4646 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4647 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
);
4648 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4649 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4650 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4652 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4655 if (idx
!= PA_INVALID_INDEX
)
4656 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4658 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4660 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4662 if ((ret
= pa_sink_set_port(sink
, port
, TRUE
)) < 0) {
4663 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4669 pa_assert(command
= PA_COMMAND_SET_SOURCE_PORT
);
4671 if (idx
!= PA_INVALID_INDEX
)
4672 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4674 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4676 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4678 if ((ret
= pa_source_set_port(source
, port
, TRUE
)) < 0) {
4679 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4684 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4687 /*** pstream callbacks ***/
4689 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4690 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4694 pa_native_connection_assert_ref(c
);
4696 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4697 pa_log("invalid packet.");
4698 native_connection_unlink(c
);
4702 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
) {
4703 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4704 output_stream
*stream
;
4708 pa_native_connection_assert_ref(c
);
4710 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4711 pa_log_debug("Client sent block for invalid stream.");
4716 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4718 if (playback_stream_isinstance(stream
)) {
4719 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4721 pa_atomic_inc(&ps
->seek_or_post_in_queue
);
4722 if (chunk
->memblock
) {
4723 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4724 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
);
4726 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4728 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
);
4731 upload_stream
*u
= UPLOAD_STREAM(stream
);
4734 if (!u
->memchunk
.memblock
) {
4735 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4736 u
->memchunk
= *chunk
;
4737 pa_memblock_ref(u
->memchunk
.memblock
);
4740 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4741 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4745 pa_assert(u
->memchunk
.memblock
);
4748 if (l
> chunk
->length
)
4753 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4755 if (chunk
->memblock
) {
4757 src
= pa_memblock_acquire(chunk
->memblock
);
4759 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4760 (uint8_t*) src
+ chunk
->index
, l
);
4762 pa_memblock_release(chunk
->memblock
);
4764 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4766 pa_memblock_release(u
->memchunk
.memblock
);
4768 u
->memchunk
.length
+= l
;
4774 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4775 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4778 pa_native_connection_assert_ref(c
);
4780 native_connection_unlink(c
);
4781 pa_log_info("Connection died.");
4784 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4785 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4788 pa_native_connection_assert_ref(c
);
4790 native_connection_send_memblock(c
);
4793 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4796 if (!(q
= pa_thread_mq_get()))
4797 pa_pstream_send_revoke(p
, block_id
);
4799 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4802 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4805 if (!(q
= pa_thread_mq_get()))
4806 pa_pstream_send_release(p
, block_id
);
4808 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4811 /*** client callbacks ***/
4813 static void client_kill_cb(pa_client
*c
) {
4816 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4817 pa_log_info("Connection killed.");
4820 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4822 pa_native_connection
*c
;
4825 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4826 pa_native_connection_assert_ref(c
);
4828 if (c
->version
< 15)
4831 t
= pa_tagstruct_new(NULL
, 0);
4832 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4833 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4834 pa_tagstruct_puts(t
, event
);
4835 pa_tagstruct_put_proplist(t
, pl
);
4836 pa_pstream_send_tagstruct(c
->pstream
, t
);
4839 /*** module entry points ***/
4841 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4842 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4845 pa_native_connection_assert_ref(c
);
4846 pa_assert(c
->auth_timeout_event
== e
);
4848 if (!c
->authorized
) {
4849 native_connection_unlink(c
);
4850 pa_log_info("Connection terminated due to authentication timeout.");
4854 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4855 pa_native_connection
*c
;
4858 pa_client_new_data data
;
4864 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4865 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4866 pa_iochannel_free(io
);
4870 pa_client_new_data_init(&data
);
4871 data
.module
= o
->module
;
4872 data
.driver
= __FILE__
;
4873 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4874 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4875 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4876 client
= pa_client_new(p
->core
, &data
);
4877 pa_client_new_data_done(&data
);
4882 c
= pa_msgobject_new(pa_native_connection
);
4883 c
->parent
.parent
.free
= native_connection_free
;
4884 c
->parent
.process_msg
= native_connection_process_msg
;
4886 c
->options
= pa_native_options_ref(o
);
4887 c
->authorized
= FALSE
;
4889 if (o
->auth_anonymous
) {
4890 pa_log_info("Client authenticated anonymously.");
4891 c
->authorized
= TRUE
;
4894 if (!c
->authorized
&&
4896 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
4898 pa_log_info("Client authenticated by IP ACL.");
4899 c
->authorized
= TRUE
;
4903 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
4905 c
->auth_timeout_event
= NULL
;
4907 c
->is_local
= pa_iochannel_socket_is_local(io
);
4911 c
->client
->kill
= client_kill_cb
;
4912 c
->client
->send_event
= client_send_event_cb
;
4913 c
->client
->userdata
= c
;
4915 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
4916 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
4917 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
4918 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
4919 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
4920 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
4921 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
4923 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, TRUE
, command_table
, PA_COMMAND_MAX
);
4925 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
4926 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
4928 c
->rrobin_index
= PA_IDXSET_INVALID
;
4929 c
->subscription
= NULL
;
4931 pa_idxset_put(p
->connections
, c
, NULL
);
4934 if (pa_iochannel_creds_supported(io
))
4935 pa_iochannel_creds_enable(io
);
4938 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
4941 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
4942 pa_native_connection
*c
;
4948 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
4949 if (c
->options
->module
== m
)
4950 native_connection_unlink(c
);
4953 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
4954 pa_native_protocol
*p
;
4959 p
= pa_xnew(pa_native_protocol
, 1);
4962 p
->connections
= pa_idxset_new(NULL
, NULL
);
4966 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
4968 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4969 pa_hook_init(&p
->hooks
[h
], p
);
4971 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
4976 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
4977 pa_native_protocol
*p
;
4979 if ((p
= pa_shared_get(c
, "native-protocol")))
4980 return pa_native_protocol_ref(p
);
4982 return native_protocol_new(c
);
4985 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
4987 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4994 void pa_native_protocol_unref(pa_native_protocol
*p
) {
4995 pa_native_connection
*c
;
4999 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5001 if (PA_REFCNT_DEC(p
) > 0)
5004 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
5005 native_connection_unlink(c
);
5007 pa_idxset_free(p
->connections
, NULL
, NULL
);
5009 pa_strlist_free(p
->servers
);
5011 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
5012 pa_hook_done(&p
->hooks
[h
]);
5014 pa_hashmap_free(p
->extensions
, NULL
, NULL
);
5016 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
5021 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
5023 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5026 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
5028 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5031 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
5033 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5036 p
->servers
= pa_strlist_remove(p
->servers
, name
);
5038 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5041 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
5043 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5048 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
5050 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5055 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
5057 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5060 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
5062 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
5066 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
5068 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5071 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
5074 pa_native_options
* pa_native_options_new(void) {
5075 pa_native_options
*o
;
5077 o
= pa_xnew0(pa_native_options
, 1);
5083 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
5085 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5092 void pa_native_options_unref(pa_native_options
*o
) {
5094 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5096 if (PA_REFCNT_DEC(o
) > 0)
5099 pa_xfree(o
->auth_group
);
5102 pa_ip_acl_free(o
->auth_ip_acl
);
5105 pa_auth_cookie_unref(o
->auth_cookie
);
5110 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
5115 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5118 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
5119 pa_log("auth-anonymous= expects a boolean argument.");
5124 if (pa_modargs_get_value_boolean(ma
, "auth-group-enabled", &enabled
) < 0) {
5125 pa_log("auth-group-enabled= expects a boolean argument.");
5129 pa_xfree(o
->auth_group
);
5130 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
5134 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5137 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
5140 if (!(ipa
= pa_ip_acl_new(acl
))) {
5141 pa_log("Failed to parse IP ACL '%s'", acl
);
5146 pa_ip_acl_free(o
->auth_ip_acl
);
5148 o
->auth_ip_acl
= ipa
;
5152 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
5153 pa_log("auth-cookie-enabled= expects a boolean argument.");
5158 pa_auth_cookie_unref(o
->auth_cookie
);
5163 /* The new name for this is 'auth-cookie', for compat reasons
5164 * we check the old name too */
5165 if (!(cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
)))
5166 if (!(cn
= pa_modargs_get_value(ma
, "cookie", NULL
)))
5167 cn
= PA_NATIVE_COOKIE_FILE
;
5169 if (!(o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, PA_NATIVE_COOKIE_LENGTH
)))
5173 o
->auth_cookie
= NULL
;
5178 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
5179 pa_native_connection_assert_ref(c
);
5184 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
5185 pa_native_connection_assert_ref(c
);