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/timeval.h>
33 #include <pulse/version.h>
34 #include <pulse/utf8.h>
35 #include <pulse/util.h>
36 #include <pulse/xmalloc.h>
38 #include <pulsecore/native-common.h>
39 #include <pulsecore/packet.h>
40 #include <pulsecore/client.h>
41 #include <pulsecore/source-output.h>
42 #include <pulsecore/sink-input.h>
43 #include <pulsecore/pstream.h>
44 #include <pulsecore/tagstruct.h>
45 #include <pulsecore/pdispatch.h>
46 #include <pulsecore/pstream-util.h>
47 #include <pulsecore/authkey.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/core-scache.h>
50 #include <pulsecore/core-subscribe.h>
51 #include <pulsecore/log.h>
52 #include <pulsecore/strlist.h>
53 #include <pulsecore/shared.h>
54 #include <pulsecore/sample-util.h>
55 #include <pulsecore/llist.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
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 pa_buffer_attr buffer_attr
;
90 pa_atomic_t on_the_fly
;
91 pa_usec_t configured_source_latency
;
94 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
95 size_t on_the_fly_snapshot
;
96 pa_usec_t current_monitor_latency
;
97 pa_usec_t current_source_latency
;
100 PA_DECLARE_CLASS(record_stream
);
101 #define RECORD_STREAM(o) (record_stream_cast(o))
102 static PA_DEFINE_CHECK_TYPE(record_stream
, pa_msgobject
);
104 typedef struct output_stream
{
108 PA_DECLARE_CLASS(output_stream
);
109 #define OUTPUT_STREAM(o) (output_stream_cast(o))
110 static PA_DEFINE_CHECK_TYPE(output_stream
, pa_msgobject
);
112 typedef struct playback_stream
{
113 output_stream parent
;
115 pa_native_connection
*connection
;
118 pa_sink_input
*sink_input
;
119 pa_memblockq
*memblockq
;
121 pa_bool_t adjust_latency
:1;
122 pa_bool_t early_requests
:1;
124 pa_bool_t is_underrun
:1;
125 pa_bool_t drain_request
:1;
130 pa_usec_t configured_sink_latency
;
131 pa_buffer_attr buffer_attr
;
133 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
134 int64_t read_index
, write_index
;
135 size_t render_memblockq_length
;
136 pa_usec_t current_sink_latency
;
137 uint64_t playing_for
, underrun_for
;
140 PA_DECLARE_CLASS(playback_stream
);
141 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
142 static PA_DEFINE_CHECK_TYPE(playback_stream
, output_stream
);
144 typedef struct upload_stream
{
145 output_stream parent
;
147 pa_native_connection
*connection
;
150 pa_memchunk memchunk
;
153 pa_sample_spec sample_spec
;
154 pa_channel_map channel_map
;
155 pa_proplist
*proplist
;
158 PA_DECLARE_CLASS(upload_stream
);
159 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
160 static PA_DEFINE_CHECK_TYPE(upload_stream
, output_stream
);
162 struct pa_native_connection
{
164 pa_native_protocol
*protocol
;
165 pa_native_options
*options
;
166 pa_bool_t authorized
:1;
167 pa_bool_t is_local
:1;
171 pa_pdispatch
*pdispatch
;
172 pa_idxset
*record_streams
, *output_streams
;
173 uint32_t rrobin_index
;
174 pa_subscription
*subscription
;
175 pa_time_event
*auth_timeout_event
;
178 PA_DECLARE_CLASS(pa_native_connection
);
179 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
180 static PA_DEFINE_CHECK_TYPE(pa_native_connection
, pa_msgobject
);
182 struct pa_native_protocol
{
186 pa_idxset
*connections
;
189 pa_hook hooks
[PA_NATIVE_HOOK_MAX
];
191 pa_hashmap
*extensions
;
195 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
= PA_SOURCE_OUTPUT_MESSAGE_MAX
199 SINK_INPUT_MESSAGE_POST_DATA
= PA_SINK_INPUT_MESSAGE_MAX
, /* data from main loop to sink input */
200 SINK_INPUT_MESSAGE_DRAIN
, /* disabled prebuf, get playback started. */
201 SINK_INPUT_MESSAGE_FLUSH
,
202 SINK_INPUT_MESSAGE_TRIGGER
,
203 SINK_INPUT_MESSAGE_SEEK
,
204 SINK_INPUT_MESSAGE_PREBUF_FORCE
,
205 SINK_INPUT_MESSAGE_UPDATE_LATENCY
,
206 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
210 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, /* data requested from sink input from the main loop */
211 PLAYBACK_STREAM_MESSAGE_UNDERFLOW
,
212 PLAYBACK_STREAM_MESSAGE_OVERFLOW
,
213 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
,
214 PLAYBACK_STREAM_MESSAGE_STARTED
,
215 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
219 RECORD_STREAM_MESSAGE_POST_DATA
/* data from source output to main loop */
223 CONNECTION_MESSAGE_RELEASE
,
224 CONNECTION_MESSAGE_REVOKE
227 static int sink_input_pop_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
);
228 static void sink_input_kill_cb(pa_sink_input
*i
);
229 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
);
230 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
);
231 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
232 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
233 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
);
234 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
);
236 static void native_connection_send_memblock(pa_native_connection
*c
);
237 static void playback_stream_request_bytes(struct playback_stream
*s
);
239 static void source_output_kill_cb(pa_source_output
*o
);
240 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
);
241 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
);
242 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
);
243 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
);
244 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
);
246 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
247 static int source_output_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
249 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
250 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
251 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
252 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
253 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
254 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
255 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
256 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
257 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
258 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
259 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
260 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
261 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
262 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
263 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
264 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
265 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
266 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
267 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
268 static void command_set_volume(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
269 static void command_set_mute(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
270 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
271 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
272 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
273 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
274 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
275 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
276 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
277 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
278 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
279 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
280 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
281 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
282 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
283 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
284 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
285 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
286 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
288 static const pa_pdispatch_cb_t command_table
[PA_COMMAND_MAX
] = {
289 [PA_COMMAND_ERROR
] = NULL
,
290 [PA_COMMAND_TIMEOUT
] = NULL
,
291 [PA_COMMAND_REPLY
] = NULL
,
292 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = command_create_playback_stream
,
293 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = command_delete_stream
,
294 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = command_drain_playback_stream
,
295 [PA_COMMAND_CREATE_RECORD_STREAM
] = command_create_record_stream
,
296 [PA_COMMAND_DELETE_RECORD_STREAM
] = command_delete_stream
,
297 [PA_COMMAND_AUTH
] = command_auth
,
298 [PA_COMMAND_REQUEST
] = NULL
,
299 [PA_COMMAND_EXIT
] = command_exit
,
300 [PA_COMMAND_SET_CLIENT_NAME
] = command_set_client_name
,
301 [PA_COMMAND_LOOKUP_SINK
] = command_lookup
,
302 [PA_COMMAND_LOOKUP_SOURCE
] = command_lookup
,
303 [PA_COMMAND_STAT
] = command_stat
,
304 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = command_get_playback_latency
,
305 [PA_COMMAND_GET_RECORD_LATENCY
] = command_get_record_latency
,
306 [PA_COMMAND_CREATE_UPLOAD_STREAM
] = command_create_upload_stream
,
307 [PA_COMMAND_DELETE_UPLOAD_STREAM
] = command_delete_stream
,
308 [PA_COMMAND_FINISH_UPLOAD_STREAM
] = command_finish_upload_stream
,
309 [PA_COMMAND_PLAY_SAMPLE
] = command_play_sample
,
310 [PA_COMMAND_REMOVE_SAMPLE
] = command_remove_sample
,
311 [PA_COMMAND_GET_SINK_INFO
] = command_get_info
,
312 [PA_COMMAND_GET_SOURCE_INFO
] = command_get_info
,
313 [PA_COMMAND_GET_CLIENT_INFO
] = command_get_info
,
314 [PA_COMMAND_GET_CARD_INFO
] = command_get_info
,
315 [PA_COMMAND_GET_MODULE_INFO
] = command_get_info
,
316 [PA_COMMAND_GET_SINK_INPUT_INFO
] = command_get_info
,
317 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO
] = command_get_info
,
318 [PA_COMMAND_GET_SAMPLE_INFO
] = command_get_info
,
319 [PA_COMMAND_GET_SINK_INFO_LIST
] = command_get_info_list
,
320 [PA_COMMAND_GET_SOURCE_INFO_LIST
] = command_get_info_list
,
321 [PA_COMMAND_GET_MODULE_INFO_LIST
] = command_get_info_list
,
322 [PA_COMMAND_GET_CLIENT_INFO_LIST
] = command_get_info_list
,
323 [PA_COMMAND_GET_CARD_INFO_LIST
] = command_get_info_list
,
324 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST
] = command_get_info_list
,
325 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
] = command_get_info_list
,
326 [PA_COMMAND_GET_SAMPLE_INFO_LIST
] = command_get_info_list
,
327 [PA_COMMAND_GET_SERVER_INFO
] = command_get_server_info
,
328 [PA_COMMAND_SUBSCRIBE
] = command_subscribe
,
330 [PA_COMMAND_SET_SINK_VOLUME
] = command_set_volume
,
331 [PA_COMMAND_SET_SINK_INPUT_VOLUME
] = command_set_volume
,
332 [PA_COMMAND_SET_SOURCE_VOLUME
] = command_set_volume
,
334 [PA_COMMAND_SET_SINK_MUTE
] = command_set_mute
,
335 [PA_COMMAND_SET_SINK_INPUT_MUTE
] = command_set_mute
,
336 [PA_COMMAND_SET_SOURCE_MUTE
] = command_set_mute
,
338 [PA_COMMAND_SUSPEND_SINK
] = command_suspend
,
339 [PA_COMMAND_SUSPEND_SOURCE
] = command_suspend
,
341 [PA_COMMAND_CORK_PLAYBACK_STREAM
] = command_cork_playback_stream
,
342 [PA_COMMAND_FLUSH_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
343 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
344 [PA_COMMAND_PREBUF_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
346 [PA_COMMAND_CORK_RECORD_STREAM
] = command_cork_record_stream
,
347 [PA_COMMAND_FLUSH_RECORD_STREAM
] = command_flush_record_stream
,
349 [PA_COMMAND_SET_DEFAULT_SINK
] = command_set_default_sink_or_source
,
350 [PA_COMMAND_SET_DEFAULT_SOURCE
] = command_set_default_sink_or_source
,
351 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME
] = command_set_stream_name
,
352 [PA_COMMAND_SET_RECORD_STREAM_NAME
] = command_set_stream_name
,
353 [PA_COMMAND_KILL_CLIENT
] = command_kill
,
354 [PA_COMMAND_KILL_SINK_INPUT
] = command_kill
,
355 [PA_COMMAND_KILL_SOURCE_OUTPUT
] = command_kill
,
356 [PA_COMMAND_LOAD_MODULE
] = command_load_module
,
357 [PA_COMMAND_UNLOAD_MODULE
] = command_unload_module
,
359 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE
] = NULL
,
360 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE
] = NULL
,
361 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE
] = NULL
,
362 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE
] = NULL
,
364 [PA_COMMAND_MOVE_SINK_INPUT
] = command_move_stream
,
365 [PA_COMMAND_MOVE_SOURCE_OUTPUT
] = command_move_stream
,
367 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
368 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
370 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
371 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
373 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
] = command_update_proplist
,
374 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
] = command_update_proplist
,
375 [PA_COMMAND_UPDATE_CLIENT_PROPLIST
] = command_update_proplist
,
377 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
] = command_remove_proplist
,
378 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
] = command_remove_proplist
,
379 [PA_COMMAND_REMOVE_CLIENT_PROPLIST
] = command_remove_proplist
,
381 [PA_COMMAND_SET_CARD_PROFILE
] = command_set_card_profile
,
383 [PA_COMMAND_EXTENSION
] = command_extension
386 /* structure management */
388 /* Called from main context */
389 static void upload_stream_unlink(upload_stream
*s
) {
395 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
396 s
->connection
= NULL
;
397 upload_stream_unref(s
);
400 /* Called from main context */
401 static void upload_stream_free(pa_object
*o
) {
402 upload_stream
*s
= UPLOAD_STREAM(o
);
405 upload_stream_unlink(s
);
410 pa_proplist_free(s
->proplist
);
412 if (s
->memchunk
.memblock
)
413 pa_memblock_unref(s
->memchunk
.memblock
);
418 /* Called from main context */
419 static upload_stream
* upload_stream_new(
420 pa_native_connection
*c
,
421 const pa_sample_spec
*ss
,
422 const pa_channel_map
*map
,
432 pa_assert(length
> 0);
435 s
= pa_msgobject_new(upload_stream
);
436 s
->parent
.parent
.parent
.free
= upload_stream_free
;
438 s
->sample_spec
= *ss
;
439 s
->channel_map
= *map
;
440 s
->name
= pa_xstrdup(name
);
441 pa_memchunk_reset(&s
->memchunk
);
443 s
->proplist
= pa_proplist_copy(p
);
444 pa_proplist_update(s
->proplist
, PA_UPDATE_MERGE
, c
->client
->proplist
);
446 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
451 /* Called from main context */
452 static void record_stream_unlink(record_stream
*s
) {
458 if (s
->source_output
) {
459 pa_source_output_unlink(s
->source_output
);
460 pa_source_output_unref(s
->source_output
);
461 s
->source_output
= NULL
;
464 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->record_streams
, s
, NULL
) == s
);
465 s
->connection
= NULL
;
466 record_stream_unref(s
);
469 /* Called from main context */
470 static void record_stream_free(pa_object
*o
) {
471 record_stream
*s
= RECORD_STREAM(o
);
474 record_stream_unlink(s
);
476 pa_memblockq_free(s
->memblockq
);
480 /* Called from main context */
481 static int record_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
482 record_stream
*s
= RECORD_STREAM(o
);
483 record_stream_assert_ref(s
);
490 case RECORD_STREAM_MESSAGE_POST_DATA
:
492 /* We try to keep up to date with how many bytes are
493 * currently on the fly */
494 pa_atomic_sub(&s
->on_the_fly
, chunk
->length
);
496 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
497 /* pa_log_warn("Failed to push data into output queue."); */
501 if (!pa_pstream_is_pending(s
->connection
->pstream
))
502 native_connection_send_memblock(s
->connection
);
510 /* Called from main context */
511 static void fix_record_buffer_attr_pre(record_stream
*s
) {
514 pa_usec_t orig_fragsize_usec
, fragsize_usec
, source_usec
;
518 /* This function will be called from the main thread, before as
519 * well as after the source output has been activated using
520 * pa_source_output_put()! That means it may not touch any
521 * ->thread_info data! */
523 frame_size
= pa_frame_size(&s
->source_output
->sample_spec
);
525 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
526 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
527 if (s
->buffer_attr
.maxlength
<= 0)
528 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
530 if (s
->buffer_attr
.fragsize
== (uint32_t) -1)
531 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC
*PA_USEC_PER_MSEC
, &s
->source_output
->sample_spec
);
532 if (s
->buffer_attr
.fragsize
<= 0)
533 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
535 orig_fragsize_usec
= fragsize_usec
= pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &s
->source_output
->sample_spec
);
537 if (s
->early_requests
) {
539 /* In early request mode we need to emulate the classic
540 * fragment-based playback model. We do this setting the source
541 * latency to the fragment size. */
543 source_usec
= fragsize_usec
;
545 } else if (s
->adjust_latency
) {
547 /* So, the user asked us to adjust the latency according to
548 * what the source can provide. Half the latency will be
549 * spent on the hw buffer, half of it in the async buffer
550 * queue we maintain for each client. */
552 source_usec
= fragsize_usec
/2;
556 /* Ok, the user didn't ask us to adjust the latency, hence we
559 source_usec
= (pa_usec_t
) -1;
562 if (source_usec
!= (pa_usec_t
) -1)
563 s
->configured_source_latency
= pa_source_output_set_requested_latency(s
->source_output
, source_usec
);
565 s
->configured_source_latency
= 0;
567 if (s
->early_requests
) {
569 /* Ok, we didn't necessarily get what we were asking for, so
570 * let's tell the user */
572 fragsize_usec
= s
->configured_source_latency
;
574 } else if (s
->adjust_latency
) {
576 /* Now subtract what we actually got */
578 if (fragsize_usec
>= s
->configured_source_latency
*2)
579 fragsize_usec
-= s
->configured_source_latency
;
581 fragsize_usec
= s
->configured_source_latency
;
584 if (pa_usec_to_bytes(orig_fragsize_usec
, &s
->source_output
->sample_spec
) !=
585 pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
))
587 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
);
589 if (s
->buffer_attr
.fragsize
<= 0)
590 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
593 /* Called from main context */
594 static void fix_record_buffer_attr_post(record_stream
*s
) {
599 /* This function will be called from the main thread, before as
600 * well as after the source output has been activated using
601 * pa_source_output_put()! That means it may not touch and
602 * ->thread_info data! */
604 base
= pa_frame_size(&s
->source_output
->sample_spec
);
606 s
->buffer_attr
.fragsize
= (s
->buffer_attr
.fragsize
/base
)*base
;
607 if (s
->buffer_attr
.fragsize
<= 0)
608 s
->buffer_attr
.fragsize
= base
;
610 if (s
->buffer_attr
.fragsize
> s
->buffer_attr
.maxlength
)
611 s
->buffer_attr
.fragsize
= s
->buffer_attr
.maxlength
;
614 /* Called from main context */
615 static record_stream
* record_stream_new(
616 pa_native_connection
*c
,
620 pa_bool_t peak_detect
,
621 pa_buffer_attr
*attr
,
622 pa_source_output_flags_t flags
,
624 pa_bool_t adjust_latency
,
625 pa_sink_input
*direct_on_input
,
626 pa_bool_t early_requests
,
630 pa_source_output
*source_output
= NULL
;
632 pa_source_output_new_data data
;
639 pa_source_output_new_data_init(&data
);
641 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
642 data
.driver
= __FILE__
;
643 data
.module
= c
->options
->module
;
644 data
.client
= c
->client
;
645 data
.source
= source
;
646 data
.direct_on_input
= direct_on_input
;
647 pa_source_output_new_data_set_sample_spec(&data
, ss
);
648 pa_source_output_new_data_set_channel_map(&data
, map
);
650 data
.resample_method
= PA_RESAMPLER_PEAKS
;
652 *ret
= -pa_source_output_new(&source_output
, c
->protocol
->core
, &data
, flags
);
654 pa_source_output_new_data_done(&data
);
659 s
= pa_msgobject_new(record_stream
);
660 s
->parent
.parent
.free
= record_stream_free
;
661 s
->parent
.process_msg
= record_stream_process_msg
;
663 s
->source_output
= source_output
;
664 s
->buffer_attr
= *attr
;
665 s
->adjust_latency
= adjust_latency
;
666 s
->early_requests
= early_requests
;
667 pa_atomic_store(&s
->on_the_fly
, 0);
669 s
->source_output
->parent
.process_msg
= source_output_process_msg
;
670 s
->source_output
->push
= source_output_push_cb
;
671 s
->source_output
->kill
= source_output_kill_cb
;
672 s
->source_output
->get_latency
= source_output_get_latency_cb
;
673 s
->source_output
->moving
= source_output_moving_cb
;
674 s
->source_output
->suspend
= source_output_suspend_cb
;
675 s
->source_output
->send_event
= source_output_send_event_cb
;
676 s
->source_output
->userdata
= s
;
678 fix_record_buffer_attr_pre(s
);
680 s
->memblockq
= pa_memblockq_new(
682 s
->buffer_attr
.maxlength
,
684 base
= pa_frame_size(&source_output
->sample_spec
),
690 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
691 fix_record_buffer_attr_post(s
);
693 *ss
= s
->source_output
->sample_spec
;
694 *map
= s
->source_output
->channel_map
;
696 pa_idxset_put(c
->record_streams
, s
, &s
->index
);
698 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
699 ((double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) + (double) s
->configured_source_latency
) / PA_USEC_PER_MSEC
,
700 (double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) / PA_USEC_PER_MSEC
,
701 (double) s
->configured_source_latency
/ PA_USEC_PER_MSEC
);
703 pa_source_output_put(s
->source_output
);
707 /* Called from main context */
708 static void record_stream_send_killed(record_stream
*r
) {
710 record_stream_assert_ref(r
);
712 t
= pa_tagstruct_new(NULL
, 0);
713 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_KILLED
);
714 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
715 pa_tagstruct_putu32(t
, r
->index
);
716 pa_pstream_send_tagstruct(r
->connection
->pstream
, t
);
719 /* Called from main context */
720 static void playback_stream_unlink(playback_stream
*s
) {
727 pa_sink_input_unlink(s
->sink_input
);
728 pa_sink_input_unref(s
->sink_input
);
729 s
->sink_input
= NULL
;
732 if (s
->drain_request
)
733 pa_pstream_send_error(s
->connection
->pstream
, s
->drain_tag
, PA_ERR_NOENTITY
);
735 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
736 s
->connection
= NULL
;
737 playback_stream_unref(s
);
740 /* Called from main context */
741 static void playback_stream_free(pa_object
* o
) {
742 playback_stream
*s
= PLAYBACK_STREAM(o
);
745 playback_stream_unlink(s
);
747 pa_memblockq_free(s
->memblockq
);
751 /* Called from main context */
752 static int playback_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
753 playback_stream
*s
= PLAYBACK_STREAM(o
);
754 playback_stream_assert_ref(s
);
760 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
: {
765 if ((l
= pa_atomic_load(&s
->missing
)) <= 0)
768 if (pa_atomic_cmpxchg(&s
->missing
, l
, 0))
772 t
= pa_tagstruct_new(NULL
, 0);
773 pa_tagstruct_putu32(t
, PA_COMMAND_REQUEST
);
774 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
775 pa_tagstruct_putu32(t
, s
->index
);
776 pa_tagstruct_putu32(t
, (uint32_t) l
);
777 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
779 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
783 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW
: {
786 /* pa_log("signalling underflow"); */
788 /* Report that we're empty */
789 t
= pa_tagstruct_new(NULL
, 0);
790 pa_tagstruct_putu32(t
, PA_COMMAND_UNDERFLOW
);
791 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
792 pa_tagstruct_putu32(t
, s
->index
);
793 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
797 case PLAYBACK_STREAM_MESSAGE_OVERFLOW
: {
800 /* Notify the user we're overflowed*/
801 t
= pa_tagstruct_new(NULL
, 0);
802 pa_tagstruct_putu32(t
, PA_COMMAND_OVERFLOW
);
803 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
804 pa_tagstruct_putu32(t
, s
->index
);
805 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
809 case PLAYBACK_STREAM_MESSAGE_STARTED
:
811 if (s
->connection
->version
>= 13) {
814 /* Notify the user we started playback */
815 t
= pa_tagstruct_new(NULL
, 0);
816 pa_tagstruct_putu32(t
, PA_COMMAND_STARTED
);
817 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
818 pa_tagstruct_putu32(t
, s
->index
);
819 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
824 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
:
825 pa_pstream_send_simple_ack(s
->connection
->pstream
, PA_PTR_TO_UINT(userdata
));
828 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
: {
831 s
->buffer_attr
.tlength
= (uint32_t) offset
;
833 t
= pa_tagstruct_new(NULL
, 0);
834 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
);
835 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
836 pa_tagstruct_putu32(t
, s
->index
);
837 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
838 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
839 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
840 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
841 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
842 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
851 /* Called from main context */
852 static void fix_playback_buffer_attr(playback_stream
*s
) {
854 pa_usec_t orig_tlength_usec
, tlength_usec
, orig_minreq_usec
, minreq_usec
, sink_usec
;
858 /* This function will be called from the main thread, before as
859 * well as after the sink input has been activated using
860 * pa_sink_input_put()! That means it may not touch any
861 * ->thread_info data, such as the memblockq! */
863 frame_size
= pa_frame_size(&s
->sink_input
->sample_spec
);
865 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
866 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
867 if (s
->buffer_attr
.maxlength
<= 0)
868 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
870 if (s
->buffer_attr
.tlength
== (uint32_t) -1)
871 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
872 if (s
->buffer_attr
.tlength
<= 0)
873 s
->buffer_attr
.tlength
= (uint32_t) frame_size
;
875 if (s
->buffer_attr
.minreq
== (uint32_t) -1)
876 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
877 if (s
->buffer_attr
.minreq
<= 0)
878 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
880 if (s
->buffer_attr
.tlength
< s
->buffer_attr
.minreq
+frame_size
)
881 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
+(uint32_t) frame_size
;
883 orig_tlength_usec
= tlength_usec
= pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
);
884 orig_minreq_usec
= minreq_usec
= pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
);
886 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
887 (double) tlength_usec
/ PA_USEC_PER_MSEC
,
888 (double) minreq_usec
/ PA_USEC_PER_MSEC
);
890 if (s
->early_requests
) {
892 /* In early request mode we need to emulate the classic
893 * fragment-based playback model. We do this setting the sink
894 * latency to the fragment size. */
896 sink_usec
= minreq_usec
;
897 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
899 } else if (s
->adjust_latency
) {
901 /* So, the user asked us to adjust the latency of the stream
902 * buffer according to the what the sink can provide. The
903 * tlength passed in shall be the overall latency. Roughly
904 * half the latency will be spent on the hw buffer, the other
905 * half of it in the async buffer queue we maintain for each
906 * client. In between we'll have a safety space of size
907 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
908 * empty and needs to be filled, then our buffer must have
909 * enough data to fulfill this request immediatly and thus
910 * have at least the same tlength as the size of the hw
911 * buffer. It additionally needs space for 2 times minreq
912 * because if the buffer ran empty and a partial fillup
913 * happens immediately on the next iteration we need to be
914 * able to fulfill it and give the application also minreq
915 * time to fill it up again for the next request Makes 2 times
916 * minreq in plus.. */
918 if (tlength_usec
> minreq_usec
*2)
919 sink_usec
= (tlength_usec
- minreq_usec
*2)/2;
923 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
927 /* Ok, the user didn't ask us to adjust the latency, but we
928 * still need to make sure that the parameters from the user
931 if (tlength_usec
> minreq_usec
*2)
932 sink_usec
= (tlength_usec
- minreq_usec
*2);
936 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
939 s
->configured_sink_latency
= pa_sink_input_set_requested_latency(s
->sink_input
, sink_usec
);
941 if (s
->early_requests
) {
943 /* Ok, we didn't necessarily get what we were asking for, so
944 * let's tell the user */
946 minreq_usec
= s
->configured_sink_latency
;
948 } else if (s
->adjust_latency
) {
950 /* Ok, we didn't necessarily get what we were asking for, so
951 * let's subtract from what we asked for for the remaining
954 if (tlength_usec
>= s
->configured_sink_latency
)
955 tlength_usec
-= s
->configured_sink_latency
;
958 /* FIXME: This is actually larger than necessary, since not all of
959 * the sink latency is actually rewritable. */
960 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
961 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
963 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
964 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
965 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
967 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
968 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
969 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
971 if (s
->buffer_attr
.minreq
<= 0) {
972 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
973 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
976 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
977 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
979 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 || s
->buffer_attr
.prebuf
> s
->buffer_attr
.tlength
)
980 s
->buffer_attr
.prebuf
= s
->buffer_attr
.tlength
;
983 /* Called from main context */
984 static playback_stream
* playback_stream_new(
985 pa_native_connection
*c
,
995 pa_sink_input_flags_t flags
,
997 pa_bool_t adjust_latency
,
998 pa_bool_t early_requests
,
1001 playback_stream
*s
, *ssync
;
1002 pa_sink_input
*sink_input
= NULL
;
1003 pa_memchunk silence
;
1005 int64_t start_index
;
1006 pa_sink_input_new_data data
;
1014 /* Find syncid group */
1015 for (ssync
= pa_idxset_first(c
->output_streams
, &idx
); ssync
; ssync
= pa_idxset_next(c
->output_streams
, &idx
)) {
1017 if (!playback_stream_isinstance(ssync
))
1020 if (ssync
->syncid
== syncid
)
1024 /* Synced streams must connect to the same sink */
1028 sink
= ssync
->sink_input
->sink
;
1029 else if (sink
!= ssync
->sink_input
->sink
) {
1030 *ret
= PA_ERR_INVALID
;
1035 pa_sink_input_new_data_init(&data
);
1037 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1038 data
.driver
= __FILE__
;
1039 data
.module
= c
->options
->module
;
1040 data
.client
= c
->client
;
1042 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1043 pa_sink_input_new_data_set_channel_map(&data
, map
);
1045 pa_sink_input_new_data_set_volume(&data
, volume
);
1047 pa_sink_input_new_data_set_muted(&data
, muted
);
1048 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1050 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
, flags
);
1052 pa_sink_input_new_data_done(&data
);
1057 s
= pa_msgobject_new(playback_stream
);
1058 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1059 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1062 s
->sink_input
= sink_input
;
1063 s
->is_underrun
= TRUE
;
1064 s
->drain_request
= FALSE
;
1065 pa_atomic_store(&s
->missing
, 0);
1066 s
->buffer_attr
= *a
;
1067 s
->adjust_latency
= adjust_latency
;
1068 s
->early_requests
= early_requests
;
1070 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1071 s
->sink_input
->pop
= sink_input_pop_cb
;
1072 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1073 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1074 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1075 s
->sink_input
->kill
= sink_input_kill_cb
;
1076 s
->sink_input
->moving
= sink_input_moving_cb
;
1077 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1078 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1079 s
->sink_input
->userdata
= s
;
1081 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1083 fix_playback_buffer_attr(s
);
1085 pa_sink_input_get_silence(sink_input
, &silence
);
1086 s
->memblockq
= pa_memblockq_new(
1088 s
->buffer_attr
.maxlength
,
1089 s
->buffer_attr
.tlength
,
1090 pa_frame_size(&sink_input
->sample_spec
),
1091 s
->buffer_attr
.prebuf
,
1092 s
->buffer_attr
.minreq
,
1095 pa_memblock_unref(silence
.memblock
);
1097 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1099 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1101 *ss
= s
->sink_input
->sample_spec
;
1102 *map
= s
->sink_input
->channel_map
;
1104 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1106 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1107 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1108 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1109 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1110 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1112 pa_sink_input_put(s
->sink_input
);
1116 /* Called from IO context */
1117 static void playback_stream_request_bytes(playback_stream
*s
) {
1119 int previous_missing
;
1121 playback_stream_assert_ref(s
);
1123 m
= pa_memblockq_pop_missing(s
->memblockq
);
1128 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1130 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1131 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1133 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1134 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1135 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1139 /* Called from main context */
1140 static void playback_stream_send_killed(playback_stream
*p
) {
1142 playback_stream_assert_ref(p
);
1144 t
= pa_tagstruct_new(NULL
, 0);
1145 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1146 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1147 pa_tagstruct_putu32(t
, p
->index
);
1148 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1151 /* Called from main context */
1152 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1153 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1154 pa_native_connection_assert_ref(c
);
1161 case CONNECTION_MESSAGE_REVOKE
:
1162 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1165 case CONNECTION_MESSAGE_RELEASE
:
1166 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1173 /* Called from main context */
1174 static void native_connection_unlink(pa_native_connection
*c
) {
1183 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1186 pa_native_options_unref(c
->options
);
1188 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1189 record_stream_unlink(r
);
1191 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1192 if (playback_stream_isinstance(o
))
1193 playback_stream_unlink(PLAYBACK_STREAM(o
));
1195 upload_stream_unlink(UPLOAD_STREAM(o
));
1197 if (c
->subscription
)
1198 pa_subscription_free(c
->subscription
);
1201 pa_pstream_unlink(c
->pstream
);
1203 if (c
->auth_timeout_event
) {
1204 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1205 c
->auth_timeout_event
= NULL
;
1208 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1210 pa_native_connection_unref(c
);
1213 /* Called from main context */
1214 static void native_connection_free(pa_object
*o
) {
1215 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1219 native_connection_unlink(c
);
1221 pa_idxset_free(c
->record_streams
, NULL
, NULL
);
1222 pa_idxset_free(c
->output_streams
, NULL
, NULL
);
1224 pa_pdispatch_unref(c
->pdispatch
);
1225 pa_pstream_unref(c
->pstream
);
1226 pa_client_free(c
->client
);
1231 /* Called from main context */
1232 static void native_connection_send_memblock(pa_native_connection
*c
) {
1236 start
= PA_IDXSET_INVALID
;
1240 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1243 if (start
== PA_IDXSET_INVALID
)
1244 start
= c
->rrobin_index
;
1245 else if (start
== c
->rrobin_index
)
1248 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1249 pa_memchunk schunk
= chunk
;
1251 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1252 schunk
.length
= r
->buffer_attr
.fragsize
;
1254 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1256 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1257 pa_memblock_unref(schunk
.memblock
);
1264 /*** sink input callbacks ***/
1266 /* Called from thread context */
1267 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1268 playback_stream_assert_ref(s
);
1270 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1272 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1274 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1276 if (pa_memblockq_is_readable(s
->memblockq
)) {
1278 /* We just ended an underrun, let's ask the sink
1279 * for a complete rewind rewrite */
1281 pa_log_debug("Requesting rewind due to end of underrun.");
1282 pa_sink_input_request_rewind(s
->sink_input
,
1283 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (size_t) -1 ? 0 : s
->sink_input
->thread_info
.underrun_for
),
1284 FALSE
, TRUE
, FALSE
);
1290 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1292 if (indexw
< indexr
) {
1293 /* OK, the sink already asked for this data, so
1294 * let's have it usk us again */
1296 pa_log_debug("Requesting rewind due to rewrite.");
1297 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), TRUE
, FALSE
, FALSE
);
1301 playback_stream_request_bytes(s
);
1304 /* Called from thread context */
1305 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1306 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1309 pa_sink_input_assert_ref(i
);
1310 s
= PLAYBACK_STREAM(i
->userdata
);
1311 playback_stream_assert_ref(s
);
1315 case SINK_INPUT_MESSAGE_SEEK
: {
1318 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1320 /* The client side is incapable of accounting correctly
1321 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1322 * able to deal with that. */
1324 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1326 handle_seek(s
, windex
);
1330 case SINK_INPUT_MESSAGE_POST_DATA
: {
1335 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1337 /* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
1339 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1340 pa_log_warn("Failed to push data into queue");
1341 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1342 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, TRUE
);
1345 handle_seek(s
, windex
);
1347 /* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1352 case SINK_INPUT_MESSAGE_DRAIN
:
1353 case SINK_INPUT_MESSAGE_FLUSH
:
1354 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1355 case SINK_INPUT_MESSAGE_TRIGGER
: {
1358 pa_sink_input
*isync
;
1359 void (*func
)(pa_memblockq
*bq
);
1362 case SINK_INPUT_MESSAGE_FLUSH
:
1363 func
= pa_memblockq_flush_write
;
1366 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1367 func
= pa_memblockq_prebuf_force
;
1370 case SINK_INPUT_MESSAGE_DRAIN
:
1371 case SINK_INPUT_MESSAGE_TRIGGER
:
1372 func
= pa_memblockq_prebuf_disable
;
1376 pa_assert_not_reached();
1379 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1381 handle_seek(s
, windex
);
1383 /* Do the same for all other members in the sync group */
1384 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1385 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1386 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1387 func(ssync
->memblockq
);
1388 handle_seek(ssync
, windex
);
1391 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1392 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1393 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1394 func(ssync
->memblockq
);
1395 handle_seek(ssync
, windex
);
1398 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1399 if (!pa_memblockq_is_readable(s
->memblockq
))
1400 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1402 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1403 s
->drain_request
= TRUE
;
1410 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1411 /* Atomically get a snapshot of all timing parameters... */
1412 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1413 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1414 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1415 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1416 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1417 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1421 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1424 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1426 pa_memblockq_prebuf_force(s
->memblockq
);
1428 handle_seek(s
, windex
);
1430 /* Fall through to the default handler */
1434 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1435 pa_usec_t
*r
= userdata
;
1437 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1439 /* Fall through, the default handler will add in the extra
1440 * latency added by the resampler */
1444 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1445 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1446 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1451 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1454 /* Called from thread context */
1455 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1458 pa_sink_input_assert_ref(i
);
1459 s
= PLAYBACK_STREAM(i
->userdata
);
1460 playback_stream_assert_ref(s
);
1463 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1465 if (pa_memblockq_is_readable(s
->memblockq
))
1466 s
->is_underrun
= FALSE
;
1468 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
));
1470 if (s
->drain_request
&& pa_sink_input_safe_to_remove(i
)) {
1471 s
->drain_request
= FALSE
;
1472 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
);
1473 } else if (!s
->is_underrun
)
1474 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UNDERFLOW
, NULL
, 0, NULL
, NULL
);
1476 s
->is_underrun
= TRUE
;
1478 playback_stream_request_bytes(s
);
1481 /* This call will not fail with prebuf=0, hence we check for
1482 underrun explicitly above */
1483 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1486 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1488 if (i
->thread_info
.underrun_for
> 0)
1489 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1491 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1492 playback_stream_request_bytes(s
);
1497 /* Called from thread context */
1498 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1501 pa_sink_input_assert_ref(i
);
1502 s
= PLAYBACK_STREAM(i
->userdata
);
1503 playback_stream_assert_ref(s
);
1505 /* If we are in an underrun, then we don't rewind */
1506 if (i
->thread_info
.underrun_for
> 0)
1509 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1512 /* Called from thread context */
1513 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1516 pa_sink_input_assert_ref(i
);
1517 s
= PLAYBACK_STREAM(i
->userdata
);
1518 playback_stream_assert_ref(s
);
1520 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1523 /* Called from thread context */
1524 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1526 size_t new_tlength
, old_tlength
;
1528 pa_sink_input_assert_ref(i
);
1529 s
= PLAYBACK_STREAM(i
->userdata
);
1530 playback_stream_assert_ref(s
);
1532 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1533 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1535 if (old_tlength
< new_tlength
) {
1536 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1537 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1538 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1540 if (new_tlength
== old_tlength
)
1541 pa_log_debug("Failed to increase tlength");
1543 pa_log_debug("Notifying client about increased tlength");
1544 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
);
1549 /* Called from main context */
1550 static void sink_input_kill_cb(pa_sink_input
*i
) {
1553 pa_sink_input_assert_ref(i
);
1554 s
= PLAYBACK_STREAM(i
->userdata
);
1555 playback_stream_assert_ref(s
);
1557 playback_stream_send_killed(s
);
1558 playback_stream_unlink(s
);
1561 /* Called from main context */
1562 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1566 pa_sink_input_assert_ref(i
);
1567 s
= PLAYBACK_STREAM(i
->userdata
);
1568 playback_stream_assert_ref(s
);
1570 if (s
->connection
->version
< 15)
1573 t
= pa_tagstruct_new(NULL
, 0);
1574 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1575 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1576 pa_tagstruct_putu32(t
, s
->index
);
1577 pa_tagstruct_puts(t
, event
);
1578 pa_tagstruct_put_proplist(t
, pl
);
1579 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1582 /* Called from main context */
1583 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
) {
1587 pa_sink_input_assert_ref(i
);
1588 s
= PLAYBACK_STREAM(i
->userdata
);
1589 playback_stream_assert_ref(s
);
1591 if (s
->connection
->version
< 12)
1594 t
= pa_tagstruct_new(NULL
, 0);
1595 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1596 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1597 pa_tagstruct_putu32(t
, s
->index
);
1598 pa_tagstruct_put_boolean(t
, suspend
);
1599 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1602 /* Called from main context */
1603 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1607 pa_sink_input_assert_ref(i
);
1608 s
= PLAYBACK_STREAM(i
->userdata
);
1609 playback_stream_assert_ref(s
);
1611 fix_playback_buffer_attr(s
);
1612 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1613 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1615 if (s
->connection
->version
< 12)
1618 t
= pa_tagstruct_new(NULL
, 0);
1619 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1620 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1621 pa_tagstruct_putu32(t
, s
->index
);
1622 pa_tagstruct_putu32(t
, dest
->index
);
1623 pa_tagstruct_puts(t
, dest
->name
);
1624 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1626 if (s
->connection
->version
>= 13) {
1627 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1628 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1629 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1630 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1631 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1634 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1637 /*** source_output callbacks ***/
1639 /* Called from thread context */
1640 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1641 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1644 pa_source_output_assert_ref(o
);
1645 s
= RECORD_STREAM(o
->userdata
);
1646 record_stream_assert_ref(s
);
1649 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1650 /* Atomically get a snapshot of all timing parameters... */
1651 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1652 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1653 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1657 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1660 /* Called from thread context */
1661 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1664 pa_source_output_assert_ref(o
);
1665 s
= RECORD_STREAM(o
->userdata
);
1666 record_stream_assert_ref(s
);
1669 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1670 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1673 static void source_output_kill_cb(pa_source_output
*o
) {
1676 pa_source_output_assert_ref(o
);
1677 s
= RECORD_STREAM(o
->userdata
);
1678 record_stream_assert_ref(s
);
1680 record_stream_send_killed(s
);
1681 record_stream_unlink(s
);
1684 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1687 pa_source_output_assert_ref(o
);
1688 s
= RECORD_STREAM(o
->userdata
);
1689 record_stream_assert_ref(s
);
1691 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1693 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1696 /* Called from main context */
1697 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1701 pa_source_output_assert_ref(o
);
1702 s
= RECORD_STREAM(o
->userdata
);
1703 record_stream_assert_ref(s
);
1705 if (s
->connection
->version
< 15)
1708 t
= pa_tagstruct_new(NULL
, 0);
1709 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1710 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1711 pa_tagstruct_putu32(t
, s
->index
);
1712 pa_tagstruct_puts(t
, event
);
1713 pa_tagstruct_put_proplist(t
, pl
);
1714 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1717 /* Called from main context */
1718 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
) {
1722 pa_source_output_assert_ref(o
);
1723 s
= RECORD_STREAM(o
->userdata
);
1724 record_stream_assert_ref(s
);
1726 if (s
->connection
->version
< 12)
1729 t
= pa_tagstruct_new(NULL
, 0);
1730 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1731 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1732 pa_tagstruct_putu32(t
, s
->index
);
1733 pa_tagstruct_put_boolean(t
, suspend
);
1734 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1737 /* Called from main context */
1738 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1742 pa_source_output_assert_ref(o
);
1743 s
= RECORD_STREAM(o
->userdata
);
1744 record_stream_assert_ref(s
);
1746 fix_record_buffer_attr_pre(s
);
1747 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1748 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1749 fix_record_buffer_attr_post(s
);
1751 if (s
->connection
->version
< 12)
1754 t
= pa_tagstruct_new(NULL
, 0);
1755 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1756 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1757 pa_tagstruct_putu32(t
, s
->index
);
1758 pa_tagstruct_putu32(t
, dest
->index
);
1759 pa_tagstruct_puts(t
, dest
->name
);
1760 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1762 if (s
->connection
->version
>= 13) {
1763 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1764 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1765 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1768 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1771 /*** pdispatch callbacks ***/
1773 static void protocol_error(pa_native_connection
*c
) {
1774 pa_log("protocol error, kicking client");
1775 native_connection_unlink(c
);
1778 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1779 if (!(expression)) { \
1780 pa_pstream_send_error((pstream), (tag), (error)); \
1785 static pa_tagstruct
*reply_new(uint32_t tag
) {
1786 pa_tagstruct
*reply
;
1788 reply
= pa_tagstruct_new(NULL
, 0);
1789 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1790 pa_tagstruct_putu32(reply
, tag
);
1794 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1795 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1797 uint32_t sink_index
, syncid
, missing
;
1798 pa_buffer_attr attr
;
1799 const char *name
= NULL
, *sink_name
;
1802 pa_tagstruct
*reply
;
1803 pa_sink
*sink
= NULL
;
1811 fix_channels
= FALSE
,
1813 variable_rate
= FALSE
,
1815 adjust_latency
= FALSE
,
1816 early_requests
= FALSE
,
1817 dont_inhibit_auto_suspend
= FALSE
,
1819 fail_on_suspend
= FALSE
;
1820 pa_sink_input_flags_t flags
= 0;
1822 pa_bool_t volume_set
= TRUE
;
1823 int ret
= PA_ERR_INVALID
;
1825 pa_native_connection_assert_ref(c
);
1827 memset(&attr
, 0, sizeof(attr
));
1829 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
1832 PA_TAG_SAMPLE_SPEC
, &ss
,
1833 PA_TAG_CHANNEL_MAP
, &map
,
1834 PA_TAG_U32
, &sink_index
,
1835 PA_TAG_STRING
, &sink_name
,
1836 PA_TAG_U32
, &attr
.maxlength
,
1837 PA_TAG_BOOLEAN
, &corked
,
1838 PA_TAG_U32
, &attr
.tlength
,
1839 PA_TAG_U32
, &attr
.prebuf
,
1840 PA_TAG_U32
, &attr
.minreq
,
1841 PA_TAG_U32
, &syncid
,
1842 PA_TAG_CVOLUME
, &volume
,
1843 PA_TAG_INVALID
) < 0) {
1849 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
1850 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name(sink_name
), tag
, PA_ERR_INVALID
);
1851 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
1852 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
1853 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
1854 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
1855 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
1856 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
1858 p
= pa_proplist_new();
1861 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
1863 if (c
->version
>= 12) {
1864 /* Since 0.9.8 the user can ask for a couple of additional flags */
1866 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
1867 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
1868 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
1869 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
1870 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
1871 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
1872 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
1875 pa_proplist_free(p
);
1880 if (c
->version
>= 13) {
1882 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
1883 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
1884 pa_tagstruct_get_proplist(t
, p
) < 0) {
1886 pa_proplist_free(p
);
1891 if (c
->version
>= 14) {
1893 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
1894 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
1896 pa_proplist_free(p
);
1901 if (c
->version
>= 15) {
1903 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
1904 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
1905 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
1907 pa_proplist_free(p
);
1912 if (!pa_tagstruct_eof(t
)) {
1914 pa_proplist_free(p
);
1918 if (sink_index
!= PA_INVALID_INDEX
) {
1920 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
1921 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
1922 pa_proplist_free(p
);
1926 } else if (sink_name
) {
1928 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
1929 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
1930 pa_proplist_free(p
);
1936 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
1937 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
1938 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
1939 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
1940 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
1941 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
1942 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
1943 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
1944 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
1945 (fail_on_suspend
? PA_SINK_INPUT_FAIL_ON_SUSPEND
: 0);
1947 /* Only since protocol version 15 there's a seperate muted_set
1948 * flag. For older versions we synthesize it here */
1949 muted_set
= muted_set
|| muted
;
1951 s
= playback_stream_new(c
, sink
, &ss
, &map
, &attr
, volume_set
? &volume
: NULL
, muted
, muted_set
, syncid
, &missing
, flags
, p
, adjust_latency
, early_requests
, &ret
);
1952 pa_proplist_free(p
);
1954 CHECK_VALIDITY(c
->pstream
, s
, tag
, ret
);
1956 reply
= reply_new(tag
);
1957 pa_tagstruct_putu32(reply
, s
->index
);
1958 pa_assert(s
->sink_input
);
1959 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
1960 pa_tagstruct_putu32(reply
, missing
);
1962 /* pa_log("initial request is %u", missing); */
1964 if (c
->version
>= 9) {
1965 /* Since 0.9.0 we support sending the buffer metrics back to the client */
1967 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
1968 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
1969 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
1970 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
1973 if (c
->version
>= 12) {
1974 /* Since 0.9.8 we support sending the chosen sample
1975 * spec/channel map/device/suspend status back to the
1978 pa_tagstruct_put_sample_spec(reply
, &ss
);
1979 pa_tagstruct_put_channel_map(reply
, &map
);
1981 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
1982 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
1984 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
1987 if (c
->version
>= 13)
1988 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
1990 pa_pstream_send_tagstruct(c
->pstream
, reply
);
1993 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1994 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1997 pa_native_connection_assert_ref(c
);
2000 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2001 !pa_tagstruct_eof(t
)) {
2006 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2010 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2012 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2013 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2017 playback_stream_unlink(s
);
2021 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2023 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2024 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2028 record_stream_unlink(s
);
2032 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2035 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2036 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2040 upload_stream_unlink(s
);
2045 pa_assert_not_reached();
2048 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2051 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2052 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2054 pa_buffer_attr attr
;
2055 uint32_t source_index
;
2056 const char *name
= NULL
, *source_name
;
2059 pa_tagstruct
*reply
;
2060 pa_source
*source
= NULL
;
2067 fix_channels
= FALSE
,
2069 variable_rate
= FALSE
,
2070 adjust_latency
= FALSE
,
2071 peak_detect
= FALSE
,
2072 early_requests
= FALSE
,
2073 dont_inhibit_auto_suspend
= FALSE
,
2074 fail_on_suspend
= FALSE
;
2075 pa_source_output_flags_t flags
= 0;
2077 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2078 pa_sink_input
*direct_on_input
= NULL
;
2079 int ret
= PA_ERR_INVALID
;
2081 pa_native_connection_assert_ref(c
);
2084 memset(&attr
, 0, sizeof(attr
));
2086 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2087 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2088 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2089 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2090 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2091 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2092 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2093 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2098 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2099 CHECK_VALIDITY(c
->pstream
, !source_name
|| pa_namereg_is_valid_name(source_name
), tag
, PA_ERR_INVALID
);
2100 CHECK_VALIDITY(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
);
2101 CHECK_VALIDITY(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2102 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2103 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2104 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2106 p
= pa_proplist_new();
2109 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2111 if (c
->version
>= 12) {
2112 /* Since 0.9.8 the user can ask for a couple of additional flags */
2114 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2115 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2116 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2117 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2118 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2119 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2120 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2123 pa_proplist_free(p
);
2128 if (c
->version
>= 13) {
2130 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2131 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2132 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2133 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2135 pa_proplist_free(p
);
2140 if (c
->version
>= 14) {
2142 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2144 pa_proplist_free(p
);
2149 if (c
->version
>= 15) {
2151 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2152 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2154 pa_proplist_free(p
);
2159 if (!pa_tagstruct_eof(t
)) {
2161 pa_proplist_free(p
);
2165 if (source_index
!= PA_INVALID_INDEX
) {
2167 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2168 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2169 pa_proplist_free(p
);
2173 } else if (source_name
) {
2175 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2176 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2177 pa_proplist_free(p
);
2182 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2184 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2185 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2186 pa_proplist_free(p
);
2192 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2193 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2194 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2195 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2196 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2197 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2198 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2199 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2200 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2201 (fail_on_suspend
? PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND
: 0);
2203 s
= record_stream_new(c
, source
, &ss
, &map
, peak_detect
, &attr
, flags
, p
, adjust_latency
, direct_on_input
, early_requests
, &ret
);
2204 pa_proplist_free(p
);
2206 CHECK_VALIDITY(c
->pstream
, s
, tag
, ret
);
2208 reply
= reply_new(tag
);
2209 pa_tagstruct_putu32(reply
, s
->index
);
2210 pa_assert(s
->source_output
);
2211 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2213 if (c
->version
>= 9) {
2214 /* Since 0.9 we support sending the buffer metrics back to the client */
2216 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2217 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2220 if (c
->version
>= 12) {
2221 /* Since 0.9.8 we support sending the chosen sample
2222 * spec/channel map/device/suspend status back to the
2225 pa_tagstruct_put_sample_spec(reply
, &ss
);
2226 pa_tagstruct_put_channel_map(reply
, &map
);
2228 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2229 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2231 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2234 if (c
->version
>= 13)
2235 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2237 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2240 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2241 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2244 pa_native_connection_assert_ref(c
);
2247 if (!pa_tagstruct_eof(t
)) {
2252 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2253 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2254 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2256 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2259 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2260 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2262 pa_tagstruct
*reply
;
2263 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2265 pa_native_connection_assert_ref(c
);
2268 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2269 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2270 !pa_tagstruct_eof(t
)) {
2275 /* Minimum supported version */
2276 if (c
->version
< 8) {
2277 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2281 /* Starting with protocol version 13 the MSB of the version tag
2282 reflects if shm is available for this pa_native_connection or
2284 if (c
->version
>= 13) {
2285 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2286 c
->version
&= 0x7FFFFFFFU
;
2289 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2291 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2293 if (!c
->authorized
) {
2294 pa_bool_t success
= FALSE
;
2297 const pa_creds
*creds
;
2299 if ((creds
= pa_pdispatch_creds(pd
))) {
2300 if (creds
->uid
== getuid())
2302 else if (c
->options
->auth_group
) {
2306 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2307 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2308 else if (gid
== creds
->gid
)
2312 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2313 pa_log_warn("Failed to check group membership.");
2319 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2320 (unsigned long) creds
->uid
,
2321 (unsigned long) creds
->gid
,
2326 if (!success
&& c
->options
->auth_cookie
) {
2329 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2330 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2335 pa_log_warn("Denied access to client with invalid authorization data.");
2336 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2340 c
->authorized
= TRUE
;
2341 if (c
->auth_timeout_event
) {
2342 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2343 c
->auth_timeout_event
= NULL
;
2347 /* Enable shared memory support if possible */
2349 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2352 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2355 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2360 /* Only enable SHM if both sides are owned by the same
2361 * user. This is a security measure because otherwise data
2362 * private to the user might leak. */
2364 const pa_creds
*creds
;
2365 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2370 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2371 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2373 reply
= reply_new(tag
);
2374 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2378 /* SHM support is only enabled after both sides made sure they are the same user. */
2382 ucred
.uid
= getuid();
2383 ucred
.gid
= getgid();
2385 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2388 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2392 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2393 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2394 const char *name
= NULL
;
2396 pa_tagstruct
*reply
;
2398 pa_native_connection_assert_ref(c
);
2401 p
= pa_proplist_new();
2403 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2404 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2405 !pa_tagstruct_eof(t
)) {
2408 pa_proplist_free(p
);
2413 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2414 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2415 pa_proplist_free(p
);
2419 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2420 pa_proplist_free(p
);
2422 reply
= reply_new(tag
);
2424 if (c
->version
>= 13)
2425 pa_tagstruct_putu32(reply
, c
->client
->index
);
2427 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2430 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2431 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2433 uint32_t idx
= PA_IDXSET_INVALID
;
2435 pa_native_connection_assert_ref(c
);
2438 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2439 !pa_tagstruct_eof(t
)) {
2444 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2445 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2447 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2449 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2453 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2454 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2455 idx
= source
->index
;
2458 if (idx
== PA_IDXSET_INVALID
)
2459 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2461 pa_tagstruct
*reply
;
2462 reply
= reply_new(tag
);
2463 pa_tagstruct_putu32(reply
, idx
);
2464 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2468 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2469 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2473 pa_native_connection_assert_ref(c
);
2476 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2477 !pa_tagstruct_eof(t
)) {
2482 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2483 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2484 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2485 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2487 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
);
2490 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2491 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2492 pa_tagstruct
*reply
;
2493 const pa_mempool_stat
*stat
;
2495 pa_native_connection_assert_ref(c
);
2498 if (!pa_tagstruct_eof(t
)) {
2503 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2505 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2507 reply
= reply_new(tag
);
2508 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2509 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2510 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2511 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2512 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2513 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2516 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2517 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2518 pa_tagstruct
*reply
;
2520 struct timeval tv
, now
;
2523 pa_native_connection_assert_ref(c
);
2526 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2527 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2528 !pa_tagstruct_eof(t
)) {
2533 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2534 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2535 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2536 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2538 /* Get an atomic snapshot of all timing parameters */
2539 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);
2541 reply
= reply_new(tag
);
2542 pa_tagstruct_put_usec(reply
,
2543 s
->current_sink_latency
+
2544 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sample_spec
));
2545 pa_tagstruct_put_usec(reply
, 0);
2546 pa_tagstruct_put_boolean(reply
,
2547 s
->playing_for
> 0 &&
2548 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2549 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2550 pa_tagstruct_put_timeval(reply
, &tv
);
2551 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2552 pa_tagstruct_puts64(reply
, s
->write_index
);
2553 pa_tagstruct_puts64(reply
, s
->read_index
);
2555 if (c
->version
>= 13) {
2556 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2557 pa_tagstruct_putu64(reply
, s
->playing_for
);
2560 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2563 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2564 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2565 pa_tagstruct
*reply
;
2567 struct timeval tv
, now
;
2570 pa_native_connection_assert_ref(c
);
2573 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2574 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2575 !pa_tagstruct_eof(t
)) {
2580 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2581 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2582 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2584 /* Get an atomic snapshot of all timing parameters */
2585 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);
2587 reply
= reply_new(tag
);
2588 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2589 pa_tagstruct_put_usec(reply
,
2590 s
->current_source_latency
+
2591 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->sample_spec
));
2592 pa_tagstruct_put_boolean(reply
,
2593 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2594 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2595 pa_tagstruct_put_timeval(reply
, &tv
);
2596 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2597 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2598 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2599 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2602 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2603 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2606 const char *name
= NULL
;
2609 pa_tagstruct
*reply
;
2612 pa_native_connection_assert_ref(c
);
2615 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2616 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2617 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2618 pa_tagstruct_getu32(t
, &length
) < 0) {
2623 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2624 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2625 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2626 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2627 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2628 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2630 p
= pa_proplist_new();
2632 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2633 !pa_tagstruct_eof(t
)) {
2636 pa_proplist_free(p
);
2640 if (c
->version
< 13)
2641 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2643 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2644 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2646 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2647 pa_proplist_free(p
);
2648 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2651 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2652 pa_proplist_free(p
);
2654 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2656 reply
= reply_new(tag
);
2657 pa_tagstruct_putu32(reply
, s
->index
);
2658 pa_tagstruct_putu32(reply
, length
);
2659 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2662 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2663 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2668 pa_native_connection_assert_ref(c
);
2671 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2672 !pa_tagstruct_eof(t
)) {
2677 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2679 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2680 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2681 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2683 if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2684 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2686 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2688 upload_stream_unlink(s
);
2691 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2692 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2693 uint32_t sink_index
;
2696 const char *name
, *sink_name
;
2699 pa_tagstruct
*reply
;
2701 pa_native_connection_assert_ref(c
);
2704 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2706 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
2707 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
2708 pa_tagstruct_getu32(t
, &volume
) < 0 ||
2709 pa_tagstruct_gets(t
, &name
) < 0) {
2714 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name(sink_name
), tag
, PA_ERR_INVALID
);
2715 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
2716 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2717 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2719 if (sink_index
!= PA_INVALID_INDEX
)
2720 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
2722 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
2724 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
2726 p
= pa_proplist_new();
2728 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2729 !pa_tagstruct_eof(t
)) {
2731 pa_proplist_free(p
);
2735 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
2737 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
2738 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2739 pa_proplist_free(p
);
2743 pa_proplist_free(p
);
2745 reply
= reply_new(tag
);
2747 if (c
->version
>= 13)
2748 pa_tagstruct_putu32(reply
, idx
);
2750 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2753 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2754 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2757 pa_native_connection_assert_ref(c
);
2760 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2761 !pa_tagstruct_eof(t
)) {
2766 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2767 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2769 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
2770 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2774 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2777 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
2780 pa_assert(original
);
2784 if (c
->version
< 12) {
2785 /* Before protocol version 12 we didn't support S32 samples,
2786 * so we need to lie about this to the client */
2788 if (fixed
->format
== PA_SAMPLE_S32LE
)
2789 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
2790 if (fixed
->format
== PA_SAMPLE_S32BE
)
2791 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
2794 if (c
->version
< 15) {
2795 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
2796 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
2797 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
2798 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
2802 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
2803 pa_sample_spec fixed_ss
;
2806 pa_sink_assert_ref(sink
);
2808 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
2812 PA_TAG_U32
, sink
->index
,
2813 PA_TAG_STRING
, sink
->name
,
2814 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
2815 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
2816 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
2817 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
2818 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
2819 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
2820 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
2821 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
2822 PA_TAG_USEC
, pa_sink_get_latency(sink
),
2823 PA_TAG_STRING
, sink
->driver
,
2824 PA_TAG_U32
, sink
->flags
,
2827 if (c
->version
>= 13) {
2828 pa_tagstruct_put_proplist(t
, sink
->proplist
);
2829 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
2832 if (c
->version
>= 15) {
2833 pa_tagstruct_put_volume(t
, sink
->base_volume
);
2834 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
2835 pa_log_error("Internal sink state is invalid.");
2836 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
2837 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
2838 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
2842 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
2843 pa_sample_spec fixed_ss
;
2846 pa_source_assert_ref(source
);
2848 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
2852 PA_TAG_U32
, source
->index
,
2853 PA_TAG_STRING
, source
->name
,
2854 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
2855 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
2856 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
2857 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
2858 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
2859 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
2860 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
2861 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
2862 PA_TAG_USEC
, pa_source_get_latency(source
),
2863 PA_TAG_STRING
, source
->driver
,
2864 PA_TAG_U32
, source
->flags
,
2867 if (c
->version
>= 13) {
2868 pa_tagstruct_put_proplist(t
, source
->proplist
);
2869 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
2872 if (c
->version
>= 15) {
2873 pa_tagstruct_put_volume(t
, source
->base_volume
);
2874 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
2875 pa_log_error("Internal source state is invalid.");
2876 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
2877 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
2878 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
2882 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
2886 pa_tagstruct_putu32(t
, client
->index
);
2887 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
2888 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
2889 pa_tagstruct_puts(t
, client
->driver
);
2891 if (c
->version
>= 13)
2892 pa_tagstruct_put_proplist(t
, client
->proplist
);
2895 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
2902 pa_tagstruct_putu32(t
, card
->index
);
2903 pa_tagstruct_puts(t
, card
->name
);
2904 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
2905 pa_tagstruct_puts(t
, card
->driver
);
2907 pa_tagstruct_putu32(t
, card
->profiles
? pa_hashmap_size(card
->profiles
) : 0);
2909 if (card
->profiles
) {
2910 while ((p
= pa_hashmap_iterate(card
->profiles
, &state
, NULL
))) {
2911 pa_tagstruct_puts(t
, p
->name
);
2912 pa_tagstruct_puts(t
, p
->description
);
2913 pa_tagstruct_putu32(t
, p
->n_sinks
);
2914 pa_tagstruct_putu32(t
, p
->n_sources
);
2915 pa_tagstruct_putu32(t
, p
->priority
);
2919 pa_tagstruct_puts(t
, card
->active_profile
? card
->active_profile
->name
: NULL
);
2920 pa_tagstruct_put_proplist(t
, card
->proplist
);
2923 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
2927 pa_tagstruct_putu32(t
, module
->index
);
2928 pa_tagstruct_puts(t
, module
->name
);
2929 pa_tagstruct_puts(t
, module
->argument
);
2930 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
2932 if (c
->version
< 15)
2933 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
2935 if (c
->version
>= 15)
2936 pa_tagstruct_put_proplist(t
, module
->proplist
);
2939 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
2940 pa_sample_spec fixed_ss
;
2941 pa_usec_t sink_latency
;
2944 pa_sink_input_assert_ref(s
);
2946 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
2948 pa_tagstruct_putu32(t
, s
->index
);
2949 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
2950 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
2951 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
2952 pa_tagstruct_putu32(t
, s
->sink
->index
);
2953 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
2954 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
2955 pa_tagstruct_put_cvolume(t
, pa_sink_input_get_volume(s
));
2956 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
2957 pa_tagstruct_put_usec(t
, sink_latency
);
2958 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
2959 pa_tagstruct_puts(t
, s
->driver
);
2960 if (c
->version
>= 11)
2961 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
2962 if (c
->version
>= 13)
2963 pa_tagstruct_put_proplist(t
, s
->proplist
);
2966 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
2967 pa_sample_spec fixed_ss
;
2968 pa_usec_t source_latency
;
2971 pa_source_output_assert_ref(s
);
2973 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
2975 pa_tagstruct_putu32(t
, s
->index
);
2976 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
2977 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
2978 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
2979 pa_tagstruct_putu32(t
, s
->source
->index
);
2980 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
2981 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
2982 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
2983 pa_tagstruct_put_usec(t
, source_latency
);
2984 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
2985 pa_tagstruct_puts(t
, s
->driver
);
2987 if (c
->version
>= 13)
2988 pa_tagstruct_put_proplist(t
, s
->proplist
);
2991 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
2992 pa_sample_spec fixed_ss
;
2998 if (e
->memchunk
.memblock
)
2999 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3001 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3003 pa_tagstruct_putu32(t
, e
->index
);
3004 pa_tagstruct_puts(t
, e
->name
);
3006 if (e
->volume_is_set
)
3009 pa_cvolume_init(&v
);
3011 pa_tagstruct_put_cvolume(t
, &v
);
3012 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3013 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3014 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3015 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3016 pa_tagstruct_put_boolean(t
, e
->lazy
);
3017 pa_tagstruct_puts(t
, e
->filename
);
3019 if (c
->version
>= 13)
3020 pa_tagstruct_put_proplist(t
, e
->proplist
);
3023 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3024 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3026 pa_sink
*sink
= NULL
;
3027 pa_source
*source
= NULL
;
3028 pa_client
*client
= NULL
;
3029 pa_card
*card
= NULL
;
3030 pa_module
*module
= NULL
;
3031 pa_sink_input
*si
= NULL
;
3032 pa_source_output
*so
= NULL
;
3033 pa_scache_entry
*sce
= NULL
;
3034 const char *name
= NULL
;
3035 pa_tagstruct
*reply
;
3037 pa_native_connection_assert_ref(c
);
3040 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3041 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3042 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3043 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3044 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3045 pa_tagstruct_gets(t
, &name
) < 0) ||
3046 !pa_tagstruct_eof(t
)) {
3051 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3052 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3053 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3054 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3055 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3057 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3058 if (idx
!= PA_INVALID_INDEX
)
3059 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3061 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3062 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3063 if (idx
!= PA_INVALID_INDEX
)
3064 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3066 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3067 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3068 if (idx
!= PA_INVALID_INDEX
)
3069 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3071 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3072 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3073 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3074 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3075 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3076 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3077 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3078 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3079 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3081 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3082 if (idx
!= PA_INVALID_INDEX
)
3083 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3085 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3088 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3089 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3093 reply
= reply_new(tag
);
3095 sink_fill_tagstruct(c
, reply
, sink
);
3097 source_fill_tagstruct(c
, reply
, source
);
3099 client_fill_tagstruct(c
, reply
, client
);
3101 card_fill_tagstruct(c
, reply
, card
);
3103 module_fill_tagstruct(c
, reply
, module
);
3105 sink_input_fill_tagstruct(c
, reply
, si
);
3107 source_output_fill_tagstruct(c
, reply
, so
);
3109 scache_fill_tagstruct(c
, reply
, sce
);
3110 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3113 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3114 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3118 pa_tagstruct
*reply
;
3120 pa_native_connection_assert_ref(c
);
3123 if (!pa_tagstruct_eof(t
)) {
3128 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3130 reply
= reply_new(tag
);
3132 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3133 i
= c
->protocol
->core
->sinks
;
3134 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3135 i
= c
->protocol
->core
->sources
;
3136 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3137 i
= c
->protocol
->core
->clients
;
3138 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3139 i
= c
->protocol
->core
->cards
;
3140 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3141 i
= c
->protocol
->core
->modules
;
3142 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3143 i
= c
->protocol
->core
->sink_inputs
;
3144 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3145 i
= c
->protocol
->core
->source_outputs
;
3147 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3148 i
= c
->protocol
->core
->scache
;
3152 for (p
= pa_idxset_first(i
, &idx
); p
; p
= pa_idxset_next(i
, &idx
)) {
3153 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3154 sink_fill_tagstruct(c
, reply
, p
);
3155 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3156 source_fill_tagstruct(c
, reply
, p
);
3157 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3158 client_fill_tagstruct(c
, reply
, p
);
3159 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3160 card_fill_tagstruct(c
, reply
, p
);
3161 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3162 module_fill_tagstruct(c
, reply
, p
);
3163 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3164 sink_input_fill_tagstruct(c
, reply
, p
);
3165 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3166 source_output_fill_tagstruct(c
, reply
, p
);
3168 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3169 scache_fill_tagstruct(c
, reply
, p
);
3174 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3177 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3178 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3179 pa_tagstruct
*reply
;
3182 pa_source
*def_source
;
3183 pa_sample_spec fixed_ss
;
3185 pa_native_connection_assert_ref(c
);
3188 if (!pa_tagstruct_eof(t
)) {
3193 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3195 reply
= reply_new(tag
);
3196 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3197 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3198 pa_tagstruct_puts(reply
, pa_get_user_name(txt
, sizeof(txt
)));
3199 pa_tagstruct_puts(reply
, pa_get_host_name(txt
, sizeof(txt
)));
3201 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3202 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3204 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3205 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3206 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3207 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3209 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3211 if (c
->version
>= 15)
3212 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3214 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3217 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3219 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3221 pa_native_connection_assert_ref(c
);
3223 t
= pa_tagstruct_new(NULL
, 0);
3224 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3225 pa_tagstruct_putu32(t
, (uint32_t) -1);
3226 pa_tagstruct_putu32(t
, e
);
3227 pa_tagstruct_putu32(t
, idx
);
3228 pa_pstream_send_tagstruct(c
->pstream
, t
);
3231 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3232 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3233 pa_subscription_mask_t m
;
3235 pa_native_connection_assert_ref(c
);
3238 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3239 !pa_tagstruct_eof(t
)) {
3244 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3245 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3247 if (c
->subscription
)
3248 pa_subscription_free(c
->subscription
);
3251 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3252 pa_assert(c
->subscription
);
3254 c
->subscription
= NULL
;
3256 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3259 static void command_set_volume(
3266 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3269 pa_sink
*sink
= NULL
;
3270 pa_source
*source
= NULL
;
3271 pa_sink_input
*si
= NULL
;
3272 const char *name
= NULL
;
3274 pa_native_connection_assert_ref(c
);
3277 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3278 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3279 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3280 pa_tagstruct_get_cvolume(t
, &volume
) ||
3281 !pa_tagstruct_eof(t
)) {
3286 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3287 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3288 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3289 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3290 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3291 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3295 case PA_COMMAND_SET_SINK_VOLUME
:
3296 if (idx
!= PA_INVALID_INDEX
)
3297 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3299 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3302 case PA_COMMAND_SET_SOURCE_VOLUME
:
3303 if (idx
!= PA_INVALID_INDEX
)
3304 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3306 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3309 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3310 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3314 pa_assert_not_reached();
3317 CHECK_VALIDITY(c
->pstream
, si
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3320 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3322 pa_source_set_volume(source
, &volume
);
3324 pa_sink_input_set_volume(si
, &volume
, TRUE
);
3326 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3329 static void command_set_mute(
3336 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3339 pa_sink
*sink
= NULL
;
3340 pa_source
*source
= NULL
;
3341 pa_sink_input
*si
= NULL
;
3342 const char *name
= NULL
;
3344 pa_native_connection_assert_ref(c
);
3347 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3348 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3349 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3350 pa_tagstruct_get_boolean(t
, &mute
) ||
3351 !pa_tagstruct_eof(t
)) {
3356 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3357 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3358 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3359 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3360 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3364 case PA_COMMAND_SET_SINK_MUTE
:
3366 if (idx
!= PA_INVALID_INDEX
)
3367 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3369 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3373 case PA_COMMAND_SET_SOURCE_MUTE
:
3374 if (idx
!= PA_INVALID_INDEX
)
3375 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3377 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3381 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3382 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3386 pa_assert_not_reached();
3389 CHECK_VALIDITY(c
->pstream
, si
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3392 pa_sink_set_mute(sink
, mute
);
3394 pa_source_set_mute(source
, mute
);
3396 pa_sink_input_set_mute(si
, mute
, TRUE
);
3398 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3401 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3402 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3407 pa_native_connection_assert_ref(c
);
3410 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3411 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3412 !pa_tagstruct_eof(t
)) {
3417 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3418 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3419 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3420 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3421 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3423 pa_sink_input_cork(s
->sink_input
, b
);
3426 s
->is_underrun
= TRUE
;
3428 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3431 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3432 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3436 pa_native_connection_assert_ref(c
);
3439 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3440 !pa_tagstruct_eof(t
)) {
3445 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3446 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3447 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3448 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3449 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3452 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3453 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3456 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3457 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3460 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3461 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3465 pa_assert_not_reached();
3468 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3471 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3472 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3477 pa_native_connection_assert_ref(c
);
3480 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3481 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3482 !pa_tagstruct_eof(t
)) {
3487 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3488 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3489 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3491 pa_source_output_cork(s
->source_output
, b
);
3492 pa_memblockq_prebuf_force(s
->memblockq
);
3493 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3496 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3497 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3501 pa_native_connection_assert_ref(c
);
3504 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3505 !pa_tagstruct_eof(t
)) {
3510 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3511 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3512 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3514 pa_memblockq_flush_read(s
->memblockq
);
3515 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3518 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3519 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3522 pa_tagstruct
*reply
;
3524 pa_native_connection_assert_ref(c
);
3527 memset(&a
, 0, sizeof(a
));
3529 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3534 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3536 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
3538 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3540 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3541 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3542 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3544 if (pa_tagstruct_get(
3546 PA_TAG_U32
, &a
.maxlength
,
3547 PA_TAG_U32
, &a
.tlength
,
3548 PA_TAG_U32
, &a
.prebuf
,
3549 PA_TAG_U32
, &a
.minreq
,
3550 PA_TAG_INVALID
) < 0 ||
3551 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3552 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3553 !pa_tagstruct_eof(t
)) {
3558 s
->adjust_latency
= adjust_latency
;
3559 s
->early_requests
= early_requests
;
3562 fix_playback_buffer_attr(s
);
3563 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);
3565 reply
= reply_new(tag
);
3566 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3567 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
3568 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
3569 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
3571 if (c
->version
>= 13)
3572 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
3576 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3577 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
3579 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3580 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3582 if (pa_tagstruct_get(
3584 PA_TAG_U32
, &a
.maxlength
,
3585 PA_TAG_U32
, &a
.fragsize
,
3586 PA_TAG_INVALID
) < 0 ||
3587 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3588 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3589 !pa_tagstruct_eof(t
)) {
3594 s
->adjust_latency
= adjust_latency
;
3595 s
->early_requests
= early_requests
;
3598 fix_record_buffer_attr_pre(s
);
3599 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
3600 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
3601 fix_record_buffer_attr_post(s
);
3603 reply
= reply_new(tag
);
3604 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3605 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
3607 if (c
->version
>= 13)
3608 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
3611 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3614 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3615 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3619 pa_native_connection_assert_ref(c
);
3622 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3623 pa_tagstruct_getu32(t
, &rate
) < 0 ||
3624 !pa_tagstruct_eof(t
)) {
3629 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3630 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
3632 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
3635 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3636 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3637 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3639 pa_sink_input_set_rate(s
->sink_input
, rate
);
3643 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
3645 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3646 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3648 pa_source_output_set_rate(s
->source_output
, rate
);
3651 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3654 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3655 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3660 pa_native_connection_assert_ref(c
);
3663 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3665 p
= pa_proplist_new();
3667 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
3669 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
3670 pa_tagstruct_get_proplist(t
, p
) < 0 ||
3671 !pa_tagstruct_eof(t
)) {
3673 pa_proplist_free(p
);
3679 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3680 pa_tagstruct_getu32(t
, &mode
) < 0 ||
3681 pa_tagstruct_get_proplist(t
, p
) < 0 ||
3682 !pa_tagstruct_eof(t
)) {
3684 pa_proplist_free(p
);
3689 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
3690 pa_proplist_free(p
);
3691 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
3694 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
3697 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3698 if (!s
|| !playback_stream_isinstance(s
)) {
3699 pa_proplist_free(p
);
3700 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
3702 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
3704 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
3707 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
3708 pa_proplist_free(p
);
3709 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
3711 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
3714 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
3716 pa_client_update_proplist(c
->client
, mode
, p
);
3719 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3720 pa_proplist_free(p
);
3723 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3724 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3726 unsigned changed
= 0;
3728 pa_strlist
*l
= NULL
;
3730 pa_native_connection_assert_ref(c
);
3733 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3735 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
3737 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3743 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
3746 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3747 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3748 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3750 p
= s
->sink_input
->proplist
;
3752 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
3755 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3756 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3758 p
= s
->source_output
->proplist
;
3760 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
3762 p
= c
->client
->proplist
;
3768 if (pa_tagstruct_gets(t
, &k
) < 0) {
3777 l
= pa_strlist_prepend(l
, k
);
3780 if (!pa_tagstruct_eof(t
)) {
3789 l
= pa_strlist_pop(l
, &z
);
3794 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
3798 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3801 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
3804 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3805 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
3807 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
3810 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3811 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
3814 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
3815 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
3820 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3821 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3824 pa_native_connection_assert_ref(c
);
3827 if (pa_tagstruct_gets(t
, &s
) < 0 ||
3828 !pa_tagstruct_eof(t
)) {
3833 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3834 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
3836 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
3839 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
3840 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
3842 pa_namereg_set_default_source(c
->protocol
->core
, source
);
3845 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
3847 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
3848 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
3850 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
3853 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3856 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3857 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3861 pa_native_connection_assert_ref(c
);
3864 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3865 pa_tagstruct_gets(t
, &name
) < 0 ||
3866 !pa_tagstruct_eof(t
)) {
3871 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3872 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
3874 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
3877 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3878 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3879 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3881 pa_sink_input_set_name(s
->sink_input
, name
);
3885 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
3887 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3888 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3890 pa_source_output_set_name(s
->source_output
, name
);
3893 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3896 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3897 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3900 pa_native_connection_assert_ref(c
);
3903 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3904 !pa_tagstruct_eof(t
)) {
3909 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3911 if (command
== PA_COMMAND_KILL_CLIENT
) {
3914 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3915 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
3917 pa_native_connection_ref(c
);
3918 pa_client_kill(client
);
3920 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
3923 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3924 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3926 pa_native_connection_ref(c
);
3927 pa_sink_input_kill(s
);
3929 pa_source_output
*s
;
3931 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
3933 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3934 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3936 pa_native_connection_ref(c
);
3937 pa_source_output_kill(s
);
3940 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3941 pa_native_connection_unref(c
);
3944 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3945 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3947 const char *name
, *argument
;
3948 pa_tagstruct
*reply
;
3950 pa_native_connection_assert_ref(c
);
3953 if (pa_tagstruct_gets(t
, &name
) < 0 ||
3954 pa_tagstruct_gets(t
, &argument
) < 0 ||
3955 !pa_tagstruct_eof(t
)) {
3960 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3961 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
3962 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
3964 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
3965 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
3969 reply
= reply_new(tag
);
3970 pa_tagstruct_putu32(reply
, m
->index
);
3971 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3974 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3975 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3979 pa_native_connection_assert_ref(c
);
3982 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3983 !pa_tagstruct_eof(t
)) {
3988 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3989 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3990 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
3992 pa_module_unload_request(m
, FALSE
);
3993 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3996 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3997 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3998 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
3999 const char *name_device
= NULL
;
4001 pa_native_connection_assert_ref(c
);
4004 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4005 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4006 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4007 !pa_tagstruct_eof(t
)) {
4012 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4013 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4015 CHECK_VALIDITY(c
->pstream
, !name_device
|| pa_namereg_is_valid_name(name_device
), tag
, PA_ERR_INVALID
);
4016 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4017 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4018 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4020 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4021 pa_sink_input
*si
= NULL
;
4022 pa_sink
*sink
= NULL
;
4024 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4026 if (idx_device
!= PA_INVALID_INDEX
)
4027 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4029 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4031 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4033 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4034 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4038 pa_source_output
*so
= NULL
;
4041 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4043 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4045 if (idx_device
!= PA_INVALID_INDEX
)
4046 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4048 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4050 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4052 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4053 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4058 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4061 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4062 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4063 uint32_t idx
= PA_INVALID_INDEX
;
4064 const char *name
= NULL
;
4067 pa_native_connection_assert_ref(c
);
4070 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4071 pa_tagstruct_gets(t
, &name
) < 0 ||
4072 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4073 !pa_tagstruct_eof(t
)) {
4078 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4079 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
) || *name
== 0, tag
, PA_ERR_INVALID
);
4080 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4081 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4082 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4084 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4086 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4088 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4090 if (pa_sink_suspend_all(c
->protocol
->core
, b
) < 0) {
4091 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4095 pa_sink
*sink
= NULL
;
4097 if (idx
!= PA_INVALID_INDEX
)
4098 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4100 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4102 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4104 if (pa_sink_suspend(sink
, b
) < 0) {
4105 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4111 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4113 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4115 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4117 if (pa_source_suspend_all(c
->protocol
->core
, b
) < 0) {
4118 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4125 if (idx
!= PA_INVALID_INDEX
)
4126 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4128 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4130 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4132 if (pa_source_suspend(source
, b
) < 0) {
4133 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4139 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4142 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4143 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4144 uint32_t idx
= PA_INVALID_INDEX
;
4145 const char *name
= NULL
;
4147 pa_native_protocol_ext_cb_t cb
;
4149 pa_native_connection_assert_ref(c
);
4152 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4153 pa_tagstruct_gets(t
, &name
) < 0) {
4158 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4159 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4160 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4161 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4162 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4164 if (idx
!= PA_INVALID_INDEX
)
4165 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4167 for (m
= pa_idxset_first(c
->protocol
->core
->modules
, &idx
); m
; m
= pa_idxset_next(c
->protocol
->core
->modules
, &idx
))
4168 if (strcmp(name
, m
->name
) == 0)
4172 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4173 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4175 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4176 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4178 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4182 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4183 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4184 uint32_t idx
= PA_INVALID_INDEX
;
4185 const char *name
= NULL
, *profile
= NULL
;
4186 pa_card
*card
= NULL
;
4188 pa_native_connection_assert_ref(c
);
4191 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4192 pa_tagstruct_gets(t
, &name
) < 0 ||
4193 pa_tagstruct_gets(t
, &profile
) < 0 ||
4194 !pa_tagstruct_eof(t
)) {
4199 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4200 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4201 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4202 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4203 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4205 if (idx
!= PA_INVALID_INDEX
)
4206 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4208 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4210 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4212 if (pa_card_set_profile(card
, profile
, TRUE
) < 0) {
4213 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4217 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4220 /*** pstream callbacks ***/
4222 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4223 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4227 pa_native_connection_assert_ref(c
);
4229 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4230 pa_log("invalid packet.");
4231 native_connection_unlink(c
);
4235 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
) {
4236 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4237 output_stream
*stream
;
4241 pa_native_connection_assert_ref(c
);
4243 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4244 pa_log("client sent block for invalid stream.");
4249 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4251 if (playback_stream_isinstance(stream
)) {
4252 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4254 if (chunk
->memblock
) {
4255 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4256 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_SEEK
, PA_UINT_TO_PTR(seek
), offset
, NULL
, NULL
);
4258 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4260 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
);
4263 upload_stream
*u
= UPLOAD_STREAM(stream
);
4266 if (!u
->memchunk
.memblock
) {
4267 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4268 u
->memchunk
= *chunk
;
4269 pa_memblock_ref(u
->memchunk
.memblock
);
4272 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4273 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4277 pa_assert(u
->memchunk
.memblock
);
4280 if (l
> chunk
->length
)
4285 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4287 if (chunk
->memblock
) {
4289 src
= pa_memblock_acquire(chunk
->memblock
);
4291 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4292 (uint8_t*) src
+ chunk
->index
, l
);
4294 pa_memblock_release(chunk
->memblock
);
4296 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4298 pa_memblock_release(u
->memchunk
.memblock
);
4300 u
->memchunk
.length
+= l
;
4306 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4307 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4310 pa_native_connection_assert_ref(c
);
4312 native_connection_unlink(c
);
4313 pa_log_info("Connection died.");
4316 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4317 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4320 pa_native_connection_assert_ref(c
);
4322 native_connection_send_memblock(c
);
4325 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4328 if (!(q
= pa_thread_mq_get()))
4329 pa_pstream_send_revoke(p
, block_id
);
4331 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4334 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4337 if (!(q
= pa_thread_mq_get()))
4338 pa_pstream_send_release(p
, block_id
);
4340 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4343 /*** client callbacks ***/
4345 static void client_kill_cb(pa_client
*c
) {
4348 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4349 pa_log_info("Connection killed.");
4352 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4354 pa_native_connection
*c
;
4357 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4358 pa_native_connection_assert_ref(c
);
4360 if (c
->version
< 15)
4363 t
= pa_tagstruct_new(NULL
, 0);
4364 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4365 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4366 pa_tagstruct_puts(t
, event
);
4367 pa_tagstruct_put_proplist(t
, pl
);
4368 pa_pstream_send_tagstruct(c
->pstream
, t
);
4371 /*** module entry points ***/
4373 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
4374 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4378 pa_native_connection_assert_ref(c
);
4379 pa_assert(c
->auth_timeout_event
== e
);
4381 if (!c
->authorized
) {
4382 native_connection_unlink(c
);
4383 pa_log_info("Connection terminated due to authentication timeout.");
4387 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4388 pa_native_connection
*c
;
4391 pa_client_new_data data
;
4397 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4398 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4399 pa_iochannel_free(io
);
4403 pa_client_new_data_init(&data
);
4404 data
.module
= o
->module
;
4405 data
.driver
= __FILE__
;
4406 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4407 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4408 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4409 client
= pa_client_new(p
->core
, &data
);
4410 pa_client_new_data_done(&data
);
4415 c
= pa_msgobject_new(pa_native_connection
);
4416 c
->parent
.parent
.free
= native_connection_free
;
4417 c
->parent
.process_msg
= native_connection_process_msg
;
4419 c
->options
= pa_native_options_ref(o
);
4420 c
->authorized
= FALSE
;
4422 if (o
->auth_anonymous
) {
4423 pa_log_info("Client authenticated anonymously.");
4424 c
->authorized
= TRUE
;
4427 if (!c
->authorized
&&
4429 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
4431 pa_log_info("Client authenticated by IP ACL.");
4432 c
->authorized
= TRUE
;
4435 if (!c
->authorized
) {
4437 pa_gettimeofday(&tv
);
4438 tv
.tv_sec
+= AUTH_TIMEOUT
;
4439 c
->auth_timeout_event
= p
->core
->mainloop
->time_new(p
->core
->mainloop
, &tv
, auth_timeout
, c
);
4441 c
->auth_timeout_event
= NULL
;
4443 c
->is_local
= pa_iochannel_socket_is_local(io
);
4447 c
->client
->kill
= client_kill_cb
;
4448 c
->client
->send_event
= client_send_event_cb
;
4449 c
->client
->userdata
= c
;
4451 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
4452 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
4453 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
4454 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
4455 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
4456 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
4457 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
4459 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, command_table
, PA_COMMAND_MAX
);
4461 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
4462 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
4464 c
->rrobin_index
= PA_IDXSET_INVALID
;
4465 c
->subscription
= NULL
;
4467 pa_idxset_put(p
->connections
, c
, NULL
);
4470 if (pa_iochannel_creds_supported(io
))
4471 pa_iochannel_creds_enable(io
);
4474 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
4477 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
4478 pa_native_connection
*c
;
4484 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
4485 if (c
->options
->module
== m
)
4486 native_connection_unlink(c
);
4489 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
4490 pa_native_protocol
*p
;
4495 p
= pa_xnew(pa_native_protocol
, 1);
4498 p
->connections
= pa_idxset_new(NULL
, NULL
);
4502 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
4504 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4505 pa_hook_init(&p
->hooks
[h
], p
);
4507 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
4512 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
4513 pa_native_protocol
*p
;
4515 if ((p
= pa_shared_get(c
, "native-protocol")))
4516 return pa_native_protocol_ref(p
);
4518 return native_protocol_new(c
);
4521 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
4523 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4530 void pa_native_protocol_unref(pa_native_protocol
*p
) {
4531 pa_native_connection
*c
;
4535 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4537 if (PA_REFCNT_DEC(p
) > 0)
4540 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
4541 native_connection_unlink(c
);
4543 pa_idxset_free(p
->connections
, NULL
, NULL
);
4545 pa_strlist_free(p
->servers
);
4547 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4548 pa_hook_done(&p
->hooks
[h
]);
4550 pa_hashmap_free(p
->extensions
, NULL
, NULL
);
4552 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
4557 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
4559 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4562 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
4564 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
4567 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
4569 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4572 p
->servers
= pa_strlist_remove(p
->servers
, name
);
4574 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
4577 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
4579 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4584 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
4586 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4591 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
4593 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4596 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
4598 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
4602 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
4604 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4607 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
4610 pa_native_options
* pa_native_options_new(void) {
4611 pa_native_options
*o
;
4613 o
= pa_xnew0(pa_native_options
, 1);
4619 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
4621 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4628 void pa_native_options_unref(pa_native_options
*o
) {
4630 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4632 if (PA_REFCNT_DEC(o
) > 0)
4635 pa_xfree(o
->auth_group
);
4638 pa_ip_acl_free(o
->auth_ip_acl
);
4641 pa_auth_cookie_unref(o
->auth_cookie
);
4646 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
4651 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4654 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
4655 pa_log("auth-anonymous= expects a boolean argument.");
4660 if (pa_modargs_get_value_boolean(ma
, "auth-group-enabled", &enabled
) < 0) {
4661 pa_log("auth-group-enabled= expects a boolean argument.");
4665 pa_xfree(o
->auth_group
);
4666 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
4670 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4673 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
4676 if (!(ipa
= pa_ip_acl_new(acl
))) {
4677 pa_log("Failed to parse IP ACL '%s'", acl
);
4682 pa_ip_acl_free(o
->auth_ip_acl
);
4684 o
->auth_ip_acl
= ipa
;
4688 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
4689 pa_log("auth-cookie-enabled= expects a boolean argument.");
4694 pa_auth_cookie_unref(o
->auth_cookie
);
4699 /* The new name for this is 'auth-cookie', for compat reasons
4700 * we check the old name too */
4701 if (!(cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
)))
4702 if (!(cn
= pa_modargs_get_value(ma
, "cookie", NULL
)))
4703 cn
= PA_NATIVE_COOKIE_FILE
;
4705 if (!(o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, PA_NATIVE_COOKIE_LENGTH
)))
4709 o
->auth_cookie
= NULL
;
4714 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
4715 pa_native_connection_assert_ref(c
);