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 /* FIXME: This is actually larger than necessary, since not all of
1012 * the sink latency is actually rewritable. */
1013 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
1014 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
1016 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
1017 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
1018 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
1020 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
1021 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
1022 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
1024 if (s
->buffer_attr
.minreq
<= 0) {
1025 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
1026 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
1029 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
1030 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
1032 max_prebuf
= s
->buffer_attr
.tlength
+ (uint32_t)frame_size
- s
->buffer_attr
.minreq
;
1034 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 ||
1035 s
->buffer_attr
.prebuf
> max_prebuf
)
1036 s
->buffer_attr
.prebuf
= max_prebuf
;
1038 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1039 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1040 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1041 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1042 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1045 /* Called from main context */
1046 static playback_stream
* playback_stream_new(
1047 pa_native_connection
*c
,
1050 pa_channel_map
*map
,
1055 pa_bool_t muted_set
,
1056 pa_sink_input_flags_t flags
,
1058 pa_bool_t adjust_latency
,
1059 pa_bool_t early_requests
,
1060 pa_bool_t relative_volume
,
1065 /* Note: This function takes ownership of the 'formats' param, so we need
1066 * to take extra care to not leak it */
1068 playback_stream
*ssync
;
1069 playback_stream
*s
= NULL
;
1070 pa_sink_input
*sink_input
= NULL
;
1071 pa_memchunk silence
;
1073 int64_t start_index
;
1074 pa_sink_input_new_data data
;
1075 char *memblockq_name
;
1083 /* Find syncid group */
1084 PA_IDXSET_FOREACH(ssync
, c
->output_streams
, idx
) {
1086 if (!playback_stream_isinstance(ssync
))
1089 if (ssync
->syncid
== syncid
)
1093 /* Synced streams must connect to the same sink */
1097 sink
= ssync
->sink_input
->sink
;
1098 else if (sink
!= ssync
->sink_input
->sink
) {
1099 *ret
= PA_ERR_INVALID
;
1104 pa_sink_input_new_data_init(&data
);
1106 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1107 data
.driver
= __FILE__
;
1108 data
.module
= c
->options
->module
;
1109 data
.client
= c
->client
;
1111 pa_sink_input_new_data_set_sink(&data
, sink
, TRUE
);
1112 if (pa_sample_spec_valid(ss
))
1113 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1114 if (pa_channel_map_valid(map
))
1115 pa_sink_input_new_data_set_channel_map(&data
, map
);
1117 pa_sink_input_new_data_set_formats(&data
, formats
);
1118 /* Ownership transferred to new_data, so we don't free it ourselves */
1122 pa_sink_input_new_data_set_volume(&data
, volume
);
1123 data
.volume_is_absolute
= !relative_volume
;
1124 data
.save_volume
= TRUE
;
1127 pa_sink_input_new_data_set_muted(&data
, muted
);
1128 data
.save_muted
= TRUE
;
1130 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1133 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
);
1135 pa_sink_input_new_data_done(&data
);
1140 s
= pa_msgobject_new(playback_stream
);
1141 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1142 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1145 s
->sink_input
= sink_input
;
1146 s
->is_underrun
= TRUE
;
1147 s
->drain_request
= FALSE
;
1148 pa_atomic_store(&s
->missing
, 0);
1149 s
->buffer_attr_req
= *a
;
1150 s
->adjust_latency
= adjust_latency
;
1151 s
->early_requests
= early_requests
;
1152 pa_atomic_store(&s
->seek_or_post_in_queue
, 0);
1153 s
->seek_windex
= -1;
1155 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1156 s
->sink_input
->pop
= sink_input_pop_cb
;
1157 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1158 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1159 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1160 s
->sink_input
->kill
= sink_input_kill_cb
;
1161 s
->sink_input
->moving
= sink_input_moving_cb
;
1162 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1163 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1164 s
->sink_input
->userdata
= s
;
1166 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1168 fix_playback_buffer_attr(s
);
1170 pa_sink_input_get_silence(sink_input
, &silence
);
1171 memblockq_name
= pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s
->sink_input
->index
);
1172 s
->memblockq
= pa_memblockq_new(
1175 s
->buffer_attr
.maxlength
,
1176 s
->buffer_attr
.tlength
,
1177 &sink_input
->sample_spec
,
1178 s
->buffer_attr
.prebuf
,
1179 s
->buffer_attr
.minreq
,
1182 pa_xfree(memblockq_name
);
1183 pa_memblock_unref(silence
.memblock
);
1185 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1187 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1189 /* pa_log("missing original: %li", (long int) *missing); */
1191 *ss
= s
->sink_input
->sample_spec
;
1192 *map
= s
->sink_input
->channel_map
;
1194 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1196 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1197 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1198 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1199 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1200 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1202 pa_sink_input_put(s
->sink_input
);
1206 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
1211 /* Called from IO context */
1212 static void playback_stream_request_bytes(playback_stream
*s
) {
1214 int previous_missing
;
1216 playback_stream_assert_ref(s
);
1218 m
= pa_memblockq_pop_missing(s
->memblockq
);
1220 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1221 /* (unsigned long) m, */
1222 /* pa_memblockq_get_tlength(s->memblockq), */
1223 /* pa_memblockq_get_minreq(s->memblockq), */
1224 /* pa_memblockq_get_length(s->memblockq), */
1225 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1230 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1232 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1233 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1235 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1236 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1237 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1240 /* Called from main context */
1241 static void playback_stream_send_killed(playback_stream
*p
) {
1243 playback_stream_assert_ref(p
);
1245 t
= pa_tagstruct_new(NULL
, 0);
1246 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1247 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1248 pa_tagstruct_putu32(t
, p
->index
);
1249 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1252 /* Called from main context */
1253 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1254 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1255 pa_native_connection_assert_ref(c
);
1262 case CONNECTION_MESSAGE_REVOKE
:
1263 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1266 case CONNECTION_MESSAGE_RELEASE
:
1267 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1274 /* Called from main context */
1275 static void native_connection_unlink(pa_native_connection
*c
) {
1284 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1287 pa_native_options_unref(c
->options
);
1289 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1290 record_stream_unlink(r
);
1292 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1293 if (playback_stream_isinstance(o
))
1294 playback_stream_unlink(PLAYBACK_STREAM(o
));
1296 upload_stream_unlink(UPLOAD_STREAM(o
));
1298 if (c
->subscription
)
1299 pa_subscription_free(c
->subscription
);
1302 pa_pstream_unlink(c
->pstream
);
1304 if (c
->auth_timeout_event
) {
1305 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1306 c
->auth_timeout_event
= NULL
;
1309 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1311 pa_native_connection_unref(c
);
1314 /* Called from main context */
1315 static void native_connection_free(pa_object
*o
) {
1316 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1320 native_connection_unlink(c
);
1322 pa_idxset_free(c
->record_streams
, NULL
, NULL
);
1323 pa_idxset_free(c
->output_streams
, NULL
, NULL
);
1325 pa_pdispatch_unref(c
->pdispatch
);
1326 pa_pstream_unref(c
->pstream
);
1327 pa_client_free(c
->client
);
1332 /* Called from main context */
1333 static void native_connection_send_memblock(pa_native_connection
*c
) {
1337 start
= PA_IDXSET_INVALID
;
1341 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1344 if (start
== PA_IDXSET_INVALID
)
1345 start
= c
->rrobin_index
;
1346 else if (start
== c
->rrobin_index
)
1349 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1350 pa_memchunk schunk
= chunk
;
1352 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1353 schunk
.length
= r
->buffer_attr
.fragsize
;
1355 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1357 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1358 pa_memblock_unref(schunk
.memblock
);
1365 /*** sink input callbacks ***/
1367 /* Called from thread context */
1368 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1369 playback_stream_assert_ref(s
);
1371 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1373 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1375 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1377 if (pa_memblockq_is_readable(s
->memblockq
)) {
1379 /* We just ended an underrun, let's ask the sink
1380 * for a complete rewind rewrite */
1382 pa_log_debug("Requesting rewind due to end of underrun.");
1383 pa_sink_input_request_rewind(s
->sink_input
,
1384 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (uint64_t) -1 ? 0 :
1385 s
->sink_input
->thread_info
.underrun_for
),
1386 FALSE
, TRUE
, FALSE
);
1392 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1394 if (indexw
< indexr
) {
1395 /* OK, the sink already asked for this data, so
1396 * let's have it ask us again */
1398 pa_log_debug("Requesting rewind due to rewrite.");
1399 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), TRUE
, FALSE
, FALSE
);
1403 playback_stream_request_bytes(s
);
1406 static void flush_write_no_account(pa_memblockq
*q
) {
1407 pa_memblockq_flush_write(q
, FALSE
);
1410 /* Called from thread context */
1411 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1412 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1415 pa_sink_input_assert_ref(i
);
1416 s
= PLAYBACK_STREAM(i
->userdata
);
1417 playback_stream_assert_ref(s
);
1421 case SINK_INPUT_MESSAGE_SEEK
:
1422 case SINK_INPUT_MESSAGE_POST_DATA
: {
1423 int64_t windex
= pa_memblockq_get_write_index(s
->memblockq
);
1425 if (code
== SINK_INPUT_MESSAGE_SEEK
) {
1426 /* The client side is incapable of accounting correctly
1427 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1428 * able to deal with that. */
1430 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1431 windex
= PA_MIN(windex
, pa_memblockq_get_write_index(s
->memblockq
));
1434 if (chunk
&& pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1435 if (pa_log_ratelimit(PA_LOG_WARN
))
1436 pa_log_warn("Failed to push data into queue");
1437 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1438 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, TRUE
);
1441 /* If more data is in queue, we rewind later instead. */
1442 if (s
->seek_windex
!= -1)
1443 windex
= PA_MIN(windex
, s
->seek_windex
);
1444 if (pa_atomic_dec(&s
->seek_or_post_in_queue
) > 1)
1445 s
->seek_windex
= windex
;
1447 s
->seek_windex
= -1;
1448 handle_seek(s
, windex
);
1453 case SINK_INPUT_MESSAGE_DRAIN
:
1454 case SINK_INPUT_MESSAGE_FLUSH
:
1455 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1456 case SINK_INPUT_MESSAGE_TRIGGER
: {
1459 pa_sink_input
*isync
;
1460 void (*func
)(pa_memblockq
*bq
);
1463 case SINK_INPUT_MESSAGE_FLUSH
:
1464 func
= flush_write_no_account
;
1467 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1468 func
= pa_memblockq_prebuf_force
;
1471 case SINK_INPUT_MESSAGE_DRAIN
:
1472 case SINK_INPUT_MESSAGE_TRIGGER
:
1473 func
= pa_memblockq_prebuf_disable
;
1477 pa_assert_not_reached();
1480 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1482 handle_seek(s
, windex
);
1484 /* Do the same for all other members in the sync group */
1485 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1486 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1487 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1488 func(ssync
->memblockq
);
1489 handle_seek(ssync
, windex
);
1492 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1493 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1494 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1495 func(ssync
->memblockq
);
1496 handle_seek(ssync
, windex
);
1499 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1500 if (!pa_memblockq_is_readable(s
->memblockq
))
1501 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1503 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1504 s
->drain_request
= TRUE
;
1511 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1512 /* Atomically get a snapshot of all timing parameters... */
1513 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1514 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1515 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1516 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1517 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1518 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1522 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1525 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1527 pa_memblockq_prebuf_force(s
->memblockq
);
1529 handle_seek(s
, windex
);
1531 /* Fall through to the default handler */
1535 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1536 pa_usec_t
*r
= userdata
;
1538 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1540 /* Fall through, the default handler will add in the extra
1541 * latency added by the resampler */
1545 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1546 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1547 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1552 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1555 /* Called from thread context */
1556 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1559 pa_sink_input_assert_ref(i
);
1560 s
= PLAYBACK_STREAM(i
->userdata
);
1561 playback_stream_assert_ref(s
);
1564 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1566 if (pa_memblockq_is_readable(s
->memblockq
))
1567 s
->is_underrun
= FALSE
;
1569 if (!s
->is_underrun
)
1570 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
));
1572 if (s
->drain_request
&& pa_sink_input_safe_to_remove(i
)) {
1573 s
->drain_request
= FALSE
;
1574 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
);
1575 } else if (!s
->is_underrun
)
1576 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
);
1578 s
->is_underrun
= TRUE
;
1580 playback_stream_request_bytes(s
);
1583 /* This call will not fail with prebuf=0, hence we check for
1584 underrun explicitly above */
1585 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1588 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1590 if (i
->thread_info
.underrun_for
> 0)
1591 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1593 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1594 playback_stream_request_bytes(s
);
1599 /* Called from thread context */
1600 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1603 pa_sink_input_assert_ref(i
);
1604 s
= PLAYBACK_STREAM(i
->userdata
);
1605 playback_stream_assert_ref(s
);
1607 /* If we are in an underrun, then we don't rewind */
1608 if (i
->thread_info
.underrun_for
> 0)
1611 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1614 /* Called from thread context */
1615 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1618 pa_sink_input_assert_ref(i
);
1619 s
= PLAYBACK_STREAM(i
->userdata
);
1620 playback_stream_assert_ref(s
);
1622 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1625 /* Called from thread context */
1626 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1628 size_t new_tlength
, old_tlength
;
1630 pa_sink_input_assert_ref(i
);
1631 s
= PLAYBACK_STREAM(i
->userdata
);
1632 playback_stream_assert_ref(s
);
1634 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1635 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1637 if (old_tlength
< new_tlength
) {
1638 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1639 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1640 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1642 if (new_tlength
== old_tlength
)
1643 pa_log_debug("Failed to increase tlength");
1645 pa_log_debug("Notifying client about increased tlength");
1646 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
);
1651 /* Called from main context */
1652 static void sink_input_kill_cb(pa_sink_input
*i
) {
1655 pa_sink_input_assert_ref(i
);
1656 s
= PLAYBACK_STREAM(i
->userdata
);
1657 playback_stream_assert_ref(s
);
1659 playback_stream_send_killed(s
);
1660 playback_stream_unlink(s
);
1663 /* Called from main context */
1664 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1668 pa_sink_input_assert_ref(i
);
1669 s
= PLAYBACK_STREAM(i
->userdata
);
1670 playback_stream_assert_ref(s
);
1672 if (s
->connection
->version
< 15)
1675 t
= pa_tagstruct_new(NULL
, 0);
1676 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1677 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1678 pa_tagstruct_putu32(t
, s
->index
);
1679 pa_tagstruct_puts(t
, event
);
1680 pa_tagstruct_put_proplist(t
, pl
);
1681 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1684 /* Called from main context */
1685 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
) {
1689 pa_sink_input_assert_ref(i
);
1690 s
= PLAYBACK_STREAM(i
->userdata
);
1691 playback_stream_assert_ref(s
);
1693 if (s
->connection
->version
< 12)
1696 t
= pa_tagstruct_new(NULL
, 0);
1697 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1698 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1699 pa_tagstruct_putu32(t
, s
->index
);
1700 pa_tagstruct_put_boolean(t
, suspend
);
1701 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1704 /* Called from main context */
1705 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1709 pa_sink_input_assert_ref(i
);
1710 s
= PLAYBACK_STREAM(i
->userdata
);
1711 playback_stream_assert_ref(s
);
1716 fix_playback_buffer_attr(s
);
1717 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1718 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1720 if (s
->connection
->version
< 12)
1723 t
= pa_tagstruct_new(NULL
, 0);
1724 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1725 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1726 pa_tagstruct_putu32(t
, s
->index
);
1727 pa_tagstruct_putu32(t
, dest
->index
);
1728 pa_tagstruct_puts(t
, dest
->name
);
1729 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1731 if (s
->connection
->version
>= 13) {
1732 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1733 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1734 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1735 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1736 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1739 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1742 /*** source_output callbacks ***/
1744 /* Called from thread context */
1745 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1746 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1749 pa_source_output_assert_ref(o
);
1750 s
= RECORD_STREAM(o
->userdata
);
1751 record_stream_assert_ref(s
);
1754 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1755 /* Atomically get a snapshot of all timing parameters... */
1756 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1757 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1758 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1762 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1765 /* Called from thread context */
1766 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1769 pa_source_output_assert_ref(o
);
1770 s
= RECORD_STREAM(o
->userdata
);
1771 record_stream_assert_ref(s
);
1774 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1775 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1778 static void source_output_kill_cb(pa_source_output
*o
) {
1781 pa_source_output_assert_ref(o
);
1782 s
= RECORD_STREAM(o
->userdata
);
1783 record_stream_assert_ref(s
);
1785 record_stream_send_killed(s
);
1786 record_stream_unlink(s
);
1789 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1792 pa_source_output_assert_ref(o
);
1793 s
= RECORD_STREAM(o
->userdata
);
1794 record_stream_assert_ref(s
);
1796 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1798 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1801 /* Called from main context */
1802 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1806 pa_source_output_assert_ref(o
);
1807 s
= RECORD_STREAM(o
->userdata
);
1808 record_stream_assert_ref(s
);
1810 if (s
->connection
->version
< 15)
1813 t
= pa_tagstruct_new(NULL
, 0);
1814 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1815 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1816 pa_tagstruct_putu32(t
, s
->index
);
1817 pa_tagstruct_puts(t
, event
);
1818 pa_tagstruct_put_proplist(t
, pl
);
1819 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1822 /* Called from main context */
1823 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
) {
1827 pa_source_output_assert_ref(o
);
1828 s
= RECORD_STREAM(o
->userdata
);
1829 record_stream_assert_ref(s
);
1831 if (s
->connection
->version
< 12)
1834 t
= pa_tagstruct_new(NULL
, 0);
1835 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1836 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1837 pa_tagstruct_putu32(t
, s
->index
);
1838 pa_tagstruct_put_boolean(t
, suspend
);
1839 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1842 /* Called from main context */
1843 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1847 pa_source_output_assert_ref(o
);
1848 s
= RECORD_STREAM(o
->userdata
);
1849 record_stream_assert_ref(s
);
1854 fix_record_buffer_attr_pre(s
);
1855 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1856 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1857 fix_record_buffer_attr_post(s
);
1859 if (s
->connection
->version
< 12)
1862 t
= pa_tagstruct_new(NULL
, 0);
1863 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1864 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1865 pa_tagstruct_putu32(t
, s
->index
);
1866 pa_tagstruct_putu32(t
, dest
->index
);
1867 pa_tagstruct_puts(t
, dest
->name
);
1868 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1870 if (s
->connection
->version
>= 13) {
1871 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1872 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1873 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1876 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1879 /*** pdispatch callbacks ***/
1881 static void protocol_error(pa_native_connection
*c
) {
1882 pa_log("protocol error, kicking client");
1883 native_connection_unlink(c
);
1886 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1887 if (!(expression)) { \
1888 pa_pstream_send_error((pstream), (tag), (error)); \
1893 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1894 if (!(expression)) { \
1895 pa_pstream_send_error((pstream), (tag), (error)); \
1900 static pa_tagstruct
*reply_new(uint32_t tag
) {
1901 pa_tagstruct
*reply
;
1903 reply
= pa_tagstruct_new(NULL
, 0);
1904 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1905 pa_tagstruct_putu32(reply
, tag
);
1909 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1910 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1912 uint32_t sink_index
, syncid
, missing
= 0;
1913 pa_buffer_attr attr
;
1914 const char *name
= NULL
, *sink_name
;
1917 pa_tagstruct
*reply
;
1918 pa_sink
*sink
= NULL
;
1926 fix_channels
= FALSE
,
1928 variable_rate
= FALSE
,
1930 adjust_latency
= FALSE
,
1931 early_requests
= FALSE
,
1932 dont_inhibit_auto_suspend
= FALSE
,
1935 fail_on_suspend
= FALSE
,
1936 relative_volume
= FALSE
,
1937 passthrough
= FALSE
;
1939 pa_sink_input_flags_t flags
= 0;
1940 pa_proplist
*p
= NULL
;
1941 int ret
= PA_ERR_INVALID
;
1942 uint8_t n_formats
= 0;
1943 pa_format_info
*format
;
1944 pa_idxset
*formats
= NULL
;
1947 pa_native_connection_assert_ref(c
);
1949 memset(&attr
, 0, sizeof(attr
));
1951 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
1954 PA_TAG_SAMPLE_SPEC
, &ss
,
1955 PA_TAG_CHANNEL_MAP
, &map
,
1956 PA_TAG_U32
, &sink_index
,
1957 PA_TAG_STRING
, &sink_name
,
1958 PA_TAG_U32
, &attr
.maxlength
,
1959 PA_TAG_BOOLEAN
, &corked
,
1960 PA_TAG_U32
, &attr
.tlength
,
1961 PA_TAG_U32
, &attr
.prebuf
,
1962 PA_TAG_U32
, &attr
.minreq
,
1963 PA_TAG_U32
, &syncid
,
1964 PA_TAG_CVOLUME
, &volume
,
1965 PA_TAG_INVALID
) < 0) {
1971 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
1972 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
, finish
);
1973 CHECK_VALIDITY_GOTO(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
, finish
);
1974 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
1975 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
1977 p
= pa_proplist_new();
1980 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
1982 if (c
->version
>= 12) {
1983 /* Since 0.9.8 the user can ask for a couple of additional flags */
1985 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
1986 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
1987 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
1988 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
1989 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
1990 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
1991 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
1998 if (c
->version
>= 13) {
2000 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2001 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2002 pa_tagstruct_get_proplist(t
, p
) < 0) {
2009 if (c
->version
>= 14) {
2011 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2012 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2019 if (c
->version
>= 15) {
2021 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2022 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2023 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2030 if (c
->version
>= 17) {
2032 if (pa_tagstruct_get_boolean(t
, &relative_volume
) < 0) {
2039 if (c
->version
>= 18) {
2041 if (pa_tagstruct_get_boolean(t
, &passthrough
) < 0 ) {
2047 if (c
->version
>= 21) {
2049 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2055 formats
= pa_idxset_new(NULL
, NULL
);
2057 for (i
= 0; i
< n_formats
; i
++) {
2058 format
= pa_format_info_new();
2059 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2063 pa_idxset_put(formats
, format
, NULL
);
2067 if (n_formats
== 0) {
2068 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2069 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2070 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2072 PA_IDXSET_FOREACH(format
, formats
, i
) {
2073 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2077 if (!pa_tagstruct_eof(t
)) {
2082 if (sink_index
!= PA_INVALID_INDEX
) {
2084 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
2085 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2089 } else if (sink_name
) {
2091 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
2092 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2098 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
2099 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
2100 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
2101 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
2102 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
2103 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
2104 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
2105 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
2106 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2107 (fail_on_suspend
? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND
|PA_SINK_INPUT_KILL_ON_SUSPEND
: 0) |
2108 (passthrough
? PA_SINK_INPUT_PASSTHROUGH
: 0);
2110 /* Only since protocol version 15 there's a separate muted_set
2111 * flag. For older versions we synthesize it here */
2112 muted_set
= muted_set
|| muted
;
2114 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
);
2115 /* We no longer own the formats idxset */
2118 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2120 reply
= reply_new(tag
);
2121 pa_tagstruct_putu32(reply
, s
->index
);
2122 pa_assert(s
->sink_input
);
2123 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
2124 pa_tagstruct_putu32(reply
, missing
);
2126 /* pa_log("initial request is %u", missing); */
2128 if (c
->version
>= 9) {
2129 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2131 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2132 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
2133 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
2134 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
2137 if (c
->version
>= 12) {
2138 /* Since 0.9.8 we support sending the chosen sample
2139 * spec/channel map/device/suspend status back to the
2142 pa_tagstruct_put_sample_spec(reply
, &ss
);
2143 pa_tagstruct_put_channel_map(reply
, &map
);
2145 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
2146 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
2148 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
2151 if (c
->version
>= 13)
2152 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
2154 if (c
->version
>= 21) {
2155 /* Send back the format we negotiated */
2156 if (s
->sink_input
->format
)
2157 pa_tagstruct_put_format_info(reply
, s
->sink_input
->format
);
2159 pa_format_info
*f
= pa_format_info_new();
2160 pa_tagstruct_put_format_info(reply
, f
);
2161 pa_format_info_free(f
);
2165 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2169 pa_proplist_free(p
);
2171 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
2174 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2175 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2178 pa_native_connection_assert_ref(c
);
2181 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2182 !pa_tagstruct_eof(t
)) {
2187 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2191 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2193 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2194 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2198 playback_stream_unlink(s
);
2202 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2204 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2205 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2209 record_stream_unlink(s
);
2213 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2216 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2217 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2221 upload_stream_unlink(s
);
2226 pa_assert_not_reached();
2229 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2232 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2233 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2235 pa_buffer_attr attr
;
2236 uint32_t source_index
;
2237 const char *name
= NULL
, *source_name
;
2240 pa_tagstruct
*reply
;
2241 pa_source
*source
= NULL
;
2249 fix_channels
= FALSE
,
2251 variable_rate
= FALSE
,
2253 adjust_latency
= FALSE
,
2254 peak_detect
= FALSE
,
2255 early_requests
= FALSE
,
2256 dont_inhibit_auto_suspend
= FALSE
,
2259 fail_on_suspend
= FALSE
,
2260 relative_volume
= FALSE
,
2261 passthrough
= FALSE
;
2263 pa_source_output_flags_t flags
= 0;
2264 pa_proplist
*p
= NULL
;
2265 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2266 pa_sink_input
*direct_on_input
= NULL
;
2267 int ret
= PA_ERR_INVALID
;
2268 uint8_t n_formats
= 0;
2269 pa_format_info
*format
;
2270 pa_idxset
*formats
= NULL
;
2273 pa_native_connection_assert_ref(c
);
2276 memset(&attr
, 0, sizeof(attr
));
2278 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2279 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2280 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2281 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2282 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2283 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2284 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2285 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2291 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
2292 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| pa_namereg_is_valid_name_or_wildcard(source_name
, PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
, finish
);
2293 CHECK_VALIDITY_GOTO(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
, finish
);
2294 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
2296 p
= pa_proplist_new();
2299 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2301 if (c
->version
>= 12) {
2302 /* Since 0.9.8 the user can ask for a couple of additional flags */
2304 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2305 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2306 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2307 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2308 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2309 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2310 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2317 if (c
->version
>= 13) {
2319 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2320 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2321 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2322 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2329 if (c
->version
>= 14) {
2331 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2337 if (c
->version
>= 15) {
2339 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2340 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2347 if (c
->version
>= 22) {
2348 /* For newer client versions (with per-source-output volumes), we try
2349 * to make the behaviour for playback and record streams the same. */
2352 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2358 formats
= pa_idxset_new(NULL
, NULL
);
2360 for (i
= 0; i
< n_formats
; i
++) {
2361 format
= pa_format_info_new();
2362 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2366 pa_idxset_put(formats
, format
, NULL
);
2369 if (pa_tagstruct_get_cvolume(t
, &volume
) < 0 ||
2370 pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2371 pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2372 pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2373 pa_tagstruct_get_boolean(t
, &relative_volume
) < 0 ||
2374 pa_tagstruct_get_boolean(t
, &passthrough
) < 0) {
2380 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
2383 if (n_formats
== 0) {
2384 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2385 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2386 CHECK_VALIDITY_GOTO(c
->pstream
, c
->version
< 22 || (volume
.channels
== ss
.channels
), tag
, PA_ERR_INVALID
, finish
);
2387 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2389 PA_IDXSET_FOREACH(format
, formats
, i
) {
2390 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2395 if (!pa_tagstruct_eof(t
)) {
2400 if (source_index
!= PA_INVALID_INDEX
) {
2402 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2403 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2407 } else if (source_name
) {
2409 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2410 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2415 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2417 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2418 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2424 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2425 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2426 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2427 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2428 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2429 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2430 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2431 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2432 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2433 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0) |
2434 (passthrough
? PA_SOURCE_OUTPUT_PASSTHROUGH
: 0);
2436 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
);
2438 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2440 reply
= reply_new(tag
);
2441 pa_tagstruct_putu32(reply
, s
->index
);
2442 pa_assert(s
->source_output
);
2443 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2445 if (c
->version
>= 9) {
2446 /* Since 0.9 we support sending the buffer metrics back to the client */
2448 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2449 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2452 if (c
->version
>= 12) {
2453 /* Since 0.9.8 we support sending the chosen sample
2454 * spec/channel map/device/suspend status back to the
2457 pa_tagstruct_put_sample_spec(reply
, &ss
);
2458 pa_tagstruct_put_channel_map(reply
, &map
);
2460 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2461 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2463 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2466 if (c
->version
>= 13)
2467 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2469 if (c
->version
>= 22) {
2470 /* Send back the format we negotiated */
2471 if (s
->source_output
->format
)
2472 pa_tagstruct_put_format_info(reply
, s
->source_output
->format
);
2474 pa_format_info
*f
= pa_format_info_new();
2475 pa_tagstruct_put_format_info(reply
, f
);
2476 pa_format_info_free(f
);
2480 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2484 pa_proplist_free(p
);
2486 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
2489 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2490 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2493 pa_native_connection_assert_ref(c
);
2496 if (!pa_tagstruct_eof(t
)) {
2501 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2502 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2503 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2505 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2507 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2510 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2511 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2513 pa_tagstruct
*reply
;
2514 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2516 pa_native_connection_assert_ref(c
);
2519 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2520 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2521 !pa_tagstruct_eof(t
)) {
2526 /* Minimum supported version */
2527 if (c
->version
< 8) {
2528 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2532 /* Starting with protocol version 13 the MSB of the version tag
2533 reflects if shm is available for this pa_native_connection or
2535 if (c
->version
>= 13) {
2536 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2537 c
->version
&= 0x7FFFFFFFU
;
2540 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2542 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2544 if (!c
->authorized
) {
2545 pa_bool_t success
= FALSE
;
2548 const pa_creds
*creds
;
2550 if ((creds
= pa_pdispatch_creds(pd
))) {
2551 if (creds
->uid
== getuid())
2553 else if (c
->options
->auth_group
) {
2557 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2558 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2559 else if (gid
== creds
->gid
)
2563 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2564 pa_log_warn("Failed to check group membership.");
2570 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2571 (unsigned long) creds
->uid
,
2572 (unsigned long) creds
->gid
,
2577 if (!success
&& c
->options
->auth_cookie
) {
2580 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2581 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2586 pa_log_warn("Denied access to client with invalid authorization data.");
2587 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2591 c
->authorized
= TRUE
;
2592 if (c
->auth_timeout_event
) {
2593 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2594 c
->auth_timeout_event
= NULL
;
2598 /* Enable shared memory support if possible */
2600 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2603 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2606 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2611 /* Only enable SHM if both sides are owned by the same
2612 * user. This is a security measure because otherwise data
2613 * private to the user might leak. */
2615 const pa_creds
*creds
;
2616 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2621 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2622 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2624 reply
= reply_new(tag
);
2625 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2629 /* SHM support is only enabled after both sides made sure they are the same user. */
2633 ucred
.uid
= getuid();
2634 ucred
.gid
= getgid();
2636 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2639 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2643 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2644 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2645 const char *name
= NULL
;
2647 pa_tagstruct
*reply
;
2649 pa_native_connection_assert_ref(c
);
2652 p
= pa_proplist_new();
2654 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2655 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2656 !pa_tagstruct_eof(t
)) {
2659 pa_proplist_free(p
);
2664 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2665 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2666 pa_proplist_free(p
);
2670 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2671 pa_proplist_free(p
);
2673 reply
= reply_new(tag
);
2675 if (c
->version
>= 13)
2676 pa_tagstruct_putu32(reply
, c
->client
->index
);
2678 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2681 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2682 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2684 uint32_t idx
= PA_IDXSET_INVALID
;
2686 pa_native_connection_assert_ref(c
);
2689 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2690 !pa_tagstruct_eof(t
)) {
2695 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2696 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
);
2698 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2700 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2704 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2705 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2706 idx
= source
->index
;
2709 if (idx
== PA_IDXSET_INVALID
)
2710 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2712 pa_tagstruct
*reply
;
2713 reply
= reply_new(tag
);
2714 pa_tagstruct_putu32(reply
, idx
);
2715 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2719 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2720 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2724 pa_native_connection_assert_ref(c
);
2727 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2728 !pa_tagstruct_eof(t
)) {
2733 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2734 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2735 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2736 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2738 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
);
2741 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2742 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2743 pa_tagstruct
*reply
;
2744 const pa_mempool_stat
*stat
;
2746 pa_native_connection_assert_ref(c
);
2749 if (!pa_tagstruct_eof(t
)) {
2754 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2756 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2758 reply
= reply_new(tag
);
2759 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2760 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2761 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2762 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2763 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2764 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2767 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2768 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2769 pa_tagstruct
*reply
;
2771 struct timeval tv
, now
;
2774 pa_native_connection_assert_ref(c
);
2777 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2778 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2779 !pa_tagstruct_eof(t
)) {
2784 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2785 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2786 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2787 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2789 /* Get an atomic snapshot of all timing parameters */
2790 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);
2792 reply
= reply_new(tag
);
2793 pa_tagstruct_put_usec(reply
,
2794 s
->current_sink_latency
+
2795 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2796 pa_tagstruct_put_usec(reply
, 0);
2797 pa_tagstruct_put_boolean(reply
,
2798 s
->playing_for
> 0 &&
2799 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2800 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2801 pa_tagstruct_put_timeval(reply
, &tv
);
2802 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2803 pa_tagstruct_puts64(reply
, s
->write_index
);
2804 pa_tagstruct_puts64(reply
, s
->read_index
);
2806 if (c
->version
>= 13) {
2807 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2808 pa_tagstruct_putu64(reply
, s
->playing_for
);
2811 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2814 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2815 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2816 pa_tagstruct
*reply
;
2818 struct timeval tv
, now
;
2821 pa_native_connection_assert_ref(c
);
2824 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2825 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2826 !pa_tagstruct_eof(t
)) {
2831 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2832 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2833 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2835 /* Get an atomic snapshot of all timing parameters */
2836 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);
2838 reply
= reply_new(tag
);
2839 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2840 pa_tagstruct_put_usec(reply
,
2841 s
->current_source_latency
+
2842 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2843 pa_tagstruct_put_boolean(reply
,
2844 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2845 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2846 pa_tagstruct_put_timeval(reply
, &tv
);
2847 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2848 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2849 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2850 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2853 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2854 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2857 const char *name
= NULL
;
2860 pa_tagstruct
*reply
;
2863 pa_native_connection_assert_ref(c
);
2866 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2867 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2868 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2869 pa_tagstruct_getu32(t
, &length
) < 0) {
2874 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2875 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2876 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2877 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2878 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2879 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2881 p
= pa_proplist_new();
2883 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2884 !pa_tagstruct_eof(t
)) {
2887 pa_proplist_free(p
);
2891 if (c
->version
< 13)
2892 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2894 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2895 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2897 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2898 pa_proplist_free(p
);
2899 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2902 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2903 pa_proplist_free(p
);
2905 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2907 reply
= reply_new(tag
);
2908 pa_tagstruct_putu32(reply
, s
->index
);
2909 pa_tagstruct_putu32(reply
, length
);
2910 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2913 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2914 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2919 pa_native_connection_assert_ref(c
);
2922 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2923 !pa_tagstruct_eof(t
)) {
2928 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2930 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2931 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2932 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2934 if (!s
->memchunk
.memblock
)
2935 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
2936 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2937 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2939 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2941 upload_stream_unlink(s
);
2944 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2945 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2946 uint32_t sink_index
;
2949 const char *name
, *sink_name
;
2952 pa_tagstruct
*reply
;
2954 pa_native_connection_assert_ref(c
);
2957 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2959 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
2960 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
2961 pa_tagstruct_getu32(t
, &volume
) < 0 ||
2962 pa_tagstruct_gets(t
, &name
) < 0) {
2967 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
2968 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
2969 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2970 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2972 if (sink_index
!= PA_INVALID_INDEX
)
2973 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
2975 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
2977 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
2979 p
= pa_proplist_new();
2981 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2982 !pa_tagstruct_eof(t
)) {
2984 pa_proplist_free(p
);
2988 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
2990 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
2991 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2992 pa_proplist_free(p
);
2996 pa_proplist_free(p
);
2998 reply
= reply_new(tag
);
3000 if (c
->version
>= 13)
3001 pa_tagstruct_putu32(reply
, idx
);
3003 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3006 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3007 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3010 pa_native_connection_assert_ref(c
);
3013 if (pa_tagstruct_gets(t
, &name
) < 0 ||
3014 !pa_tagstruct_eof(t
)) {
3019 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3020 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3022 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
3023 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3027 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3030 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
3033 pa_assert(original
);
3037 if (c
->version
< 12) {
3038 /* Before protocol version 12 we didn't support S32 samples,
3039 * so we need to lie about this to the client */
3041 if (fixed
->format
== PA_SAMPLE_S32LE
)
3042 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3043 if (fixed
->format
== PA_SAMPLE_S32BE
)
3044 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3047 if (c
->version
< 15) {
3048 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
3049 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3050 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
3051 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3055 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
3056 pa_sample_spec fixed_ss
;
3059 pa_sink_assert_ref(sink
);
3061 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
3065 PA_TAG_U32
, sink
->index
,
3066 PA_TAG_STRING
, sink
->name
,
3067 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3068 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3069 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
3070 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
3071 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
3072 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
3073 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
3074 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
3075 PA_TAG_USEC
, pa_sink_get_latency(sink
),
3076 PA_TAG_STRING
, sink
->driver
,
3077 PA_TAG_U32
, sink
->flags
& PA_SINK_CLIENT_FLAGS_MASK
,
3080 if (c
->version
>= 13) {
3081 pa_tagstruct_put_proplist(t
, sink
->proplist
);
3082 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
3085 if (c
->version
>= 15) {
3086 pa_tagstruct_put_volume(t
, sink
->base_volume
);
3087 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
3088 pa_log_error("Internal sink state is invalid.");
3089 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
3090 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
3091 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
3094 if (c
->version
>= 16) {
3095 pa_tagstruct_putu32(t
, sink
->ports
? pa_hashmap_size(sink
->ports
) : 0);
3101 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
3102 pa_tagstruct_puts(t
, p
->name
);
3103 pa_tagstruct_puts(t
, p
->description
);
3104 pa_tagstruct_putu32(t
, p
->priority
);
3108 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
3111 if (c
->version
>= 21) {
3114 pa_idxset
*formats
= pa_sink_get_formats(sink
);
3116 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3117 PA_IDXSET_FOREACH(f
, formats
, i
) {
3118 pa_tagstruct_put_format_info(t
, f
);
3121 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3125 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
3126 pa_sample_spec fixed_ss
;
3129 pa_source_assert_ref(source
);
3131 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
3135 PA_TAG_U32
, source
->index
,
3136 PA_TAG_STRING
, source
->name
,
3137 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3138 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3139 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
3140 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
3141 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
3142 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
3143 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
3144 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
3145 PA_TAG_USEC
, pa_source_get_latency(source
),
3146 PA_TAG_STRING
, source
->driver
,
3147 PA_TAG_U32
, source
->flags
& PA_SOURCE_CLIENT_FLAGS_MASK
,
3150 if (c
->version
>= 13) {
3151 pa_tagstruct_put_proplist(t
, source
->proplist
);
3152 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
3155 if (c
->version
>= 15) {
3156 pa_tagstruct_put_volume(t
, source
->base_volume
);
3157 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
3158 pa_log_error("Internal source state is invalid.");
3159 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
3160 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
3161 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
3164 if (c
->version
>= 16) {
3166 pa_tagstruct_putu32(t
, source
->ports
? pa_hashmap_size(source
->ports
) : 0);
3168 if (source
->ports
) {
3172 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
3173 pa_tagstruct_puts(t
, p
->name
);
3174 pa_tagstruct_puts(t
, p
->description
);
3175 pa_tagstruct_putu32(t
, p
->priority
);
3179 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
3182 if (c
->version
>= 22) {
3185 pa_idxset
*formats
= pa_source_get_formats(source
);
3187 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3188 PA_IDXSET_FOREACH(f
, formats
, i
) {
3189 pa_tagstruct_put_format_info(t
, f
);
3192 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3196 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
3200 pa_tagstruct_putu32(t
, client
->index
);
3201 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
3202 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
3203 pa_tagstruct_puts(t
, client
->driver
);
3205 if (c
->version
>= 13)
3206 pa_tagstruct_put_proplist(t
, client
->proplist
);
3209 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
3216 pa_tagstruct_putu32(t
, card
->index
);
3217 pa_tagstruct_puts(t
, card
->name
);
3218 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
3219 pa_tagstruct_puts(t
, card
->driver
);
3221 pa_tagstruct_putu32(t
, card
->profiles
? pa_hashmap_size(card
->profiles
) : 0);
3223 if (card
->profiles
) {
3224 while ((p
= pa_hashmap_iterate(card
->profiles
, &state
, NULL
))) {
3225 pa_tagstruct_puts(t
, p
->name
);
3226 pa_tagstruct_puts(t
, p
->description
);
3227 pa_tagstruct_putu32(t
, p
->n_sinks
);
3228 pa_tagstruct_putu32(t
, p
->n_sources
);
3229 pa_tagstruct_putu32(t
, p
->priority
);
3233 pa_tagstruct_puts(t
, card
->active_profile
? card
->active_profile
->name
: NULL
);
3234 pa_tagstruct_put_proplist(t
, card
->proplist
);
3237 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3241 pa_tagstruct_putu32(t
, module
->index
);
3242 pa_tagstruct_puts(t
, module
->name
);
3243 pa_tagstruct_puts(t
, module
->argument
);
3244 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3246 if (c
->version
< 15)
3247 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
3249 if (c
->version
>= 15)
3250 pa_tagstruct_put_proplist(t
, module
->proplist
);
3253 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3254 pa_sample_spec fixed_ss
;
3255 pa_usec_t sink_latency
;
3257 pa_bool_t has_volume
= FALSE
;
3260 pa_sink_input_assert_ref(s
);
3262 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3264 has_volume
= pa_sink_input_is_volume_readable(s
);
3266 pa_sink_input_get_volume(s
, &v
, TRUE
);
3268 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3270 pa_tagstruct_putu32(t
, s
->index
);
3271 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3272 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3273 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3274 pa_tagstruct_putu32(t
, s
->sink
->index
);
3275 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3276 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3277 pa_tagstruct_put_cvolume(t
, &v
);
3278 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3279 pa_tagstruct_put_usec(t
, sink_latency
);
3280 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3281 pa_tagstruct_puts(t
, s
->driver
);
3282 if (c
->version
>= 11)
3283 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
3284 if (c
->version
>= 13)
3285 pa_tagstruct_put_proplist(t
, s
->proplist
);
3286 if (c
->version
>= 19)
3287 pa_tagstruct_put_boolean(t
, (pa_sink_input_get_state(s
) == PA_SINK_INPUT_CORKED
));
3288 if (c
->version
>= 20) {
3289 pa_tagstruct_put_boolean(t
, has_volume
);
3290 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3292 if (c
->version
>= 21)
3293 pa_tagstruct_put_format_info(t
, s
->format
);
3296 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3297 pa_sample_spec fixed_ss
;
3298 pa_usec_t source_latency
;
3300 pa_bool_t has_volume
= FALSE
;
3303 pa_source_output_assert_ref(s
);
3305 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3307 has_volume
= pa_source_output_is_volume_readable(s
);
3309 pa_source_output_get_volume(s
, &v
, TRUE
);
3311 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3313 pa_tagstruct_putu32(t
, s
->index
);
3314 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3315 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3316 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3317 pa_tagstruct_putu32(t
, s
->source
->index
);
3318 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3319 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3320 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3321 pa_tagstruct_put_usec(t
, source_latency
);
3322 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3323 pa_tagstruct_puts(t
, s
->driver
);
3324 if (c
->version
>= 13)
3325 pa_tagstruct_put_proplist(t
, s
->proplist
);
3326 if (c
->version
>= 19)
3327 pa_tagstruct_put_boolean(t
, (pa_source_output_get_state(s
) == PA_SOURCE_OUTPUT_CORKED
));
3328 if (c
->version
>= 22) {
3329 pa_tagstruct_put_cvolume(t
, &v
);
3330 pa_tagstruct_put_boolean(t
, pa_source_output_get_mute(s
));
3331 pa_tagstruct_put_boolean(t
, has_volume
);
3332 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3333 pa_tagstruct_put_format_info(t
, s
->format
);
3337 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3338 pa_sample_spec fixed_ss
;
3344 if (e
->memchunk
.memblock
)
3345 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3347 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3349 pa_tagstruct_putu32(t
, e
->index
);
3350 pa_tagstruct_puts(t
, e
->name
);
3352 if (e
->volume_is_set
)
3355 pa_cvolume_init(&v
);
3357 pa_tagstruct_put_cvolume(t
, &v
);
3358 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3359 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3360 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3361 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3362 pa_tagstruct_put_boolean(t
, e
->lazy
);
3363 pa_tagstruct_puts(t
, e
->filename
);
3365 if (c
->version
>= 13)
3366 pa_tagstruct_put_proplist(t
, e
->proplist
);
3369 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3370 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3372 pa_sink
*sink
= NULL
;
3373 pa_source
*source
= NULL
;
3374 pa_client
*client
= NULL
;
3375 pa_card
*card
= NULL
;
3376 pa_module
*module
= NULL
;
3377 pa_sink_input
*si
= NULL
;
3378 pa_source_output
*so
= NULL
;
3379 pa_scache_entry
*sce
= NULL
;
3380 const char *name
= NULL
;
3381 pa_tagstruct
*reply
;
3383 pa_native_connection_assert_ref(c
);
3386 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3387 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3388 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3389 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3390 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3391 pa_tagstruct_gets(t
, &name
) < 0) ||
3392 !pa_tagstruct_eof(t
)) {
3397 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3398 CHECK_VALIDITY(c
->pstream
, !name
||
3399 (command
== PA_COMMAND_GET_SINK_INFO
&&
3400 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3401 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3402 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3403 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3404 CHECK_VALIDITY(c
->pstream
, command
== PA_COMMAND_GET_SINK_INFO
||
3405 command
== PA_COMMAND_GET_SOURCE_INFO
||
3406 (idx
!= PA_INVALID_INDEX
|| name
), tag
, PA_ERR_INVALID
);
3407 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3408 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3410 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3411 if (idx
!= PA_INVALID_INDEX
)
3412 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3414 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3415 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3416 if (idx
!= PA_INVALID_INDEX
)
3417 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3419 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3420 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3421 if (idx
!= PA_INVALID_INDEX
)
3422 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3424 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3425 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3426 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3427 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3428 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3429 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3430 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3431 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3432 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3434 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3435 if (idx
!= PA_INVALID_INDEX
)
3436 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3438 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3441 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3442 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3446 reply
= reply_new(tag
);
3448 sink_fill_tagstruct(c
, reply
, sink
);
3450 source_fill_tagstruct(c
, reply
, source
);
3452 client_fill_tagstruct(c
, reply
, client
);
3454 card_fill_tagstruct(c
, reply
, card
);
3456 module_fill_tagstruct(c
, reply
, module
);
3458 sink_input_fill_tagstruct(c
, reply
, si
);
3460 source_output_fill_tagstruct(c
, reply
, so
);
3462 scache_fill_tagstruct(c
, reply
, sce
);
3463 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3466 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3467 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3471 pa_tagstruct
*reply
;
3473 pa_native_connection_assert_ref(c
);
3476 if (!pa_tagstruct_eof(t
)) {
3481 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3483 reply
= reply_new(tag
);
3485 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3486 i
= c
->protocol
->core
->sinks
;
3487 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3488 i
= c
->protocol
->core
->sources
;
3489 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3490 i
= c
->protocol
->core
->clients
;
3491 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3492 i
= c
->protocol
->core
->cards
;
3493 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3494 i
= c
->protocol
->core
->modules
;
3495 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3496 i
= c
->protocol
->core
->sink_inputs
;
3497 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3498 i
= c
->protocol
->core
->source_outputs
;
3500 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3501 i
= c
->protocol
->core
->scache
;
3505 for (p
= pa_idxset_first(i
, &idx
); p
; p
= pa_idxset_next(i
, &idx
)) {
3506 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3507 sink_fill_tagstruct(c
, reply
, p
);
3508 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3509 source_fill_tagstruct(c
, reply
, p
);
3510 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3511 client_fill_tagstruct(c
, reply
, p
);
3512 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3513 card_fill_tagstruct(c
, reply
, p
);
3514 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3515 module_fill_tagstruct(c
, reply
, p
);
3516 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3517 sink_input_fill_tagstruct(c
, reply
, p
);
3518 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3519 source_output_fill_tagstruct(c
, reply
, p
);
3521 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3522 scache_fill_tagstruct(c
, reply
, p
);
3527 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3530 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3531 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3532 pa_tagstruct
*reply
;
3534 pa_source
*def_source
;
3535 pa_sample_spec fixed_ss
;
3538 pa_native_connection_assert_ref(c
);
3541 if (!pa_tagstruct_eof(t
)) {
3546 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3548 reply
= reply_new(tag
);
3549 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3550 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3552 u
= pa_get_user_name_malloc();
3553 pa_tagstruct_puts(reply
, u
);
3556 h
= pa_get_host_name_malloc();
3557 pa_tagstruct_puts(reply
, h
);
3560 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3561 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3563 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3564 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3565 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3566 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3568 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3570 if (c
->version
>= 15)
3571 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3573 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3576 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3578 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3580 pa_native_connection_assert_ref(c
);
3582 t
= pa_tagstruct_new(NULL
, 0);
3583 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3584 pa_tagstruct_putu32(t
, (uint32_t) -1);
3585 pa_tagstruct_putu32(t
, e
);
3586 pa_tagstruct_putu32(t
, idx
);
3587 pa_pstream_send_tagstruct(c
->pstream
, t
);
3590 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3591 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3592 pa_subscription_mask_t m
;
3594 pa_native_connection_assert_ref(c
);
3597 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3598 !pa_tagstruct_eof(t
)) {
3603 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3604 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3606 if (c
->subscription
)
3607 pa_subscription_free(c
->subscription
);
3610 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3611 pa_assert(c
->subscription
);
3613 c
->subscription
= NULL
;
3615 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3618 static void command_set_volume(
3625 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3628 pa_sink
*sink
= NULL
;
3629 pa_source
*source
= NULL
;
3630 pa_sink_input
*si
= NULL
;
3631 pa_source_output
*so
= NULL
;
3632 const char *name
= NULL
;
3633 const char *client_name
;
3635 pa_native_connection_assert_ref(c
);
3638 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3639 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3640 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3641 pa_tagstruct_get_cvolume(t
, &volume
) ||
3642 !pa_tagstruct_eof(t
)) {
3647 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3648 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
);
3649 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3650 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3651 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3652 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3656 case PA_COMMAND_SET_SINK_VOLUME
:
3657 if (idx
!= PA_INVALID_INDEX
)
3658 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3660 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3663 case PA_COMMAND_SET_SOURCE_VOLUME
:
3664 if (idx
!= PA_INVALID_INDEX
)
3665 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3667 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3670 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3671 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3674 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
:
3675 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3679 pa_assert_not_reached();
3682 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3684 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3687 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3689 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3690 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3691 } else if (source
) {
3692 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3694 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3695 pa_source_set_volume(source
, &volume
, TRUE
, TRUE
);
3697 CHECK_VALIDITY(c
->pstream
, si
->volume_writable
, tag
, PA_ERR_BADSTATE
);
3698 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3700 pa_log_debug("Client %s changes volume of sink input %s.",
3702 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3703 pa_sink_input_set_volume(si
, &volume
, TRUE
, TRUE
);
3705 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &so
->sample_spec
), tag
, PA_ERR_INVALID
);
3707 pa_log_debug("Client %s changes volume of source output %s.",
3709 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3710 pa_source_output_set_volume(so
, &volume
, TRUE
, TRUE
);
3713 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3716 static void command_set_mute(
3723 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3726 pa_sink
*sink
= NULL
;
3727 pa_source
*source
= NULL
;
3728 pa_sink_input
*si
= NULL
;
3729 pa_source_output
*so
= NULL
;
3730 const char *name
= NULL
, *client_name
;
3732 pa_native_connection_assert_ref(c
);
3735 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3736 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3737 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3738 pa_tagstruct_get_boolean(t
, &mute
) ||
3739 !pa_tagstruct_eof(t
)) {
3744 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3745 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
);
3746 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3747 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3748 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3752 case PA_COMMAND_SET_SINK_MUTE
:
3753 if (idx
!= PA_INVALID_INDEX
)
3754 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3756 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3760 case PA_COMMAND_SET_SOURCE_MUTE
:
3761 if (idx
!= PA_INVALID_INDEX
)
3762 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3764 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3768 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3769 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3772 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
:
3773 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3777 pa_assert_not_reached();
3780 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3782 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3785 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3786 pa_sink_set_mute(sink
, mute
, TRUE
);
3787 } else if (source
) {
3788 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3789 pa_source_set_mute(source
, mute
, TRUE
);
3791 pa_log_debug("Client %s changes mute of sink input %s.",
3793 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3794 pa_sink_input_set_mute(si
, mute
, TRUE
);
3796 pa_log_debug("Client %s changes mute of source output %s.",
3798 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3799 pa_source_output_set_mute(so
, mute
, TRUE
);
3802 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3805 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3806 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3811 pa_native_connection_assert_ref(c
);
3814 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3815 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3816 !pa_tagstruct_eof(t
)) {
3821 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3822 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3823 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3824 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3825 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3827 pa_sink_input_cork(s
->sink_input
, b
);
3830 s
->is_underrun
= TRUE
;
3832 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3835 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3836 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3840 pa_native_connection_assert_ref(c
);
3843 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3844 !pa_tagstruct_eof(t
)) {
3849 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3850 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3851 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3852 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3853 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3856 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3857 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3860 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3861 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3864 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3865 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3869 pa_assert_not_reached();
3872 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3875 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3876 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3881 pa_native_connection_assert_ref(c
);
3884 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3885 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3886 !pa_tagstruct_eof(t
)) {
3891 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3892 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3893 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3895 pa_source_output_cork(s
->source_output
, b
);
3896 pa_memblockq_prebuf_force(s
->memblockq
);
3897 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3900 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3901 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3905 pa_native_connection_assert_ref(c
);
3908 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3909 !pa_tagstruct_eof(t
)) {
3914 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3915 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3916 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3918 pa_memblockq_flush_read(s
->memblockq
);
3919 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3922 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3923 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3926 pa_tagstruct
*reply
;
3928 pa_native_connection_assert_ref(c
);
3931 memset(&a
, 0, sizeof(a
));
3933 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3938 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3940 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
3942 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3944 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3945 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3946 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3948 if (pa_tagstruct_get(
3950 PA_TAG_U32
, &a
.maxlength
,
3951 PA_TAG_U32
, &a
.tlength
,
3952 PA_TAG_U32
, &a
.prebuf
,
3953 PA_TAG_U32
, &a
.minreq
,
3954 PA_TAG_INVALID
) < 0 ||
3955 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3956 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3957 !pa_tagstruct_eof(t
)) {
3962 s
->adjust_latency
= adjust_latency
;
3963 s
->early_requests
= early_requests
;
3964 s
->buffer_attr_req
= a
;
3966 fix_playback_buffer_attr(s
);
3967 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);
3969 reply
= reply_new(tag
);
3970 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3971 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
3972 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
3973 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
3975 if (c
->version
>= 13)
3976 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
3980 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3981 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
3983 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3984 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3986 if (pa_tagstruct_get(
3988 PA_TAG_U32
, &a
.maxlength
,
3989 PA_TAG_U32
, &a
.fragsize
,
3990 PA_TAG_INVALID
) < 0 ||
3991 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3992 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3993 !pa_tagstruct_eof(t
)) {
3998 s
->adjust_latency
= adjust_latency
;
3999 s
->early_requests
= early_requests
;
4000 s
->buffer_attr_req
= a
;
4002 fix_record_buffer_attr_pre(s
);
4003 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
4004 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
4005 fix_record_buffer_attr_post(s
);
4007 reply
= reply_new(tag
);
4008 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
4009 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
4011 if (c
->version
>= 13)
4012 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
4015 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4018 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4019 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4023 pa_native_connection_assert_ref(c
);
4026 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4027 pa_tagstruct_getu32(t
, &rate
) < 0 ||
4028 !pa_tagstruct_eof(t
)) {
4033 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4034 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
4036 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
4039 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4040 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4041 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4043 pa_sink_input_set_rate(s
->sink_input
, rate
);
4047 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
4049 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4050 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4052 pa_source_output_set_rate(s
->source_output
, rate
);
4055 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4058 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4059 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4064 pa_native_connection_assert_ref(c
);
4067 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4069 p
= pa_proplist_new();
4071 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
4073 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
4074 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4075 !pa_tagstruct_eof(t
)) {
4077 pa_proplist_free(p
);
4083 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4084 pa_tagstruct_getu32(t
, &mode
) < 0 ||
4085 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4086 !pa_tagstruct_eof(t
)) {
4088 pa_proplist_free(p
);
4093 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
4094 pa_proplist_free(p
);
4095 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
4098 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
4101 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4102 if (!s
|| !playback_stream_isinstance(s
)) {
4103 pa_proplist_free(p
);
4104 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4106 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
4108 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
4111 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
4112 pa_proplist_free(p
);
4113 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4115 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
4118 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
4120 pa_client_update_proplist(c
->client
, mode
, p
);
4123 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4124 pa_proplist_free(p
);
4127 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4128 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4130 unsigned changed
= 0;
4132 pa_strlist
*l
= NULL
;
4134 pa_native_connection_assert_ref(c
);
4137 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4139 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
4141 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
4147 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4150 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4151 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4152 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4154 p
= s
->sink_input
->proplist
;
4156 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4159 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4160 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4162 p
= s
->source_output
->proplist
;
4164 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4166 p
= c
->client
->proplist
;
4172 if (pa_tagstruct_gets(t
, &k
) < 0) {
4181 l
= pa_strlist_prepend(l
, k
);
4184 if (!pa_tagstruct_eof(t
)) {
4193 l
= pa_strlist_pop(l
, &z
);
4198 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
4202 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4205 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4208 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4209 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
4211 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4214 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4215 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
4218 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4219 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
4224 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4225 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4228 pa_native_connection_assert_ref(c
);
4231 if (pa_tagstruct_gets(t
, &s
) < 0 ||
4232 !pa_tagstruct_eof(t
)) {
4237 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4238 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
4240 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
4243 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
4244 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4246 pa_namereg_set_default_source(c
->protocol
->core
, source
);
4249 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
4251 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
4252 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4254 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
4257 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4260 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4261 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4265 pa_native_connection_assert_ref(c
);
4268 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4269 pa_tagstruct_gets(t
, &name
) < 0 ||
4270 !pa_tagstruct_eof(t
)) {
4275 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4276 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4278 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
4281 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4282 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4283 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4285 pa_sink_input_set_name(s
->sink_input
, name
);
4289 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4291 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4292 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4294 pa_source_output_set_name(s
->source_output
, name
);
4297 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4300 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4301 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4304 pa_native_connection_assert_ref(c
);
4307 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4308 !pa_tagstruct_eof(t
)) {
4313 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4315 if (command
== PA_COMMAND_KILL_CLIENT
) {
4318 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4319 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4321 pa_native_connection_ref(c
);
4322 pa_client_kill(client
);
4324 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4327 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4328 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4330 pa_native_connection_ref(c
);
4331 pa_sink_input_kill(s
);
4333 pa_source_output
*s
;
4335 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4337 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4338 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4340 pa_native_connection_ref(c
);
4341 pa_source_output_kill(s
);
4344 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4345 pa_native_connection_unref(c
);
4348 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4349 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4351 const char *name
, *argument
;
4352 pa_tagstruct
*reply
;
4354 pa_native_connection_assert_ref(c
);
4357 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4358 pa_tagstruct_gets(t
, &argument
) < 0 ||
4359 !pa_tagstruct_eof(t
)) {
4364 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4365 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4366 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4368 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4369 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4373 reply
= reply_new(tag
);
4374 pa_tagstruct_putu32(reply
, m
->index
);
4375 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4378 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4379 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4383 pa_native_connection_assert_ref(c
);
4386 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4387 !pa_tagstruct_eof(t
)) {
4392 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4393 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4394 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4396 pa_module_unload_request(m
, FALSE
);
4397 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4400 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4401 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4402 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4403 const char *name_device
= NULL
;
4405 pa_native_connection_assert_ref(c
);
4408 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4409 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4410 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4411 !pa_tagstruct_eof(t
)) {
4416 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4417 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4419 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
);
4420 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4421 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4422 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4424 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4425 pa_sink_input
*si
= NULL
;
4426 pa_sink
*sink
= NULL
;
4428 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4430 if (idx_device
!= PA_INVALID_INDEX
)
4431 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4433 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4435 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4437 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4438 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4442 pa_source_output
*so
= NULL
;
4445 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4447 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4449 if (idx_device
!= PA_INVALID_INDEX
)
4450 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4452 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4454 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4456 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4457 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4462 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4465 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4466 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4467 uint32_t idx
= PA_INVALID_INDEX
;
4468 const char *name
= NULL
;
4471 pa_native_connection_assert_ref(c
);
4474 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4475 pa_tagstruct_gets(t
, &name
) < 0 ||
4476 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4477 !pa_tagstruct_eof(t
)) {
4482 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4483 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
);
4484 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4485 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4486 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4488 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4490 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4492 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4494 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4495 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4499 pa_sink
*sink
= NULL
;
4501 if (idx
!= PA_INVALID_INDEX
)
4502 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4504 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4506 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4508 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4509 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4515 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4517 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4519 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4521 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4522 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4529 if (idx
!= PA_INVALID_INDEX
)
4530 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4532 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4534 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4536 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4537 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4543 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4546 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4547 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4548 uint32_t idx
= PA_INVALID_INDEX
;
4549 const char *name
= NULL
;
4551 pa_native_protocol_ext_cb_t cb
;
4553 pa_native_connection_assert_ref(c
);
4556 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4557 pa_tagstruct_gets(t
, &name
) < 0) {
4562 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4563 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4564 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4565 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4566 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4568 if (idx
!= PA_INVALID_INDEX
)
4569 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4571 for (m
= pa_idxset_first(c
->protocol
->core
->modules
, &idx
); m
; m
= pa_idxset_next(c
->protocol
->core
->modules
, &idx
))
4572 if (strcmp(name
, m
->name
) == 0)
4576 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4577 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4579 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4580 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4582 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4586 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4587 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4588 uint32_t idx
= PA_INVALID_INDEX
;
4589 const char *name
= NULL
, *profile
= NULL
;
4590 pa_card
*card
= NULL
;
4593 pa_native_connection_assert_ref(c
);
4596 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4597 pa_tagstruct_gets(t
, &name
) < 0 ||
4598 pa_tagstruct_gets(t
, &profile
) < 0 ||
4599 !pa_tagstruct_eof(t
)) {
4604 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4605 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4606 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4607 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4608 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4610 if (idx
!= PA_INVALID_INDEX
)
4611 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4613 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4615 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4617 if ((ret
= pa_card_set_profile(card
, profile
, TRUE
)) < 0) {
4618 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4622 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4625 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4626 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4627 uint32_t idx
= PA_INVALID_INDEX
;
4628 const char *name
= NULL
, *port
= NULL
;
4631 pa_native_connection_assert_ref(c
);
4634 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4635 pa_tagstruct_gets(t
, &name
) < 0 ||
4636 pa_tagstruct_gets(t
, &port
) < 0 ||
4637 !pa_tagstruct_eof(t
)) {
4642 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4643 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
);
4644 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4645 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4646 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4648 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4651 if (idx
!= PA_INVALID_INDEX
)
4652 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4654 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4656 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4658 if ((ret
= pa_sink_set_port(sink
, port
, TRUE
)) < 0) {
4659 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4665 pa_assert(command
= PA_COMMAND_SET_SOURCE_PORT
);
4667 if (idx
!= PA_INVALID_INDEX
)
4668 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4670 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4672 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4674 if ((ret
= pa_source_set_port(source
, port
, TRUE
)) < 0) {
4675 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4680 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4683 /*** pstream callbacks ***/
4685 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4686 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4690 pa_native_connection_assert_ref(c
);
4692 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4693 pa_log("invalid packet.");
4694 native_connection_unlink(c
);
4698 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
) {
4699 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4700 output_stream
*stream
;
4704 pa_native_connection_assert_ref(c
);
4706 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4707 pa_log_debug("Client sent block for invalid stream.");
4712 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4714 if (playback_stream_isinstance(stream
)) {
4715 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4717 pa_atomic_inc(&ps
->seek_or_post_in_queue
);
4718 if (chunk
->memblock
) {
4719 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4720 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
);
4722 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
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
->length
, NULL
, NULL
);
4727 upload_stream
*u
= UPLOAD_STREAM(stream
);
4730 if (!u
->memchunk
.memblock
) {
4731 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4732 u
->memchunk
= *chunk
;
4733 pa_memblock_ref(u
->memchunk
.memblock
);
4736 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4737 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4741 pa_assert(u
->memchunk
.memblock
);
4744 if (l
> chunk
->length
)
4749 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4751 if (chunk
->memblock
) {
4753 src
= pa_memblock_acquire(chunk
->memblock
);
4755 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4756 (uint8_t*) src
+ chunk
->index
, l
);
4758 pa_memblock_release(chunk
->memblock
);
4760 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4762 pa_memblock_release(u
->memchunk
.memblock
);
4764 u
->memchunk
.length
+= l
;
4770 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4771 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4774 pa_native_connection_assert_ref(c
);
4776 native_connection_unlink(c
);
4777 pa_log_info("Connection died.");
4780 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4781 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4784 pa_native_connection_assert_ref(c
);
4786 native_connection_send_memblock(c
);
4789 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4792 if (!(q
= pa_thread_mq_get()))
4793 pa_pstream_send_revoke(p
, block_id
);
4795 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4798 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4801 if (!(q
= pa_thread_mq_get()))
4802 pa_pstream_send_release(p
, block_id
);
4804 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4807 /*** client callbacks ***/
4809 static void client_kill_cb(pa_client
*c
) {
4812 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4813 pa_log_info("Connection killed.");
4816 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4818 pa_native_connection
*c
;
4821 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4822 pa_native_connection_assert_ref(c
);
4824 if (c
->version
< 15)
4827 t
= pa_tagstruct_new(NULL
, 0);
4828 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4829 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4830 pa_tagstruct_puts(t
, event
);
4831 pa_tagstruct_put_proplist(t
, pl
);
4832 pa_pstream_send_tagstruct(c
->pstream
, t
);
4835 /*** module entry points ***/
4837 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4838 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4841 pa_native_connection_assert_ref(c
);
4842 pa_assert(c
->auth_timeout_event
== e
);
4844 if (!c
->authorized
) {
4845 native_connection_unlink(c
);
4846 pa_log_info("Connection terminated due to authentication timeout.");
4850 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4851 pa_native_connection
*c
;
4854 pa_client_new_data data
;
4860 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4861 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4862 pa_iochannel_free(io
);
4866 pa_client_new_data_init(&data
);
4867 data
.module
= o
->module
;
4868 data
.driver
= __FILE__
;
4869 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4870 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4871 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4872 client
= pa_client_new(p
->core
, &data
);
4873 pa_client_new_data_done(&data
);
4878 c
= pa_msgobject_new(pa_native_connection
);
4879 c
->parent
.parent
.free
= native_connection_free
;
4880 c
->parent
.process_msg
= native_connection_process_msg
;
4882 c
->options
= pa_native_options_ref(o
);
4883 c
->authorized
= FALSE
;
4885 if (o
->auth_anonymous
) {
4886 pa_log_info("Client authenticated anonymously.");
4887 c
->authorized
= TRUE
;
4890 if (!c
->authorized
&&
4892 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
4894 pa_log_info("Client authenticated by IP ACL.");
4895 c
->authorized
= TRUE
;
4899 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
4901 c
->auth_timeout_event
= NULL
;
4903 c
->is_local
= pa_iochannel_socket_is_local(io
);
4907 c
->client
->kill
= client_kill_cb
;
4908 c
->client
->send_event
= client_send_event_cb
;
4909 c
->client
->userdata
= c
;
4911 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
4912 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
4913 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
4914 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
4915 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
4916 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
4917 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
4919 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, TRUE
, command_table
, PA_COMMAND_MAX
);
4921 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
4922 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
4924 c
->rrobin_index
= PA_IDXSET_INVALID
;
4925 c
->subscription
= NULL
;
4927 pa_idxset_put(p
->connections
, c
, NULL
);
4930 if (pa_iochannel_creds_supported(io
))
4931 pa_iochannel_creds_enable(io
);
4934 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
4937 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
4938 pa_native_connection
*c
;
4944 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
4945 if (c
->options
->module
== m
)
4946 native_connection_unlink(c
);
4949 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
4950 pa_native_protocol
*p
;
4955 p
= pa_xnew(pa_native_protocol
, 1);
4958 p
->connections
= pa_idxset_new(NULL
, NULL
);
4962 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
4964 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4965 pa_hook_init(&p
->hooks
[h
], p
);
4967 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
4972 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
4973 pa_native_protocol
*p
;
4975 if ((p
= pa_shared_get(c
, "native-protocol")))
4976 return pa_native_protocol_ref(p
);
4978 return native_protocol_new(c
);
4981 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
4983 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4990 void pa_native_protocol_unref(pa_native_protocol
*p
) {
4991 pa_native_connection
*c
;
4995 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4997 if (PA_REFCNT_DEC(p
) > 0)
5000 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
5001 native_connection_unlink(c
);
5003 pa_idxset_free(p
->connections
, NULL
, NULL
);
5005 pa_strlist_free(p
->servers
);
5007 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
5008 pa_hook_done(&p
->hooks
[h
]);
5010 pa_hashmap_free(p
->extensions
, NULL
, NULL
);
5012 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
5017 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
5019 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5022 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
5024 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5027 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
5029 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5032 p
->servers
= pa_strlist_remove(p
->servers
, name
);
5034 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5037 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
5039 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5044 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
5046 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5051 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
5053 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5056 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
5058 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
5062 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
5064 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5067 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
5070 pa_native_options
* pa_native_options_new(void) {
5071 pa_native_options
*o
;
5073 o
= pa_xnew0(pa_native_options
, 1);
5079 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
5081 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5088 void pa_native_options_unref(pa_native_options
*o
) {
5090 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5092 if (PA_REFCNT_DEC(o
) > 0)
5095 pa_xfree(o
->auth_group
);
5098 pa_ip_acl_free(o
->auth_ip_acl
);
5101 pa_auth_cookie_unref(o
->auth_cookie
);
5106 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
5111 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5114 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
5115 pa_log("auth-anonymous= expects a boolean argument.");
5120 if (pa_modargs_get_value_boolean(ma
, "auth-group-enabled", &enabled
) < 0) {
5121 pa_log("auth-group-enabled= expects a boolean argument.");
5125 pa_xfree(o
->auth_group
);
5126 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
5130 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5133 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
5136 if (!(ipa
= pa_ip_acl_new(acl
))) {
5137 pa_log("Failed to parse IP ACL '%s'", acl
);
5142 pa_ip_acl_free(o
->auth_ip_acl
);
5144 o
->auth_ip_acl
= ipa
;
5148 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
5149 pa_log("auth-cookie-enabled= expects a boolean argument.");
5154 pa_auth_cookie_unref(o
->auth_cookie
);
5159 /* The new name for this is 'auth-cookie', for compat reasons
5160 * we check the old name too */
5161 if (!(cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
)))
5162 if (!(cn
= pa_modargs_get_value(ma
, "cookie", NULL
)))
5163 cn
= PA_NATIVE_COOKIE_FILE
;
5165 if (!(o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, PA_NATIVE_COOKIE_LENGTH
)))
5169 o
->auth_cookie
= NULL
;
5174 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
5175 pa_native_connection_assert_ref(c
);
5180 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
5181 pa_native_connection_assert_ref(c
);