2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32 #include <pulse/rtclock.h>
33 #include <pulse/timeval.h>
34 #include <pulse/version.h>
35 #include <pulse/utf8.h>
36 #include <pulse/util.h>
37 #include <pulse/xmalloc.h>
38 #include <pulse/internal.h>
40 #include <pulsecore/native-common.h>
41 #include <pulsecore/packet.h>
42 #include <pulsecore/client.h>
43 #include <pulsecore/source-output.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/pstream.h>
46 #include <pulsecore/tagstruct.h>
47 #include <pulsecore/pdispatch.h>
48 #include <pulsecore/pstream-util.h>
49 #include <pulsecore/authkey.h>
50 #include <pulsecore/namereg.h>
51 #include <pulsecore/core-scache.h>
52 #include <pulsecore/core-subscribe.h>
53 #include <pulsecore/log.h>
54 #include <pulsecore/strlist.h>
55 #include <pulsecore/shared.h>
56 #include <pulsecore/sample-util.h>
57 #include <pulsecore/llist.h>
58 #include <pulsecore/creds.h>
59 #include <pulsecore/core-util.h>
60 #include <pulsecore/ipacl.h>
61 #include <pulsecore/thread-mq.h>
63 #include "protocol-native.h"
65 /* Kick a client if it doesn't authenticate within this time */
66 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
68 /* Don't accept more connection than this */
69 #define MAX_CONNECTIONS 64
71 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
72 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
73 #define DEFAULT_PROCESS_MSEC 20 /* 20ms */
74 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
76 struct pa_native_protocol
;
78 typedef struct record_stream
{
81 pa_native_connection
*connection
;
84 pa_source_output
*source_output
;
85 pa_memblockq
*memblockq
;
87 pa_bool_t adjust_latency
:1;
88 pa_bool_t early_requests
:1;
90 pa_buffer_attr buffer_attr
;
92 pa_atomic_t on_the_fly
;
93 pa_usec_t configured_source_latency
;
96 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
97 size_t on_the_fly_snapshot
;
98 pa_usec_t current_monitor_latency
;
99 pa_usec_t current_source_latency
;
102 #define RECORD_STREAM(o) (record_stream_cast(o))
103 PA_DEFINE_PRIVATE_CLASS(record_stream
, pa_msgobject
);
105 typedef struct output_stream
{
109 #define OUTPUT_STREAM(o) (output_stream_cast(o))
110 PA_DEFINE_PRIVATE_CLASS(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;
129 /* Optimization to avoid too many rewinds with a lot of small blocks */
130 pa_atomic_t seek_or_post_in_queue
;
134 pa_usec_t configured_sink_latency
;
135 pa_buffer_attr buffer_attr
;
137 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
138 int64_t read_index
, write_index
;
139 size_t render_memblockq_length
;
140 pa_usec_t current_sink_latency
;
141 uint64_t playing_for
, underrun_for
;
144 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
145 PA_DEFINE_PRIVATE_CLASS(playback_stream
, output_stream
);
147 typedef struct upload_stream
{
148 output_stream parent
;
150 pa_native_connection
*connection
;
153 pa_memchunk memchunk
;
156 pa_sample_spec sample_spec
;
157 pa_channel_map channel_map
;
158 pa_proplist
*proplist
;
161 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
162 PA_DEFINE_PRIVATE_CLASS(upload_stream
, output_stream
);
164 struct pa_native_connection
{
166 pa_native_protocol
*protocol
;
167 pa_native_options
*options
;
168 pa_bool_t authorized
:1;
169 pa_bool_t is_local
:1;
173 pa_pdispatch
*pdispatch
;
174 pa_idxset
*record_streams
, *output_streams
;
175 uint32_t rrobin_index
;
176 pa_subscription
*subscription
;
177 pa_time_event
*auth_timeout_event
;
180 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
181 PA_DEFINE_PRIVATE_CLASS(pa_native_connection
, pa_msgobject
);
183 struct pa_native_protocol
{
187 pa_idxset
*connections
;
190 pa_hook hooks
[PA_NATIVE_HOOK_MAX
];
192 pa_hashmap
*extensions
;
196 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
= PA_SOURCE_OUTPUT_MESSAGE_MAX
200 SINK_INPUT_MESSAGE_POST_DATA
= PA_SINK_INPUT_MESSAGE_MAX
, /* data from main loop to sink input */
201 SINK_INPUT_MESSAGE_DRAIN
, /* disabled prebuf, get playback started. */
202 SINK_INPUT_MESSAGE_FLUSH
,
203 SINK_INPUT_MESSAGE_TRIGGER
,
204 SINK_INPUT_MESSAGE_SEEK
,
205 SINK_INPUT_MESSAGE_PREBUF_FORCE
,
206 SINK_INPUT_MESSAGE_UPDATE_LATENCY
,
207 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
211 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, /* data requested from sink input from the main loop */
212 PLAYBACK_STREAM_MESSAGE_UNDERFLOW
,
213 PLAYBACK_STREAM_MESSAGE_OVERFLOW
,
214 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
,
215 PLAYBACK_STREAM_MESSAGE_STARTED
,
216 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
220 RECORD_STREAM_MESSAGE_POST_DATA
/* data from source output to main loop */
224 CONNECTION_MESSAGE_RELEASE
,
225 CONNECTION_MESSAGE_REVOKE
228 static int sink_input_pop_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
);
229 static void sink_input_kill_cb(pa_sink_input
*i
);
230 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
);
231 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
);
232 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
233 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
234 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
);
235 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
);
237 static void native_connection_send_memblock(pa_native_connection
*c
);
238 static void playback_stream_request_bytes(struct playback_stream
*s
);
240 static void source_output_kill_cb(pa_source_output
*o
);
241 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
);
242 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
);
243 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
);
244 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
);
245 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
);
247 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
248 static int source_output_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
250 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
251 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
252 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
253 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
254 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
255 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
256 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
257 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
258 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
259 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
260 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
261 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
262 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
263 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
264 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
265 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
266 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
267 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
268 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
269 static void command_set_volume(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
270 static void command_set_mute(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
271 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
272 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
273 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
274 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
275 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
276 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
277 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
278 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
279 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
280 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
281 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
282 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
283 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
284 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
285 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
286 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
287 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
288 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
290 static const pa_pdispatch_cb_t command_table
[PA_COMMAND_MAX
] = {
291 [PA_COMMAND_ERROR
] = NULL
,
292 [PA_COMMAND_TIMEOUT
] = NULL
,
293 [PA_COMMAND_REPLY
] = NULL
,
294 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = command_create_playback_stream
,
295 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = command_delete_stream
,
296 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = command_drain_playback_stream
,
297 [PA_COMMAND_CREATE_RECORD_STREAM
] = command_create_record_stream
,
298 [PA_COMMAND_DELETE_RECORD_STREAM
] = command_delete_stream
,
299 [PA_COMMAND_AUTH
] = command_auth
,
300 [PA_COMMAND_REQUEST
] = NULL
,
301 [PA_COMMAND_EXIT
] = command_exit
,
302 [PA_COMMAND_SET_CLIENT_NAME
] = command_set_client_name
,
303 [PA_COMMAND_LOOKUP_SINK
] = command_lookup
,
304 [PA_COMMAND_LOOKUP_SOURCE
] = command_lookup
,
305 [PA_COMMAND_STAT
] = command_stat
,
306 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = command_get_playback_latency
,
307 [PA_COMMAND_GET_RECORD_LATENCY
] = command_get_record_latency
,
308 [PA_COMMAND_CREATE_UPLOAD_STREAM
] = command_create_upload_stream
,
309 [PA_COMMAND_DELETE_UPLOAD_STREAM
] = command_delete_stream
,
310 [PA_COMMAND_FINISH_UPLOAD_STREAM
] = command_finish_upload_stream
,
311 [PA_COMMAND_PLAY_SAMPLE
] = command_play_sample
,
312 [PA_COMMAND_REMOVE_SAMPLE
] = command_remove_sample
,
313 [PA_COMMAND_GET_SINK_INFO
] = command_get_info
,
314 [PA_COMMAND_GET_SOURCE_INFO
] = command_get_info
,
315 [PA_COMMAND_GET_CLIENT_INFO
] = command_get_info
,
316 [PA_COMMAND_GET_CARD_INFO
] = command_get_info
,
317 [PA_COMMAND_GET_MODULE_INFO
] = command_get_info
,
318 [PA_COMMAND_GET_SINK_INPUT_INFO
] = command_get_info
,
319 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO
] = command_get_info
,
320 [PA_COMMAND_GET_SAMPLE_INFO
] = command_get_info
,
321 [PA_COMMAND_GET_SINK_INFO_LIST
] = command_get_info_list
,
322 [PA_COMMAND_GET_SOURCE_INFO_LIST
] = command_get_info_list
,
323 [PA_COMMAND_GET_MODULE_INFO_LIST
] = command_get_info_list
,
324 [PA_COMMAND_GET_CLIENT_INFO_LIST
] = command_get_info_list
,
325 [PA_COMMAND_GET_CARD_INFO_LIST
] = command_get_info_list
,
326 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST
] = command_get_info_list
,
327 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
] = command_get_info_list
,
328 [PA_COMMAND_GET_SAMPLE_INFO_LIST
] = command_get_info_list
,
329 [PA_COMMAND_GET_SERVER_INFO
] = command_get_server_info
,
330 [PA_COMMAND_SUBSCRIBE
] = command_subscribe
,
332 [PA_COMMAND_SET_SINK_VOLUME
] = command_set_volume
,
333 [PA_COMMAND_SET_SINK_INPUT_VOLUME
] = command_set_volume
,
334 [PA_COMMAND_SET_SOURCE_VOLUME
] = command_set_volume
,
336 [PA_COMMAND_SET_SINK_MUTE
] = command_set_mute
,
337 [PA_COMMAND_SET_SINK_INPUT_MUTE
] = command_set_mute
,
338 [PA_COMMAND_SET_SOURCE_MUTE
] = command_set_mute
,
340 [PA_COMMAND_SUSPEND_SINK
] = command_suspend
,
341 [PA_COMMAND_SUSPEND_SOURCE
] = command_suspend
,
343 [PA_COMMAND_CORK_PLAYBACK_STREAM
] = command_cork_playback_stream
,
344 [PA_COMMAND_FLUSH_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
345 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
346 [PA_COMMAND_PREBUF_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
348 [PA_COMMAND_CORK_RECORD_STREAM
] = command_cork_record_stream
,
349 [PA_COMMAND_FLUSH_RECORD_STREAM
] = command_flush_record_stream
,
351 [PA_COMMAND_SET_DEFAULT_SINK
] = command_set_default_sink_or_source
,
352 [PA_COMMAND_SET_DEFAULT_SOURCE
] = command_set_default_sink_or_source
,
353 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME
] = command_set_stream_name
,
354 [PA_COMMAND_SET_RECORD_STREAM_NAME
] = command_set_stream_name
,
355 [PA_COMMAND_KILL_CLIENT
] = command_kill
,
356 [PA_COMMAND_KILL_SINK_INPUT
] = command_kill
,
357 [PA_COMMAND_KILL_SOURCE_OUTPUT
] = command_kill
,
358 [PA_COMMAND_LOAD_MODULE
] = command_load_module
,
359 [PA_COMMAND_UNLOAD_MODULE
] = command_unload_module
,
361 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE
] = NULL
,
362 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE
] = NULL
,
363 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE
] = NULL
,
364 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE
] = NULL
,
366 [PA_COMMAND_MOVE_SINK_INPUT
] = command_move_stream
,
367 [PA_COMMAND_MOVE_SOURCE_OUTPUT
] = command_move_stream
,
369 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
370 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
372 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
373 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
375 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
] = command_update_proplist
,
376 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
] = command_update_proplist
,
377 [PA_COMMAND_UPDATE_CLIENT_PROPLIST
] = command_update_proplist
,
379 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
] = command_remove_proplist
,
380 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
] = command_remove_proplist
,
381 [PA_COMMAND_REMOVE_CLIENT_PROPLIST
] = command_remove_proplist
,
383 [PA_COMMAND_SET_CARD_PROFILE
] = command_set_card_profile
,
385 [PA_COMMAND_SET_SINK_PORT
] = command_set_sink_or_source_port
,
386 [PA_COMMAND_SET_SOURCE_PORT
] = command_set_sink_or_source_port
,
388 [PA_COMMAND_EXTENSION
] = command_extension
391 /* structure management */
393 /* Called from main context */
394 static void upload_stream_unlink(upload_stream
*s
) {
400 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
401 s
->connection
= NULL
;
402 upload_stream_unref(s
);
405 /* Called from main context */
406 static void upload_stream_free(pa_object
*o
) {
407 upload_stream
*s
= UPLOAD_STREAM(o
);
410 upload_stream_unlink(s
);
415 pa_proplist_free(s
->proplist
);
417 if (s
->memchunk
.memblock
)
418 pa_memblock_unref(s
->memchunk
.memblock
);
423 /* Called from main context */
424 static upload_stream
* upload_stream_new(
425 pa_native_connection
*c
,
426 const pa_sample_spec
*ss
,
427 const pa_channel_map
*map
,
437 pa_assert(length
> 0);
440 s
= pa_msgobject_new(upload_stream
);
441 s
->parent
.parent
.parent
.free
= upload_stream_free
;
443 s
->sample_spec
= *ss
;
444 s
->channel_map
= *map
;
445 s
->name
= pa_xstrdup(name
);
446 pa_memchunk_reset(&s
->memchunk
);
448 s
->proplist
= pa_proplist_copy(p
);
449 pa_proplist_update(s
->proplist
, PA_UPDATE_MERGE
, c
->client
->proplist
);
451 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
456 /* Called from main context */
457 static void record_stream_unlink(record_stream
*s
) {
463 if (s
->source_output
) {
464 pa_source_output_unlink(s
->source_output
);
465 pa_source_output_unref(s
->source_output
);
466 s
->source_output
= NULL
;
469 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->record_streams
, s
, NULL
) == s
);
470 s
->connection
= NULL
;
471 record_stream_unref(s
);
474 /* Called from main context */
475 static void record_stream_free(pa_object
*o
) {
476 record_stream
*s
= RECORD_STREAM(o
);
479 record_stream_unlink(s
);
481 pa_memblockq_free(s
->memblockq
);
485 /* Called from main context */
486 static int record_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
487 record_stream
*s
= RECORD_STREAM(o
);
488 record_stream_assert_ref(s
);
495 case RECORD_STREAM_MESSAGE_POST_DATA
:
497 /* We try to keep up to date with how many bytes are
498 * currently on the fly */
499 pa_atomic_sub(&s
->on_the_fly
, chunk
->length
);
501 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
502 /* pa_log_warn("Failed to push data into output queue."); */
506 if (!pa_pstream_is_pending(s
->connection
->pstream
))
507 native_connection_send_memblock(s
->connection
);
515 /* Called from main context */
516 static void fix_record_buffer_attr_pre(record_stream
*s
) {
519 pa_usec_t orig_fragsize_usec
, fragsize_usec
, source_usec
;
523 /* This function will be called from the main thread, before as
524 * well as after the source output has been activated using
525 * pa_source_output_put()! That means it may not touch any
526 * ->thread_info data! */
528 frame_size
= pa_frame_size(&s
->source_output
->sample_spec
);
530 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
531 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
532 if (s
->buffer_attr
.maxlength
<= 0)
533 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
535 if (s
->buffer_attr
.fragsize
== (uint32_t) -1)
536 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC
*PA_USEC_PER_MSEC
, &s
->source_output
->sample_spec
);
537 if (s
->buffer_attr
.fragsize
<= 0)
538 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
540 orig_fragsize_usec
= fragsize_usec
= pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &s
->source_output
->sample_spec
);
542 if (s
->early_requests
) {
544 /* In early request mode we need to emulate the classic
545 * fragment-based playback model. We do this setting the source
546 * latency to the fragment size. */
548 source_usec
= fragsize_usec
;
550 } else if (s
->adjust_latency
) {
552 /* So, the user asked us to adjust the latency according to
553 * what the source can provide. Half the latency will be
554 * spent on the hw buffer, half of it in the async buffer
555 * queue we maintain for each client. */
557 source_usec
= fragsize_usec
/2;
561 /* Ok, the user didn't ask us to adjust the latency, hence we
564 source_usec
= (pa_usec_t
) -1;
567 if (source_usec
!= (pa_usec_t
) -1)
568 s
->configured_source_latency
= pa_source_output_set_requested_latency(s
->source_output
, source_usec
);
570 s
->configured_source_latency
= 0;
572 if (s
->early_requests
) {
574 /* Ok, we didn't necessarily get what we were asking for, so
575 * let's tell the user */
577 fragsize_usec
= s
->configured_source_latency
;
579 } else if (s
->adjust_latency
) {
581 /* Now subtract what we actually got */
583 if (fragsize_usec
>= s
->configured_source_latency
*2)
584 fragsize_usec
-= s
->configured_source_latency
;
586 fragsize_usec
= s
->configured_source_latency
;
589 if (pa_usec_to_bytes(orig_fragsize_usec
, &s
->source_output
->sample_spec
) !=
590 pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
))
592 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
);
594 if (s
->buffer_attr
.fragsize
<= 0)
595 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
598 /* Called from main context */
599 static void fix_record_buffer_attr_post(record_stream
*s
) {
604 /* This function will be called from the main thread, before as
605 * well as after the source output has been activated using
606 * pa_source_output_put()! That means it may not touch and
607 * ->thread_info data! */
609 base
= pa_frame_size(&s
->source_output
->sample_spec
);
611 s
->buffer_attr
.fragsize
= (s
->buffer_attr
.fragsize
/base
)*base
;
612 if (s
->buffer_attr
.fragsize
<= 0)
613 s
->buffer_attr
.fragsize
= base
;
615 if (s
->buffer_attr
.fragsize
> s
->buffer_attr
.maxlength
)
616 s
->buffer_attr
.fragsize
= s
->buffer_attr
.maxlength
;
619 /* Called from main context */
620 static record_stream
* record_stream_new(
621 pa_native_connection
*c
,
625 pa_bool_t peak_detect
,
626 pa_buffer_attr
*attr
,
627 pa_source_output_flags_t flags
,
629 pa_bool_t adjust_latency
,
630 pa_sink_input
*direct_on_input
,
631 pa_bool_t early_requests
,
635 pa_source_output
*source_output
= NULL
;
636 pa_source_output_new_data data
;
643 pa_source_output_new_data_init(&data
);
645 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
646 data
.driver
= __FILE__
;
647 data
.module
= c
->options
->module
;
648 data
.client
= c
->client
;
649 data
.source
= source
;
650 data
.direct_on_input
= direct_on_input
;
651 pa_source_output_new_data_set_sample_spec(&data
, ss
);
652 pa_source_output_new_data_set_channel_map(&data
, map
);
654 data
.resample_method
= PA_RESAMPLER_PEAKS
;
657 *ret
= -pa_source_output_new(&source_output
, c
->protocol
->core
, &data
);
659 pa_source_output_new_data_done(&data
);
664 s
= pa_msgobject_new(record_stream
);
665 s
->parent
.parent
.free
= record_stream_free
;
666 s
->parent
.process_msg
= record_stream_process_msg
;
668 s
->source_output
= source_output
;
669 s
->buffer_attr
= *attr
;
670 s
->adjust_latency
= adjust_latency
;
671 s
->early_requests
= early_requests
;
672 pa_atomic_store(&s
->on_the_fly
, 0);
674 s
->source_output
->parent
.process_msg
= source_output_process_msg
;
675 s
->source_output
->push
= source_output_push_cb
;
676 s
->source_output
->kill
= source_output_kill_cb
;
677 s
->source_output
->get_latency
= source_output_get_latency_cb
;
678 s
->source_output
->moving
= source_output_moving_cb
;
679 s
->source_output
->suspend
= source_output_suspend_cb
;
680 s
->source_output
->send_event
= source_output_send_event_cb
;
681 s
->source_output
->userdata
= s
;
683 fix_record_buffer_attr_pre(s
);
685 s
->memblockq
= pa_memblockq_new(
687 s
->buffer_attr
.maxlength
,
689 pa_frame_size(&source_output
->sample_spec
),
695 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
696 fix_record_buffer_attr_post(s
);
698 *ss
= s
->source_output
->sample_spec
;
699 *map
= s
->source_output
->channel_map
;
701 pa_idxset_put(c
->record_streams
, s
, &s
->index
);
703 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
704 ((double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) + (double) s
->configured_source_latency
) / PA_USEC_PER_MSEC
,
705 (double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) / PA_USEC_PER_MSEC
,
706 (double) s
->configured_source_latency
/ PA_USEC_PER_MSEC
);
708 pa_source_output_put(s
->source_output
);
712 /* Called from main context */
713 static void record_stream_send_killed(record_stream
*r
) {
715 record_stream_assert_ref(r
);
717 t
= pa_tagstruct_new(NULL
, 0);
718 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_KILLED
);
719 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
720 pa_tagstruct_putu32(t
, r
->index
);
721 pa_pstream_send_tagstruct(r
->connection
->pstream
, t
);
724 /* Called from main context */
725 static void playback_stream_unlink(playback_stream
*s
) {
732 pa_sink_input_unlink(s
->sink_input
);
733 pa_sink_input_unref(s
->sink_input
);
734 s
->sink_input
= NULL
;
737 if (s
->drain_request
)
738 pa_pstream_send_error(s
->connection
->pstream
, s
->drain_tag
, PA_ERR_NOENTITY
);
740 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
741 s
->connection
= NULL
;
742 playback_stream_unref(s
);
745 /* Called from main context */
746 static void playback_stream_free(pa_object
* o
) {
747 playback_stream
*s
= PLAYBACK_STREAM(o
);
750 playback_stream_unlink(s
);
752 pa_memblockq_free(s
->memblockq
);
756 /* Called from main context */
757 static int playback_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
758 playback_stream
*s
= PLAYBACK_STREAM(o
);
759 playback_stream_assert_ref(s
);
766 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
: {
771 if ((l
= pa_atomic_load(&s
->missing
)) <= 0)
774 if (pa_atomic_cmpxchg(&s
->missing
, l
, 0))
778 t
= pa_tagstruct_new(NULL
, 0);
779 pa_tagstruct_putu32(t
, PA_COMMAND_REQUEST
);
780 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
781 pa_tagstruct_putu32(t
, s
->index
);
782 pa_tagstruct_putu32(t
, (uint32_t) l
);
783 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
785 /* pa_log("Requesting %lu bytes", (unsigned long) l); */
789 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW
: {
792 /* pa_log("signalling underflow"); */
794 /* Report that we're empty */
795 t
= pa_tagstruct_new(NULL
, 0);
796 pa_tagstruct_putu32(t
, PA_COMMAND_UNDERFLOW
);
797 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
798 pa_tagstruct_putu32(t
, s
->index
);
799 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
803 case PLAYBACK_STREAM_MESSAGE_OVERFLOW
: {
806 /* Notify the user we're overflowed*/
807 t
= pa_tagstruct_new(NULL
, 0);
808 pa_tagstruct_putu32(t
, PA_COMMAND_OVERFLOW
);
809 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
810 pa_tagstruct_putu32(t
, s
->index
);
811 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
815 case PLAYBACK_STREAM_MESSAGE_STARTED
:
817 if (s
->connection
->version
>= 13) {
820 /* Notify the user we started playback */
821 t
= pa_tagstruct_new(NULL
, 0);
822 pa_tagstruct_putu32(t
, PA_COMMAND_STARTED
);
823 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
824 pa_tagstruct_putu32(t
, s
->index
);
825 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
830 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
:
831 pa_pstream_send_simple_ack(s
->connection
->pstream
, PA_PTR_TO_UINT(userdata
));
834 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
:
836 s
->buffer_attr
.tlength
= (uint32_t) offset
;
838 if (s
->connection
->version
>= 15) {
841 t
= pa_tagstruct_new(NULL
, 0);
842 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
);
843 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
844 pa_tagstruct_putu32(t
, s
->index
);
845 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
846 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
847 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
848 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
849 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
850 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
859 /* Called from main context */
860 static void fix_playback_buffer_attr(playback_stream
*s
) {
861 size_t frame_size
, max_prebuf
;
862 pa_usec_t orig_tlength_usec
, tlength_usec
, orig_minreq_usec
, minreq_usec
, sink_usec
;
866 /* pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", */
867 /* (long) s->buffer_attr.maxlength, */
868 /* (long) s->buffer_attr.tlength, */
869 /* (long) s->buffer_attr.minreq, */
870 /* (long) s->buffer_attr.prebuf); */
872 /* pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
873 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
874 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
875 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
876 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
878 /* This function will be called from the main thread, before as
879 * well as after the sink input has been activated using
880 * pa_sink_input_put()! That means it may not touch any
881 * ->thread_info data, such as the memblockq! */
883 frame_size
= pa_frame_size(&s
->sink_input
->sample_spec
);
885 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
886 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
887 if (s
->buffer_attr
.maxlength
<= 0)
888 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
890 if (s
->buffer_attr
.tlength
== (uint32_t) -1)
891 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
892 if (s
->buffer_attr
.tlength
<= 0)
893 s
->buffer_attr
.tlength
= (uint32_t) frame_size
;
895 if (s
->buffer_attr
.minreq
== (uint32_t) -1)
896 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
897 if (s
->buffer_attr
.minreq
<= 0)
898 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
900 if (s
->buffer_attr
.tlength
< s
->buffer_attr
.minreq
+frame_size
)
901 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
+(uint32_t) frame_size
;
903 orig_tlength_usec
= tlength_usec
= pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
);
904 orig_minreq_usec
= minreq_usec
= pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
);
906 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
907 (double) tlength_usec
/ PA_USEC_PER_MSEC
,
908 (double) minreq_usec
/ PA_USEC_PER_MSEC
);
910 if (s
->early_requests
) {
912 /* In early request mode we need to emulate the classic
913 * fragment-based playback model. We do this setting the sink
914 * latency to the fragment size. */
916 sink_usec
= minreq_usec
;
917 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
919 } else if (s
->adjust_latency
) {
921 /* So, the user asked us to adjust the latency of the stream
922 * buffer according to the what the sink can provide. The
923 * tlength passed in shall be the overall latency. Roughly
924 * half the latency will be spent on the hw buffer, the other
925 * half of it in the async buffer queue we maintain for each
926 * client. In between we'll have a safety space of size
927 * 2*minreq. Why the 2*minreq? When the hw buffer is completey
928 * empty and needs to be filled, then our buffer must have
929 * enough data to fulfill this request immediatly and thus
930 * have at least the same tlength as the size of the hw
931 * buffer. It additionally needs space for 2 times minreq
932 * because if the buffer ran empty and a partial fillup
933 * happens immediately on the next iteration we need to be
934 * able to fulfill it and give the application also minreq
935 * time to fill it up again for the next request Makes 2 times
936 * minreq in plus.. */
938 if (tlength_usec
> minreq_usec
*2)
939 sink_usec
= (tlength_usec
- minreq_usec
*2)/2;
943 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
947 /* Ok, the user didn't ask us to adjust the latency, but we
948 * still need to make sure that the parameters from the user
951 if (tlength_usec
> minreq_usec
*2)
952 sink_usec
= (tlength_usec
- minreq_usec
*2);
956 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
959 s
->configured_sink_latency
= pa_sink_input_set_requested_latency(s
->sink_input
, sink_usec
);
961 if (s
->early_requests
) {
963 /* Ok, we didn't necessarily get what we were asking for, so
964 * let's tell the user */
966 minreq_usec
= s
->configured_sink_latency
;
968 } else if (s
->adjust_latency
) {
970 /* Ok, we didn't necessarily get what we were asking for, so
971 * let's subtract from what we asked for for the remaining
974 if (tlength_usec
>= s
->configured_sink_latency
)
975 tlength_usec
-= s
->configured_sink_latency
;
978 /* FIXME: This is actually larger than necessary, since not all of
979 * the sink latency is actually rewritable. */
980 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
981 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
983 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
984 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
985 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
987 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
988 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
989 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
991 if (s
->buffer_attr
.minreq
<= 0) {
992 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
993 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
996 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
997 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
999 max_prebuf
= s
->buffer_attr
.tlength
+ (uint32_t)frame_size
- s
->buffer_attr
.minreq
;
1001 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 ||
1002 s
->buffer_attr
.prebuf
> max_prebuf
)
1003 s
->buffer_attr
.prebuf
= max_prebuf
;
1005 /* pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", */
1006 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1007 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1008 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), */
1009 /* (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); */
1012 /* Called from main context */
1013 static playback_stream
* playback_stream_new(
1014 pa_native_connection
*c
,
1017 pa_channel_map
*map
,
1022 pa_bool_t muted_set
,
1025 pa_sink_input_flags_t flags
,
1027 pa_bool_t adjust_latency
,
1028 pa_bool_t early_requests
,
1029 pa_bool_t relative_volume
,
1032 playback_stream
*s
, *ssync
;
1033 pa_sink_input
*sink_input
= NULL
;
1034 pa_memchunk silence
;
1036 int64_t start_index
;
1037 pa_sink_input_new_data data
;
1045 /* Find syncid group */
1046 PA_IDXSET_FOREACH(ssync
, c
->output_streams
, idx
) {
1048 if (!playback_stream_isinstance(ssync
))
1051 if (ssync
->syncid
== syncid
)
1055 /* Synced streams must connect to the same sink */
1059 sink
= ssync
->sink_input
->sink
;
1060 else if (sink
!= ssync
->sink_input
->sink
) {
1061 *ret
= PA_ERR_INVALID
;
1066 pa_sink_input_new_data_init(&data
);
1068 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1069 data
.driver
= __FILE__
;
1070 data
.module
= c
->options
->module
;
1071 data
.client
= c
->client
;
1073 pa_sink_input_new_data_set_sink(&data
, sink
, TRUE
);
1074 if (pa_sample_spec_valid(ss
))
1075 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1076 if (pa_channel_map_valid(map
))
1077 pa_sink_input_new_data_set_channel_map(&data
, map
);
1079 pa_sink_input_new_data_set_formats(&data
, formats
);
1081 pa_sink_input_new_data_set_volume(&data
, volume
);
1082 data
.volume_is_absolute
= !relative_volume
;
1083 data
.save_volume
= TRUE
;
1086 pa_sink_input_new_data_set_muted(&data
, muted
);
1087 data
.save_muted
= TRUE
;
1089 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1092 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
);
1094 pa_sink_input_new_data_done(&data
);
1099 s
= pa_msgobject_new(playback_stream
);
1100 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1101 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1104 s
->sink_input
= sink_input
;
1105 s
->is_underrun
= TRUE
;
1106 s
->drain_request
= FALSE
;
1107 pa_atomic_store(&s
->missing
, 0);
1108 s
->buffer_attr
= *a
;
1109 s
->adjust_latency
= adjust_latency
;
1110 s
->early_requests
= early_requests
;
1111 pa_atomic_store(&s
->seek_or_post_in_queue
, 0);
1112 s
->seek_windex
= -1;
1114 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1115 s
->sink_input
->pop
= sink_input_pop_cb
;
1116 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1117 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1118 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1119 s
->sink_input
->kill
= sink_input_kill_cb
;
1120 s
->sink_input
->moving
= sink_input_moving_cb
;
1121 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1122 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1123 s
->sink_input
->userdata
= s
;
1125 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1127 fix_playback_buffer_attr(s
);
1129 pa_sink_input_get_silence(sink_input
, &silence
);
1130 s
->memblockq
= pa_memblockq_new(
1132 s
->buffer_attr
.maxlength
,
1133 s
->buffer_attr
.tlength
,
1134 pa_frame_size(&sink_input
->sample_spec
),
1135 s
->buffer_attr
.prebuf
,
1136 s
->buffer_attr
.minreq
,
1139 pa_memblock_unref(silence
.memblock
);
1141 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1143 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1145 /* pa_log("missing original: %li", (long int) *missing); */
1147 *ss
= s
->sink_input
->sample_spec
;
1148 *map
= s
->sink_input
->channel_map
;
1150 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1152 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1153 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1154 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1155 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1156 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1158 pa_sink_input_put(s
->sink_input
);
1162 /* Called from IO context */
1163 static void playback_stream_request_bytes(playback_stream
*s
) {
1165 int previous_missing
;
1167 playback_stream_assert_ref(s
);
1169 m
= pa_memblockq_pop_missing(s
->memblockq
);
1171 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1172 /* (unsigned long) m, */
1173 /* pa_memblockq_get_tlength(s->memblockq), */
1174 /* pa_memblockq_get_minreq(s->memblockq), */
1175 /* pa_memblockq_get_length(s->memblockq), */
1176 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1181 /* pa_log("request_bytes(%lu)", (unsigned long) m); */
1183 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1184 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1186 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1187 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1188 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1191 /* Called from main context */
1192 static void playback_stream_send_killed(playback_stream
*p
) {
1194 playback_stream_assert_ref(p
);
1196 t
= pa_tagstruct_new(NULL
, 0);
1197 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1198 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1199 pa_tagstruct_putu32(t
, p
->index
);
1200 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1203 /* Called from main context */
1204 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1205 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1206 pa_native_connection_assert_ref(c
);
1213 case CONNECTION_MESSAGE_REVOKE
:
1214 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1217 case CONNECTION_MESSAGE_RELEASE
:
1218 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1225 /* Called from main context */
1226 static void native_connection_unlink(pa_native_connection
*c
) {
1235 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1238 pa_native_options_unref(c
->options
);
1240 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1241 record_stream_unlink(r
);
1243 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1244 if (playback_stream_isinstance(o
))
1245 playback_stream_unlink(PLAYBACK_STREAM(o
));
1247 upload_stream_unlink(UPLOAD_STREAM(o
));
1249 if (c
->subscription
)
1250 pa_subscription_free(c
->subscription
);
1253 pa_pstream_unlink(c
->pstream
);
1255 if (c
->auth_timeout_event
) {
1256 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1257 c
->auth_timeout_event
= NULL
;
1260 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1262 pa_native_connection_unref(c
);
1265 /* Called from main context */
1266 static void native_connection_free(pa_object
*o
) {
1267 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1271 native_connection_unlink(c
);
1273 pa_idxset_free(c
->record_streams
, NULL
, NULL
);
1274 pa_idxset_free(c
->output_streams
, NULL
, NULL
);
1276 pa_pdispatch_unref(c
->pdispatch
);
1277 pa_pstream_unref(c
->pstream
);
1278 pa_client_free(c
->client
);
1283 /* Called from main context */
1284 static void native_connection_send_memblock(pa_native_connection
*c
) {
1288 start
= PA_IDXSET_INVALID
;
1292 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1295 if (start
== PA_IDXSET_INVALID
)
1296 start
= c
->rrobin_index
;
1297 else if (start
== c
->rrobin_index
)
1300 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1301 pa_memchunk schunk
= chunk
;
1303 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1304 schunk
.length
= r
->buffer_attr
.fragsize
;
1306 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1308 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1309 pa_memblock_unref(schunk
.memblock
);
1316 /*** sink input callbacks ***/
1318 /* Called from thread context */
1319 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1320 playback_stream_assert_ref(s
);
1322 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1324 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1326 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1328 if (pa_memblockq_is_readable(s
->memblockq
)) {
1330 /* We just ended an underrun, let's ask the sink
1331 * for a complete rewind rewrite */
1333 pa_log_debug("Requesting rewind due to end of underrun.");
1334 pa_sink_input_request_rewind(s
->sink_input
,
1335 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (uint64_t) -1 ? 0 :
1336 s
->sink_input
->thread_info
.underrun_for
),
1337 FALSE
, TRUE
, FALSE
);
1343 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1345 if (indexw
< indexr
) {
1346 /* OK, the sink already asked for this data, so
1347 * let's have it usk us again */
1349 pa_log_debug("Requesting rewind due to rewrite.");
1350 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), TRUE
, FALSE
, FALSE
);
1354 playback_stream_request_bytes(s
);
1357 static void flush_write_no_account(pa_memblockq
*q
) {
1358 pa_memblockq_flush_write(q
, FALSE
);
1361 /* Called from thread context */
1362 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1363 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1366 pa_sink_input_assert_ref(i
);
1367 s
= PLAYBACK_STREAM(i
->userdata
);
1368 playback_stream_assert_ref(s
);
1372 case SINK_INPUT_MESSAGE_SEEK
:
1373 case SINK_INPUT_MESSAGE_POST_DATA
: {
1374 int64_t windex
= pa_memblockq_get_write_index(s
->memblockq
);
1376 if (code
== SINK_INPUT_MESSAGE_SEEK
) {
1377 /* The client side is incapable of accounting correctly
1378 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1379 * able to deal with that. */
1381 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1382 windex
= PA_MIN(windex
, pa_memblockq_get_write_index(s
->memblockq
));
1385 if (chunk
&& pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1386 if (pa_log_ratelimit(PA_LOG_WARN
))
1387 pa_log_warn("Failed to push data into queue");
1388 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1389 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, TRUE
);
1392 /* If more data is in queue, we rewind later instead. */
1393 if (s
->seek_windex
!= -1)
1394 windex
= PA_MIN(windex
, s
->seek_windex
);
1395 if (pa_atomic_dec(&s
->seek_or_post_in_queue
) > 1)
1396 s
->seek_windex
= windex
;
1398 s
->seek_windex
= -1;
1399 handle_seek(s
, windex
);
1404 case SINK_INPUT_MESSAGE_DRAIN
:
1405 case SINK_INPUT_MESSAGE_FLUSH
:
1406 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1407 case SINK_INPUT_MESSAGE_TRIGGER
: {
1410 pa_sink_input
*isync
;
1411 void (*func
)(pa_memblockq
*bq
);
1414 case SINK_INPUT_MESSAGE_FLUSH
:
1415 func
= flush_write_no_account
;
1418 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1419 func
= pa_memblockq_prebuf_force
;
1422 case SINK_INPUT_MESSAGE_DRAIN
:
1423 case SINK_INPUT_MESSAGE_TRIGGER
:
1424 func
= pa_memblockq_prebuf_disable
;
1428 pa_assert_not_reached();
1431 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1433 handle_seek(s
, windex
);
1435 /* Do the same for all other members in the sync group */
1436 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1437 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1438 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1439 func(ssync
->memblockq
);
1440 handle_seek(ssync
, windex
);
1443 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1444 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1445 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1446 func(ssync
->memblockq
);
1447 handle_seek(ssync
, windex
);
1450 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1451 if (!pa_memblockq_is_readable(s
->memblockq
))
1452 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1454 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1455 s
->drain_request
= TRUE
;
1462 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1463 /* Atomically get a snapshot of all timing parameters... */
1464 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1465 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1466 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1467 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1468 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1469 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1473 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1476 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1478 pa_memblockq_prebuf_force(s
->memblockq
);
1480 handle_seek(s
, windex
);
1482 /* Fall through to the default handler */
1486 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1487 pa_usec_t
*r
= userdata
;
1489 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1491 /* Fall through, the default handler will add in the extra
1492 * latency added by the resampler */
1496 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1497 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1498 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1503 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1506 /* Called from thread context */
1507 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1510 pa_sink_input_assert_ref(i
);
1511 s
= PLAYBACK_STREAM(i
->userdata
);
1512 playback_stream_assert_ref(s
);
1515 /* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
1517 if (pa_memblockq_is_readable(s
->memblockq
))
1518 s
->is_underrun
= FALSE
;
1520 if (!s
->is_underrun
)
1521 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
));
1523 if (s
->drain_request
&& pa_sink_input_safe_to_remove(i
)) {
1524 s
->drain_request
= FALSE
;
1525 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
);
1526 } else if (!s
->is_underrun
)
1527 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UNDERFLOW
, NULL
, 0, NULL
, NULL
);
1529 s
->is_underrun
= TRUE
;
1531 playback_stream_request_bytes(s
);
1534 /* This call will not fail with prebuf=0, hence we check for
1535 underrun explicitly above */
1536 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1539 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1541 if (i
->thread_info
.underrun_for
> 0)
1542 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1544 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1545 playback_stream_request_bytes(s
);
1550 /* Called from thread context */
1551 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1554 pa_sink_input_assert_ref(i
);
1555 s
= PLAYBACK_STREAM(i
->userdata
);
1556 playback_stream_assert_ref(s
);
1558 /* If we are in an underrun, then we don't rewind */
1559 if (i
->thread_info
.underrun_for
> 0)
1562 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1565 /* Called from thread context */
1566 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1569 pa_sink_input_assert_ref(i
);
1570 s
= PLAYBACK_STREAM(i
->userdata
);
1571 playback_stream_assert_ref(s
);
1573 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1576 /* Called from thread context */
1577 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1579 size_t new_tlength
, old_tlength
;
1581 pa_sink_input_assert_ref(i
);
1582 s
= PLAYBACK_STREAM(i
->userdata
);
1583 playback_stream_assert_ref(s
);
1585 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1586 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1588 if (old_tlength
< new_tlength
) {
1589 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1590 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1591 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1593 if (new_tlength
== old_tlength
)
1594 pa_log_debug("Failed to increase tlength");
1596 pa_log_debug("Notifying client about increased tlength");
1597 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
);
1602 /* Called from main context */
1603 static void sink_input_kill_cb(pa_sink_input
*i
) {
1606 pa_sink_input_assert_ref(i
);
1607 s
= PLAYBACK_STREAM(i
->userdata
);
1608 playback_stream_assert_ref(s
);
1610 playback_stream_send_killed(s
);
1611 playback_stream_unlink(s
);
1614 /* Called from main context */
1615 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1619 pa_sink_input_assert_ref(i
);
1620 s
= PLAYBACK_STREAM(i
->userdata
);
1621 playback_stream_assert_ref(s
);
1623 if (s
->connection
->version
< 15)
1626 t
= pa_tagstruct_new(NULL
, 0);
1627 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1628 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1629 pa_tagstruct_putu32(t
, s
->index
);
1630 pa_tagstruct_puts(t
, event
);
1631 pa_tagstruct_put_proplist(t
, pl
);
1632 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1635 /* Called from main context */
1636 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
) {
1640 pa_sink_input_assert_ref(i
);
1641 s
= PLAYBACK_STREAM(i
->userdata
);
1642 playback_stream_assert_ref(s
);
1644 if (s
->connection
->version
< 12)
1647 t
= pa_tagstruct_new(NULL
, 0);
1648 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1649 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1650 pa_tagstruct_putu32(t
, s
->index
);
1651 pa_tagstruct_put_boolean(t
, suspend
);
1652 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1655 /* Called from main context */
1656 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1660 pa_sink_input_assert_ref(i
);
1661 s
= PLAYBACK_STREAM(i
->userdata
);
1662 playback_stream_assert_ref(s
);
1667 fix_playback_buffer_attr(s
);
1668 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1669 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1671 if (s
->connection
->version
< 12)
1674 t
= pa_tagstruct_new(NULL
, 0);
1675 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1676 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1677 pa_tagstruct_putu32(t
, s
->index
);
1678 pa_tagstruct_putu32(t
, dest
->index
);
1679 pa_tagstruct_puts(t
, dest
->name
);
1680 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1682 if (s
->connection
->version
>= 13) {
1683 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1684 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1685 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1686 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1687 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1690 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1693 /*** source_output callbacks ***/
1695 /* Called from thread context */
1696 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1697 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1700 pa_source_output_assert_ref(o
);
1701 s
= RECORD_STREAM(o
->userdata
);
1702 record_stream_assert_ref(s
);
1705 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1706 /* Atomically get a snapshot of all timing parameters... */
1707 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1708 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1709 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1713 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1716 /* Called from thread context */
1717 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1720 pa_source_output_assert_ref(o
);
1721 s
= RECORD_STREAM(o
->userdata
);
1722 record_stream_assert_ref(s
);
1725 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1726 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1729 static void source_output_kill_cb(pa_source_output
*o
) {
1732 pa_source_output_assert_ref(o
);
1733 s
= RECORD_STREAM(o
->userdata
);
1734 record_stream_assert_ref(s
);
1736 record_stream_send_killed(s
);
1737 record_stream_unlink(s
);
1740 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1743 pa_source_output_assert_ref(o
);
1744 s
= RECORD_STREAM(o
->userdata
);
1745 record_stream_assert_ref(s
);
1747 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1749 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1752 /* Called from main context */
1753 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1757 pa_source_output_assert_ref(o
);
1758 s
= RECORD_STREAM(o
->userdata
);
1759 record_stream_assert_ref(s
);
1761 if (s
->connection
->version
< 15)
1764 t
= pa_tagstruct_new(NULL
, 0);
1765 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1766 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1767 pa_tagstruct_putu32(t
, s
->index
);
1768 pa_tagstruct_puts(t
, event
);
1769 pa_tagstruct_put_proplist(t
, pl
);
1770 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1773 /* Called from main context */
1774 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
) {
1778 pa_source_output_assert_ref(o
);
1779 s
= RECORD_STREAM(o
->userdata
);
1780 record_stream_assert_ref(s
);
1782 if (s
->connection
->version
< 12)
1785 t
= pa_tagstruct_new(NULL
, 0);
1786 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1787 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1788 pa_tagstruct_putu32(t
, s
->index
);
1789 pa_tagstruct_put_boolean(t
, suspend
);
1790 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1793 /* Called from main context */
1794 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1798 pa_source_output_assert_ref(o
);
1799 s
= RECORD_STREAM(o
->userdata
);
1800 record_stream_assert_ref(s
);
1805 fix_record_buffer_attr_pre(s
);
1806 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1807 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1808 fix_record_buffer_attr_post(s
);
1810 if (s
->connection
->version
< 12)
1813 t
= pa_tagstruct_new(NULL
, 0);
1814 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1815 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1816 pa_tagstruct_putu32(t
, s
->index
);
1817 pa_tagstruct_putu32(t
, dest
->index
);
1818 pa_tagstruct_puts(t
, dest
->name
);
1819 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1821 if (s
->connection
->version
>= 13) {
1822 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1823 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1824 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1827 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1830 /*** pdispatch callbacks ***/
1832 static void protocol_error(pa_native_connection
*c
) {
1833 pa_log("protocol error, kicking client");
1834 native_connection_unlink(c
);
1837 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1838 if (!(expression)) { \
1839 pa_pstream_send_error((pstream), (tag), (error)); \
1844 static pa_tagstruct
*reply_new(uint32_t tag
) {
1845 pa_tagstruct
*reply
;
1847 reply
= pa_tagstruct_new(NULL
, 0);
1848 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1849 pa_tagstruct_putu32(reply
, tag
);
1853 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1854 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1856 uint32_t sink_index
, syncid
, missing
;
1857 pa_buffer_attr attr
;
1858 const char *name
= NULL
, *sink_name
;
1861 pa_tagstruct
*reply
;
1862 pa_sink
*sink
= NULL
;
1870 fix_channels
= FALSE
,
1872 variable_rate
= FALSE
,
1874 adjust_latency
= FALSE
,
1875 early_requests
= FALSE
,
1876 dont_inhibit_auto_suspend
= FALSE
,
1878 fail_on_suspend
= FALSE
,
1879 relative_volume
= FALSE
,
1880 passthrough
= FALSE
;
1882 pa_sink_input_flags_t flags
= 0;
1883 pa_proplist
*p
= NULL
;
1884 pa_bool_t volume_set
= TRUE
;
1885 int ret
= PA_ERR_INVALID
;
1886 uint8_t n_formats
= 0;
1887 pa_format_info
*format
;
1888 pa_idxset
*formats
= NULL
;
1891 pa_native_connection_assert_ref(c
);
1893 memset(&attr
, 0, sizeof(attr
));
1895 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
1898 PA_TAG_SAMPLE_SPEC
, &ss
,
1899 PA_TAG_CHANNEL_MAP
, &map
,
1900 PA_TAG_U32
, &sink_index
,
1901 PA_TAG_STRING
, &sink_name
,
1902 PA_TAG_U32
, &attr
.maxlength
,
1903 PA_TAG_BOOLEAN
, &corked
,
1904 PA_TAG_U32
, &attr
.tlength
,
1905 PA_TAG_U32
, &attr
.prebuf
,
1906 PA_TAG_U32
, &attr
.minreq
,
1907 PA_TAG_U32
, &syncid
,
1908 PA_TAG_CVOLUME
, &volume
,
1909 PA_TAG_INVALID
) < 0) {
1915 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
1916 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
1917 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
1918 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
1919 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
1921 p
= pa_proplist_new();
1924 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
1926 if (c
->version
>= 12) {
1927 /* Since 0.9.8 the user can ask for a couple of additional flags */
1929 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
1930 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
1931 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
1932 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
1933 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
1934 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
1935 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
1942 if (c
->version
>= 13) {
1944 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
1945 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
1946 pa_tagstruct_get_proplist(t
, p
) < 0) {
1953 if (c
->version
>= 14) {
1955 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
1956 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
1963 if (c
->version
>= 15) {
1965 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
1966 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
1967 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
1974 if (c
->version
>= 17) {
1976 if (pa_tagstruct_get_boolean(t
, &relative_volume
) < 0) {
1983 if (c
->version
>= 18) {
1985 if (pa_tagstruct_get_boolean(t
, &passthrough
) < 0 ) {
1991 if (c
->version
>= 21) {
1993 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
1999 formats
= pa_idxset_new(NULL
, NULL
);
2001 for (i
= 0; i
< n_formats
; i
++) {
2002 format
= pa_format_info_new();
2003 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2007 pa_idxset_put(formats
, format
, NULL
);
2011 if (n_formats
== 0) {
2012 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2013 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2014 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2016 PA_IDXSET_FOREACH(format
, formats
, i
) {
2017 CHECK_VALIDITY(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
);
2021 if (!pa_tagstruct_eof(t
)) {
2026 if (sink_index
!= PA_INVALID_INDEX
) {
2028 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
2029 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2033 } else if (sink_name
) {
2035 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
2036 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2042 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
2043 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
2044 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
2045 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
2046 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
2047 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
2048 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
2049 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
2050 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2051 (fail_on_suspend
? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND
|PA_SINK_INPUT_KILL_ON_SUSPEND
: 0) |
2052 (passthrough
? PA_SINK_INPUT_PASSTHROUGH
: 0);
2054 /* Only since protocol version 15 there's a seperate muted_set
2055 * flag. For older versions we synthesize it here */
2056 muted_set
= muted_set
|| muted
;
2058 s
= playback_stream_new(c
, sink
, &ss
, &map
, formats
, &attr
, volume_set
? &volume
: NULL
, muted
, muted_set
, syncid
, &missing
, flags
, p
, adjust_latency
, early_requests
, relative_volume
, &ret
);
2059 pa_proplist_free(p
);
2061 CHECK_VALIDITY(c
->pstream
, s
, tag
, ret
);
2063 reply
= reply_new(tag
);
2064 pa_tagstruct_putu32(reply
, s
->index
);
2065 pa_assert(s
->sink_input
);
2066 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
2067 pa_tagstruct_putu32(reply
, missing
);
2069 /* pa_log("initial request is %u", missing); */
2071 if (c
->version
>= 9) {
2072 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2074 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2075 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
2076 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
2077 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
2080 if (c
->version
>= 12) {
2081 /* Since 0.9.8 we support sending the chosen sample
2082 * spec/channel map/device/suspend status back to the
2085 pa_tagstruct_put_sample_spec(reply
, &ss
);
2086 pa_tagstruct_put_channel_map(reply
, &map
);
2088 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
2089 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
2091 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
2094 if (c
->version
>= 13)
2095 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
2097 if (c
->version
>= 21) {
2098 /* Send back the format we negotiated */
2099 if (s
->sink_input
->format
)
2100 pa_tagstruct_put_format_info(reply
, s
->sink_input
->format
);
2102 pa_format_info
*f
= pa_format_info_new();
2103 pa_tagstruct_put_format_info(reply
, f
);
2104 pa_format_info_free(f
);
2108 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2113 pa_proplist_free(p
);
2115 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
2119 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2120 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2123 pa_native_connection_assert_ref(c
);
2126 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2127 !pa_tagstruct_eof(t
)) {
2132 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2136 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2138 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2139 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2143 playback_stream_unlink(s
);
2147 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2149 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2150 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2154 record_stream_unlink(s
);
2158 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2161 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2162 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2166 upload_stream_unlink(s
);
2171 pa_assert_not_reached();
2174 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2177 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2178 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2180 pa_buffer_attr attr
;
2181 uint32_t source_index
;
2182 const char *name
= NULL
, *source_name
;
2185 pa_tagstruct
*reply
;
2186 pa_source
*source
= NULL
;
2193 fix_channels
= FALSE
,
2195 variable_rate
= FALSE
,
2196 adjust_latency
= FALSE
,
2197 peak_detect
= FALSE
,
2198 early_requests
= FALSE
,
2199 dont_inhibit_auto_suspend
= FALSE
,
2200 fail_on_suspend
= FALSE
;
2201 pa_source_output_flags_t flags
= 0;
2203 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2204 pa_sink_input
*direct_on_input
= NULL
;
2205 int ret
= PA_ERR_INVALID
;
2207 pa_native_connection_assert_ref(c
);
2210 memset(&attr
, 0, sizeof(attr
));
2212 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2213 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2214 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2215 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2216 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2217 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2218 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2219 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2224 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2225 CHECK_VALIDITY(c
->pstream
, !source_name
|| pa_namereg_is_valid_name_or_wildcard(source_name
, PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
);
2226 CHECK_VALIDITY(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
);
2227 CHECK_VALIDITY(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2228 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2229 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2230 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2232 p
= pa_proplist_new();
2235 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2237 if (c
->version
>= 12) {
2238 /* Since 0.9.8 the user can ask for a couple of additional flags */
2240 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2241 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2242 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2243 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2244 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2245 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2246 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2249 pa_proplist_free(p
);
2254 if (c
->version
>= 13) {
2256 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2257 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2258 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2259 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2261 pa_proplist_free(p
);
2266 if (c
->version
>= 14) {
2268 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2270 pa_proplist_free(p
);
2275 if (c
->version
>= 15) {
2277 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2278 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2280 pa_proplist_free(p
);
2285 if (!pa_tagstruct_eof(t
)) {
2287 pa_proplist_free(p
);
2291 if (source_index
!= PA_INVALID_INDEX
) {
2293 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2294 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2295 pa_proplist_free(p
);
2299 } else if (source_name
) {
2301 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2302 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2303 pa_proplist_free(p
);
2308 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2310 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2311 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2312 pa_proplist_free(p
);
2318 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2319 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2320 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2321 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2322 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2323 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2324 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2325 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2326 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2327 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0);
2329 s
= record_stream_new(c
, source
, &ss
, &map
, peak_detect
, &attr
, flags
, p
, adjust_latency
, direct_on_input
, early_requests
, &ret
);
2330 pa_proplist_free(p
);
2332 CHECK_VALIDITY(c
->pstream
, s
, tag
, ret
);
2334 reply
= reply_new(tag
);
2335 pa_tagstruct_putu32(reply
, s
->index
);
2336 pa_assert(s
->source_output
);
2337 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2339 if (c
->version
>= 9) {
2340 /* Since 0.9 we support sending the buffer metrics back to the client */
2342 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2343 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2346 if (c
->version
>= 12) {
2347 /* Since 0.9.8 we support sending the chosen sample
2348 * spec/channel map/device/suspend status back to the
2351 pa_tagstruct_put_sample_spec(reply
, &ss
);
2352 pa_tagstruct_put_channel_map(reply
, &map
);
2354 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2355 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2357 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2360 if (c
->version
>= 13)
2361 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2363 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2366 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2367 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2370 pa_native_connection_assert_ref(c
);
2373 if (!pa_tagstruct_eof(t
)) {
2378 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2379 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2380 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2382 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2384 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2387 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2388 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2390 pa_tagstruct
*reply
;
2391 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2393 pa_native_connection_assert_ref(c
);
2396 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2397 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2398 !pa_tagstruct_eof(t
)) {
2403 /* Minimum supported version */
2404 if (c
->version
< 8) {
2405 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2409 /* Starting with protocol version 13 the MSB of the version tag
2410 reflects if shm is available for this pa_native_connection or
2412 if (c
->version
>= 13) {
2413 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2414 c
->version
&= 0x7FFFFFFFU
;
2417 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2419 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2421 if (!c
->authorized
) {
2422 pa_bool_t success
= FALSE
;
2425 const pa_creds
*creds
;
2427 if ((creds
= pa_pdispatch_creds(pd
))) {
2428 if (creds
->uid
== getuid())
2430 else if (c
->options
->auth_group
) {
2434 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2435 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2436 else if (gid
== creds
->gid
)
2440 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2441 pa_log_warn("Failed to check group membership.");
2447 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2448 (unsigned long) creds
->uid
,
2449 (unsigned long) creds
->gid
,
2454 if (!success
&& c
->options
->auth_cookie
) {
2457 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2458 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2463 pa_log_warn("Denied access to client with invalid authorization data.");
2464 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2468 c
->authorized
= TRUE
;
2469 if (c
->auth_timeout_event
) {
2470 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2471 c
->auth_timeout_event
= NULL
;
2475 /* Enable shared memory support if possible */
2477 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2480 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2483 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2488 /* Only enable SHM if both sides are owned by the same
2489 * user. This is a security measure because otherwise data
2490 * private to the user might leak. */
2492 const pa_creds
*creds
;
2493 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2498 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2499 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2501 reply
= reply_new(tag
);
2502 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2506 /* SHM support is only enabled after both sides made sure they are the same user. */
2510 ucred
.uid
= getuid();
2511 ucred
.gid
= getgid();
2513 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2516 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2520 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2521 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2522 const char *name
= NULL
;
2524 pa_tagstruct
*reply
;
2526 pa_native_connection_assert_ref(c
);
2529 p
= pa_proplist_new();
2531 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2532 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2533 !pa_tagstruct_eof(t
)) {
2536 pa_proplist_free(p
);
2541 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2542 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2543 pa_proplist_free(p
);
2547 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2548 pa_proplist_free(p
);
2550 reply
= reply_new(tag
);
2552 if (c
->version
>= 13)
2553 pa_tagstruct_putu32(reply
, c
->client
->index
);
2555 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2558 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2559 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2561 uint32_t idx
= PA_IDXSET_INVALID
;
2563 pa_native_connection_assert_ref(c
);
2566 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2567 !pa_tagstruct_eof(t
)) {
2572 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2573 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name_or_wildcard(name
, command
== PA_COMMAND_LOOKUP_SINK
? PA_NAMEREG_SINK
: PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
);
2575 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2577 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2581 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2582 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2583 idx
= source
->index
;
2586 if (idx
== PA_IDXSET_INVALID
)
2587 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2589 pa_tagstruct
*reply
;
2590 reply
= reply_new(tag
);
2591 pa_tagstruct_putu32(reply
, idx
);
2592 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2596 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2597 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2601 pa_native_connection_assert_ref(c
);
2604 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2605 !pa_tagstruct_eof(t
)) {
2610 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2611 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2612 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2613 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2615 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
);
2618 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2619 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2620 pa_tagstruct
*reply
;
2621 const pa_mempool_stat
*stat
;
2623 pa_native_connection_assert_ref(c
);
2626 if (!pa_tagstruct_eof(t
)) {
2631 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2633 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2635 reply
= reply_new(tag
);
2636 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2637 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2638 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2639 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2640 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2641 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2644 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2645 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2646 pa_tagstruct
*reply
;
2648 struct timeval tv
, now
;
2651 pa_native_connection_assert_ref(c
);
2654 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2655 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2656 !pa_tagstruct_eof(t
)) {
2661 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2662 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2663 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2664 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2666 /* Get an atomic snapshot of all timing parameters */
2667 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);
2669 reply
= reply_new(tag
);
2670 pa_tagstruct_put_usec(reply
,
2671 s
->current_sink_latency
+
2672 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2673 pa_tagstruct_put_usec(reply
, 0);
2674 pa_tagstruct_put_boolean(reply
,
2675 s
->playing_for
> 0 &&
2676 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2677 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2678 pa_tagstruct_put_timeval(reply
, &tv
);
2679 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2680 pa_tagstruct_puts64(reply
, s
->write_index
);
2681 pa_tagstruct_puts64(reply
, s
->read_index
);
2683 if (c
->version
>= 13) {
2684 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2685 pa_tagstruct_putu64(reply
, s
->playing_for
);
2688 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2691 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2692 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2693 pa_tagstruct
*reply
;
2695 struct timeval tv
, now
;
2698 pa_native_connection_assert_ref(c
);
2701 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2702 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2703 !pa_tagstruct_eof(t
)) {
2708 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2709 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2710 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2712 /* Get an atomic snapshot of all timing parameters */
2713 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);
2715 reply
= reply_new(tag
);
2716 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2717 pa_tagstruct_put_usec(reply
,
2718 s
->current_source_latency
+
2719 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2720 pa_tagstruct_put_boolean(reply
,
2721 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2722 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2723 pa_tagstruct_put_timeval(reply
, &tv
);
2724 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2725 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2726 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2727 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2730 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2731 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2734 const char *name
= NULL
;
2737 pa_tagstruct
*reply
;
2740 pa_native_connection_assert_ref(c
);
2743 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2744 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2745 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2746 pa_tagstruct_getu32(t
, &length
) < 0) {
2751 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2752 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2753 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2754 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2755 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2756 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2758 p
= pa_proplist_new();
2760 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2761 !pa_tagstruct_eof(t
)) {
2764 pa_proplist_free(p
);
2768 if (c
->version
< 13)
2769 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2771 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2772 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2774 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2775 pa_proplist_free(p
);
2776 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2779 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2780 pa_proplist_free(p
);
2782 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2784 reply
= reply_new(tag
);
2785 pa_tagstruct_putu32(reply
, s
->index
);
2786 pa_tagstruct_putu32(reply
, length
);
2787 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2790 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2791 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2796 pa_native_connection_assert_ref(c
);
2799 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2800 !pa_tagstruct_eof(t
)) {
2805 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2807 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2808 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2809 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2811 if (!s
->memchunk
.memblock
)
2812 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
2813 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2814 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2816 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2818 upload_stream_unlink(s
);
2821 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2822 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2823 uint32_t sink_index
;
2826 const char *name
, *sink_name
;
2829 pa_tagstruct
*reply
;
2831 pa_native_connection_assert_ref(c
);
2834 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2836 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
2837 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
2838 pa_tagstruct_getu32(t
, &volume
) < 0 ||
2839 pa_tagstruct_gets(t
, &name
) < 0) {
2844 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
2845 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
2846 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
2847 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2849 if (sink_index
!= PA_INVALID_INDEX
)
2850 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
2852 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
2854 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
2856 p
= pa_proplist_new();
2858 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2859 !pa_tagstruct_eof(t
)) {
2861 pa_proplist_free(p
);
2865 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
2867 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
2868 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2869 pa_proplist_free(p
);
2873 pa_proplist_free(p
);
2875 reply
= reply_new(tag
);
2877 if (c
->version
>= 13)
2878 pa_tagstruct_putu32(reply
, idx
);
2880 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2883 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2884 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2887 pa_native_connection_assert_ref(c
);
2890 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2891 !pa_tagstruct_eof(t
)) {
2896 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2897 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
2899 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
2900 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2904 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2907 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
2910 pa_assert(original
);
2914 if (c
->version
< 12) {
2915 /* Before protocol version 12 we didn't support S32 samples,
2916 * so we need to lie about this to the client */
2918 if (fixed
->format
== PA_SAMPLE_S32LE
)
2919 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
2920 if (fixed
->format
== PA_SAMPLE_S32BE
)
2921 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
2924 if (c
->version
< 15) {
2925 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
2926 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
2927 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
2928 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
2932 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
2933 pa_sample_spec fixed_ss
;
2936 pa_sink_assert_ref(sink
);
2938 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
2942 PA_TAG_U32
, sink
->index
,
2943 PA_TAG_STRING
, sink
->name
,
2944 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
2945 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
2946 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
2947 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
2948 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
2949 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
2950 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
2951 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
2952 PA_TAG_USEC
, pa_sink_get_latency(sink
),
2953 PA_TAG_STRING
, sink
->driver
,
2954 PA_TAG_U32
, sink
->flags
& ~PA_SINK_SHARE_VOLUME_WITH_MASTER
,
2957 if (c
->version
>= 13) {
2958 pa_tagstruct_put_proplist(t
, sink
->proplist
);
2959 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
2962 if (c
->version
>= 15) {
2963 pa_tagstruct_put_volume(t
, sink
->base_volume
);
2964 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
2965 pa_log_error("Internal sink state is invalid.");
2966 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
2967 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
2968 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
2971 if (c
->version
>= 16) {
2972 pa_tagstruct_putu32(t
, sink
->ports
? pa_hashmap_size(sink
->ports
) : 0);
2978 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
2979 pa_tagstruct_puts(t
, p
->name
);
2980 pa_tagstruct_puts(t
, p
->description
);
2981 pa_tagstruct_putu32(t
, p
->priority
);
2985 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
2988 if (c
->version
>= 21) {
2991 pa_idxset
*formats
= pa_sink_get_formats(sink
);
2993 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
2994 PA_IDXSET_FOREACH(f
, formats
, i
) {
2995 pa_tagstruct_put_format_info(t
, f
);
2998 pa_idxset_free(formats
, (pa_free2_cb_t
) pa_format_info_free2
, NULL
);
3002 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
3003 pa_sample_spec fixed_ss
;
3006 pa_source_assert_ref(source
);
3008 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
3012 PA_TAG_U32
, source
->index
,
3013 PA_TAG_STRING
, source
->name
,
3014 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3015 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3016 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
3017 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
3018 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
3019 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
3020 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
3021 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
3022 PA_TAG_USEC
, pa_source_get_latency(source
),
3023 PA_TAG_STRING
, source
->driver
,
3024 PA_TAG_U32
, source
->flags
,
3027 if (c
->version
>= 13) {
3028 pa_tagstruct_put_proplist(t
, source
->proplist
);
3029 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
3032 if (c
->version
>= 15) {
3033 pa_tagstruct_put_volume(t
, source
->base_volume
);
3034 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
3035 pa_log_error("Internal source state is invalid.");
3036 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
3037 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
3038 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
3041 if (c
->version
>= 16) {
3043 pa_tagstruct_putu32(t
, source
->ports
? pa_hashmap_size(source
->ports
) : 0);
3045 if (source
->ports
) {
3049 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
3050 pa_tagstruct_puts(t
, p
->name
);
3051 pa_tagstruct_puts(t
, p
->description
);
3052 pa_tagstruct_putu32(t
, p
->priority
);
3056 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
3060 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
3064 pa_tagstruct_putu32(t
, client
->index
);
3065 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
3066 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
3067 pa_tagstruct_puts(t
, client
->driver
);
3069 if (c
->version
>= 13)
3070 pa_tagstruct_put_proplist(t
, client
->proplist
);
3073 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
3080 pa_tagstruct_putu32(t
, card
->index
);
3081 pa_tagstruct_puts(t
, card
->name
);
3082 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
3083 pa_tagstruct_puts(t
, card
->driver
);
3085 pa_tagstruct_putu32(t
, card
->profiles
? pa_hashmap_size(card
->profiles
) : 0);
3087 if (card
->profiles
) {
3088 while ((p
= pa_hashmap_iterate(card
->profiles
, &state
, NULL
))) {
3089 pa_tagstruct_puts(t
, p
->name
);
3090 pa_tagstruct_puts(t
, p
->description
);
3091 pa_tagstruct_putu32(t
, p
->n_sinks
);
3092 pa_tagstruct_putu32(t
, p
->n_sources
);
3093 pa_tagstruct_putu32(t
, p
->priority
);
3097 pa_tagstruct_puts(t
, card
->active_profile
? card
->active_profile
->name
: NULL
);
3098 pa_tagstruct_put_proplist(t
, card
->proplist
);
3101 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3105 pa_tagstruct_putu32(t
, module
->index
);
3106 pa_tagstruct_puts(t
, module
->name
);
3107 pa_tagstruct_puts(t
, module
->argument
);
3108 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3110 if (c
->version
< 15)
3111 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
3113 if (c
->version
>= 15)
3114 pa_tagstruct_put_proplist(t
, module
->proplist
);
3117 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3118 pa_sample_spec fixed_ss
;
3119 pa_usec_t sink_latency
;
3121 pa_bool_t has_volume
= FALSE
;
3124 pa_sink_input_assert_ref(s
);
3126 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3128 has_volume
= pa_sink_input_is_volume_readable(s
);
3130 pa_sink_input_get_volume(s
, &v
, TRUE
);
3132 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3134 pa_tagstruct_putu32(t
, s
->index
);
3135 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3136 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3137 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3138 pa_tagstruct_putu32(t
, s
->sink
->index
);
3139 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3140 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3141 pa_tagstruct_put_cvolume(t
, &v
);
3142 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3143 pa_tagstruct_put_usec(t
, sink_latency
);
3144 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3145 pa_tagstruct_puts(t
, s
->driver
);
3146 if (c
->version
>= 11)
3147 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
3148 if (c
->version
>= 13)
3149 pa_tagstruct_put_proplist(t
, s
->proplist
);
3150 if (c
->version
>= 19)
3151 pa_tagstruct_put_boolean(t
, (pa_sink_input_get_state(s
) == PA_SINK_INPUT_CORKED
));
3152 if (c
->version
>= 20) {
3153 pa_tagstruct_put_boolean(t
, has_volume
);
3154 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3156 if (c
->version
>= 21)
3157 pa_tagstruct_put_format_info(t
, s
->format
);
3160 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3161 pa_sample_spec fixed_ss
;
3162 pa_usec_t source_latency
;
3165 pa_source_output_assert_ref(s
);
3167 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3169 pa_tagstruct_putu32(t
, s
->index
);
3170 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3171 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3172 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3173 pa_tagstruct_putu32(t
, s
->source
->index
);
3174 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3175 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3176 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3177 pa_tagstruct_put_usec(t
, source_latency
);
3178 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3179 pa_tagstruct_puts(t
, s
->driver
);
3180 if (c
->version
>= 13)
3181 pa_tagstruct_put_proplist(t
, s
->proplist
);
3182 if (c
->version
>= 19)
3183 pa_tagstruct_put_boolean(t
, (pa_source_output_get_state(s
) == PA_SOURCE_OUTPUT_CORKED
));
3186 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3187 pa_sample_spec fixed_ss
;
3193 if (e
->memchunk
.memblock
)
3194 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3196 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3198 pa_tagstruct_putu32(t
, e
->index
);
3199 pa_tagstruct_puts(t
, e
->name
);
3201 if (e
->volume_is_set
)
3204 pa_cvolume_init(&v
);
3206 pa_tagstruct_put_cvolume(t
, &v
);
3207 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3208 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3209 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3210 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3211 pa_tagstruct_put_boolean(t
, e
->lazy
);
3212 pa_tagstruct_puts(t
, e
->filename
);
3214 if (c
->version
>= 13)
3215 pa_tagstruct_put_proplist(t
, e
->proplist
);
3218 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3219 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3221 pa_sink
*sink
= NULL
;
3222 pa_source
*source
= NULL
;
3223 pa_client
*client
= NULL
;
3224 pa_card
*card
= NULL
;
3225 pa_module
*module
= NULL
;
3226 pa_sink_input
*si
= NULL
;
3227 pa_source_output
*so
= NULL
;
3228 pa_scache_entry
*sce
= NULL
;
3229 const char *name
= NULL
;
3230 pa_tagstruct
*reply
;
3232 pa_native_connection_assert_ref(c
);
3235 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3236 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3237 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3238 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3239 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3240 pa_tagstruct_gets(t
, &name
) < 0) ||
3241 !pa_tagstruct_eof(t
)) {
3246 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3247 CHECK_VALIDITY(c
->pstream
, !name
||
3248 (command
== PA_COMMAND_GET_SINK_INFO
&&
3249 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3250 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3251 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3252 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3253 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3254 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3255 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3257 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3258 if (idx
!= PA_INVALID_INDEX
)
3259 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3261 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3262 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3263 if (idx
!= PA_INVALID_INDEX
)
3264 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3266 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3267 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3268 if (idx
!= PA_INVALID_INDEX
)
3269 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3271 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3272 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3273 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3274 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3275 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3276 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3277 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3278 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3279 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3281 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3282 if (idx
!= PA_INVALID_INDEX
)
3283 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3285 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3288 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3289 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3293 reply
= reply_new(tag
);
3295 sink_fill_tagstruct(c
, reply
, sink
);
3297 source_fill_tagstruct(c
, reply
, source
);
3299 client_fill_tagstruct(c
, reply
, client
);
3301 card_fill_tagstruct(c
, reply
, card
);
3303 module_fill_tagstruct(c
, reply
, module
);
3305 sink_input_fill_tagstruct(c
, reply
, si
);
3307 source_output_fill_tagstruct(c
, reply
, so
);
3309 scache_fill_tagstruct(c
, reply
, sce
);
3310 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3313 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3314 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3318 pa_tagstruct
*reply
;
3320 pa_native_connection_assert_ref(c
);
3323 if (!pa_tagstruct_eof(t
)) {
3328 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3330 reply
= reply_new(tag
);
3332 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3333 i
= c
->protocol
->core
->sinks
;
3334 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3335 i
= c
->protocol
->core
->sources
;
3336 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3337 i
= c
->protocol
->core
->clients
;
3338 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3339 i
= c
->protocol
->core
->cards
;
3340 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3341 i
= c
->protocol
->core
->modules
;
3342 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3343 i
= c
->protocol
->core
->sink_inputs
;
3344 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3345 i
= c
->protocol
->core
->source_outputs
;
3347 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3348 i
= c
->protocol
->core
->scache
;
3352 for (p
= pa_idxset_first(i
, &idx
); p
; p
= pa_idxset_next(i
, &idx
)) {
3353 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3354 sink_fill_tagstruct(c
, reply
, p
);
3355 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3356 source_fill_tagstruct(c
, reply
, p
);
3357 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3358 client_fill_tagstruct(c
, reply
, p
);
3359 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3360 card_fill_tagstruct(c
, reply
, p
);
3361 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3362 module_fill_tagstruct(c
, reply
, p
);
3363 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3364 sink_input_fill_tagstruct(c
, reply
, p
);
3365 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3366 source_output_fill_tagstruct(c
, reply
, p
);
3368 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3369 scache_fill_tagstruct(c
, reply
, p
);
3374 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3377 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3378 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3379 pa_tagstruct
*reply
;
3381 pa_source
*def_source
;
3382 pa_sample_spec fixed_ss
;
3385 pa_native_connection_assert_ref(c
);
3388 if (!pa_tagstruct_eof(t
)) {
3393 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3395 reply
= reply_new(tag
);
3396 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3397 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3399 u
= pa_get_user_name_malloc();
3400 pa_tagstruct_puts(reply
, u
);
3403 h
= pa_get_host_name_malloc();
3404 pa_tagstruct_puts(reply
, h
);
3407 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3408 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3410 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3411 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3412 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3413 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3415 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3417 if (c
->version
>= 15)
3418 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3420 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3423 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3425 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3427 pa_native_connection_assert_ref(c
);
3429 t
= pa_tagstruct_new(NULL
, 0);
3430 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3431 pa_tagstruct_putu32(t
, (uint32_t) -1);
3432 pa_tagstruct_putu32(t
, e
);
3433 pa_tagstruct_putu32(t
, idx
);
3434 pa_pstream_send_tagstruct(c
->pstream
, t
);
3437 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3438 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3439 pa_subscription_mask_t m
;
3441 pa_native_connection_assert_ref(c
);
3444 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3445 !pa_tagstruct_eof(t
)) {
3450 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3451 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3453 if (c
->subscription
)
3454 pa_subscription_free(c
->subscription
);
3457 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3458 pa_assert(c
->subscription
);
3460 c
->subscription
= NULL
;
3462 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3465 static void command_set_volume(
3472 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3475 pa_sink
*sink
= NULL
;
3476 pa_source
*source
= NULL
;
3477 pa_sink_input
*si
= NULL
;
3478 const char *name
= NULL
;
3479 const char *client_name
;
3481 pa_native_connection_assert_ref(c
);
3484 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3485 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3486 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3487 pa_tagstruct_get_cvolume(t
, &volume
) ||
3488 !pa_tagstruct_eof(t
)) {
3493 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3494 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name_or_wildcard(name
, command
== PA_COMMAND_SET_SINK_VOLUME
? PA_NAMEREG_SINK
: PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
);
3495 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3496 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3497 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3498 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3502 case PA_COMMAND_SET_SINK_VOLUME
:
3503 if (idx
!= PA_INVALID_INDEX
)
3504 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3506 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3509 case PA_COMMAND_SET_SOURCE_VOLUME
:
3510 if (idx
!= PA_INVALID_INDEX
)
3511 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3513 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3516 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3517 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3521 pa_assert_not_reached();
3524 CHECK_VALIDITY(c
->pstream
, si
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3526 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3529 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3531 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3532 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3533 } else if (source
) {
3534 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3536 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3537 pa_source_set_volume(source
, &volume
, TRUE
);
3539 CHECK_VALIDITY(c
->pstream
, si
->volume_writable
, tag
, PA_ERR_BADSTATE
);
3540 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3542 pa_log_debug("Client %s changes volume of sink input %s.",
3544 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3545 pa_sink_input_set_volume(si
, &volume
, TRUE
, TRUE
);
3548 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3551 static void command_set_mute(
3558 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3561 pa_sink
*sink
= NULL
;
3562 pa_source
*source
= NULL
;
3563 pa_sink_input
*si
= NULL
;
3564 const char *name
= NULL
, *client_name
;
3566 pa_native_connection_assert_ref(c
);
3569 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3570 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3571 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3572 pa_tagstruct_get_boolean(t
, &mute
) ||
3573 !pa_tagstruct_eof(t
)) {
3578 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3579 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name_or_wildcard(name
, command
== PA_COMMAND_SET_SINK_MUTE
? PA_NAMEREG_SINK
: PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
);
3580 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3581 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3582 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3586 case PA_COMMAND_SET_SINK_MUTE
:
3587 if (idx
!= PA_INVALID_INDEX
)
3588 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3590 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3594 case PA_COMMAND_SET_SOURCE_MUTE
:
3595 if (idx
!= PA_INVALID_INDEX
)
3596 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3598 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3602 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3603 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3607 pa_assert_not_reached();
3610 CHECK_VALIDITY(c
->pstream
, si
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3612 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3615 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3616 pa_sink_set_mute(sink
, mute
, TRUE
);
3617 } else if (source
) {
3618 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3619 pa_source_set_mute(source
, mute
, TRUE
);
3621 pa_log_debug("Client %s changes mute of sink input %s.",
3623 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3624 pa_sink_input_set_mute(si
, mute
, TRUE
);
3627 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3630 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3631 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3636 pa_native_connection_assert_ref(c
);
3639 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3640 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3641 !pa_tagstruct_eof(t
)) {
3646 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3647 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3648 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3649 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3650 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3652 pa_sink_input_cork(s
->sink_input
, b
);
3655 s
->is_underrun
= TRUE
;
3657 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3660 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3661 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3665 pa_native_connection_assert_ref(c
);
3668 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3669 !pa_tagstruct_eof(t
)) {
3674 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3675 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3676 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3677 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3678 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3681 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3682 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3685 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3686 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3689 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3690 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3694 pa_assert_not_reached();
3697 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3700 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3701 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3706 pa_native_connection_assert_ref(c
);
3709 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3710 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3711 !pa_tagstruct_eof(t
)) {
3716 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3717 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3718 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3720 pa_source_output_cork(s
->source_output
, b
);
3721 pa_memblockq_prebuf_force(s
->memblockq
);
3722 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3725 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3726 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3730 pa_native_connection_assert_ref(c
);
3733 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3734 !pa_tagstruct_eof(t
)) {
3739 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3740 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3741 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3743 pa_memblockq_flush_read(s
->memblockq
);
3744 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3747 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3748 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3751 pa_tagstruct
*reply
;
3753 pa_native_connection_assert_ref(c
);
3756 memset(&a
, 0, sizeof(a
));
3758 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3763 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3765 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
3767 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3769 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3770 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3771 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3773 if (pa_tagstruct_get(
3775 PA_TAG_U32
, &a
.maxlength
,
3776 PA_TAG_U32
, &a
.tlength
,
3777 PA_TAG_U32
, &a
.prebuf
,
3778 PA_TAG_U32
, &a
.minreq
,
3779 PA_TAG_INVALID
) < 0 ||
3780 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3781 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3782 !pa_tagstruct_eof(t
)) {
3787 s
->adjust_latency
= adjust_latency
;
3788 s
->early_requests
= early_requests
;
3791 fix_playback_buffer_attr(s
);
3792 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);
3794 reply
= reply_new(tag
);
3795 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3796 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
3797 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
3798 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
3800 if (c
->version
>= 13)
3801 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
3805 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
3806 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
3808 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3809 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3811 if (pa_tagstruct_get(
3813 PA_TAG_U32
, &a
.maxlength
,
3814 PA_TAG_U32
, &a
.fragsize
,
3815 PA_TAG_INVALID
) < 0 ||
3816 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
3817 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
3818 !pa_tagstruct_eof(t
)) {
3823 s
->adjust_latency
= adjust_latency
;
3824 s
->early_requests
= early_requests
;
3827 fix_record_buffer_attr_pre(s
);
3828 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
3829 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
3830 fix_record_buffer_attr_post(s
);
3832 reply
= reply_new(tag
);
3833 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
3834 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
3836 if (c
->version
>= 13)
3837 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
3840 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3843 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3844 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3848 pa_native_connection_assert_ref(c
);
3851 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3852 pa_tagstruct_getu32(t
, &rate
) < 0 ||
3853 !pa_tagstruct_eof(t
)) {
3858 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3859 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
3861 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
3864 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3865 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3866 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3868 pa_sink_input_set_rate(s
->sink_input
, rate
);
3872 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
3874 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3875 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3877 pa_source_output_set_rate(s
->source_output
, rate
);
3880 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3883 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3884 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3889 pa_native_connection_assert_ref(c
);
3892 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3894 p
= pa_proplist_new();
3896 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
3898 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
3899 pa_tagstruct_get_proplist(t
, p
) < 0 ||
3900 !pa_tagstruct_eof(t
)) {
3902 pa_proplist_free(p
);
3908 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3909 pa_tagstruct_getu32(t
, &mode
) < 0 ||
3910 pa_tagstruct_get_proplist(t
, p
) < 0 ||
3911 !pa_tagstruct_eof(t
)) {
3913 pa_proplist_free(p
);
3918 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
3919 pa_proplist_free(p
);
3920 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
3923 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
3926 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3927 if (!s
|| !playback_stream_isinstance(s
)) {
3928 pa_proplist_free(p
);
3929 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
3931 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
3933 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
3936 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
3937 pa_proplist_free(p
);
3938 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
3940 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
3943 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
3945 pa_client_update_proplist(c
->client
, mode
, p
);
3948 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3949 pa_proplist_free(p
);
3952 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3953 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3955 unsigned changed
= 0;
3957 pa_strlist
*l
= NULL
;
3959 pa_native_connection_assert_ref(c
);
3962 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3964 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
3966 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
3972 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
3975 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3976 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3977 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3979 p
= s
->sink_input
->proplist
;
3981 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
3984 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3985 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3987 p
= s
->source_output
->proplist
;
3989 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
3991 p
= c
->client
->proplist
;
3997 if (pa_tagstruct_gets(t
, &k
) < 0) {
4006 l
= pa_strlist_prepend(l
, k
);
4009 if (!pa_tagstruct_eof(t
)) {
4018 l
= pa_strlist_pop(l
, &z
);
4023 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
4027 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4030 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4033 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4034 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
4036 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4039 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4040 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
4043 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4044 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
4049 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4050 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4053 pa_native_connection_assert_ref(c
);
4056 if (pa_tagstruct_gets(t
, &s
) < 0 ||
4057 !pa_tagstruct_eof(t
)) {
4062 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4063 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
4065 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
4068 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
4069 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4071 pa_namereg_set_default_source(c
->protocol
->core
, source
);
4074 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
4076 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
4077 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4079 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
4082 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4085 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4086 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4090 pa_native_connection_assert_ref(c
);
4093 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4094 pa_tagstruct_gets(t
, &name
) < 0 ||
4095 !pa_tagstruct_eof(t
)) {
4100 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4101 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4103 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
4106 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4107 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4108 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4110 pa_sink_input_set_name(s
->sink_input
, name
);
4114 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4116 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4117 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4119 pa_source_output_set_name(s
->source_output
, name
);
4122 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4125 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4126 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4129 pa_native_connection_assert_ref(c
);
4132 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4133 !pa_tagstruct_eof(t
)) {
4138 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4140 if (command
== PA_COMMAND_KILL_CLIENT
) {
4143 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4144 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4146 pa_native_connection_ref(c
);
4147 pa_client_kill(client
);
4149 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4152 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4153 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4155 pa_native_connection_ref(c
);
4156 pa_sink_input_kill(s
);
4158 pa_source_output
*s
;
4160 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4162 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4163 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4165 pa_native_connection_ref(c
);
4166 pa_source_output_kill(s
);
4169 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4170 pa_native_connection_unref(c
);
4173 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4174 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4176 const char *name
, *argument
;
4177 pa_tagstruct
*reply
;
4179 pa_native_connection_assert_ref(c
);
4182 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4183 pa_tagstruct_gets(t
, &argument
) < 0 ||
4184 !pa_tagstruct_eof(t
)) {
4189 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4190 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4191 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4193 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4194 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4198 reply
= reply_new(tag
);
4199 pa_tagstruct_putu32(reply
, m
->index
);
4200 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4203 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4204 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4208 pa_native_connection_assert_ref(c
);
4211 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4212 !pa_tagstruct_eof(t
)) {
4217 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4218 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4219 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4221 pa_module_unload_request(m
, FALSE
);
4222 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4225 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4226 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4227 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4228 const char *name_device
= NULL
;
4230 pa_native_connection_assert_ref(c
);
4233 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4234 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4235 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4236 !pa_tagstruct_eof(t
)) {
4241 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4242 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4244 CHECK_VALIDITY(c
->pstream
, !name_device
|| pa_namereg_is_valid_name_or_wildcard(name_device
, command
== PA_COMMAND_MOVE_SINK_INPUT
? PA_NAMEREG_SINK
: PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
);
4245 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4246 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4247 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4249 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4250 pa_sink_input
*si
= NULL
;
4251 pa_sink
*sink
= NULL
;
4253 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4255 if (idx_device
!= PA_INVALID_INDEX
)
4256 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4258 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4260 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4262 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4263 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4267 pa_source_output
*so
= NULL
;
4270 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4272 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4274 if (idx_device
!= PA_INVALID_INDEX
)
4275 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4277 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4279 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4281 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4282 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4287 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4290 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4291 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4292 uint32_t idx
= PA_INVALID_INDEX
;
4293 const char *name
= NULL
;
4296 pa_native_connection_assert_ref(c
);
4299 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4300 pa_tagstruct_gets(t
, &name
) < 0 ||
4301 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4302 !pa_tagstruct_eof(t
)) {
4307 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4308 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name_or_wildcard(name
, command
== PA_COMMAND_SUSPEND_SINK
? PA_NAMEREG_SINK
: PA_NAMEREG_SOURCE
) || *name
== 0, tag
, PA_ERR_INVALID
);
4309 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4310 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4311 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4313 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4315 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4317 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4319 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4320 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4324 pa_sink
*sink
= NULL
;
4326 if (idx
!= PA_INVALID_INDEX
)
4327 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4329 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4331 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4333 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4334 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4340 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4342 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4344 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4346 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4347 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4354 if (idx
!= PA_INVALID_INDEX
)
4355 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4357 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4359 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4361 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4362 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4368 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4371 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4372 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4373 uint32_t idx
= PA_INVALID_INDEX
;
4374 const char *name
= NULL
;
4376 pa_native_protocol_ext_cb_t cb
;
4378 pa_native_connection_assert_ref(c
);
4381 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4382 pa_tagstruct_gets(t
, &name
) < 0) {
4387 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4388 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4389 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4390 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4391 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4393 if (idx
!= PA_INVALID_INDEX
)
4394 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4396 for (m
= pa_idxset_first(c
->protocol
->core
->modules
, &idx
); m
; m
= pa_idxset_next(c
->protocol
->core
->modules
, &idx
))
4397 if (strcmp(name
, m
->name
) == 0)
4401 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4402 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4404 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4405 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4407 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4411 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4412 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4413 uint32_t idx
= PA_INVALID_INDEX
;
4414 const char *name
= NULL
, *profile
= NULL
;
4415 pa_card
*card
= NULL
;
4418 pa_native_connection_assert_ref(c
);
4421 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4422 pa_tagstruct_gets(t
, &name
) < 0 ||
4423 pa_tagstruct_gets(t
, &profile
) < 0 ||
4424 !pa_tagstruct_eof(t
)) {
4429 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4430 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4431 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4432 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4433 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4435 if (idx
!= PA_INVALID_INDEX
)
4436 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4438 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4440 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4442 if ((ret
= pa_card_set_profile(card
, profile
, TRUE
)) < 0) {
4443 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4447 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4450 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4451 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4452 uint32_t idx
= PA_INVALID_INDEX
;
4453 const char *name
= NULL
, *port
= NULL
;
4456 pa_native_connection_assert_ref(c
);
4459 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4460 pa_tagstruct_gets(t
, &name
) < 0 ||
4461 pa_tagstruct_gets(t
, &port
) < 0 ||
4462 !pa_tagstruct_eof(t
)) {
4467 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4468 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name_or_wildcard(name
, command
== PA_COMMAND_SET_SINK_PORT
? PA_NAMEREG_SINK
: PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
);
4469 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4470 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4471 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4473 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4476 if (idx
!= PA_INVALID_INDEX
)
4477 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4479 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4481 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4483 if ((ret
= pa_sink_set_port(sink
, port
, TRUE
)) < 0) {
4484 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4490 pa_assert(command
= PA_COMMAND_SET_SOURCE_PORT
);
4492 if (idx
!= PA_INVALID_INDEX
)
4493 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4495 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4497 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4499 if ((ret
= pa_source_set_port(source
, port
, TRUE
)) < 0) {
4500 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4505 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4508 /*** pstream callbacks ***/
4510 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4511 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4515 pa_native_connection_assert_ref(c
);
4517 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4518 pa_log("invalid packet.");
4519 native_connection_unlink(c
);
4523 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
) {
4524 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4525 output_stream
*stream
;
4529 pa_native_connection_assert_ref(c
);
4531 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4532 pa_log_debug("Client sent block for invalid stream.");
4537 /* pa_log("got %lu bytes", (unsigned long) chunk->length); */
4539 if (playback_stream_isinstance(stream
)) {
4540 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4542 pa_atomic_inc(&ps
->seek_or_post_in_queue
);
4543 if (chunk
->memblock
) {
4544 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4545 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_SEEK
, PA_UINT_TO_PTR(seek
), offset
, chunk
, NULL
);
4547 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4549 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
);
4552 upload_stream
*u
= UPLOAD_STREAM(stream
);
4555 if (!u
->memchunk
.memblock
) {
4556 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4557 u
->memchunk
= *chunk
;
4558 pa_memblock_ref(u
->memchunk
.memblock
);
4561 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4562 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4566 pa_assert(u
->memchunk
.memblock
);
4569 if (l
> chunk
->length
)
4574 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4576 if (chunk
->memblock
) {
4578 src
= pa_memblock_acquire(chunk
->memblock
);
4580 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4581 (uint8_t*) src
+ chunk
->index
, l
);
4583 pa_memblock_release(chunk
->memblock
);
4585 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4587 pa_memblock_release(u
->memchunk
.memblock
);
4589 u
->memchunk
.length
+= l
;
4595 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4596 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4599 pa_native_connection_assert_ref(c
);
4601 native_connection_unlink(c
);
4602 pa_log_info("Connection died.");
4605 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4606 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4609 pa_native_connection_assert_ref(c
);
4611 native_connection_send_memblock(c
);
4614 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4617 if (!(q
= pa_thread_mq_get()))
4618 pa_pstream_send_revoke(p
, block_id
);
4620 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4623 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4626 if (!(q
= pa_thread_mq_get()))
4627 pa_pstream_send_release(p
, block_id
);
4629 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4632 /*** client callbacks ***/
4634 static void client_kill_cb(pa_client
*c
) {
4637 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4638 pa_log_info("Connection killed.");
4641 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4643 pa_native_connection
*c
;
4646 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4647 pa_native_connection_assert_ref(c
);
4649 if (c
->version
< 15)
4652 t
= pa_tagstruct_new(NULL
, 0);
4653 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4654 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4655 pa_tagstruct_puts(t
, event
);
4656 pa_tagstruct_put_proplist(t
, pl
);
4657 pa_pstream_send_tagstruct(c
->pstream
, t
);
4660 /*** module entry points ***/
4662 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4663 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4666 pa_native_connection_assert_ref(c
);
4667 pa_assert(c
->auth_timeout_event
== e
);
4669 if (!c
->authorized
) {
4670 native_connection_unlink(c
);
4671 pa_log_info("Connection terminated due to authentication timeout.");
4675 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4676 pa_native_connection
*c
;
4679 pa_client_new_data data
;
4685 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4686 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4687 pa_iochannel_free(io
);
4691 pa_client_new_data_init(&data
);
4692 data
.module
= o
->module
;
4693 data
.driver
= __FILE__
;
4694 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4695 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4696 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4697 client
= pa_client_new(p
->core
, &data
);
4698 pa_client_new_data_done(&data
);
4703 c
= pa_msgobject_new(pa_native_connection
);
4704 c
->parent
.parent
.free
= native_connection_free
;
4705 c
->parent
.process_msg
= native_connection_process_msg
;
4707 c
->options
= pa_native_options_ref(o
);
4708 c
->authorized
= FALSE
;
4710 if (o
->auth_anonymous
) {
4711 pa_log_info("Client authenticated anonymously.");
4712 c
->authorized
= TRUE
;
4715 if (!c
->authorized
&&
4717 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
4719 pa_log_info("Client authenticated by IP ACL.");
4720 c
->authorized
= TRUE
;
4724 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
4726 c
->auth_timeout_event
= NULL
;
4728 c
->is_local
= pa_iochannel_socket_is_local(io
);
4732 c
->client
->kill
= client_kill_cb
;
4733 c
->client
->send_event
= client_send_event_cb
;
4734 c
->client
->userdata
= c
;
4736 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
4737 pa_pstream_set_recieve_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
4738 pa_pstream_set_recieve_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
4739 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
4740 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
4741 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
4742 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
4744 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, TRUE
, command_table
, PA_COMMAND_MAX
);
4746 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
4747 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
4749 c
->rrobin_index
= PA_IDXSET_INVALID
;
4750 c
->subscription
= NULL
;
4752 pa_idxset_put(p
->connections
, c
, NULL
);
4755 if (pa_iochannel_creds_supported(io
))
4756 pa_iochannel_creds_enable(io
);
4759 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
4762 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
4763 pa_native_connection
*c
;
4769 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
4770 if (c
->options
->module
== m
)
4771 native_connection_unlink(c
);
4774 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
4775 pa_native_protocol
*p
;
4780 p
= pa_xnew(pa_native_protocol
, 1);
4783 p
->connections
= pa_idxset_new(NULL
, NULL
);
4787 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
4789 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4790 pa_hook_init(&p
->hooks
[h
], p
);
4792 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
4797 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
4798 pa_native_protocol
*p
;
4800 if ((p
= pa_shared_get(c
, "native-protocol")))
4801 return pa_native_protocol_ref(p
);
4803 return native_protocol_new(c
);
4806 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
4808 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4815 void pa_native_protocol_unref(pa_native_protocol
*p
) {
4816 pa_native_connection
*c
;
4820 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4822 if (PA_REFCNT_DEC(p
) > 0)
4825 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
4826 native_connection_unlink(c
);
4828 pa_idxset_free(p
->connections
, NULL
, NULL
);
4830 pa_strlist_free(p
->servers
);
4832 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
4833 pa_hook_done(&p
->hooks
[h
]);
4835 pa_hashmap_free(p
->extensions
, NULL
, NULL
);
4837 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
4842 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
4844 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4847 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
4849 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
4852 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
4854 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4857 p
->servers
= pa_strlist_remove(p
->servers
, name
);
4859 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
4862 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
4864 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4869 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
4871 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4876 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
4878 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4881 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
4883 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
4887 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
4889 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
4892 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
4895 pa_native_options
* pa_native_options_new(void) {
4896 pa_native_options
*o
;
4898 o
= pa_xnew0(pa_native_options
, 1);
4904 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
4906 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4913 void pa_native_options_unref(pa_native_options
*o
) {
4915 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4917 if (PA_REFCNT_DEC(o
) > 0)
4920 pa_xfree(o
->auth_group
);
4923 pa_ip_acl_free(o
->auth_ip_acl
);
4926 pa_auth_cookie_unref(o
->auth_cookie
);
4931 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
4936 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
4939 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
4940 pa_log("auth-anonymous= expects a boolean argument.");
4945 if (pa_modargs_get_value_boolean(ma
, "auth-group-enabled", &enabled
) < 0) {
4946 pa_log("auth-group-enabled= expects a boolean argument.");
4950 pa_xfree(o
->auth_group
);
4951 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
4955 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
4958 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
4961 if (!(ipa
= pa_ip_acl_new(acl
))) {
4962 pa_log("Failed to parse IP ACL '%s'", acl
);
4967 pa_ip_acl_free(o
->auth_ip_acl
);
4969 o
->auth_ip_acl
= ipa
;
4973 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
4974 pa_log("auth-cookie-enabled= expects a boolean argument.");
4979 pa_auth_cookie_unref(o
->auth_cookie
);
4984 /* The new name for this is 'auth-cookie', for compat reasons
4985 * we check the old name too */
4986 if (!(cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
)))
4987 if (!(cn
= pa_modargs_get_value(ma
, "cookie", NULL
)))
4988 cn
= PA_NATIVE_COOKIE_FILE
;
4990 if (!(o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, PA_NATIVE_COOKIE_LENGTH
)))
4994 o
->auth_cookie
= NULL
;
4999 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
5000 pa_native_connection_assert_ref(c
);
5005 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
5006 pa_native_connection_assert_ref(c
);