2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
32 #include <pulse/rtclock.h>
33 #include <pulse/timeval.h>
34 #include <pulse/version.h>
35 #include <pulse/utf8.h>
36 #include <pulse/util.h>
37 #include <pulse/xmalloc.h>
38 #include <pulse/internal.h>
40 #include <pulsecore/native-common.h>
41 #include <pulsecore/packet.h>
42 #include <pulsecore/client.h>
43 #include <pulsecore/source-output.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/pstream.h>
46 #include <pulsecore/tagstruct.h>
47 #include <pulsecore/pdispatch.h>
48 #include <pulsecore/pstream-util.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/core-subscribe.h>
52 #include <pulsecore/log.h>
53 #include <pulsecore/strlist.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/sample-util.h>
56 #include <pulsecore/creds.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/ipacl.h>
59 #include <pulsecore/thread-mq.h>
61 #include "protocol-native.h"
63 /* #define PROTOCOL_NATIVE_DEBUG */
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 /* Requested buffer attributes */
91 pa_buffer_attr buffer_attr_req
;
92 /* Fixed-up and adjusted buffer attributes */
93 pa_buffer_attr buffer_attr
;
95 pa_atomic_t on_the_fly
;
96 pa_usec_t configured_source_latency
;
99 /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
100 size_t on_the_fly_snapshot
;
101 pa_usec_t current_monitor_latency
;
102 pa_usec_t current_source_latency
;
105 #define RECORD_STREAM(o) (record_stream_cast(o))
106 PA_DEFINE_PRIVATE_CLASS(record_stream
, pa_msgobject
);
108 typedef struct output_stream
{
112 #define OUTPUT_STREAM(o) (output_stream_cast(o))
113 PA_DEFINE_PRIVATE_CLASS(output_stream
, pa_msgobject
);
115 typedef struct playback_stream
{
116 output_stream parent
;
118 pa_native_connection
*connection
;
121 pa_sink_input
*sink_input
;
122 pa_memblockq
*memblockq
;
124 pa_bool_t adjust_latency
:1;
125 pa_bool_t early_requests
:1;
127 pa_bool_t is_underrun
:1;
128 pa_bool_t drain_request
:1;
132 /* Optimization to avoid too many rewinds with a lot of small blocks */
133 pa_atomic_t seek_or_post_in_queue
;
137 pa_usec_t configured_sink_latency
;
138 /* Requested buffer attributes */
139 pa_buffer_attr buffer_attr_req
;
140 /* Fixed-up and adjusted buffer attributes */
141 pa_buffer_attr buffer_attr
;
143 /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
144 int64_t read_index
, write_index
;
145 size_t render_memblockq_length
;
146 pa_usec_t current_sink_latency
;
147 uint64_t playing_for
, underrun_for
;
150 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
151 PA_DEFINE_PRIVATE_CLASS(playback_stream
, output_stream
);
153 typedef struct upload_stream
{
154 output_stream parent
;
156 pa_native_connection
*connection
;
159 pa_memchunk memchunk
;
162 pa_sample_spec sample_spec
;
163 pa_channel_map channel_map
;
164 pa_proplist
*proplist
;
167 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
168 PA_DEFINE_PRIVATE_CLASS(upload_stream
, output_stream
);
170 struct pa_native_connection
{
172 pa_native_protocol
*protocol
;
173 pa_native_options
*options
;
174 pa_bool_t authorized
:1;
175 pa_bool_t is_local
:1;
179 pa_pdispatch
*pdispatch
;
180 pa_idxset
*record_streams
, *output_streams
;
181 uint32_t rrobin_index
;
182 pa_subscription
*subscription
;
183 pa_time_event
*auth_timeout_event
;
186 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
187 PA_DEFINE_PRIVATE_CLASS(pa_native_connection
, pa_msgobject
);
189 struct pa_native_protocol
{
193 pa_idxset
*connections
;
196 pa_hook hooks
[PA_NATIVE_HOOK_MAX
];
198 pa_hashmap
*extensions
;
202 SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
= PA_SOURCE_OUTPUT_MESSAGE_MAX
206 SINK_INPUT_MESSAGE_POST_DATA
= PA_SINK_INPUT_MESSAGE_MAX
, /* data from main loop to sink input */
207 SINK_INPUT_MESSAGE_DRAIN
, /* disabled prebuf, get playback started. */
208 SINK_INPUT_MESSAGE_FLUSH
,
209 SINK_INPUT_MESSAGE_TRIGGER
,
210 SINK_INPUT_MESSAGE_SEEK
,
211 SINK_INPUT_MESSAGE_PREBUF_FORCE
,
212 SINK_INPUT_MESSAGE_UPDATE_LATENCY
,
213 SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
217 PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, /* data requested from sink input from the main loop */
218 PLAYBACK_STREAM_MESSAGE_UNDERFLOW
,
219 PLAYBACK_STREAM_MESSAGE_OVERFLOW
,
220 PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
,
221 PLAYBACK_STREAM_MESSAGE_STARTED
,
222 PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
226 RECORD_STREAM_MESSAGE_POST_DATA
/* data from source output to main loop */
230 CONNECTION_MESSAGE_RELEASE
,
231 CONNECTION_MESSAGE_REVOKE
234 static bool sink_input_process_underrun_cb(pa_sink_input
*i
);
235 static int sink_input_pop_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
);
236 static void sink_input_kill_cb(pa_sink_input
*i
);
237 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
);
238 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
);
239 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
240 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
);
241 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
);
242 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
);
244 static void native_connection_send_memblock(pa_native_connection
*c
);
245 static void playback_stream_request_bytes(struct playback_stream
*s
);
247 static void source_output_kill_cb(pa_source_output
*o
);
248 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
);
249 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
);
250 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
);
251 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
);
252 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
);
254 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
255 static int source_output_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
);
257 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
258 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
259 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
260 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
261 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
262 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
263 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
264 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
265 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
266 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
267 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
268 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
269 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
270 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
271 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
272 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
273 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
274 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
275 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
276 static void command_set_volume(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
277 static void command_set_mute(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
278 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
279 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
280 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
281 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
282 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
283 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
284 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
285 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
286 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
287 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
288 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
289 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
290 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
291 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
292 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
293 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
294 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
295 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
296 static void command_set_port_latency_offset(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
);
298 static const pa_pdispatch_cb_t command_table
[PA_COMMAND_MAX
] = {
299 [PA_COMMAND_ERROR
] = NULL
,
300 [PA_COMMAND_TIMEOUT
] = NULL
,
301 [PA_COMMAND_REPLY
] = NULL
,
302 [PA_COMMAND_CREATE_PLAYBACK_STREAM
] = command_create_playback_stream
,
303 [PA_COMMAND_DELETE_PLAYBACK_STREAM
] = command_delete_stream
,
304 [PA_COMMAND_DRAIN_PLAYBACK_STREAM
] = command_drain_playback_stream
,
305 [PA_COMMAND_CREATE_RECORD_STREAM
] = command_create_record_stream
,
306 [PA_COMMAND_DELETE_RECORD_STREAM
] = command_delete_stream
,
307 [PA_COMMAND_AUTH
] = command_auth
,
308 [PA_COMMAND_REQUEST
] = NULL
,
309 [PA_COMMAND_EXIT
] = command_exit
,
310 [PA_COMMAND_SET_CLIENT_NAME
] = command_set_client_name
,
311 [PA_COMMAND_LOOKUP_SINK
] = command_lookup
,
312 [PA_COMMAND_LOOKUP_SOURCE
] = command_lookup
,
313 [PA_COMMAND_STAT
] = command_stat
,
314 [PA_COMMAND_GET_PLAYBACK_LATENCY
] = command_get_playback_latency
,
315 [PA_COMMAND_GET_RECORD_LATENCY
] = command_get_record_latency
,
316 [PA_COMMAND_CREATE_UPLOAD_STREAM
] = command_create_upload_stream
,
317 [PA_COMMAND_DELETE_UPLOAD_STREAM
] = command_delete_stream
,
318 [PA_COMMAND_FINISH_UPLOAD_STREAM
] = command_finish_upload_stream
,
319 [PA_COMMAND_PLAY_SAMPLE
] = command_play_sample
,
320 [PA_COMMAND_REMOVE_SAMPLE
] = command_remove_sample
,
321 [PA_COMMAND_GET_SINK_INFO
] = command_get_info
,
322 [PA_COMMAND_GET_SOURCE_INFO
] = command_get_info
,
323 [PA_COMMAND_GET_CLIENT_INFO
] = command_get_info
,
324 [PA_COMMAND_GET_CARD_INFO
] = command_get_info
,
325 [PA_COMMAND_GET_MODULE_INFO
] = command_get_info
,
326 [PA_COMMAND_GET_SINK_INPUT_INFO
] = command_get_info
,
327 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO
] = command_get_info
,
328 [PA_COMMAND_GET_SAMPLE_INFO
] = command_get_info
,
329 [PA_COMMAND_GET_SINK_INFO_LIST
] = command_get_info_list
,
330 [PA_COMMAND_GET_SOURCE_INFO_LIST
] = command_get_info_list
,
331 [PA_COMMAND_GET_MODULE_INFO_LIST
] = command_get_info_list
,
332 [PA_COMMAND_GET_CLIENT_INFO_LIST
] = command_get_info_list
,
333 [PA_COMMAND_GET_CARD_INFO_LIST
] = command_get_info_list
,
334 [PA_COMMAND_GET_SINK_INPUT_INFO_LIST
] = command_get_info_list
,
335 [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
] = command_get_info_list
,
336 [PA_COMMAND_GET_SAMPLE_INFO_LIST
] = command_get_info_list
,
337 [PA_COMMAND_GET_SERVER_INFO
] = command_get_server_info
,
338 [PA_COMMAND_SUBSCRIBE
] = command_subscribe
,
340 [PA_COMMAND_SET_SINK_VOLUME
] = command_set_volume
,
341 [PA_COMMAND_SET_SINK_INPUT_VOLUME
] = command_set_volume
,
342 [PA_COMMAND_SET_SOURCE_VOLUME
] = command_set_volume
,
343 [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
] = command_set_volume
,
345 [PA_COMMAND_SET_SINK_MUTE
] = command_set_mute
,
346 [PA_COMMAND_SET_SINK_INPUT_MUTE
] = command_set_mute
,
347 [PA_COMMAND_SET_SOURCE_MUTE
] = command_set_mute
,
348 [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
] = command_set_mute
,
350 [PA_COMMAND_SUSPEND_SINK
] = command_suspend
,
351 [PA_COMMAND_SUSPEND_SOURCE
] = command_suspend
,
353 [PA_COMMAND_CORK_PLAYBACK_STREAM
] = command_cork_playback_stream
,
354 [PA_COMMAND_FLUSH_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
355 [PA_COMMAND_TRIGGER_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
356 [PA_COMMAND_PREBUF_PLAYBACK_STREAM
] = command_trigger_or_flush_or_prebuf_playback_stream
,
358 [PA_COMMAND_CORK_RECORD_STREAM
] = command_cork_record_stream
,
359 [PA_COMMAND_FLUSH_RECORD_STREAM
] = command_flush_record_stream
,
361 [PA_COMMAND_SET_DEFAULT_SINK
] = command_set_default_sink_or_source
,
362 [PA_COMMAND_SET_DEFAULT_SOURCE
] = command_set_default_sink_or_source
,
363 [PA_COMMAND_SET_PLAYBACK_STREAM_NAME
] = command_set_stream_name
,
364 [PA_COMMAND_SET_RECORD_STREAM_NAME
] = command_set_stream_name
,
365 [PA_COMMAND_KILL_CLIENT
] = command_kill
,
366 [PA_COMMAND_KILL_SINK_INPUT
] = command_kill
,
367 [PA_COMMAND_KILL_SOURCE_OUTPUT
] = command_kill
,
368 [PA_COMMAND_LOAD_MODULE
] = command_load_module
,
369 [PA_COMMAND_UNLOAD_MODULE
] = command_unload_module
,
371 [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE
] = NULL
,
372 [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE
] = NULL
,
373 [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE
] = NULL
,
374 [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE
] = NULL
,
376 [PA_COMMAND_MOVE_SINK_INPUT
] = command_move_stream
,
377 [PA_COMMAND_MOVE_SOURCE_OUTPUT
] = command_move_stream
,
379 [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
380 [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
] = command_set_stream_buffer_attr
,
382 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
383 [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
] = command_update_stream_sample_rate
,
385 [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
] = command_update_proplist
,
386 [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
] = command_update_proplist
,
387 [PA_COMMAND_UPDATE_CLIENT_PROPLIST
] = command_update_proplist
,
389 [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
] = command_remove_proplist
,
390 [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
] = command_remove_proplist
,
391 [PA_COMMAND_REMOVE_CLIENT_PROPLIST
] = command_remove_proplist
,
393 [PA_COMMAND_SET_CARD_PROFILE
] = command_set_card_profile
,
395 [PA_COMMAND_SET_SINK_PORT
] = command_set_sink_or_source_port
,
396 [PA_COMMAND_SET_SOURCE_PORT
] = command_set_sink_or_source_port
,
398 [PA_COMMAND_SET_PORT_LATENCY_OFFSET
] = command_set_port_latency_offset
,
400 [PA_COMMAND_EXTENSION
] = command_extension
403 /* structure management */
405 /* Called from main context */
406 static void upload_stream_unlink(upload_stream
*s
) {
412 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
413 s
->connection
= NULL
;
414 upload_stream_unref(s
);
417 /* Called from main context */
418 static void upload_stream_free(pa_object
*o
) {
419 upload_stream
*s
= UPLOAD_STREAM(o
);
422 upload_stream_unlink(s
);
427 pa_proplist_free(s
->proplist
);
429 if (s
->memchunk
.memblock
)
430 pa_memblock_unref(s
->memchunk
.memblock
);
435 /* Called from main context */
436 static upload_stream
* upload_stream_new(
437 pa_native_connection
*c
,
438 const pa_sample_spec
*ss
,
439 const pa_channel_map
*map
,
449 pa_assert(length
> 0);
452 s
= pa_msgobject_new(upload_stream
);
453 s
->parent
.parent
.parent
.free
= upload_stream_free
;
455 s
->sample_spec
= *ss
;
456 s
->channel_map
= *map
;
457 s
->name
= pa_xstrdup(name
);
458 pa_memchunk_reset(&s
->memchunk
);
460 s
->proplist
= pa_proplist_copy(p
);
461 pa_proplist_update(s
->proplist
, PA_UPDATE_MERGE
, c
->client
->proplist
);
463 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
468 /* Called from main context */
469 static void record_stream_unlink(record_stream
*s
) {
475 if (s
->source_output
) {
476 pa_source_output_unlink(s
->source_output
);
477 pa_source_output_unref(s
->source_output
);
478 s
->source_output
= NULL
;
481 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->record_streams
, s
, NULL
) == s
);
482 s
->connection
= NULL
;
483 record_stream_unref(s
);
486 /* Called from main context */
487 static void record_stream_free(pa_object
*o
) {
488 record_stream
*s
= RECORD_STREAM(o
);
491 record_stream_unlink(s
);
493 pa_memblockq_free(s
->memblockq
);
497 /* Called from main context */
498 static int record_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
499 record_stream
*s
= RECORD_STREAM(o
);
500 record_stream_assert_ref(s
);
507 case RECORD_STREAM_MESSAGE_POST_DATA
:
509 /* We try to keep up to date with how many bytes are
510 * currently on the fly */
511 pa_atomic_sub(&s
->on_the_fly
, chunk
->length
);
513 if (pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
514 /* pa_log_warn("Failed to push data into output queue."); */
518 if (!pa_pstream_is_pending(s
->connection
->pstream
))
519 native_connection_send_memblock(s
->connection
);
527 /* Called from main context */
528 static void fix_record_buffer_attr_pre(record_stream
*s
) {
531 pa_usec_t orig_fragsize_usec
, fragsize_usec
, source_usec
;
535 /* This function will be called from the main thread, before as
536 * well as after the source output has been activated using
537 * pa_source_output_put()! That means it may not touch any
538 * ->thread_info data! */
540 frame_size
= pa_frame_size(&s
->source_output
->sample_spec
);
541 s
->buffer_attr
= s
->buffer_attr_req
;
543 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
544 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
545 if (s
->buffer_attr
.maxlength
<= 0)
546 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
548 if (s
->buffer_attr
.fragsize
== (uint32_t) -1)
549 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC
*PA_USEC_PER_MSEC
, &s
->source_output
->sample_spec
);
550 if (s
->buffer_attr
.fragsize
<= 0)
551 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
553 orig_fragsize_usec
= fragsize_usec
= pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &s
->source_output
->sample_spec
);
555 if (s
->early_requests
) {
557 /* In early request mode we need to emulate the classic
558 * fragment-based playback model. We do this setting the source
559 * latency to the fragment size. */
561 source_usec
= fragsize_usec
;
563 } else if (s
->adjust_latency
) {
565 /* So, the user asked us to adjust the latency according to
566 * what the source can provide. Half the latency will be
567 * spent on the hw buffer, half of it in the async buffer
568 * queue we maintain for each client. */
570 source_usec
= fragsize_usec
/2;
574 /* Ok, the user didn't ask us to adjust the latency, hence we
577 source_usec
= (pa_usec_t
) -1;
580 if (source_usec
!= (pa_usec_t
) -1)
581 s
->configured_source_latency
= pa_source_output_set_requested_latency(s
->source_output
, source_usec
);
583 s
->configured_source_latency
= 0;
585 if (s
->early_requests
) {
587 /* Ok, we didn't necessarily get what we were asking for, so
588 * let's tell the user */
590 fragsize_usec
= s
->configured_source_latency
;
592 } else if (s
->adjust_latency
) {
594 /* Now subtract what we actually got */
596 if (fragsize_usec
>= s
->configured_source_latency
*2)
597 fragsize_usec
-= s
->configured_source_latency
;
599 fragsize_usec
= s
->configured_source_latency
;
602 if (pa_usec_to_bytes(orig_fragsize_usec
, &s
->source_output
->sample_spec
) !=
603 pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
))
605 s
->buffer_attr
.fragsize
= (uint32_t) pa_usec_to_bytes(fragsize_usec
, &s
->source_output
->sample_spec
);
607 if (s
->buffer_attr
.fragsize
<= 0)
608 s
->buffer_attr
.fragsize
= (uint32_t) frame_size
;
611 /* Called from main context */
612 static void fix_record_buffer_attr_post(record_stream
*s
) {
617 /* This function will be called from the main thread, before as
618 * well as after the source output has been activated using
619 * pa_source_output_put()! That means it may not touch and
620 * ->thread_info data! */
622 base
= pa_frame_size(&s
->source_output
->sample_spec
);
624 s
->buffer_attr
.fragsize
= (s
->buffer_attr
.fragsize
/base
)*base
;
625 if (s
->buffer_attr
.fragsize
<= 0)
626 s
->buffer_attr
.fragsize
= base
;
628 if (s
->buffer_attr
.fragsize
> s
->buffer_attr
.maxlength
)
629 s
->buffer_attr
.fragsize
= s
->buffer_attr
.maxlength
;
632 /* Called from main context */
633 static record_stream
* record_stream_new(
634 pa_native_connection
*c
,
639 pa_buffer_attr
*attr
,
643 pa_source_output_flags_t flags
,
645 pa_bool_t adjust_latency
,
646 pa_bool_t early_requests
,
647 pa_bool_t relative_volume
,
648 pa_bool_t peak_detect
,
649 pa_sink_input
*direct_on_input
,
653 pa_source_output
*source_output
= NULL
;
654 pa_source_output_new_data data
;
655 char *memblockq_name
;
662 pa_source_output_new_data_init(&data
);
664 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
665 data
.driver
= __FILE__
;
666 data
.module
= c
->options
->module
;
667 data
.client
= c
->client
;
669 pa_source_output_new_data_set_source(&data
, source
, FALSE
);
670 if (pa_sample_spec_valid(ss
))
671 pa_source_output_new_data_set_sample_spec(&data
, ss
);
672 if (pa_channel_map_valid(map
))
673 pa_source_output_new_data_set_channel_map(&data
, map
);
675 pa_source_output_new_data_set_formats(&data
, formats
);
676 data
.direct_on_input
= direct_on_input
;
678 pa_source_output_new_data_set_volume(&data
, volume
);
679 data
.volume_is_absolute
= !relative_volume
;
680 data
.save_volume
= FALSE
;
683 pa_source_output_new_data_set_muted(&data
, muted
);
684 data
.save_muted
= FALSE
;
687 data
.resample_method
= PA_RESAMPLER_PEAKS
;
690 *ret
= -pa_source_output_new(&source_output
, c
->protocol
->core
, &data
);
692 pa_source_output_new_data_done(&data
);
697 s
= pa_msgobject_new(record_stream
);
698 s
->parent
.parent
.free
= record_stream_free
;
699 s
->parent
.process_msg
= record_stream_process_msg
;
701 s
->source_output
= source_output
;
702 s
->buffer_attr_req
= *attr
;
703 s
->adjust_latency
= adjust_latency
;
704 s
->early_requests
= early_requests
;
705 pa_atomic_store(&s
->on_the_fly
, 0);
707 s
->source_output
->parent
.process_msg
= source_output_process_msg
;
708 s
->source_output
->push
= source_output_push_cb
;
709 s
->source_output
->kill
= source_output_kill_cb
;
710 s
->source_output
->get_latency
= source_output_get_latency_cb
;
711 s
->source_output
->moving
= source_output_moving_cb
;
712 s
->source_output
->suspend
= source_output_suspend_cb
;
713 s
->source_output
->send_event
= source_output_send_event_cb
;
714 s
->source_output
->userdata
= s
;
716 fix_record_buffer_attr_pre(s
);
718 memblockq_name
= pa_sprintf_malloc("native protocol record stream memblockq [%u]", s
->source_output
->index
);
719 s
->memblockq
= pa_memblockq_new(
722 s
->buffer_attr
.maxlength
,
724 &source_output
->sample_spec
,
729 pa_xfree(memblockq_name
);
731 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
732 fix_record_buffer_attr_post(s
);
734 *ss
= s
->source_output
->sample_spec
;
735 *map
= s
->source_output
->channel_map
;
737 pa_idxset_put(c
->record_streams
, s
, &s
->index
);
739 pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
740 ((double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) + (double) s
->configured_source_latency
) / PA_USEC_PER_MSEC
,
741 (double) pa_bytes_to_usec(s
->buffer_attr
.fragsize
, &source_output
->sample_spec
) / PA_USEC_PER_MSEC
,
742 (double) s
->configured_source_latency
/ PA_USEC_PER_MSEC
);
744 pa_source_output_put(s
->source_output
);
748 /* Called from main context */
749 static void record_stream_send_killed(record_stream
*r
) {
751 record_stream_assert_ref(r
);
753 t
= pa_tagstruct_new(NULL
, 0);
754 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_KILLED
);
755 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
756 pa_tagstruct_putu32(t
, r
->index
);
757 pa_pstream_send_tagstruct(r
->connection
->pstream
, t
);
760 /* Called from main context */
761 static void playback_stream_unlink(playback_stream
*s
) {
768 pa_sink_input_unlink(s
->sink_input
);
769 pa_sink_input_unref(s
->sink_input
);
770 s
->sink_input
= NULL
;
773 if (s
->drain_request
)
774 pa_pstream_send_error(s
->connection
->pstream
, s
->drain_tag
, PA_ERR_NOENTITY
);
776 pa_assert_se(pa_idxset_remove_by_data(s
->connection
->output_streams
, s
, NULL
) == s
);
777 s
->connection
= NULL
;
778 playback_stream_unref(s
);
781 /* Called from main context */
782 static void playback_stream_free(pa_object
* o
) {
783 playback_stream
*s
= PLAYBACK_STREAM(o
);
786 playback_stream_unlink(s
);
788 pa_memblockq_free(s
->memblockq
);
792 /* Called from main context */
793 static int playback_stream_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
794 playback_stream
*s
= PLAYBACK_STREAM(o
);
795 playback_stream_assert_ref(s
);
802 case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
: {
807 if ((l
= pa_atomic_load(&s
->missing
)) <= 0)
810 if (pa_atomic_cmpxchg(&s
->missing
, l
, 0))
814 t
= pa_tagstruct_new(NULL
, 0);
815 pa_tagstruct_putu32(t
, PA_COMMAND_REQUEST
);
816 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
817 pa_tagstruct_putu32(t
, s
->index
);
818 pa_tagstruct_putu32(t
, (uint32_t) l
);
819 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
821 #ifdef PROTOCOL_NATIVE_DEBUG
822 pa_log("Requesting %lu bytes", (unsigned long) l
);
827 case PLAYBACK_STREAM_MESSAGE_UNDERFLOW
: {
830 #ifdef PROTOCOL_NATIVE_DEBUG
831 pa_log("signalling underflow");
834 /* Report that we're empty */
835 t
= pa_tagstruct_new(NULL
, 0);
836 pa_tagstruct_putu32(t
, PA_COMMAND_UNDERFLOW
);
837 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
838 pa_tagstruct_putu32(t
, s
->index
);
839 if (s
->connection
->version
>= 23)
840 pa_tagstruct_puts64(t
, offset
);
841 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
845 case PLAYBACK_STREAM_MESSAGE_OVERFLOW
: {
848 /* Notify the user we're overflowed*/
849 t
= pa_tagstruct_new(NULL
, 0);
850 pa_tagstruct_putu32(t
, PA_COMMAND_OVERFLOW
);
851 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
852 pa_tagstruct_putu32(t
, s
->index
);
853 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
857 case PLAYBACK_STREAM_MESSAGE_STARTED
:
859 if (s
->connection
->version
>= 13) {
862 /* Notify the user we started playback */
863 t
= pa_tagstruct_new(NULL
, 0);
864 pa_tagstruct_putu32(t
, PA_COMMAND_STARTED
);
865 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
866 pa_tagstruct_putu32(t
, s
->index
);
867 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
872 case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
:
873 pa_pstream_send_simple_ack(s
->connection
->pstream
, PA_PTR_TO_UINT(userdata
));
876 case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
:
878 s
->buffer_attr
.tlength
= (uint32_t) offset
;
880 if (s
->connection
->version
>= 15) {
883 t
= pa_tagstruct_new(NULL
, 0);
884 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
);
885 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
886 pa_tagstruct_putu32(t
, s
->index
);
887 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
888 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
889 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
890 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
891 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
892 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
901 /* Called from main context */
902 static void fix_playback_buffer_attr(playback_stream
*s
) {
903 size_t frame_size
, max_prebuf
;
904 pa_usec_t orig_tlength_usec
, tlength_usec
, orig_minreq_usec
, minreq_usec
, sink_usec
;
908 #ifdef PROTOCOL_NATIVE_DEBUG
909 pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes",
910 (long) s
->buffer_attr_req
.maxlength
,
911 (long) s
->buffer_attr_req
.tlength
,
912 (long) s
->buffer_attr_req
.minreq
,
913 (long) s
->buffer_attr_req
.prebuf
);
915 pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
916 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr_req
.maxlength
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
917 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr_req
.tlength
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
918 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr_req
.minreq
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
919 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr_req
.prebuf
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
));
922 /* This function will be called from the main thread, before as
923 * well as after the sink input has been activated using
924 * pa_sink_input_put()! That means it may not touch any
925 * ->thread_info data, such as the memblockq! */
927 frame_size
= pa_frame_size(&s
->sink_input
->sample_spec
);
928 s
->buffer_attr
= s
->buffer_attr_req
;
930 if (s
->buffer_attr
.maxlength
== (uint32_t) -1 || s
->buffer_attr
.maxlength
> MAX_MEMBLOCKQ_LENGTH
)
931 s
->buffer_attr
.maxlength
= MAX_MEMBLOCKQ_LENGTH
;
932 if (s
->buffer_attr
.maxlength
<= 0)
933 s
->buffer_attr
.maxlength
= (uint32_t) frame_size
;
935 if (s
->buffer_attr
.tlength
== (uint32_t) -1)
936 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
937 if (s
->buffer_attr
.tlength
<= 0)
938 s
->buffer_attr
.tlength
= (uint32_t) frame_size
;
939 if (s
->buffer_attr
.tlength
> s
->buffer_attr
.maxlength
)
940 s
->buffer_attr
.tlength
= s
->buffer_attr
.maxlength
;
942 if (s
->buffer_attr
.minreq
== (uint32_t) -1)
943 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC
*PA_USEC_PER_MSEC
, &s
->sink_input
->sample_spec
);
944 if (s
->buffer_attr
.minreq
<= 0)
945 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
947 if (s
->buffer_attr
.tlength
< s
->buffer_attr
.minreq
+frame_size
)
948 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
+(uint32_t) frame_size
;
950 orig_tlength_usec
= tlength_usec
= pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
);
951 orig_minreq_usec
= minreq_usec
= pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
);
953 pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
954 (double) tlength_usec
/ PA_USEC_PER_MSEC
,
955 (double) minreq_usec
/ PA_USEC_PER_MSEC
);
957 if (s
->early_requests
) {
959 /* In early request mode we need to emulate the classic
960 * fragment-based playback model. We do this setting the sink
961 * latency to the fragment size. */
963 sink_usec
= minreq_usec
;
964 pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
966 } else if (s
->adjust_latency
) {
968 /* So, the user asked us to adjust the latency of the stream
969 * buffer according to the what the sink can provide. The
970 * tlength passed in shall be the overall latency. Roughly
971 * half the latency will be spent on the hw buffer, the other
972 * half of it in the async buffer queue we maintain for each
973 * client. In between we'll have a safety space of size
974 * 2*minreq. Why the 2*minreq? When the hw buffer is completely
975 * empty and needs to be filled, then our buffer must have
976 * enough data to fulfill this request immediately and thus
977 * have at least the same tlength as the size of the hw
978 * buffer. It additionally needs space for 2 times minreq
979 * because if the buffer ran empty and a partial fillup
980 * happens immediately on the next iteration we need to be
981 * able to fulfill it and give the application also minreq
982 * time to fill it up again for the next request Makes 2 times
983 * minreq in plus.. */
985 if (tlength_usec
> minreq_usec
*2)
986 sink_usec
= (tlength_usec
- minreq_usec
*2)/2;
990 pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
994 /* Ok, the user didn't ask us to adjust the latency, but we
995 * still need to make sure that the parameters from the user
998 if (tlength_usec
> minreq_usec
*2)
999 sink_usec
= (tlength_usec
- minreq_usec
*2);
1003 pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
1006 s
->configured_sink_latency
= pa_sink_input_set_requested_latency(s
->sink_input
, sink_usec
);
1008 if (s
->early_requests
) {
1010 /* Ok, we didn't necessarily get what we were asking for, so
1011 * let's tell the user */
1013 minreq_usec
= s
->configured_sink_latency
;
1015 } else if (s
->adjust_latency
) {
1017 /* Ok, we didn't necessarily get what we were asking for, so
1018 * let's subtract from what we asked for for the remaining
1021 if (tlength_usec
>= s
->configured_sink_latency
)
1022 tlength_usec
-= s
->configured_sink_latency
;
1025 pa_log_debug("Requested latency=%0.2f ms, Received latency=%0.2f ms",
1026 (double) sink_usec
/ PA_USEC_PER_MSEC
,
1027 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1029 /* FIXME: This is actually larger than necessary, since not all of
1030 * the sink latency is actually rewritable. */
1031 if (tlength_usec
< s
->configured_sink_latency
+ 2*minreq_usec
)
1032 tlength_usec
= s
->configured_sink_latency
+ 2*minreq_usec
;
1034 if (pa_usec_to_bytes_round_up(orig_tlength_usec
, &s
->sink_input
->sample_spec
) !=
1035 pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
))
1036 s
->buffer_attr
.tlength
= (uint32_t) pa_usec_to_bytes_round_up(tlength_usec
, &s
->sink_input
->sample_spec
);
1038 if (pa_usec_to_bytes(orig_minreq_usec
, &s
->sink_input
->sample_spec
) !=
1039 pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
))
1040 s
->buffer_attr
.minreq
= (uint32_t) pa_usec_to_bytes(minreq_usec
, &s
->sink_input
->sample_spec
);
1042 if (s
->buffer_attr
.minreq
<= 0) {
1043 s
->buffer_attr
.minreq
= (uint32_t) frame_size
;
1044 s
->buffer_attr
.tlength
+= (uint32_t) frame_size
*2;
1047 if (s
->buffer_attr
.tlength
<= s
->buffer_attr
.minreq
)
1048 s
->buffer_attr
.tlength
= s
->buffer_attr
.minreq
*2 + (uint32_t) frame_size
;
1050 max_prebuf
= s
->buffer_attr
.tlength
+ (uint32_t)frame_size
- s
->buffer_attr
.minreq
;
1052 if (s
->buffer_attr
.prebuf
== (uint32_t) -1 ||
1053 s
->buffer_attr
.prebuf
> max_prebuf
)
1054 s
->buffer_attr
.prebuf
= max_prebuf
;
1056 #ifdef PROTOCOL_NATIVE_DEBUG
1057 pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
1058 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr
.maxlength
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
1059 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr
.tlength
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
1060 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr
.minreq
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
),
1061 (unsigned long) (pa_bytes_to_usec(s
->buffer_attr
.prebuf
, &s
->sink_input
->sample_spec
) / PA_USEC_PER_MSEC
));
1065 /* Called from main context */
1066 static playback_stream
* playback_stream_new(
1067 pa_native_connection
*c
,
1070 pa_channel_map
*map
,
1075 pa_bool_t muted_set
,
1076 pa_sink_input_flags_t flags
,
1078 pa_bool_t adjust_latency
,
1079 pa_bool_t early_requests
,
1080 pa_bool_t relative_volume
,
1085 /* Note: This function takes ownership of the 'formats' param, so we need
1086 * to take extra care to not leak it */
1088 playback_stream
*ssync
;
1089 playback_stream
*s
= NULL
;
1090 pa_sink_input
*sink_input
= NULL
;
1091 pa_memchunk silence
;
1093 int64_t start_index
;
1094 pa_sink_input_new_data data
;
1095 char *memblockq_name
;
1103 /* Find syncid group */
1104 PA_IDXSET_FOREACH(ssync
, c
->output_streams
, idx
) {
1106 if (!playback_stream_isinstance(ssync
))
1109 if (ssync
->syncid
== syncid
)
1113 /* Synced streams must connect to the same sink */
1117 sink
= ssync
->sink_input
->sink
;
1118 else if (sink
!= ssync
->sink_input
->sink
) {
1119 *ret
= PA_ERR_INVALID
;
1124 pa_sink_input_new_data_init(&data
);
1126 pa_proplist_update(data
.proplist
, PA_UPDATE_REPLACE
, p
);
1127 data
.driver
= __FILE__
;
1128 data
.module
= c
->options
->module
;
1129 data
.client
= c
->client
;
1131 pa_sink_input_new_data_set_sink(&data
, sink
, FALSE
);
1132 if (pa_sample_spec_valid(ss
))
1133 pa_sink_input_new_data_set_sample_spec(&data
, ss
);
1134 if (pa_channel_map_valid(map
))
1135 pa_sink_input_new_data_set_channel_map(&data
, map
);
1137 pa_sink_input_new_data_set_formats(&data
, formats
);
1138 /* Ownership transferred to new_data, so we don't free it ourselves */
1142 pa_sink_input_new_data_set_volume(&data
, volume
);
1143 data
.volume_is_absolute
= !relative_volume
;
1144 data
.save_volume
= FALSE
;
1147 pa_sink_input_new_data_set_muted(&data
, muted
);
1148 data
.save_muted
= FALSE
;
1150 data
.sync_base
= ssync
? ssync
->sink_input
: NULL
;
1153 *ret
= -pa_sink_input_new(&sink_input
, c
->protocol
->core
, &data
);
1155 pa_sink_input_new_data_done(&data
);
1160 s
= pa_msgobject_new(playback_stream
);
1161 s
->parent
.parent
.parent
.free
= playback_stream_free
;
1162 s
->parent
.parent
.process_msg
= playback_stream_process_msg
;
1165 s
->sink_input
= sink_input
;
1166 s
->is_underrun
= TRUE
;
1167 s
->drain_request
= FALSE
;
1168 pa_atomic_store(&s
->missing
, 0);
1169 s
->buffer_attr_req
= *a
;
1170 s
->adjust_latency
= adjust_latency
;
1171 s
->early_requests
= early_requests
;
1172 pa_atomic_store(&s
->seek_or_post_in_queue
, 0);
1173 s
->seek_windex
= -1;
1175 s
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
1176 s
->sink_input
->pop
= sink_input_pop_cb
;
1177 s
->sink_input
->process_underrun
= sink_input_process_underrun_cb
;
1178 s
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
1179 s
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
1180 s
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
1181 s
->sink_input
->kill
= sink_input_kill_cb
;
1182 s
->sink_input
->moving
= sink_input_moving_cb
;
1183 s
->sink_input
->suspend
= sink_input_suspend_cb
;
1184 s
->sink_input
->send_event
= sink_input_send_event_cb
;
1185 s
->sink_input
->userdata
= s
;
1187 start_index
= ssync
? pa_memblockq_get_read_index(ssync
->memblockq
) : 0;
1189 fix_playback_buffer_attr(s
);
1191 pa_sink_input_get_silence(sink_input
, &silence
);
1192 memblockq_name
= pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s
->sink_input
->index
);
1193 s
->memblockq
= pa_memblockq_new(
1196 s
->buffer_attr
.maxlength
,
1197 s
->buffer_attr
.tlength
,
1198 &sink_input
->sample_spec
,
1199 s
->buffer_attr
.prebuf
,
1200 s
->buffer_attr
.minreq
,
1203 pa_xfree(memblockq_name
);
1204 pa_memblock_unref(silence
.memblock
);
1206 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1208 *missing
= (uint32_t) pa_memblockq_pop_missing(s
->memblockq
);
1210 #ifdef PROTOCOL_NATIVE_DEBUG
1211 pa_log("missing original: %li", (long int) *missing
);
1214 *ss
= s
->sink_input
->sample_spec
;
1215 *map
= s
->sink_input
->channel_map
;
1217 pa_idxset_put(c
->output_streams
, s
, &s
->index
);
1219 pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1220 ((double) pa_bytes_to_usec(s
->buffer_attr
.tlength
, &sink_input
->sample_spec
) + (double) s
->configured_sink_latency
) / PA_USEC_PER_MSEC
,
1221 (double) pa_bytes_to_usec(s
->buffer_attr
.tlength
-s
->buffer_attr
.minreq
*2, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1222 (double) pa_bytes_to_usec(s
->buffer_attr
.minreq
, &sink_input
->sample_spec
) / PA_USEC_PER_MSEC
,
1223 (double) s
->configured_sink_latency
/ PA_USEC_PER_MSEC
);
1225 pa_sink_input_put(s
->sink_input
);
1229 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
1234 /* Called from IO context */
1235 static void playback_stream_request_bytes(playback_stream
*s
) {
1237 int previous_missing
;
1239 playback_stream_assert_ref(s
);
1241 m
= pa_memblockq_pop_missing(s
->memblockq
);
1243 /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1244 /* (unsigned long) m, */
1245 /* pa_memblockq_get_tlength(s->memblockq), */
1246 /* pa_memblockq_get_minreq(s->memblockq), */
1247 /* pa_memblockq_get_length(s->memblockq), */
1248 /* (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1253 #ifdef PROTOCOL_NATIVE_DEBUG
1254 pa_log("request_bytes(%lu)", (unsigned long) m
);
1257 previous_missing
= pa_atomic_add(&s
->missing
, (int) m
);
1258 minreq
= pa_memblockq_get_minreq(s
->memblockq
);
1260 if (pa_memblockq_prebuf_active(s
->memblockq
) ||
1261 (previous_missing
< (int) minreq
&& previous_missing
+ (int) m
>= (int) minreq
))
1262 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA
, NULL
, 0, NULL
, NULL
);
1265 /* Called from main context */
1266 static void playback_stream_send_killed(playback_stream
*p
) {
1268 playback_stream_assert_ref(p
);
1270 t
= pa_tagstruct_new(NULL
, 0);
1271 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_KILLED
);
1272 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1273 pa_tagstruct_putu32(t
, p
->index
);
1274 pa_pstream_send_tagstruct(p
->connection
->pstream
, t
);
1277 /* Called from main context */
1278 static int native_connection_process_msg(pa_msgobject
*o
, int code
, void*userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1279 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1280 pa_native_connection_assert_ref(c
);
1287 case CONNECTION_MESSAGE_REVOKE
:
1288 pa_pstream_send_revoke(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1291 case CONNECTION_MESSAGE_RELEASE
:
1292 pa_pstream_send_release(c
->pstream
, PA_PTR_TO_UINT(userdata
));
1299 /* Called from main context */
1300 static void native_connection_unlink(pa_native_connection
*c
) {
1309 pa_hook_fire(&c
->protocol
->hooks
[PA_NATIVE_HOOK_CONNECTION_UNLINK
], c
);
1312 pa_native_options_unref(c
->options
);
1314 while ((r
= pa_idxset_first(c
->record_streams
, NULL
)))
1315 record_stream_unlink(r
);
1317 while ((o
= pa_idxset_first(c
->output_streams
, NULL
)))
1318 if (playback_stream_isinstance(o
))
1319 playback_stream_unlink(PLAYBACK_STREAM(o
));
1321 upload_stream_unlink(UPLOAD_STREAM(o
));
1323 if (c
->subscription
)
1324 pa_subscription_free(c
->subscription
);
1327 pa_pstream_unlink(c
->pstream
);
1329 if (c
->auth_timeout_event
) {
1330 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
1331 c
->auth_timeout_event
= NULL
;
1334 pa_assert_se(pa_idxset_remove_by_data(c
->protocol
->connections
, c
, NULL
) == c
);
1336 pa_native_connection_unref(c
);
1339 /* Called from main context */
1340 static void native_connection_free(pa_object
*o
) {
1341 pa_native_connection
*c
= PA_NATIVE_CONNECTION(o
);
1345 native_connection_unlink(c
);
1347 pa_idxset_free(c
->record_streams
, NULL
);
1348 pa_idxset_free(c
->output_streams
, NULL
);
1350 pa_pdispatch_unref(c
->pdispatch
);
1351 pa_pstream_unref(c
->pstream
);
1352 pa_client_free(c
->client
);
1357 /* Called from main context */
1358 static void native_connection_send_memblock(pa_native_connection
*c
) {
1362 start
= PA_IDXSET_INVALID
;
1366 if (!(r
= RECORD_STREAM(pa_idxset_rrobin(c
->record_streams
, &c
->rrobin_index
))))
1369 if (start
== PA_IDXSET_INVALID
)
1370 start
= c
->rrobin_index
;
1371 else if (start
== c
->rrobin_index
)
1374 if (pa_memblockq_peek(r
->memblockq
, &chunk
) >= 0) {
1375 pa_memchunk schunk
= chunk
;
1377 if (schunk
.length
> r
->buffer_attr
.fragsize
)
1378 schunk
.length
= r
->buffer_attr
.fragsize
;
1380 pa_pstream_send_memblock(c
->pstream
, r
->index
, 0, PA_SEEK_RELATIVE
, &schunk
);
1382 pa_memblockq_drop(r
->memblockq
, schunk
.length
);
1383 pa_memblock_unref(schunk
.memblock
);
1390 /*** sink input callbacks ***/
1392 /* Called from thread context */
1393 static void handle_seek(playback_stream
*s
, int64_t indexw
) {
1394 playback_stream_assert_ref(s
);
1396 /* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1398 if (s
->sink_input
->thread_info
.underrun_for
> 0) {
1400 /* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1402 if (pa_memblockq_is_readable(s
->memblockq
)) {
1404 /* We just ended an underrun, let's ask the sink
1405 * for a complete rewind rewrite */
1407 pa_log_debug("Requesting rewind due to end of underrun.");
1408 pa_sink_input_request_rewind(s
->sink_input
,
1409 (size_t) (s
->sink_input
->thread_info
.underrun_for
== (uint64_t) -1 ? 0 :
1410 s
->sink_input
->thread_info
.underrun_for
),
1411 FALSE
, TRUE
, FALSE
);
1417 indexr
= pa_memblockq_get_read_index(s
->memblockq
);
1419 if (indexw
< indexr
) {
1420 /* OK, the sink already asked for this data, so
1421 * let's have it ask us again */
1423 pa_log_debug("Requesting rewind due to rewrite.");
1424 pa_sink_input_request_rewind(s
->sink_input
, (size_t) (indexr
- indexw
), TRUE
, FALSE
, FALSE
);
1428 playback_stream_request_bytes(s
);
1431 static void flush_write_no_account(pa_memblockq
*q
) {
1432 pa_memblockq_flush_write(q
, FALSE
);
1435 /* Called from thread context */
1436 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1437 pa_sink_input
*i
= PA_SINK_INPUT(o
);
1440 pa_sink_input_assert_ref(i
);
1441 s
= PLAYBACK_STREAM(i
->userdata
);
1442 playback_stream_assert_ref(s
);
1446 case SINK_INPUT_MESSAGE_SEEK
:
1447 case SINK_INPUT_MESSAGE_POST_DATA
: {
1448 int64_t windex
= pa_memblockq_get_write_index(s
->memblockq
);
1450 if (code
== SINK_INPUT_MESSAGE_SEEK
) {
1451 /* The client side is incapable of accounting correctly
1452 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1453 * able to deal with that. */
1455 pa_memblockq_seek(s
->memblockq
, offset
, PA_PTR_TO_UINT(userdata
), PA_PTR_TO_UINT(userdata
) == PA_SEEK_RELATIVE
);
1456 windex
= PA_MIN(windex
, pa_memblockq_get_write_index(s
->memblockq
));
1459 if (chunk
&& pa_memblockq_push_align(s
->memblockq
, chunk
) < 0) {
1460 if (pa_log_ratelimit(PA_LOG_WARN
))
1461 pa_log_warn("Failed to push data into queue");
1462 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_OVERFLOW
, NULL
, 0, NULL
, NULL
);
1463 pa_memblockq_seek(s
->memblockq
, (int64_t) chunk
->length
, PA_SEEK_RELATIVE
, TRUE
);
1466 /* If more data is in queue, we rewind later instead. */
1467 if (s
->seek_windex
!= -1)
1468 windex
= PA_MIN(windex
, s
->seek_windex
);
1469 if (pa_atomic_dec(&s
->seek_or_post_in_queue
) > 1)
1470 s
->seek_windex
= windex
;
1472 s
->seek_windex
= -1;
1473 handle_seek(s
, windex
);
1478 case SINK_INPUT_MESSAGE_DRAIN
:
1479 case SINK_INPUT_MESSAGE_FLUSH
:
1480 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1481 case SINK_INPUT_MESSAGE_TRIGGER
: {
1484 pa_sink_input
*isync
;
1485 void (*func
)(pa_memblockq
*bq
);
1488 case SINK_INPUT_MESSAGE_FLUSH
:
1489 func
= flush_write_no_account
;
1492 case SINK_INPUT_MESSAGE_PREBUF_FORCE
:
1493 func
= pa_memblockq_prebuf_force
;
1496 case SINK_INPUT_MESSAGE_DRAIN
:
1497 case SINK_INPUT_MESSAGE_TRIGGER
:
1498 func
= pa_memblockq_prebuf_disable
;
1502 pa_assert_not_reached();
1505 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1507 handle_seek(s
, windex
);
1509 /* Do the same for all other members in the sync group */
1510 for (isync
= i
->sync_prev
; isync
; isync
= isync
->sync_prev
) {
1511 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1512 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1513 func(ssync
->memblockq
);
1514 handle_seek(ssync
, windex
);
1517 for (isync
= i
->sync_next
; isync
; isync
= isync
->sync_next
) {
1518 playback_stream
*ssync
= PLAYBACK_STREAM(isync
->userdata
);
1519 windex
= pa_memblockq_get_write_index(ssync
->memblockq
);
1520 func(ssync
->memblockq
);
1521 handle_seek(ssync
, windex
);
1524 if (code
== SINK_INPUT_MESSAGE_DRAIN
) {
1525 if (!pa_memblockq_is_readable(s
->memblockq
))
1526 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK
, userdata
, 0, NULL
, NULL
);
1528 s
->drain_tag
= PA_PTR_TO_UINT(userdata
);
1529 s
->drain_request
= TRUE
;
1536 case SINK_INPUT_MESSAGE_UPDATE_LATENCY
:
1537 /* Atomically get a snapshot of all timing parameters... */
1538 s
->read_index
= pa_memblockq_get_read_index(s
->memblockq
);
1539 s
->write_index
= pa_memblockq_get_write_index(s
->memblockq
);
1540 s
->render_memblockq_length
= pa_memblockq_get_length(s
->sink_input
->thread_info
.render_memblockq
);
1541 s
->current_sink_latency
= pa_sink_get_latency_within_thread(s
->sink_input
->sink
);
1542 s
->underrun_for
= s
->sink_input
->thread_info
.underrun_for
;
1543 s
->playing_for
= s
->sink_input
->thread_info
.playing_for
;
1547 case PA_SINK_INPUT_MESSAGE_SET_STATE
: {
1550 windex
= pa_memblockq_get_write_index(s
->memblockq
);
1552 pa_memblockq_prebuf_force(s
->memblockq
);
1554 handle_seek(s
, windex
);
1556 /* Fall through to the default handler */
1560 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
: {
1561 pa_usec_t
*r
= userdata
;
1563 *r
= pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &i
->sample_spec
);
1565 /* Fall through, the default handler will add in the extra
1566 * latency added by the resampler */
1570 case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
: {
1571 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1572 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1577 return pa_sink_input_process_msg(o
, code
, userdata
, offset
, chunk
);
1581 static bool handle_input_underrun(playback_stream
*s
, bool force
)
1585 if (pa_memblockq_is_readable(s
->memblockq
))
1588 if (!s
->is_underrun
)
1589 pa_log_debug("%s %s of '%s'", force
? "Actual" : "Implicit",
1590 s
->drain_request
? "drain" : "underrun", pa_strnull(pa_proplist_gets(s
->sink_input
->proplist
, PA_PROP_MEDIA_NAME
)));
1592 send_drain
= s
->drain_request
&& (force
|| pa_sink_input_safe_to_remove(s
->sink_input
));
1595 s
->drain_request
= false;
1596 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
);
1597 pa_log_debug("Drain acknowledged of '%s'", pa_strnull(pa_proplist_gets(s
->sink_input
->proplist
, PA_PROP_MEDIA_NAME
)));
1598 } else if (!s
->is_underrun
) {
1599 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_UNDERFLOW
, NULL
, pa_memblockq_get_read_index(s
->memblockq
), NULL
, NULL
);
1601 s
->is_underrun
= true;
1602 playback_stream_request_bytes(s
);
1606 /* Called from thread context */
1607 static bool sink_input_process_underrun_cb(pa_sink_input
*i
) {
1610 pa_sink_input_assert_ref(i
);
1611 s
= PLAYBACK_STREAM(i
->userdata
);
1612 playback_stream_assert_ref(s
);
1614 return handle_input_underrun(s
, true);
1618 /* Called from thread context */
1619 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
1622 pa_sink_input_assert_ref(i
);
1623 s
= PLAYBACK_STREAM(i
->userdata
);
1624 playback_stream_assert_ref(s
);
1627 #ifdef PROTOCOL_NATIVE_DEBUG
1628 pa_log("%s, pop(): %lu", pa_proplist_gets(i
->proplist
, PA_PROP_MEDIA_NAME
), (unsigned long) pa_memblockq_get_length(s
->memblockq
));
1631 if (!handle_input_underrun(s
, false))
1632 s
->is_underrun
= false;
1634 /* This call will not fail with prebuf=0, hence we check for
1635 underrun explicitly in handle_input_underrun */
1636 if (pa_memblockq_peek(s
->memblockq
, chunk
) < 0)
1639 chunk
->length
= PA_MIN(nbytes
, chunk
->length
);
1641 if (i
->thread_info
.underrun_for
> 0)
1642 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), PLAYBACK_STREAM_MESSAGE_STARTED
, NULL
, 0, NULL
, NULL
);
1644 pa_memblockq_drop(s
->memblockq
, chunk
->length
);
1645 playback_stream_request_bytes(s
);
1650 /* Called from thread context */
1651 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1654 pa_sink_input_assert_ref(i
);
1655 s
= PLAYBACK_STREAM(i
->userdata
);
1656 playback_stream_assert_ref(s
);
1658 /* If we are in an underrun, then we don't rewind */
1659 if (i
->thread_info
.underrun_for
> 0)
1662 pa_memblockq_rewind(s
->memblockq
, nbytes
);
1665 /* Called from thread context */
1666 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
1669 pa_sink_input_assert_ref(i
);
1670 s
= PLAYBACK_STREAM(i
->userdata
);
1671 playback_stream_assert_ref(s
);
1673 pa_memblockq_set_maxrewind(s
->memblockq
, nbytes
);
1676 /* Called from thread context */
1677 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
1679 size_t new_tlength
, old_tlength
;
1681 pa_sink_input_assert_ref(i
);
1682 s
= PLAYBACK_STREAM(i
->userdata
);
1683 playback_stream_assert_ref(s
);
1685 old_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1686 new_tlength
= nbytes
+2*pa_memblockq_get_minreq(s
->memblockq
);
1688 if (old_tlength
< new_tlength
) {
1689 pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength
, new_tlength
);
1690 pa_memblockq_set_tlength(s
->memblockq
, new_tlength
);
1691 new_tlength
= pa_memblockq_get_tlength(s
->memblockq
);
1693 if (new_tlength
== old_tlength
)
1694 pa_log_debug("Failed to increase tlength");
1696 pa_log_debug("Notifying client about increased tlength");
1697 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
);
1702 /* Called from main context */
1703 static void sink_input_kill_cb(pa_sink_input
*i
) {
1706 pa_sink_input_assert_ref(i
);
1707 s
= PLAYBACK_STREAM(i
->userdata
);
1708 playback_stream_assert_ref(s
);
1710 playback_stream_send_killed(s
);
1711 playback_stream_unlink(s
);
1714 /* Called from main context */
1715 static void sink_input_send_event_cb(pa_sink_input
*i
, const char *event
, pa_proplist
*pl
) {
1719 pa_sink_input_assert_ref(i
);
1720 s
= PLAYBACK_STREAM(i
->userdata
);
1721 playback_stream_assert_ref(s
);
1723 if (s
->connection
->version
< 15)
1726 t
= pa_tagstruct_new(NULL
, 0);
1727 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_EVENT
);
1728 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1729 pa_tagstruct_putu32(t
, s
->index
);
1730 pa_tagstruct_puts(t
, event
);
1731 pa_tagstruct_put_proplist(t
, pl
);
1732 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1735 /* Called from main context */
1736 static void sink_input_suspend_cb(pa_sink_input
*i
, pa_bool_t suspend
) {
1740 pa_sink_input_assert_ref(i
);
1741 s
= PLAYBACK_STREAM(i
->userdata
);
1742 playback_stream_assert_ref(s
);
1744 if (s
->connection
->version
< 12)
1747 t
= pa_tagstruct_new(NULL
, 0);
1748 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
);
1749 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1750 pa_tagstruct_putu32(t
, s
->index
);
1751 pa_tagstruct_put_boolean(t
, suspend
);
1752 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1755 /* Called from main context */
1756 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
1760 pa_sink_input_assert_ref(i
);
1761 s
= PLAYBACK_STREAM(i
->userdata
);
1762 playback_stream_assert_ref(s
);
1767 fix_playback_buffer_attr(s
);
1768 pa_memblockq_apply_attr(s
->memblockq
, &s
->buffer_attr
);
1769 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1771 if (s
->connection
->version
< 12)
1774 t
= pa_tagstruct_new(NULL
, 0);
1775 pa_tagstruct_putu32(t
, PA_COMMAND_PLAYBACK_STREAM_MOVED
);
1776 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1777 pa_tagstruct_putu32(t
, s
->index
);
1778 pa_tagstruct_putu32(t
, dest
->index
);
1779 pa_tagstruct_puts(t
, dest
->name
);
1780 pa_tagstruct_put_boolean(t
, pa_sink_get_state(dest
) == PA_SINK_SUSPENDED
);
1782 if (s
->connection
->version
>= 13) {
1783 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1784 pa_tagstruct_putu32(t
, s
->buffer_attr
.tlength
);
1785 pa_tagstruct_putu32(t
, s
->buffer_attr
.prebuf
);
1786 pa_tagstruct_putu32(t
, s
->buffer_attr
.minreq
);
1787 pa_tagstruct_put_usec(t
, s
->configured_sink_latency
);
1790 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1793 /*** source_output callbacks ***/
1795 /* Called from thread context */
1796 static int source_output_process_msg(pa_msgobject
*_o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1797 pa_source_output
*o
= PA_SOURCE_OUTPUT(_o
);
1800 pa_source_output_assert_ref(o
);
1801 s
= RECORD_STREAM(o
->userdata
);
1802 record_stream_assert_ref(s
);
1805 case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY
:
1806 /* Atomically get a snapshot of all timing parameters... */
1807 s
->current_monitor_latency
= o
->source
->monitor_of
? pa_sink_get_latency_within_thread(o
->source
->monitor_of
) : 0;
1808 s
->current_source_latency
= pa_source_get_latency_within_thread(o
->source
);
1809 s
->on_the_fly_snapshot
= pa_atomic_load(&s
->on_the_fly
);
1813 return pa_source_output_process_msg(_o
, code
, userdata
, offset
, chunk
);
1816 /* Called from thread context */
1817 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
1820 pa_source_output_assert_ref(o
);
1821 s
= RECORD_STREAM(o
->userdata
);
1822 record_stream_assert_ref(s
);
1825 pa_atomic_add(&s
->on_the_fly
, chunk
->length
);
1826 pa_asyncmsgq_post(pa_thread_mq_get()->outq
, PA_MSGOBJECT(s
), RECORD_STREAM_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
1829 static void source_output_kill_cb(pa_source_output
*o
) {
1832 pa_source_output_assert_ref(o
);
1833 s
= RECORD_STREAM(o
->userdata
);
1834 record_stream_assert_ref(s
);
1836 record_stream_send_killed(s
);
1837 record_stream_unlink(s
);
1840 static pa_usec_t
source_output_get_latency_cb(pa_source_output
*o
) {
1843 pa_source_output_assert_ref(o
);
1844 s
= RECORD_STREAM(o
->userdata
);
1845 record_stream_assert_ref(s
);
1847 /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
1849 return pa_bytes_to_usec(pa_memblockq_get_length(s
->memblockq
), &o
->sample_spec
);
1852 /* Called from main context */
1853 static void source_output_send_event_cb(pa_source_output
*o
, const char *event
, pa_proplist
*pl
) {
1857 pa_source_output_assert_ref(o
);
1858 s
= RECORD_STREAM(o
->userdata
);
1859 record_stream_assert_ref(s
);
1861 if (s
->connection
->version
< 15)
1864 t
= pa_tagstruct_new(NULL
, 0);
1865 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_EVENT
);
1866 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1867 pa_tagstruct_putu32(t
, s
->index
);
1868 pa_tagstruct_puts(t
, event
);
1869 pa_tagstruct_put_proplist(t
, pl
);
1870 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1873 /* Called from main context */
1874 static void source_output_suspend_cb(pa_source_output
*o
, pa_bool_t suspend
) {
1878 pa_source_output_assert_ref(o
);
1879 s
= RECORD_STREAM(o
->userdata
);
1880 record_stream_assert_ref(s
);
1882 if (s
->connection
->version
< 12)
1885 t
= pa_tagstruct_new(NULL
, 0);
1886 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_SUSPENDED
);
1887 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1888 pa_tagstruct_putu32(t
, s
->index
);
1889 pa_tagstruct_put_boolean(t
, suspend
);
1890 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1893 /* Called from main context */
1894 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
1898 pa_source_output_assert_ref(o
);
1899 s
= RECORD_STREAM(o
->userdata
);
1900 record_stream_assert_ref(s
);
1905 fix_record_buffer_attr_pre(s
);
1906 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
1907 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
1908 fix_record_buffer_attr_post(s
);
1910 if (s
->connection
->version
< 12)
1913 t
= pa_tagstruct_new(NULL
, 0);
1914 pa_tagstruct_putu32(t
, PA_COMMAND_RECORD_STREAM_MOVED
);
1915 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
1916 pa_tagstruct_putu32(t
, s
->index
);
1917 pa_tagstruct_putu32(t
, dest
->index
);
1918 pa_tagstruct_puts(t
, dest
->name
);
1919 pa_tagstruct_put_boolean(t
, pa_source_get_state(dest
) == PA_SOURCE_SUSPENDED
);
1921 if (s
->connection
->version
>= 13) {
1922 pa_tagstruct_putu32(t
, s
->buffer_attr
.maxlength
);
1923 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
1924 pa_tagstruct_put_usec(t
, s
->configured_source_latency
);
1927 pa_pstream_send_tagstruct(s
->connection
->pstream
, t
);
1930 /*** pdispatch callbacks ***/
1932 static void protocol_error(pa_native_connection
*c
) {
1933 pa_log("protocol error, kicking client");
1934 native_connection_unlink(c
);
1937 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
1938 if (!(expression)) { \
1939 pa_pstream_send_error((pstream), (tag), (error)); \
1944 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
1945 if (!(expression)) { \
1946 pa_pstream_send_error((pstream), (tag), (error)); \
1951 static pa_tagstruct
*reply_new(uint32_t tag
) {
1952 pa_tagstruct
*reply
;
1954 reply
= pa_tagstruct_new(NULL
, 0);
1955 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1956 pa_tagstruct_putu32(reply
, tag
);
1960 static void command_create_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1961 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
1963 uint32_t sink_index
, syncid
, missing
= 0;
1964 pa_buffer_attr attr
;
1965 const char *name
= NULL
, *sink_name
;
1968 pa_tagstruct
*reply
;
1969 pa_sink
*sink
= NULL
;
1977 fix_channels
= FALSE
,
1979 variable_rate
= FALSE
,
1981 adjust_latency
= FALSE
,
1982 early_requests
= FALSE
,
1983 dont_inhibit_auto_suspend
= FALSE
,
1986 fail_on_suspend
= FALSE
,
1987 relative_volume
= FALSE
,
1988 passthrough
= FALSE
;
1990 pa_sink_input_flags_t flags
= 0;
1991 pa_proplist
*p
= NULL
;
1992 int ret
= PA_ERR_INVALID
;
1993 uint8_t n_formats
= 0;
1994 pa_format_info
*format
;
1995 pa_idxset
*formats
= NULL
;
1998 pa_native_connection_assert_ref(c
);
2000 memset(&attr
, 0, sizeof(attr
));
2002 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2005 PA_TAG_SAMPLE_SPEC
, &ss
,
2006 PA_TAG_CHANNEL_MAP
, &map
,
2007 PA_TAG_U32
, &sink_index
,
2008 PA_TAG_STRING
, &sink_name
,
2009 PA_TAG_U32
, &attr
.maxlength
,
2010 PA_TAG_BOOLEAN
, &corked
,
2011 PA_TAG_U32
, &attr
.tlength
,
2012 PA_TAG_U32
, &attr
.prebuf
,
2013 PA_TAG_U32
, &attr
.minreq
,
2014 PA_TAG_U32
, &syncid
,
2015 PA_TAG_CVOLUME
, &volume
,
2016 PA_TAG_INVALID
) < 0) {
2022 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
2023 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
, finish
);
2024 CHECK_VALIDITY_GOTO(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
, finish
);
2025 CHECK_VALIDITY_GOTO(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
2026 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
2028 p
= pa_proplist_new();
2031 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2033 if (c
->version
>= 12) {
2034 /* Since 0.9.8 the user can ask for a couple of additional flags */
2036 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2037 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2038 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2039 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2040 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2041 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2042 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2049 if (c
->version
>= 13) {
2051 if (pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2052 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2053 pa_tagstruct_get_proplist(t
, p
) < 0) {
2060 if (c
->version
>= 14) {
2062 if (pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2063 pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2070 if (c
->version
>= 15) {
2072 if (pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2073 pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2074 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2081 if (c
->version
>= 17) {
2083 if (pa_tagstruct_get_boolean(t
, &relative_volume
) < 0) {
2090 if (c
->version
>= 18) {
2092 if (pa_tagstruct_get_boolean(t
, &passthrough
) < 0 ) {
2098 if (c
->version
>= 21) {
2100 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2106 formats
= pa_idxset_new(NULL
, NULL
);
2108 for (i
= 0; i
< n_formats
; i
++) {
2109 format
= pa_format_info_new();
2110 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2114 pa_idxset_put(formats
, format
, NULL
);
2118 if (n_formats
== 0) {
2119 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2120 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
&& volume
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2121 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2123 PA_IDXSET_FOREACH(format
, formats
, i
) {
2124 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2128 if (!pa_tagstruct_eof(t
)) {
2133 if (sink_index
!= PA_INVALID_INDEX
) {
2135 if (!(sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
))) {
2136 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2140 } else if (sink_name
) {
2142 if (!(sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
))) {
2143 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2149 (corked
? PA_SINK_INPUT_START_CORKED
: 0) |
2150 (no_remap
? PA_SINK_INPUT_NO_REMAP
: 0) |
2151 (no_remix
? PA_SINK_INPUT_NO_REMIX
: 0) |
2152 (fix_format
? PA_SINK_INPUT_FIX_FORMAT
: 0) |
2153 (fix_rate
? PA_SINK_INPUT_FIX_RATE
: 0) |
2154 (fix_channels
? PA_SINK_INPUT_FIX_CHANNELS
: 0) |
2155 (no_move
? PA_SINK_INPUT_DONT_MOVE
: 0) |
2156 (variable_rate
? PA_SINK_INPUT_VARIABLE_RATE
: 0) |
2157 (dont_inhibit_auto_suspend
? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2158 (fail_on_suspend
? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND
|PA_SINK_INPUT_KILL_ON_SUSPEND
: 0) |
2159 (passthrough
? PA_SINK_INPUT_PASSTHROUGH
: 0);
2161 /* Only since protocol version 15 there's a separate muted_set
2162 * flag. For older versions we synthesize it here */
2163 muted_set
= muted_set
|| muted
;
2165 s
= playback_stream_new(c
, sink
, &ss
, &map
, formats
, &attr
, volume_set
? &volume
: NULL
, muted
, muted_set
, flags
, p
, adjust_latency
, early_requests
, relative_volume
, syncid
, &missing
, &ret
);
2166 /* We no longer own the formats idxset */
2169 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2171 reply
= reply_new(tag
);
2172 pa_tagstruct_putu32(reply
, s
->index
);
2173 pa_assert(s
->sink_input
);
2174 pa_tagstruct_putu32(reply
, s
->sink_input
->index
);
2175 pa_tagstruct_putu32(reply
, missing
);
2177 #ifdef PROTOCOL_NATIVE_DEBUG
2178 pa_log("initial request is %u", missing
);
2181 if (c
->version
>= 9) {
2182 /* Since 0.9.0 we support sending the buffer metrics back to the client */
2184 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2185 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.tlength
);
2186 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.prebuf
);
2187 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.minreq
);
2190 if (c
->version
>= 12) {
2191 /* Since 0.9.8 we support sending the chosen sample
2192 * spec/channel map/device/suspend status back to the
2195 pa_tagstruct_put_sample_spec(reply
, &ss
);
2196 pa_tagstruct_put_channel_map(reply
, &map
);
2198 pa_tagstruct_putu32(reply
, s
->sink_input
->sink
->index
);
2199 pa_tagstruct_puts(reply
, s
->sink_input
->sink
->name
);
2201 pa_tagstruct_put_boolean(reply
, pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_SUSPENDED
);
2204 if (c
->version
>= 13)
2205 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
2207 if (c
->version
>= 21) {
2208 /* Send back the format we negotiated */
2209 if (s
->sink_input
->format
)
2210 pa_tagstruct_put_format_info(reply
, s
->sink_input
->format
);
2212 pa_format_info
*f
= pa_format_info_new();
2213 pa_tagstruct_put_format_info(reply
, f
);
2214 pa_format_info_free(f
);
2218 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2222 pa_proplist_free(p
);
2224 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
2227 static void command_delete_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2228 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2231 pa_native_connection_assert_ref(c
);
2234 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2235 !pa_tagstruct_eof(t
)) {
2240 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2244 case PA_COMMAND_DELETE_PLAYBACK_STREAM
: {
2246 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !playback_stream_isinstance(s
)) {
2247 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2251 playback_stream_unlink(s
);
2255 case PA_COMMAND_DELETE_RECORD_STREAM
: {
2257 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, channel
))) {
2258 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2262 record_stream_unlink(s
);
2266 case PA_COMMAND_DELETE_UPLOAD_STREAM
: {
2269 if (!(s
= pa_idxset_get_by_index(c
->output_streams
, channel
)) || !upload_stream_isinstance(s
)) {
2270 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_EXIST
);
2274 upload_stream_unlink(s
);
2279 pa_assert_not_reached();
2282 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2285 static void command_create_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2286 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2288 pa_buffer_attr attr
;
2289 uint32_t source_index
;
2290 const char *name
= NULL
, *source_name
;
2293 pa_tagstruct
*reply
;
2294 pa_source
*source
= NULL
;
2302 fix_channels
= FALSE
,
2304 variable_rate
= FALSE
,
2306 adjust_latency
= FALSE
,
2307 peak_detect
= FALSE
,
2308 early_requests
= FALSE
,
2309 dont_inhibit_auto_suspend
= FALSE
,
2312 fail_on_suspend
= FALSE
,
2313 relative_volume
= FALSE
,
2314 passthrough
= FALSE
;
2316 pa_source_output_flags_t flags
= 0;
2317 pa_proplist
*p
= NULL
;
2318 uint32_t direct_on_input_idx
= PA_INVALID_INDEX
;
2319 pa_sink_input
*direct_on_input
= NULL
;
2320 int ret
= PA_ERR_INVALID
;
2321 uint8_t n_formats
= 0;
2322 pa_format_info
*format
;
2323 pa_idxset
*formats
= NULL
;
2326 pa_native_connection_assert_ref(c
);
2329 memset(&attr
, 0, sizeof(attr
));
2331 if ((c
->version
< 13 && (pa_tagstruct_gets(t
, &name
) < 0 || !name
)) ||
2332 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2333 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2334 pa_tagstruct_getu32(t
, &source_index
) < 0 ||
2335 pa_tagstruct_gets(t
, &source_name
) < 0 ||
2336 pa_tagstruct_getu32(t
, &attr
.maxlength
) < 0 ||
2337 pa_tagstruct_get_boolean(t
, &corked
) < 0 ||
2338 pa_tagstruct_getu32(t
, &attr
.fragsize
) < 0) {
2344 CHECK_VALIDITY_GOTO(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
, finish
);
2345 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| pa_namereg_is_valid_name_or_wildcard(source_name
, PA_NAMEREG_SOURCE
), tag
, PA_ERR_INVALID
, finish
);
2346 CHECK_VALIDITY_GOTO(c
->pstream
, source_index
== PA_INVALID_INDEX
|| !source_name
, tag
, PA_ERR_INVALID
, finish
);
2347 CHECK_VALIDITY_GOTO(c
->pstream
, !source_name
|| source_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
, finish
);
2349 p
= pa_proplist_new();
2352 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2354 if (c
->version
>= 12) {
2355 /* Since 0.9.8 the user can ask for a couple of additional flags */
2357 if (pa_tagstruct_get_boolean(t
, &no_remap
) < 0 ||
2358 pa_tagstruct_get_boolean(t
, &no_remix
) < 0 ||
2359 pa_tagstruct_get_boolean(t
, &fix_format
) < 0 ||
2360 pa_tagstruct_get_boolean(t
, &fix_rate
) < 0 ||
2361 pa_tagstruct_get_boolean(t
, &fix_channels
) < 0 ||
2362 pa_tagstruct_get_boolean(t
, &no_move
) < 0 ||
2363 pa_tagstruct_get_boolean(t
, &variable_rate
) < 0) {
2370 if (c
->version
>= 13) {
2372 if (pa_tagstruct_get_boolean(t
, &peak_detect
) < 0 ||
2373 pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0 ||
2374 pa_tagstruct_get_proplist(t
, p
) < 0 ||
2375 pa_tagstruct_getu32(t
, &direct_on_input_idx
) < 0) {
2382 if (c
->version
>= 14) {
2384 if (pa_tagstruct_get_boolean(t
, &early_requests
) < 0) {
2390 if (c
->version
>= 15) {
2392 if (pa_tagstruct_get_boolean(t
, &dont_inhibit_auto_suspend
) < 0 ||
2393 pa_tagstruct_get_boolean(t
, &fail_on_suspend
) < 0) {
2400 if (c
->version
>= 22) {
2401 /* For newer client versions (with per-source-output volumes), we try
2402 * to make the behaviour for playback and record streams the same. */
2405 if (pa_tagstruct_getu8(t
, &n_formats
) < 0) {
2411 formats
= pa_idxset_new(NULL
, NULL
);
2413 for (i
= 0; i
< n_formats
; i
++) {
2414 format
= pa_format_info_new();
2415 if (pa_tagstruct_get_format_info(t
, format
) < 0) {
2419 pa_idxset_put(formats
, format
, NULL
);
2422 if (pa_tagstruct_get_cvolume(t
, &volume
) < 0 ||
2423 pa_tagstruct_get_boolean(t
, &muted
) < 0 ||
2424 pa_tagstruct_get_boolean(t
, &volume_set
) < 0 ||
2425 pa_tagstruct_get_boolean(t
, &muted_set
) < 0 ||
2426 pa_tagstruct_get_boolean(t
, &relative_volume
) < 0 ||
2427 pa_tagstruct_get_boolean(t
, &passthrough
) < 0) {
2433 CHECK_VALIDITY_GOTO(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
, finish
);
2436 if (n_formats
== 0) {
2437 CHECK_VALIDITY_GOTO(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
, finish
);
2438 CHECK_VALIDITY_GOTO(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
, finish
);
2439 CHECK_VALIDITY_GOTO(c
->pstream
, c
->version
< 22 || (volume
.channels
== ss
.channels
), tag
, PA_ERR_INVALID
, finish
);
2440 CHECK_VALIDITY_GOTO(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
, finish
);
2442 PA_IDXSET_FOREACH(format
, formats
, i
) {
2443 CHECK_VALIDITY_GOTO(c
->pstream
, pa_format_info_valid(format
), tag
, PA_ERR_INVALID
, finish
);
2448 if (!pa_tagstruct_eof(t
)) {
2453 if (source_index
!= PA_INVALID_INDEX
) {
2455 if (!(source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, source_index
))) {
2456 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2460 } else if (source_name
) {
2462 if (!(source
= pa_namereg_get(c
->protocol
->core
, source_name
, PA_NAMEREG_SOURCE
))) {
2463 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2468 if (direct_on_input_idx
!= PA_INVALID_INDEX
) {
2470 if (!(direct_on_input
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, direct_on_input_idx
))) {
2471 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2477 (corked
? PA_SOURCE_OUTPUT_START_CORKED
: 0) |
2478 (no_remap
? PA_SOURCE_OUTPUT_NO_REMAP
: 0) |
2479 (no_remix
? PA_SOURCE_OUTPUT_NO_REMIX
: 0) |
2480 (fix_format
? PA_SOURCE_OUTPUT_FIX_FORMAT
: 0) |
2481 (fix_rate
? PA_SOURCE_OUTPUT_FIX_RATE
: 0) |
2482 (fix_channels
? PA_SOURCE_OUTPUT_FIX_CHANNELS
: 0) |
2483 (no_move
? PA_SOURCE_OUTPUT_DONT_MOVE
: 0) |
2484 (variable_rate
? PA_SOURCE_OUTPUT_VARIABLE_RATE
: 0) |
2485 (dont_inhibit_auto_suspend
? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
: 0) |
2486 (fail_on_suspend
? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND
|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
: 0) |
2487 (passthrough
? PA_SOURCE_OUTPUT_PASSTHROUGH
: 0);
2489 s
= record_stream_new(c
, source
, &ss
, &map
, formats
, &attr
, volume_set
? &volume
: NULL
, muted
, muted_set
, flags
, p
, adjust_latency
, early_requests
, relative_volume
, peak_detect
, direct_on_input
, &ret
);
2491 CHECK_VALIDITY_GOTO(c
->pstream
, s
, tag
, ret
, finish
);
2493 reply
= reply_new(tag
);
2494 pa_tagstruct_putu32(reply
, s
->index
);
2495 pa_assert(s
->source_output
);
2496 pa_tagstruct_putu32(reply
, s
->source_output
->index
);
2498 if (c
->version
>= 9) {
2499 /* Since 0.9 we support sending the buffer metrics back to the client */
2501 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.maxlength
);
2502 pa_tagstruct_putu32(reply
, (uint32_t) s
->buffer_attr
.fragsize
);
2505 if (c
->version
>= 12) {
2506 /* Since 0.9.8 we support sending the chosen sample
2507 * spec/channel map/device/suspend status back to the
2510 pa_tagstruct_put_sample_spec(reply
, &ss
);
2511 pa_tagstruct_put_channel_map(reply
, &map
);
2513 pa_tagstruct_putu32(reply
, s
->source_output
->source
->index
);
2514 pa_tagstruct_puts(reply
, s
->source_output
->source
->name
);
2516 pa_tagstruct_put_boolean(reply
, pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_SUSPENDED
);
2519 if (c
->version
>= 13)
2520 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
2522 if (c
->version
>= 22) {
2523 /* Send back the format we negotiated */
2524 if (s
->source_output
->format
)
2525 pa_tagstruct_put_format_info(reply
, s
->source_output
->format
);
2527 pa_format_info
*f
= pa_format_info_new();
2528 pa_tagstruct_put_format_info(reply
, f
);
2529 pa_format_info_free(f
);
2533 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2537 pa_proplist_free(p
);
2539 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
2542 static void command_exit(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2543 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2546 pa_native_connection_assert_ref(c
);
2549 if (!pa_tagstruct_eof(t
)) {
2554 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2555 ret
= pa_core_exit(c
->protocol
->core
, FALSE
, 0);
2556 CHECK_VALIDITY(c
->pstream
, ret
>= 0, tag
, PA_ERR_ACCESS
);
2558 pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
)));
2560 pa_pstream_send_simple_ack(c
->pstream
, tag
); /* nonsense */
2563 static void command_auth(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2564 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2566 pa_tagstruct
*reply
;
2567 pa_bool_t shm_on_remote
= FALSE
, do_shm
;
2569 pa_native_connection_assert_ref(c
);
2572 if (pa_tagstruct_getu32(t
, &c
->version
) < 0 ||
2573 pa_tagstruct_get_arbitrary(t
, &cookie
, PA_NATIVE_COOKIE_LENGTH
) < 0 ||
2574 !pa_tagstruct_eof(t
)) {
2579 /* Minimum supported version */
2580 if (c
->version
< 8) {
2581 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_VERSION
);
2585 /* Starting with protocol version 13 the MSB of the version tag
2586 reflects if shm is available for this pa_native_connection or
2588 if (c
->version
>= 13) {
2589 shm_on_remote
= !!(c
->version
& 0x80000000U
);
2590 c
->version
&= 0x7FFFFFFFU
;
2593 pa_log_debug("Protocol version: remote %u, local %u", c
->version
, PA_PROTOCOL_VERSION
);
2595 pa_proplist_setf(c
->client
->proplist
, "native-protocol.version", "%u", c
->version
);
2597 if (!c
->authorized
) {
2598 pa_bool_t success
= FALSE
;
2601 const pa_creds
*creds
;
2603 if ((creds
= pa_pdispatch_creds(pd
))) {
2604 if (creds
->uid
== getuid())
2606 else if (c
->options
->auth_group
) {
2610 if ((gid
= pa_get_gid_of_group(c
->options
->auth_group
)) == (gid_t
) -1)
2611 pa_log_warn("Failed to get GID of group '%s'", c
->options
->auth_group
);
2612 else if (gid
== creds
->gid
)
2616 if ((r
= pa_uid_in_group(creds
->uid
, c
->options
->auth_group
)) < 0)
2617 pa_log_warn("Failed to check group membership.");
2623 pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2624 (unsigned long) creds
->uid
,
2625 (unsigned long) creds
->gid
,
2630 if (!success
&& c
->options
->auth_cookie
) {
2633 if ((ac
= pa_auth_cookie_read(c
->options
->auth_cookie
, PA_NATIVE_COOKIE_LENGTH
)))
2634 if (memcmp(ac
, cookie
, PA_NATIVE_COOKIE_LENGTH
) == 0)
2639 pa_log_warn("Denied access to client with invalid authorization data.");
2640 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_ACCESS
);
2644 c
->authorized
= TRUE
;
2645 if (c
->auth_timeout_event
) {
2646 c
->protocol
->core
->mainloop
->time_free(c
->auth_timeout_event
);
2647 c
->auth_timeout_event
= NULL
;
2651 /* Enable shared memory support if possible */
2653 pa_mempool_is_shared(c
->protocol
->core
->mempool
) &&
2656 pa_log_debug("SHM possible: %s", pa_yes_no(do_shm
));
2659 if (c
->version
< 10 || (c
->version
>= 13 && !shm_on_remote
))
2664 /* Only enable SHM if both sides are owned by the same
2665 * user. This is a security measure because otherwise data
2666 * private to the user might leak. */
2668 const pa_creds
*creds
;
2669 if (!(creds
= pa_pdispatch_creds(pd
)) || getuid() != creds
->uid
)
2674 pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm
));
2675 pa_pstream_enable_shm(c
->pstream
, do_shm
);
2677 reply
= reply_new(tag
);
2678 pa_tagstruct_putu32(reply
, PA_PROTOCOL_VERSION
| (do_shm
? 0x80000000 : 0));
2682 /* SHM support is only enabled after both sides made sure they are the same user. */
2686 ucred
.uid
= getuid();
2687 ucred
.gid
= getgid();
2689 pa_pstream_send_tagstruct_with_creds(c
->pstream
, reply
, &ucred
);
2692 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2696 static void command_set_client_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2697 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2698 const char *name
= NULL
;
2700 pa_tagstruct
*reply
;
2702 pa_native_connection_assert_ref(c
);
2705 p
= pa_proplist_new();
2707 if ((c
->version
< 13 && pa_tagstruct_gets(t
, &name
) < 0) ||
2708 (c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2709 !pa_tagstruct_eof(t
)) {
2712 pa_proplist_free(p
);
2717 if (pa_proplist_sets(p
, PA_PROP_APPLICATION_NAME
, name
) < 0) {
2718 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
2719 pa_proplist_free(p
);
2723 pa_client_update_proplist(c
->client
, PA_UPDATE_REPLACE
, p
);
2724 pa_proplist_free(p
);
2726 reply
= reply_new(tag
);
2728 if (c
->version
>= 13)
2729 pa_tagstruct_putu32(reply
, c
->client
->index
);
2731 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2734 static void command_lookup(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2735 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2737 uint32_t idx
= PA_IDXSET_INVALID
;
2739 pa_native_connection_assert_ref(c
);
2742 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2743 !pa_tagstruct_eof(t
)) {
2748 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2749 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
);
2751 if (command
== PA_COMMAND_LOOKUP_SINK
) {
2753 if ((sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
)))
2757 pa_assert(command
== PA_COMMAND_LOOKUP_SOURCE
);
2758 if ((source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
)))
2759 idx
= source
->index
;
2762 if (idx
== PA_IDXSET_INVALID
)
2763 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
2765 pa_tagstruct
*reply
;
2766 reply
= reply_new(tag
);
2767 pa_tagstruct_putu32(reply
, idx
);
2768 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2772 static void command_drain_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2773 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2777 pa_native_connection_assert_ref(c
);
2780 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2781 !pa_tagstruct_eof(t
)) {
2786 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2787 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2788 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2789 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2791 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
);
2794 static void command_stat(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2795 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2796 pa_tagstruct
*reply
;
2797 const pa_mempool_stat
*stat
;
2799 pa_native_connection_assert_ref(c
);
2802 if (!pa_tagstruct_eof(t
)) {
2807 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2809 stat
= pa_mempool_get_stat(c
->protocol
->core
->mempool
);
2811 reply
= reply_new(tag
);
2812 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_allocated
));
2813 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->allocated_size
));
2814 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->n_accumulated
));
2815 pa_tagstruct_putu32(reply
, (uint32_t) pa_atomic_load(&stat
->accumulated_size
));
2816 pa_tagstruct_putu32(reply
, (uint32_t) pa_scache_total_size(c
->protocol
->core
));
2817 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2820 static void command_get_playback_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2821 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2822 pa_tagstruct
*reply
;
2824 struct timeval tv
, now
;
2827 pa_native_connection_assert_ref(c
);
2830 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2831 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2832 !pa_tagstruct_eof(t
)) {
2837 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2838 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
2839 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2840 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2842 /* Get an atomic snapshot of all timing parameters */
2843 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);
2845 reply
= reply_new(tag
);
2846 pa_tagstruct_put_usec(reply
,
2847 s
->current_sink_latency
+
2848 pa_bytes_to_usec(s
->render_memblockq_length
, &s
->sink_input
->sink
->sample_spec
));
2849 pa_tagstruct_put_usec(reply
, 0);
2850 pa_tagstruct_put_boolean(reply
,
2851 s
->playing_for
> 0 &&
2852 pa_sink_get_state(s
->sink_input
->sink
) == PA_SINK_RUNNING
&&
2853 pa_sink_input_get_state(s
->sink_input
) == PA_SINK_INPUT_RUNNING
);
2854 pa_tagstruct_put_timeval(reply
, &tv
);
2855 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2856 pa_tagstruct_puts64(reply
, s
->write_index
);
2857 pa_tagstruct_puts64(reply
, s
->read_index
);
2859 if (c
->version
>= 13) {
2860 pa_tagstruct_putu64(reply
, s
->underrun_for
);
2861 pa_tagstruct_putu64(reply
, s
->playing_for
);
2864 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2867 static void command_get_record_latency(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2868 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2869 pa_tagstruct
*reply
;
2871 struct timeval tv
, now
;
2874 pa_native_connection_assert_ref(c
);
2877 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
2878 pa_tagstruct_get_timeval(t
, &tv
) < 0 ||
2879 !pa_tagstruct_eof(t
)) {
2884 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2885 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
2886 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2888 /* Get an atomic snapshot of all timing parameters */
2889 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);
2891 reply
= reply_new(tag
);
2892 pa_tagstruct_put_usec(reply
, s
->current_monitor_latency
);
2893 pa_tagstruct_put_usec(reply
,
2894 s
->current_source_latency
+
2895 pa_bytes_to_usec(s
->on_the_fly_snapshot
, &s
->source_output
->source
->sample_spec
));
2896 pa_tagstruct_put_boolean(reply
,
2897 pa_source_get_state(s
->source_output
->source
) == PA_SOURCE_RUNNING
&&
2898 pa_source_output_get_state(s
->source_output
) == PA_SOURCE_OUTPUT_RUNNING
);
2899 pa_tagstruct_put_timeval(reply
, &tv
);
2900 pa_tagstruct_put_timeval(reply
, pa_gettimeofday(&now
));
2901 pa_tagstruct_puts64(reply
, pa_memblockq_get_write_index(s
->memblockq
));
2902 pa_tagstruct_puts64(reply
, pa_memblockq_get_read_index(s
->memblockq
));
2903 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2906 static void command_create_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2907 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2910 const char *name
= NULL
;
2913 pa_tagstruct
*reply
;
2916 pa_native_connection_assert_ref(c
);
2919 if (pa_tagstruct_gets(t
, &name
) < 0 ||
2920 pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
2921 pa_tagstruct_get_channel_map(t
, &map
) < 0 ||
2922 pa_tagstruct_getu32(t
, &length
) < 0) {
2927 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2928 CHECK_VALIDITY(c
->pstream
, pa_sample_spec_valid(&ss
), tag
, PA_ERR_INVALID
);
2929 CHECK_VALIDITY(c
->pstream
, pa_channel_map_valid(&map
), tag
, PA_ERR_INVALID
);
2930 CHECK_VALIDITY(c
->pstream
, map
.channels
== ss
.channels
, tag
, PA_ERR_INVALID
);
2931 CHECK_VALIDITY(c
->pstream
, (length
% pa_frame_size(&ss
)) == 0 && length
> 0, tag
, PA_ERR_INVALID
);
2932 CHECK_VALIDITY(c
->pstream
, length
<= PA_SCACHE_ENTRY_SIZE_MAX
, tag
, PA_ERR_TOOLARGE
);
2934 p
= pa_proplist_new();
2936 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
2937 !pa_tagstruct_eof(t
)) {
2940 pa_proplist_free(p
);
2944 if (c
->version
< 13)
2945 pa_proplist_sets(p
, PA_PROP_MEDIA_NAME
, name
);
2947 if (!(name
= pa_proplist_gets(p
, PA_PROP_EVENT_ID
)))
2948 name
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
);
2950 if (!name
|| !pa_namereg_is_valid_name(name
)) {
2951 pa_proplist_free(p
);
2952 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
2955 s
= upload_stream_new(c
, &ss
, &map
, name
, length
, p
);
2956 pa_proplist_free(p
);
2958 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_INVALID
);
2960 reply
= reply_new(tag
);
2961 pa_tagstruct_putu32(reply
, s
->index
);
2962 pa_tagstruct_putu32(reply
, length
);
2963 pa_pstream_send_tagstruct(c
->pstream
, reply
);
2966 static void command_finish_upload_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2967 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2972 pa_native_connection_assert_ref(c
);
2975 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
2976 !pa_tagstruct_eof(t
)) {
2981 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
2983 s
= pa_idxset_get_by_index(c
->output_streams
, channel
);
2984 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
2985 CHECK_VALIDITY(c
->pstream
, upload_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
2987 if (!s
->memchunk
.memblock
)
2988 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_TOOLARGE
);
2989 else if (pa_scache_add_item(c
->protocol
->core
, s
->name
, &s
->sample_spec
, &s
->channel_map
, &s
->memchunk
, s
->proplist
, &idx
) < 0)
2990 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INTERNAL
);
2992 pa_pstream_send_simple_ack(c
->pstream
, tag
);
2994 upload_stream_unlink(s
);
2997 static void command_play_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
2998 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
2999 uint32_t sink_index
;
3002 const char *name
, *sink_name
;
3005 pa_tagstruct
*reply
;
3007 pa_native_connection_assert_ref(c
);
3010 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3012 if (pa_tagstruct_getu32(t
, &sink_index
) < 0 ||
3013 pa_tagstruct_gets(t
, &sink_name
) < 0 ||
3014 pa_tagstruct_getu32(t
, &volume
) < 0 ||
3015 pa_tagstruct_gets(t
, &name
) < 0) {
3020 CHECK_VALIDITY(c
->pstream
, !sink_name
|| pa_namereg_is_valid_name_or_wildcard(sink_name
, PA_NAMEREG_SINK
), tag
, PA_ERR_INVALID
);
3021 CHECK_VALIDITY(c
->pstream
, sink_index
== PA_INVALID_INDEX
|| !sink_name
, tag
, PA_ERR_INVALID
);
3022 CHECK_VALIDITY(c
->pstream
, !sink_name
|| sink_index
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3023 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3025 if (sink_index
!= PA_INVALID_INDEX
)
3026 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, sink_index
);
3028 sink
= pa_namereg_get(c
->protocol
->core
, sink_name
, PA_NAMEREG_SINK
);
3030 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
3032 p
= pa_proplist_new();
3034 if ((c
->version
>= 13 && pa_tagstruct_get_proplist(t
, p
) < 0) ||
3035 !pa_tagstruct_eof(t
)) {
3037 pa_proplist_free(p
);
3041 pa_proplist_update(p
, PA_UPDATE_MERGE
, c
->client
->proplist
);
3043 if (pa_scache_play_item(c
->protocol
->core
, name
, sink
, volume
, p
, &idx
) < 0) {
3044 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3045 pa_proplist_free(p
);
3049 pa_proplist_free(p
);
3051 reply
= reply_new(tag
);
3053 if (c
->version
>= 13)
3054 pa_tagstruct_putu32(reply
, idx
);
3056 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3059 static void command_remove_sample(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3060 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3063 pa_native_connection_assert_ref(c
);
3066 if (pa_tagstruct_gets(t
, &name
) < 0 ||
3067 !pa_tagstruct_eof(t
)) {
3072 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3073 CHECK_VALIDITY(c
->pstream
, name
&& pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3075 if (pa_scache_remove_item(c
->protocol
->core
, name
) < 0) {
3076 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3080 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3083 static void fixup_sample_spec(pa_native_connection
*c
, pa_sample_spec
*fixed
, const pa_sample_spec
*original
) {
3086 pa_assert(original
);
3090 if (c
->version
< 12) {
3091 /* Before protocol version 12 we didn't support S32 samples,
3092 * so we need to lie about this to the client */
3094 if (fixed
->format
== PA_SAMPLE_S32LE
)
3095 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3096 if (fixed
->format
== PA_SAMPLE_S32BE
)
3097 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3100 if (c
->version
< 15) {
3101 if (fixed
->format
== PA_SAMPLE_S24LE
|| fixed
->format
== PA_SAMPLE_S24_32LE
)
3102 fixed
->format
= PA_SAMPLE_FLOAT32LE
;
3103 if (fixed
->format
== PA_SAMPLE_S24BE
|| fixed
->format
== PA_SAMPLE_S24_32BE
)
3104 fixed
->format
= PA_SAMPLE_FLOAT32BE
;
3108 static void sink_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink
*sink
) {
3109 pa_sample_spec fixed_ss
;
3112 pa_sink_assert_ref(sink
);
3114 fixup_sample_spec(c
, &fixed_ss
, &sink
->sample_spec
);
3118 PA_TAG_U32
, sink
->index
,
3119 PA_TAG_STRING
, sink
->name
,
3120 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(sink
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3121 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3122 PA_TAG_CHANNEL_MAP
, &sink
->channel_map
,
3123 PA_TAG_U32
, sink
->module
? sink
->module
->index
: PA_INVALID_INDEX
,
3124 PA_TAG_CVOLUME
, pa_sink_get_volume(sink
, FALSE
),
3125 PA_TAG_BOOLEAN
, pa_sink_get_mute(sink
, FALSE
),
3126 PA_TAG_U32
, sink
->monitor_source
? sink
->monitor_source
->index
: PA_INVALID_INDEX
,
3127 PA_TAG_STRING
, sink
->monitor_source
? sink
->monitor_source
->name
: NULL
,
3128 PA_TAG_USEC
, pa_sink_get_latency(sink
),
3129 PA_TAG_STRING
, sink
->driver
,
3130 PA_TAG_U32
, sink
->flags
& PA_SINK_CLIENT_FLAGS_MASK
,
3133 if (c
->version
>= 13) {
3134 pa_tagstruct_put_proplist(t
, sink
->proplist
);
3135 pa_tagstruct_put_usec(t
, pa_sink_get_requested_latency(sink
));
3138 if (c
->version
>= 15) {
3139 pa_tagstruct_put_volume(t
, sink
->base_volume
);
3140 if (PA_UNLIKELY(pa_sink_get_state(sink
) == PA_SINK_INVALID_STATE
))
3141 pa_log_error("Internal sink state is invalid.");
3142 pa_tagstruct_putu32(t
, pa_sink_get_state(sink
));
3143 pa_tagstruct_putu32(t
, sink
->n_volume_steps
);
3144 pa_tagstruct_putu32(t
, sink
->card
? sink
->card
->index
: PA_INVALID_INDEX
);
3147 if (c
->version
>= 16) {
3151 pa_tagstruct_putu32(t
, pa_hashmap_size(sink
->ports
));
3153 PA_HASHMAP_FOREACH(p
, sink
->ports
, state
) {
3154 pa_tagstruct_puts(t
, p
->name
);
3155 pa_tagstruct_puts(t
, p
->description
);
3156 pa_tagstruct_putu32(t
, p
->priority
);
3157 if (c
->version
>= 24)
3158 pa_tagstruct_putu32(t
, p
->available
);
3161 pa_tagstruct_puts(t
, sink
->active_port
? sink
->active_port
->name
: NULL
);
3164 if (c
->version
>= 21) {
3167 pa_idxset
*formats
= pa_sink_get_formats(sink
);
3169 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3170 PA_IDXSET_FOREACH(f
, formats
, i
) {
3171 pa_tagstruct_put_format_info(t
, f
);
3174 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
3178 static void source_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source
*source
) {
3179 pa_sample_spec fixed_ss
;
3182 pa_source_assert_ref(source
);
3184 fixup_sample_spec(c
, &fixed_ss
, &source
->sample_spec
);
3188 PA_TAG_U32
, source
->index
,
3189 PA_TAG_STRING
, source
->name
,
3190 PA_TAG_STRING
, pa_strnull(pa_proplist_gets(source
->proplist
, PA_PROP_DEVICE_DESCRIPTION
)),
3191 PA_TAG_SAMPLE_SPEC
, &fixed_ss
,
3192 PA_TAG_CHANNEL_MAP
, &source
->channel_map
,
3193 PA_TAG_U32
, source
->module
? source
->module
->index
: PA_INVALID_INDEX
,
3194 PA_TAG_CVOLUME
, pa_source_get_volume(source
, FALSE
),
3195 PA_TAG_BOOLEAN
, pa_source_get_mute(source
, FALSE
),
3196 PA_TAG_U32
, source
->monitor_of
? source
->monitor_of
->index
: PA_INVALID_INDEX
,
3197 PA_TAG_STRING
, source
->monitor_of
? source
->monitor_of
->name
: NULL
,
3198 PA_TAG_USEC
, pa_source_get_latency(source
),
3199 PA_TAG_STRING
, source
->driver
,
3200 PA_TAG_U32
, source
->flags
& PA_SOURCE_CLIENT_FLAGS_MASK
,
3203 if (c
->version
>= 13) {
3204 pa_tagstruct_put_proplist(t
, source
->proplist
);
3205 pa_tagstruct_put_usec(t
, pa_source_get_requested_latency(source
));
3208 if (c
->version
>= 15) {
3209 pa_tagstruct_put_volume(t
, source
->base_volume
);
3210 if (PA_UNLIKELY(pa_source_get_state(source
) == PA_SOURCE_INVALID_STATE
))
3211 pa_log_error("Internal source state is invalid.");
3212 pa_tagstruct_putu32(t
, pa_source_get_state(source
));
3213 pa_tagstruct_putu32(t
, source
->n_volume_steps
);
3214 pa_tagstruct_putu32(t
, source
->card
? source
->card
->index
: PA_INVALID_INDEX
);
3217 if (c
->version
>= 16) {
3221 pa_tagstruct_putu32(t
, pa_hashmap_size(source
->ports
));
3223 PA_HASHMAP_FOREACH(p
, source
->ports
, state
) {
3224 pa_tagstruct_puts(t
, p
->name
);
3225 pa_tagstruct_puts(t
, p
->description
);
3226 pa_tagstruct_putu32(t
, p
->priority
);
3227 if (c
->version
>= 24)
3228 pa_tagstruct_putu32(t
, p
->available
);
3231 pa_tagstruct_puts(t
, source
->active_port
? source
->active_port
->name
: NULL
);
3234 if (c
->version
>= 22) {
3237 pa_idxset
*formats
= pa_source_get_formats(source
);
3239 pa_tagstruct_putu8(t
, (uint8_t) pa_idxset_size(formats
));
3240 PA_IDXSET_FOREACH(f
, formats
, i
) {
3241 pa_tagstruct_put_format_info(t
, f
);
3244 pa_idxset_free(formats
, (pa_free_cb_t
) pa_format_info_free
);
3248 static void client_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_client
*client
) {
3252 pa_tagstruct_putu32(t
, client
->index
);
3253 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(client
->proplist
, PA_PROP_APPLICATION_NAME
)));
3254 pa_tagstruct_putu32(t
, client
->module
? client
->module
->index
: PA_INVALID_INDEX
);
3255 pa_tagstruct_puts(t
, client
->driver
);
3257 if (c
->version
>= 13)
3258 pa_tagstruct_put_proplist(t
, client
->proplist
);
3261 static void card_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_card
*card
) {
3264 pa_device_port
*port
;
3269 pa_tagstruct_putu32(t
, card
->index
);
3270 pa_tagstruct_puts(t
, card
->name
);
3271 pa_tagstruct_putu32(t
, card
->module
? card
->module
->index
: PA_INVALID_INDEX
);
3272 pa_tagstruct_puts(t
, card
->driver
);
3274 pa_tagstruct_putu32(t
, pa_hashmap_size(card
->profiles
));
3276 PA_HASHMAP_FOREACH(p
, card
->profiles
, state
) {
3277 pa_tagstruct_puts(t
, p
->name
);
3278 pa_tagstruct_puts(t
, p
->description
);
3279 pa_tagstruct_putu32(t
, p
->n_sinks
);
3280 pa_tagstruct_putu32(t
, p
->n_sources
);
3281 pa_tagstruct_putu32(t
, p
->priority
);
3284 pa_tagstruct_puts(t
, card
->active_profile
->name
);
3285 pa_tagstruct_put_proplist(t
, card
->proplist
);
3287 if (c
->version
< 26)
3290 pa_tagstruct_putu32(t
, pa_hashmap_size(card
->ports
));
3292 PA_HASHMAP_FOREACH(port
, card
->ports
, state
) {
3295 pa_tagstruct_puts(t
, port
->name
);
3296 pa_tagstruct_puts(t
, port
->description
);
3297 pa_tagstruct_putu32(t
, port
->priority
);
3298 pa_tagstruct_putu32(t
, port
->available
);
3299 pa_tagstruct_putu8(t
, /* FIXME: port->direction */ (port
->is_input
? PA_DIRECTION_INPUT
: 0) | (port
->is_output
? PA_DIRECTION_OUTPUT
: 0));
3300 pa_tagstruct_put_proplist(t
, port
->proplist
);
3302 pa_tagstruct_putu32(t
, pa_hashmap_size(port
->profiles
));
3304 PA_HASHMAP_FOREACH(p
, port
->profiles
, state2
)
3305 pa_tagstruct_puts(t
, p
->name
);
3307 if (c
->version
>= 27)
3308 pa_tagstruct_puts64(t
, port
->latency_offset
);
3312 static void module_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_module
*module
) {
3316 pa_tagstruct_putu32(t
, module
->index
);
3317 pa_tagstruct_puts(t
, module
->name
);
3318 pa_tagstruct_puts(t
, module
->argument
);
3319 pa_tagstruct_putu32(t
, (uint32_t) pa_module_get_n_used(module
));
3321 if (c
->version
< 15)
3322 pa_tagstruct_put_boolean(t
, FALSE
); /* autoload is obsolete */
3324 if (c
->version
>= 15)
3325 pa_tagstruct_put_proplist(t
, module
->proplist
);
3328 static void sink_input_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_sink_input
*s
) {
3329 pa_sample_spec fixed_ss
;
3330 pa_usec_t sink_latency
;
3332 pa_bool_t has_volume
= FALSE
;
3335 pa_sink_input_assert_ref(s
);
3337 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3339 has_volume
= pa_sink_input_is_volume_readable(s
);
3341 pa_sink_input_get_volume(s
, &v
, TRUE
);
3343 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3345 pa_tagstruct_putu32(t
, s
->index
);
3346 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3347 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3348 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3349 pa_tagstruct_putu32(t
, s
->sink
->index
);
3350 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3351 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3352 pa_tagstruct_put_cvolume(t
, &v
);
3353 pa_tagstruct_put_usec(t
, pa_sink_input_get_latency(s
, &sink_latency
));
3354 pa_tagstruct_put_usec(t
, sink_latency
);
3355 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_sink_input_get_resample_method(s
)));
3356 pa_tagstruct_puts(t
, s
->driver
);
3357 if (c
->version
>= 11)
3358 pa_tagstruct_put_boolean(t
, pa_sink_input_get_mute(s
));
3359 if (c
->version
>= 13)
3360 pa_tagstruct_put_proplist(t
, s
->proplist
);
3361 if (c
->version
>= 19)
3362 pa_tagstruct_put_boolean(t
, (pa_sink_input_get_state(s
) == PA_SINK_INPUT_CORKED
));
3363 if (c
->version
>= 20) {
3364 pa_tagstruct_put_boolean(t
, has_volume
);
3365 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3367 if (c
->version
>= 21)
3368 pa_tagstruct_put_format_info(t
, s
->format
);
3371 static void source_output_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_source_output
*s
) {
3372 pa_sample_spec fixed_ss
;
3373 pa_usec_t source_latency
;
3375 pa_bool_t has_volume
= FALSE
;
3378 pa_source_output_assert_ref(s
);
3380 fixup_sample_spec(c
, &fixed_ss
, &s
->sample_spec
);
3382 has_volume
= pa_source_output_is_volume_readable(s
);
3384 pa_source_output_get_volume(s
, &v
, TRUE
);
3386 pa_cvolume_reset(&v
, fixed_ss
.channels
);
3388 pa_tagstruct_putu32(t
, s
->index
);
3389 pa_tagstruct_puts(t
, pa_strnull(pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
)));
3390 pa_tagstruct_putu32(t
, s
->module
? s
->module
->index
: PA_INVALID_INDEX
);
3391 pa_tagstruct_putu32(t
, s
->client
? s
->client
->index
: PA_INVALID_INDEX
);
3392 pa_tagstruct_putu32(t
, s
->source
->index
);
3393 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3394 pa_tagstruct_put_channel_map(t
, &s
->channel_map
);
3395 pa_tagstruct_put_usec(t
, pa_source_output_get_latency(s
, &source_latency
));
3396 pa_tagstruct_put_usec(t
, source_latency
);
3397 pa_tagstruct_puts(t
, pa_resample_method_to_string(pa_source_output_get_resample_method(s
)));
3398 pa_tagstruct_puts(t
, s
->driver
);
3399 if (c
->version
>= 13)
3400 pa_tagstruct_put_proplist(t
, s
->proplist
);
3401 if (c
->version
>= 19)
3402 pa_tagstruct_put_boolean(t
, (pa_source_output_get_state(s
) == PA_SOURCE_OUTPUT_CORKED
));
3403 if (c
->version
>= 22) {
3404 pa_tagstruct_put_cvolume(t
, &v
);
3405 pa_tagstruct_put_boolean(t
, pa_source_output_get_mute(s
));
3406 pa_tagstruct_put_boolean(t
, has_volume
);
3407 pa_tagstruct_put_boolean(t
, s
->volume_writable
);
3408 pa_tagstruct_put_format_info(t
, s
->format
);
3412 static void scache_fill_tagstruct(pa_native_connection
*c
, pa_tagstruct
*t
, pa_scache_entry
*e
) {
3413 pa_sample_spec fixed_ss
;
3419 if (e
->memchunk
.memblock
)
3420 fixup_sample_spec(c
, &fixed_ss
, &e
->sample_spec
);
3422 memset(&fixed_ss
, 0, sizeof(fixed_ss
));
3424 pa_tagstruct_putu32(t
, e
->index
);
3425 pa_tagstruct_puts(t
, e
->name
);
3427 if (e
->volume_is_set
)
3430 pa_cvolume_init(&v
);
3432 pa_tagstruct_put_cvolume(t
, &v
);
3433 pa_tagstruct_put_usec(t
, e
->memchunk
.memblock
? pa_bytes_to_usec(e
->memchunk
.length
, &e
->sample_spec
) : 0);
3434 pa_tagstruct_put_sample_spec(t
, &fixed_ss
);
3435 pa_tagstruct_put_channel_map(t
, &e
->channel_map
);
3436 pa_tagstruct_putu32(t
, (uint32_t) e
->memchunk
.length
);
3437 pa_tagstruct_put_boolean(t
, e
->lazy
);
3438 pa_tagstruct_puts(t
, e
->filename
);
3440 if (c
->version
>= 13)
3441 pa_tagstruct_put_proplist(t
, e
->proplist
);
3444 static void command_get_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3445 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3447 pa_sink
*sink
= NULL
;
3448 pa_source
*source
= NULL
;
3449 pa_client
*client
= NULL
;
3450 pa_card
*card
= NULL
;
3451 pa_module
*module
= NULL
;
3452 pa_sink_input
*si
= NULL
;
3453 pa_source_output
*so
= NULL
;
3454 pa_scache_entry
*sce
= NULL
;
3455 const char *name
= NULL
;
3456 pa_tagstruct
*reply
;
3458 pa_native_connection_assert_ref(c
);
3461 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3462 (command
!= PA_COMMAND_GET_CLIENT_INFO
&&
3463 command
!= PA_COMMAND_GET_MODULE_INFO
&&
3464 command
!= PA_COMMAND_GET_SINK_INPUT_INFO
&&
3465 command
!= PA_COMMAND_GET_SOURCE_OUTPUT_INFO
&&
3466 pa_tagstruct_gets(t
, &name
) < 0) ||
3467 !pa_tagstruct_eof(t
)) {
3472 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3473 CHECK_VALIDITY(c
->pstream
, !name
||
3474 (command
== PA_COMMAND_GET_SINK_INFO
&&
3475 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SINK
)) ||
3476 (command
== PA_COMMAND_GET_SOURCE_INFO
&&
3477 pa_namereg_is_valid_name_or_wildcard(name
, PA_NAMEREG_SOURCE
)) ||
3478 pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
3479 CHECK_VALIDITY(c
->pstream
, command
== PA_COMMAND_GET_SINK_INFO
||
3480 command
== PA_COMMAND_GET_SOURCE_INFO
||
3481 (idx
!= PA_INVALID_INDEX
|| name
), tag
, PA_ERR_INVALID
);
3482 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3483 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3485 if (command
== PA_COMMAND_GET_SINK_INFO
) {
3486 if (idx
!= PA_INVALID_INDEX
)
3487 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3489 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3490 } else if (command
== PA_COMMAND_GET_SOURCE_INFO
) {
3491 if (idx
!= PA_INVALID_INDEX
)
3492 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3494 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3495 } else if (command
== PA_COMMAND_GET_CARD_INFO
) {
3496 if (idx
!= PA_INVALID_INDEX
)
3497 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
3499 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
3500 } else if (command
== PA_COMMAND_GET_CLIENT_INFO
)
3501 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
3502 else if (command
== PA_COMMAND_GET_MODULE_INFO
)
3503 module
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
3504 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO
)
3505 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3506 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO
)
3507 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3509 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO
);
3510 if (idx
!= PA_INVALID_INDEX
)
3511 sce
= pa_idxset_get_by_index(c
->protocol
->core
->scache
, idx
);
3513 sce
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SAMPLE
);
3516 if (!sink
&& !source
&& !client
&& !card
&& !module
&& !si
&& !so
&& !sce
) {
3517 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_NOENTITY
);
3521 reply
= reply_new(tag
);
3523 sink_fill_tagstruct(c
, reply
, sink
);
3525 source_fill_tagstruct(c
, reply
, source
);
3527 client_fill_tagstruct(c
, reply
, client
);
3529 card_fill_tagstruct(c
, reply
, card
);
3531 module_fill_tagstruct(c
, reply
, module
);
3533 sink_input_fill_tagstruct(c
, reply
, si
);
3535 source_output_fill_tagstruct(c
, reply
, so
);
3537 scache_fill_tagstruct(c
, reply
, sce
);
3538 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3541 static void command_get_info_list(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3542 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3546 pa_tagstruct
*reply
;
3548 pa_native_connection_assert_ref(c
);
3551 if (!pa_tagstruct_eof(t
)) {
3556 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3558 reply
= reply_new(tag
);
3560 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3561 i
= c
->protocol
->core
->sinks
;
3562 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3563 i
= c
->protocol
->core
->sources
;
3564 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3565 i
= c
->protocol
->core
->clients
;
3566 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3567 i
= c
->protocol
->core
->cards
;
3568 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3569 i
= c
->protocol
->core
->modules
;
3570 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3571 i
= c
->protocol
->core
->sink_inputs
;
3572 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3573 i
= c
->protocol
->core
->source_outputs
;
3575 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3576 i
= c
->protocol
->core
->scache
;
3580 PA_IDXSET_FOREACH(p
, i
, idx
) {
3581 if (command
== PA_COMMAND_GET_SINK_INFO_LIST
)
3582 sink_fill_tagstruct(c
, reply
, p
);
3583 else if (command
== PA_COMMAND_GET_SOURCE_INFO_LIST
)
3584 source_fill_tagstruct(c
, reply
, p
);
3585 else if (command
== PA_COMMAND_GET_CLIENT_INFO_LIST
)
3586 client_fill_tagstruct(c
, reply
, p
);
3587 else if (command
== PA_COMMAND_GET_CARD_INFO_LIST
)
3588 card_fill_tagstruct(c
, reply
, p
);
3589 else if (command
== PA_COMMAND_GET_MODULE_INFO_LIST
)
3590 module_fill_tagstruct(c
, reply
, p
);
3591 else if (command
== PA_COMMAND_GET_SINK_INPUT_INFO_LIST
)
3592 sink_input_fill_tagstruct(c
, reply
, p
);
3593 else if (command
== PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST
)
3594 source_output_fill_tagstruct(c
, reply
, p
);
3596 pa_assert(command
== PA_COMMAND_GET_SAMPLE_INFO_LIST
);
3597 scache_fill_tagstruct(c
, reply
, p
);
3602 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3605 static void command_get_server_info(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3606 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3607 pa_tagstruct
*reply
;
3609 pa_source
*def_source
;
3610 pa_sample_spec fixed_ss
;
3613 pa_native_connection_assert_ref(c
);
3616 if (!pa_tagstruct_eof(t
)) {
3621 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3623 reply
= reply_new(tag
);
3624 pa_tagstruct_puts(reply
, PACKAGE_NAME
);
3625 pa_tagstruct_puts(reply
, PACKAGE_VERSION
);
3627 u
= pa_get_user_name_malloc();
3628 pa_tagstruct_puts(reply
, u
);
3631 h
= pa_get_host_name_malloc();
3632 pa_tagstruct_puts(reply
, h
);
3635 fixup_sample_spec(c
, &fixed_ss
, &c
->protocol
->core
->default_sample_spec
);
3636 pa_tagstruct_put_sample_spec(reply
, &fixed_ss
);
3638 def_sink
= pa_namereg_get_default_sink(c
->protocol
->core
);
3639 pa_tagstruct_puts(reply
, def_sink
? def_sink
->name
: NULL
);
3640 def_source
= pa_namereg_get_default_source(c
->protocol
->core
);
3641 pa_tagstruct_puts(reply
, def_source
? def_source
->name
: NULL
);
3643 pa_tagstruct_putu32(reply
, c
->protocol
->core
->cookie
);
3645 if (c
->version
>= 15)
3646 pa_tagstruct_put_channel_map(reply
, &c
->protocol
->core
->default_channel_map
);
3648 pa_pstream_send_tagstruct(c
->pstream
, reply
);
3651 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t e
, uint32_t idx
, void *userdata
) {
3653 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3655 pa_native_connection_assert_ref(c
);
3657 t
= pa_tagstruct_new(NULL
, 0);
3658 pa_tagstruct_putu32(t
, PA_COMMAND_SUBSCRIBE_EVENT
);
3659 pa_tagstruct_putu32(t
, (uint32_t) -1);
3660 pa_tagstruct_putu32(t
, e
);
3661 pa_tagstruct_putu32(t
, idx
);
3662 pa_pstream_send_tagstruct(c
->pstream
, t
);
3665 static void command_subscribe(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3666 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3667 pa_subscription_mask_t m
;
3669 pa_native_connection_assert_ref(c
);
3672 if (pa_tagstruct_getu32(t
, &m
) < 0 ||
3673 !pa_tagstruct_eof(t
)) {
3678 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3679 CHECK_VALIDITY(c
->pstream
, (m
& ~PA_SUBSCRIPTION_MASK_ALL
) == 0, tag
, PA_ERR_INVALID
);
3681 if (c
->subscription
)
3682 pa_subscription_free(c
->subscription
);
3685 c
->subscription
= pa_subscription_new(c
->protocol
->core
, m
, subscription_cb
, c
);
3686 pa_assert(c
->subscription
);
3688 c
->subscription
= NULL
;
3690 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3693 static void command_set_volume(
3700 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3703 pa_sink
*sink
= NULL
;
3704 pa_source
*source
= NULL
;
3705 pa_sink_input
*si
= NULL
;
3706 pa_source_output
*so
= NULL
;
3707 const char *name
= NULL
;
3708 const char *client_name
;
3710 pa_native_connection_assert_ref(c
);
3713 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3714 (command
== PA_COMMAND_SET_SINK_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3715 (command
== PA_COMMAND_SET_SOURCE_VOLUME
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3716 pa_tagstruct_get_cvolume(t
, &volume
) ||
3717 !pa_tagstruct_eof(t
)) {
3722 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3723 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
);
3724 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3725 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3726 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3727 CHECK_VALIDITY(c
->pstream
, pa_cvolume_valid(&volume
), tag
, PA_ERR_INVALID
);
3731 case PA_COMMAND_SET_SINK_VOLUME
:
3732 if (idx
!= PA_INVALID_INDEX
)
3733 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3735 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3738 case PA_COMMAND_SET_SOURCE_VOLUME
:
3739 if (idx
!= PA_INVALID_INDEX
)
3740 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3742 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3745 case PA_COMMAND_SET_SINK_INPUT_VOLUME
:
3746 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3749 case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME
:
3750 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3754 pa_assert_not_reached();
3757 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3759 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3762 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &sink
->sample_spec
), tag
, PA_ERR_INVALID
);
3764 pa_log_debug("Client %s changes volume of sink %s.", client_name
, sink
->name
);
3765 pa_sink_set_volume(sink
, &volume
, TRUE
, TRUE
);
3766 } else if (source
) {
3767 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &source
->sample_spec
), tag
, PA_ERR_INVALID
);
3769 pa_log_debug("Client %s changes volume of source %s.", client_name
, source
->name
);
3770 pa_source_set_volume(source
, &volume
, TRUE
, TRUE
);
3772 CHECK_VALIDITY(c
->pstream
, si
->volume_writable
, tag
, PA_ERR_BADSTATE
);
3773 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &si
->sample_spec
), tag
, PA_ERR_INVALID
);
3775 pa_log_debug("Client %s changes volume of sink input %s.",
3777 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3778 pa_sink_input_set_volume(si
, &volume
, TRUE
, TRUE
);
3780 CHECK_VALIDITY(c
->pstream
, volume
.channels
== 1 || pa_cvolume_compatible(&volume
, &so
->sample_spec
), tag
, PA_ERR_INVALID
);
3782 pa_log_debug("Client %s changes volume of source output %s.",
3784 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3785 pa_source_output_set_volume(so
, &volume
, TRUE
, TRUE
);
3788 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3791 static void command_set_mute(
3798 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3801 pa_sink
*sink
= NULL
;
3802 pa_source
*source
= NULL
;
3803 pa_sink_input
*si
= NULL
;
3804 pa_source_output
*so
= NULL
;
3805 const char *name
= NULL
, *client_name
;
3807 pa_native_connection_assert_ref(c
);
3810 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3811 (command
== PA_COMMAND_SET_SINK_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3812 (command
== PA_COMMAND_SET_SOURCE_MUTE
&& pa_tagstruct_gets(t
, &name
) < 0) ||
3813 pa_tagstruct_get_boolean(t
, &mute
) ||
3814 !pa_tagstruct_eof(t
)) {
3819 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3820 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
);
3821 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
3822 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
3823 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3827 case PA_COMMAND_SET_SINK_MUTE
:
3828 if (idx
!= PA_INVALID_INDEX
)
3829 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
3831 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
3835 case PA_COMMAND_SET_SOURCE_MUTE
:
3836 if (idx
!= PA_INVALID_INDEX
)
3837 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
3839 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
3843 case PA_COMMAND_SET_SINK_INPUT_MUTE
:
3844 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
3847 case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE
:
3848 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
3852 pa_assert_not_reached();
3855 CHECK_VALIDITY(c
->pstream
, si
|| so
|| sink
|| source
, tag
, PA_ERR_NOENTITY
);
3857 client_name
= pa_strnull(pa_proplist_gets(c
->client
->proplist
, PA_PROP_APPLICATION_PROCESS_BINARY
));
3860 pa_log_debug("Client %s changes mute of sink %s.", client_name
, sink
->name
);
3861 pa_sink_set_mute(sink
, mute
, TRUE
);
3862 } else if (source
) {
3863 pa_log_debug("Client %s changes mute of source %s.", client_name
, source
->name
);
3864 pa_source_set_mute(source
, mute
, TRUE
);
3866 pa_log_debug("Client %s changes mute of sink input %s.",
3868 pa_strnull(pa_proplist_gets(si
->proplist
, PA_PROP_MEDIA_NAME
)));
3869 pa_sink_input_set_mute(si
, mute
, TRUE
);
3871 pa_log_debug("Client %s changes mute of source output %s.",
3873 pa_strnull(pa_proplist_gets(so
->proplist
, PA_PROP_MEDIA_NAME
)));
3874 pa_source_output_set_mute(so
, mute
, TRUE
);
3877 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3880 static void command_cork_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3881 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3886 pa_native_connection_assert_ref(c
);
3889 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3890 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3891 !pa_tagstruct_eof(t
)) {
3896 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3897 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3898 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3899 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3900 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3902 pa_sink_input_cork(s
->sink_input
, b
);
3905 s
->is_underrun
= TRUE
;
3907 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3910 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3911 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3915 pa_native_connection_assert_ref(c
);
3918 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3919 !pa_tagstruct_eof(t
)) {
3924 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3925 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
3926 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
3927 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3928 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
3931 case PA_COMMAND_FLUSH_PLAYBACK_STREAM
:
3932 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_FLUSH
, NULL
, 0, NULL
);
3935 case PA_COMMAND_PREBUF_PLAYBACK_STREAM
:
3936 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_PREBUF_FORCE
, NULL
, 0, NULL
);
3939 case PA_COMMAND_TRIGGER_PLAYBACK_STREAM
:
3940 pa_asyncmsgq_send(s
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(s
->sink_input
), SINK_INPUT_MESSAGE_TRIGGER
, NULL
, 0, NULL
);
3944 pa_assert_not_reached();
3947 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3950 static void command_cork_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3951 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3956 pa_native_connection_assert_ref(c
);
3959 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3960 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
3961 !pa_tagstruct_eof(t
)) {
3966 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3967 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3968 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3970 pa_source_output_cork(s
->source_output
, b
);
3971 pa_memblockq_prebuf_force(s
->memblockq
);
3972 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3975 static void command_flush_record_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3976 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
3980 pa_native_connection_assert_ref(c
);
3983 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
3984 !pa_tagstruct_eof(t
)) {
3989 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
3990 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
3991 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
3993 pa_memblockq_flush_read(s
->memblockq
);
3994 pa_pstream_send_simple_ack(c
->pstream
, tag
);
3997 static void command_set_stream_buffer_attr(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
3998 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4001 pa_tagstruct
*reply
;
4003 pa_native_connection_assert_ref(c
);
4006 memset(&a
, 0, sizeof(a
));
4008 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
4013 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4015 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
) {
4017 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
4019 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4020 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4021 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4023 if (pa_tagstruct_get(
4025 PA_TAG_U32
, &a
.maxlength
,
4026 PA_TAG_U32
, &a
.tlength
,
4027 PA_TAG_U32
, &a
.prebuf
,
4028 PA_TAG_U32
, &a
.minreq
,
4029 PA_TAG_INVALID
) < 0 ||
4030 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
4031 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
4032 !pa_tagstruct_eof(t
)) {
4037 s
->adjust_latency
= adjust_latency
;
4038 s
->early_requests
= early_requests
;
4039 s
->buffer_attr_req
= a
;
4041 fix_playback_buffer_attr(s
);
4042 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);
4044 reply
= reply_new(tag
);
4045 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
4046 pa_tagstruct_putu32(reply
, s
->buffer_attr
.tlength
);
4047 pa_tagstruct_putu32(reply
, s
->buffer_attr
.prebuf
);
4048 pa_tagstruct_putu32(reply
, s
->buffer_attr
.minreq
);
4050 if (c
->version
>= 13)
4051 pa_tagstruct_put_usec(reply
, s
->configured_sink_latency
);
4055 pa_bool_t adjust_latency
= FALSE
, early_requests
= FALSE
;
4056 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
);
4058 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4059 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4061 if (pa_tagstruct_get(
4063 PA_TAG_U32
, &a
.maxlength
,
4064 PA_TAG_U32
, &a
.fragsize
,
4065 PA_TAG_INVALID
) < 0 ||
4066 (c
->version
>= 13 && pa_tagstruct_get_boolean(t
, &adjust_latency
) < 0) ||
4067 (c
->version
>= 14 && pa_tagstruct_get_boolean(t
, &early_requests
) < 0) ||
4068 !pa_tagstruct_eof(t
)) {
4073 s
->adjust_latency
= adjust_latency
;
4074 s
->early_requests
= early_requests
;
4075 s
->buffer_attr_req
= a
;
4077 fix_record_buffer_attr_pre(s
);
4078 pa_memblockq_set_maxlength(s
->memblockq
, s
->buffer_attr
.maxlength
);
4079 pa_memblockq_get_attr(s
->memblockq
, &s
->buffer_attr
);
4080 fix_record_buffer_attr_post(s
);
4082 reply
= reply_new(tag
);
4083 pa_tagstruct_putu32(reply
, s
->buffer_attr
.maxlength
);
4084 pa_tagstruct_putu32(reply
, s
->buffer_attr
.fragsize
);
4086 if (c
->version
>= 13)
4087 pa_tagstruct_put_usec(reply
, s
->configured_source_latency
);
4090 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4093 static void command_update_stream_sample_rate(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4094 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4098 pa_native_connection_assert_ref(c
);
4101 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4102 pa_tagstruct_getu32(t
, &rate
) < 0 ||
4103 !pa_tagstruct_eof(t
)) {
4108 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4109 CHECK_VALIDITY(c
->pstream
, rate
> 0 && rate
<= PA_RATE_MAX
, tag
, PA_ERR_INVALID
);
4111 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
) {
4114 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4115 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4116 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4118 pa_sink_input_set_rate(s
->sink_input
, rate
);
4122 pa_assert(command
== PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
);
4124 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4125 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4127 pa_source_output_set_rate(s
->source_output
, rate
);
4130 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4133 static void command_update_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4134 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4139 pa_native_connection_assert_ref(c
);
4142 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4144 p
= pa_proplist_new();
4146 if (command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
) {
4148 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
4149 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4150 !pa_tagstruct_eof(t
)) {
4152 pa_proplist_free(p
);
4158 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4159 pa_tagstruct_getu32(t
, &mode
) < 0 ||
4160 pa_tagstruct_get_proplist(t
, p
) < 0 ||
4161 !pa_tagstruct_eof(t
)) {
4163 pa_proplist_free(p
);
4168 if (!(mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
)) {
4169 pa_proplist_free(p
);
4170 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_INVALID
);
4173 if (command
== PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
) {
4176 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4177 if (!s
|| !playback_stream_isinstance(s
)) {
4178 pa_proplist_free(p
);
4179 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4181 pa_sink_input_update_proplist(s
->sink_input
, mode
, p
);
4183 } else if (command
== PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
) {
4186 if (!(s
= pa_idxset_get_by_index(c
->record_streams
, idx
))) {
4187 pa_proplist_free(p
);
4188 CHECK_VALIDITY(c
->pstream
, FALSE
, tag
, PA_ERR_NOENTITY
);
4190 pa_source_output_update_proplist(s
->source_output
, mode
, p
);
4193 pa_assert(command
== PA_COMMAND_UPDATE_CLIENT_PROPLIST
);
4195 pa_client_update_proplist(c
->client
, mode
, p
);
4198 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4199 pa_proplist_free(p
);
4202 static void command_remove_proplist(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4203 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4205 unsigned changed
= 0;
4207 pa_strlist
*l
= NULL
;
4209 pa_native_connection_assert_ref(c
);
4212 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4214 if (command
!= PA_COMMAND_REMOVE_CLIENT_PROPLIST
) {
4216 if (pa_tagstruct_getu32(t
, &idx
) < 0) {
4222 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4225 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4226 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4227 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4229 p
= s
->sink_input
->proplist
;
4231 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4234 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4235 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4237 p
= s
->source_output
->proplist
;
4239 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4241 p
= c
->client
->proplist
;
4247 if (pa_tagstruct_gets(t
, &k
) < 0) {
4256 l
= pa_strlist_prepend(l
, k
);
4259 if (!pa_tagstruct_eof(t
)) {
4268 l
= pa_strlist_pop(l
, &z
);
4273 changed
+= (unsigned) (pa_proplist_unset(p
, z
) >= 0);
4277 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4280 if (command
== PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
) {
4283 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4284 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->sink_input
->index
);
4286 } else if (command
== PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
) {
4289 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4290 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->source_output
->index
);
4293 pa_assert(command
== PA_COMMAND_REMOVE_CLIENT_PROPLIST
);
4294 pa_subscription_post(c
->protocol
->core
, PA_SUBSCRIPTION_EVENT_CLIENT
|PA_SUBSCRIPTION_EVENT_CHANGE
, c
->client
->index
);
4299 static void command_set_default_sink_or_source(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4300 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4303 pa_native_connection_assert_ref(c
);
4306 if (pa_tagstruct_gets(t
, &s
) < 0 ||
4307 !pa_tagstruct_eof(t
)) {
4312 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4313 CHECK_VALIDITY(c
->pstream
, !s
|| pa_namereg_is_valid_name(s
), tag
, PA_ERR_INVALID
);
4315 if (command
== PA_COMMAND_SET_DEFAULT_SOURCE
) {
4318 source
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SOURCE
);
4319 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4321 pa_namereg_set_default_source(c
->protocol
->core
, source
);
4324 pa_assert(command
== PA_COMMAND_SET_DEFAULT_SINK
);
4326 sink
= pa_namereg_get(c
->protocol
->core
, s
, PA_NAMEREG_SINK
);
4327 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4329 pa_namereg_set_default_sink(c
->protocol
->core
, sink
);
4332 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4335 static void command_set_stream_name(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4336 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4340 pa_native_connection_assert_ref(c
);
4343 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4344 pa_tagstruct_gets(t
, &name
) < 0 ||
4345 !pa_tagstruct_eof(t
)) {
4350 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4351 CHECK_VALIDITY(c
->pstream
, name
&& pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4353 if (command
== PA_COMMAND_SET_PLAYBACK_STREAM_NAME
) {
4356 s
= pa_idxset_get_by_index(c
->output_streams
, idx
);
4357 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4358 CHECK_VALIDITY(c
->pstream
, playback_stream_isinstance(s
), tag
, PA_ERR_NOENTITY
);
4360 pa_sink_input_set_name(s
->sink_input
, name
);
4364 pa_assert(command
== PA_COMMAND_SET_RECORD_STREAM_NAME
);
4366 s
= pa_idxset_get_by_index(c
->record_streams
, idx
);
4367 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4369 pa_source_output_set_name(s
->source_output
, name
);
4372 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4375 static void command_kill(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4376 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4379 pa_native_connection_assert_ref(c
);
4382 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4383 !pa_tagstruct_eof(t
)) {
4388 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4390 if (command
== PA_COMMAND_KILL_CLIENT
) {
4393 client
= pa_idxset_get_by_index(c
->protocol
->core
->clients
, idx
);
4394 CHECK_VALIDITY(c
->pstream
, client
, tag
, PA_ERR_NOENTITY
);
4396 pa_native_connection_ref(c
);
4397 pa_client_kill(client
);
4399 } else if (command
== PA_COMMAND_KILL_SINK_INPUT
) {
4402 s
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4403 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4405 pa_native_connection_ref(c
);
4406 pa_sink_input_kill(s
);
4408 pa_source_output
*s
;
4410 pa_assert(command
== PA_COMMAND_KILL_SOURCE_OUTPUT
);
4412 s
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4413 CHECK_VALIDITY(c
->pstream
, s
, tag
, PA_ERR_NOENTITY
);
4415 pa_native_connection_ref(c
);
4416 pa_source_output_kill(s
);
4419 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4420 pa_native_connection_unref(c
);
4423 static void command_load_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4424 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4426 const char *name
, *argument
;
4427 pa_tagstruct
*reply
;
4429 pa_native_connection_assert_ref(c
);
4432 if (pa_tagstruct_gets(t
, &name
) < 0 ||
4433 pa_tagstruct_gets(t
, &argument
) < 0 ||
4434 !pa_tagstruct_eof(t
)) {
4439 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4440 CHECK_VALIDITY(c
->pstream
, name
&& *name
&& pa_utf8_valid(name
) && !strchr(name
, '/'), tag
, PA_ERR_INVALID
);
4441 CHECK_VALIDITY(c
->pstream
, !argument
|| pa_utf8_valid(argument
), tag
, PA_ERR_INVALID
);
4443 if (!(m
= pa_module_load(c
->protocol
->core
, name
, argument
))) {
4444 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_MODINITFAILED
);
4448 reply
= reply_new(tag
);
4449 pa_tagstruct_putu32(reply
, m
->index
);
4450 pa_pstream_send_tagstruct(c
->pstream
, reply
);
4453 static void command_unload_module(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4454 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4458 pa_native_connection_assert_ref(c
);
4461 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4462 !pa_tagstruct_eof(t
)) {
4467 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4468 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4469 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOENTITY
);
4471 pa_module_unload_request(m
, FALSE
);
4472 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4475 static void command_move_stream(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4476 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4477 uint32_t idx
= PA_INVALID_INDEX
, idx_device
= PA_INVALID_INDEX
;
4478 const char *name_device
= NULL
;
4480 pa_native_connection_assert_ref(c
);
4483 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4484 pa_tagstruct_getu32(t
, &idx_device
) < 0 ||
4485 pa_tagstruct_gets(t
, &name_device
) < 0 ||
4486 !pa_tagstruct_eof(t
)) {
4491 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4492 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4494 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
);
4495 CHECK_VALIDITY(c
->pstream
, idx_device
!= PA_INVALID_INDEX
|| name_device
, tag
, PA_ERR_INVALID
);
4496 CHECK_VALIDITY(c
->pstream
, idx_device
== PA_INVALID_INDEX
|| !name_device
, tag
, PA_ERR_INVALID
);
4497 CHECK_VALIDITY(c
->pstream
, !name_device
|| idx_device
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4499 if (command
== PA_COMMAND_MOVE_SINK_INPUT
) {
4500 pa_sink_input
*si
= NULL
;
4501 pa_sink
*sink
= NULL
;
4503 si
= pa_idxset_get_by_index(c
->protocol
->core
->sink_inputs
, idx
);
4505 if (idx_device
!= PA_INVALID_INDEX
)
4506 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx_device
);
4508 sink
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SINK
);
4510 CHECK_VALIDITY(c
->pstream
, si
&& sink
, tag
, PA_ERR_NOENTITY
);
4512 if (pa_sink_input_move_to(si
, sink
, TRUE
) < 0) {
4513 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4517 pa_source_output
*so
= NULL
;
4520 pa_assert(command
== PA_COMMAND_MOVE_SOURCE_OUTPUT
);
4522 so
= pa_idxset_get_by_index(c
->protocol
->core
->source_outputs
, idx
);
4524 if (idx_device
!= PA_INVALID_INDEX
)
4525 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx_device
);
4527 source
= pa_namereg_get(c
->protocol
->core
, name_device
, PA_NAMEREG_SOURCE
);
4529 CHECK_VALIDITY(c
->pstream
, so
&& source
, tag
, PA_ERR_NOENTITY
);
4531 if (pa_source_output_move_to(so
, source
, TRUE
) < 0) {
4532 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4537 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4540 static void command_suspend(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4541 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4542 uint32_t idx
= PA_INVALID_INDEX
;
4543 const char *name
= NULL
;
4546 pa_native_connection_assert_ref(c
);
4549 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4550 pa_tagstruct_gets(t
, &name
) < 0 ||
4551 pa_tagstruct_get_boolean(t
, &b
) < 0 ||
4552 !pa_tagstruct_eof(t
)) {
4557 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4558 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
);
4559 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4560 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4561 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4563 if (command
== PA_COMMAND_SUSPEND_SINK
) {
4565 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4567 pa_log_debug("%s all sinks", b
? "Suspending" : "Resuming");
4569 if (pa_sink_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4570 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4574 pa_sink
*sink
= NULL
;
4576 if (idx
!= PA_INVALID_INDEX
)
4577 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4579 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4581 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4583 pa_log_debug("%s of sink %s requested by client %" PRIu32
".",
4584 b
? "Suspending" : "Resuming", sink
->name
, c
->client
->index
);
4586 if (pa_sink_suspend(sink
, b
, PA_SUSPEND_USER
) < 0) {
4587 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4593 pa_assert(command
== PA_COMMAND_SUSPEND_SOURCE
);
4595 if (idx
== PA_INVALID_INDEX
&& name
&& !*name
) {
4597 pa_log_debug("%s all sources", b
? "Suspending" : "Resuming");
4599 if (pa_source_suspend_all(c
->protocol
->core
, b
, PA_SUSPEND_USER
) < 0) {
4600 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4607 if (idx
!= PA_INVALID_INDEX
)
4608 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4610 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4612 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4614 pa_log_debug("%s of source %s requested by client %" PRIu32
".",
4615 b
? "Suspending" : "Resuming", source
->name
, c
->client
->index
);
4617 if (pa_source_suspend(source
, b
, PA_SUSPEND_USER
) < 0) {
4618 pa_pstream_send_error(c
->pstream
, tag
, PA_ERR_INVALID
);
4624 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4627 static void command_extension(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4628 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4629 uint32_t idx
= PA_INVALID_INDEX
;
4630 const char *name
= NULL
;
4632 pa_native_protocol_ext_cb_t cb
;
4634 pa_native_connection_assert_ref(c
);
4637 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4638 pa_tagstruct_gets(t
, &name
) < 0) {
4643 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4644 CHECK_VALIDITY(c
->pstream
, !name
|| pa_utf8_valid(name
), tag
, PA_ERR_INVALID
);
4645 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4646 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4647 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4649 if (idx
!= PA_INVALID_INDEX
)
4650 m
= pa_idxset_get_by_index(c
->protocol
->core
->modules
, idx
);
4652 PA_IDXSET_FOREACH(m
, c
->protocol
->core
->modules
, idx
)
4653 if (pa_streq(name
, m
->name
))
4656 CHECK_VALIDITY(c
->pstream
, m
, tag
, PA_ERR_NOEXTENSION
);
4657 CHECK_VALIDITY(c
->pstream
, m
->load_once
|| idx
!= PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4659 cb
= (pa_native_protocol_ext_cb_t
) (unsigned long) pa_hashmap_get(c
->protocol
->extensions
, m
);
4660 CHECK_VALIDITY(c
->pstream
, cb
, tag
, PA_ERR_NOEXTENSION
);
4662 if (cb(c
->protocol
, m
, c
, tag
, t
) < 0)
4666 static void command_set_card_profile(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4667 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4668 uint32_t idx
= PA_INVALID_INDEX
;
4669 const char *name
= NULL
, *profile
= NULL
;
4670 pa_card
*card
= NULL
;
4673 pa_native_connection_assert_ref(c
);
4676 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4677 pa_tagstruct_gets(t
, &name
) < 0 ||
4678 pa_tagstruct_gets(t
, &profile
) < 0 ||
4679 !pa_tagstruct_eof(t
)) {
4684 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4685 CHECK_VALIDITY(c
->pstream
, !name
|| pa_namereg_is_valid_name(name
), tag
, PA_ERR_INVALID
);
4686 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| name
, tag
, PA_ERR_INVALID
);
4687 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !name
, tag
, PA_ERR_INVALID
);
4688 CHECK_VALIDITY(c
->pstream
, !name
|| idx
== PA_INVALID_INDEX
, tag
, PA_ERR_INVALID
);
4690 if (idx
!= PA_INVALID_INDEX
)
4691 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4693 card
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_CARD
);
4695 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4697 if ((ret
= pa_card_set_profile(card
, profile
, TRUE
)) < 0) {
4698 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4702 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4705 static void command_set_sink_or_source_port(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4706 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4707 uint32_t idx
= PA_INVALID_INDEX
;
4708 const char *name
= NULL
, *port
= NULL
;
4711 pa_native_connection_assert_ref(c
);
4714 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4715 pa_tagstruct_gets(t
, &name
) < 0 ||
4716 pa_tagstruct_gets(t
, &port
) < 0 ||
4717 !pa_tagstruct_eof(t
)) {
4722 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4723 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
);
4724 CHECK_VALIDITY(c
->pstream
, (idx
!= PA_INVALID_INDEX
) ^ (name
!= NULL
), tag
, PA_ERR_INVALID
);
4725 CHECK_VALIDITY(c
->pstream
, port
, tag
, PA_ERR_INVALID
);
4727 if (command
== PA_COMMAND_SET_SINK_PORT
) {
4730 if (idx
!= PA_INVALID_INDEX
)
4731 sink
= pa_idxset_get_by_index(c
->protocol
->core
->sinks
, idx
);
4733 sink
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SINK
);
4735 CHECK_VALIDITY(c
->pstream
, sink
, tag
, PA_ERR_NOENTITY
);
4737 if ((ret
= pa_sink_set_port(sink
, port
, TRUE
)) < 0) {
4738 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4744 pa_assert(command
= PA_COMMAND_SET_SOURCE_PORT
);
4746 if (idx
!= PA_INVALID_INDEX
)
4747 source
= pa_idxset_get_by_index(c
->protocol
->core
->sources
, idx
);
4749 source
= pa_namereg_get(c
->protocol
->core
, name
, PA_NAMEREG_SOURCE
);
4751 CHECK_VALIDITY(c
->pstream
, source
, tag
, PA_ERR_NOENTITY
);
4753 if ((ret
= pa_source_set_port(source
, port
, TRUE
)) < 0) {
4754 pa_pstream_send_error(c
->pstream
, tag
, -ret
);
4759 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4762 static void command_set_port_latency_offset(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
4763 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4764 const char *port_name
, *card_name
;
4765 uint32_t idx
= PA_INVALID_INDEX
;
4767 pa_card
*card
= NULL
;
4768 pa_device_port
*port
= NULL
;
4770 pa_native_connection_assert_ref(c
);
4773 if (pa_tagstruct_getu32(t
, &idx
) < 0 ||
4774 pa_tagstruct_gets(t
, &card_name
) < 0 ||
4775 pa_tagstruct_gets(t
, &port_name
) < 0 ||
4776 pa_tagstruct_gets64(t
, &offset
) < 0 ||
4777 !pa_tagstruct_eof(t
)) {
4781 CHECK_VALIDITY(c
->pstream
, c
->authorized
, tag
, PA_ERR_ACCESS
);
4782 CHECK_VALIDITY(c
->pstream
, !card_name
|| pa_namereg_is_valid_name(card_name
), tag
, PA_ERR_INVALID
);
4783 CHECK_VALIDITY(c
->pstream
, idx
!= PA_INVALID_INDEX
|| card_name
, tag
, PA_ERR_INVALID
);
4784 CHECK_VALIDITY(c
->pstream
, idx
== PA_INVALID_INDEX
|| !card_name
, tag
, PA_ERR_INVALID
);
4785 CHECK_VALIDITY(c
->pstream
, port_name
, tag
, PA_ERR_INVALID
);
4787 if (idx
!= PA_INVALID_INDEX
)
4788 card
= pa_idxset_get_by_index(c
->protocol
->core
->cards
, idx
);
4790 card
= pa_namereg_get(c
->protocol
->core
, card_name
, PA_NAMEREG_CARD
);
4792 CHECK_VALIDITY(c
->pstream
, card
, tag
, PA_ERR_NOENTITY
);
4794 port
= pa_hashmap_get(card
->ports
, port_name
);
4795 CHECK_VALIDITY(c
->pstream
, port
, tag
, PA_ERR_NOENTITY
);
4797 pa_device_port_set_latency_offset(port
, offset
);
4799 pa_pstream_send_simple_ack(c
->pstream
, tag
);
4802 /*** pstream callbacks ***/
4804 static void pstream_packet_callback(pa_pstream
*p
, pa_packet
*packet
, const pa_creds
*creds
, void *userdata
) {
4805 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4809 pa_native_connection_assert_ref(c
);
4811 if (pa_pdispatch_run(c
->pdispatch
, packet
, creds
, c
) < 0) {
4812 pa_log("invalid packet.");
4813 native_connection_unlink(c
);
4817 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
) {
4818 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4819 output_stream
*stream
;
4823 pa_native_connection_assert_ref(c
);
4825 if (!(stream
= OUTPUT_STREAM(pa_idxset_get_by_index(c
->output_streams
, channel
)))) {
4826 pa_log_debug("Client sent block for invalid stream.");
4831 #ifdef PROTOCOL_NATIVE_DEBUG
4832 pa_log("got %lu bytes from client", (unsigned long) chunk
->length
);
4835 if (playback_stream_isinstance(stream
)) {
4836 playback_stream
*ps
= PLAYBACK_STREAM(stream
);
4838 pa_atomic_inc(&ps
->seek_or_post_in_queue
);
4839 if (chunk
->memblock
) {
4840 if (seek
!= PA_SEEK_RELATIVE
|| offset
!= 0)
4841 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
);
4843 pa_asyncmsgq_post(ps
->sink_input
->sink
->asyncmsgq
, PA_MSGOBJECT(ps
->sink_input
), SINK_INPUT_MESSAGE_POST_DATA
, NULL
, 0, chunk
, NULL
);
4845 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
);
4848 upload_stream
*u
= UPLOAD_STREAM(stream
);
4851 if (!u
->memchunk
.memblock
) {
4852 if (u
->length
== chunk
->length
&& chunk
->memblock
) {
4853 u
->memchunk
= *chunk
;
4854 pa_memblock_ref(u
->memchunk
.memblock
);
4857 u
->memchunk
.memblock
= pa_memblock_new(c
->protocol
->core
->mempool
, u
->length
);
4858 u
->memchunk
.index
= u
->memchunk
.length
= 0;
4862 pa_assert(u
->memchunk
.memblock
);
4865 if (l
> chunk
->length
)
4870 dst
= pa_memblock_acquire(u
->memchunk
.memblock
);
4872 if (chunk
->memblock
) {
4874 src
= pa_memblock_acquire(chunk
->memblock
);
4876 memcpy((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
,
4877 (uint8_t*) src
+ chunk
->index
, l
);
4879 pa_memblock_release(chunk
->memblock
);
4881 pa_silence_memory((uint8_t*) dst
+ u
->memchunk
.index
+ u
->memchunk
.length
, l
, &u
->sample_spec
);
4883 pa_memblock_release(u
->memchunk
.memblock
);
4885 u
->memchunk
.length
+= l
;
4891 static void pstream_die_callback(pa_pstream
*p
, void *userdata
) {
4892 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4895 pa_native_connection_assert_ref(c
);
4897 native_connection_unlink(c
);
4898 pa_log_info("Connection died.");
4901 static void pstream_drain_callback(pa_pstream
*p
, void *userdata
) {
4902 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4905 pa_native_connection_assert_ref(c
);
4907 native_connection_send_memblock(c
);
4910 static void pstream_revoke_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4913 if (!(q
= pa_thread_mq_get()))
4914 pa_pstream_send_revoke(p
, block_id
);
4916 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_REVOKE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4919 static void pstream_release_callback(pa_pstream
*p
, uint32_t block_id
, void *userdata
) {
4922 if (!(q
= pa_thread_mq_get()))
4923 pa_pstream_send_release(p
, block_id
);
4925 pa_asyncmsgq_post(q
->outq
, PA_MSGOBJECT(userdata
), CONNECTION_MESSAGE_RELEASE
, PA_UINT_TO_PTR(block_id
), 0, NULL
, NULL
);
4928 /*** client callbacks ***/
4930 static void client_kill_cb(pa_client
*c
) {
4933 native_connection_unlink(PA_NATIVE_CONNECTION(c
->userdata
));
4934 pa_log_info("Connection killed.");
4937 static void client_send_event_cb(pa_client
*client
, const char*event
, pa_proplist
*pl
) {
4939 pa_native_connection
*c
;
4942 c
= PA_NATIVE_CONNECTION(client
->userdata
);
4943 pa_native_connection_assert_ref(c
);
4945 if (c
->version
< 15)
4948 t
= pa_tagstruct_new(NULL
, 0);
4949 pa_tagstruct_putu32(t
, PA_COMMAND_CLIENT_EVENT
);
4950 pa_tagstruct_putu32(t
, (uint32_t) -1); /* tag */
4951 pa_tagstruct_puts(t
, event
);
4952 pa_tagstruct_put_proplist(t
, pl
);
4953 pa_pstream_send_tagstruct(c
->pstream
, t
);
4956 /*** module entry points ***/
4958 static void auth_timeout(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
4959 pa_native_connection
*c
= PA_NATIVE_CONNECTION(userdata
);
4962 pa_native_connection_assert_ref(c
);
4963 pa_assert(c
->auth_timeout_event
== e
);
4965 if (!c
->authorized
) {
4966 native_connection_unlink(c
);
4967 pa_log_info("Connection terminated due to authentication timeout.");
4971 void pa_native_protocol_connect(pa_native_protocol
*p
, pa_iochannel
*io
, pa_native_options
*o
) {
4972 pa_native_connection
*c
;
4975 pa_client_new_data data
;
4981 if (pa_idxset_size(p
->connections
)+1 > MAX_CONNECTIONS
) {
4982 pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS
);
4983 pa_iochannel_free(io
);
4987 pa_client_new_data_init(&data
);
4988 data
.module
= o
->module
;
4989 data
.driver
= __FILE__
;
4990 pa_iochannel_socket_peer_to_string(io
, pname
, sizeof(pname
));
4991 pa_proplist_setf(data
.proplist
, PA_PROP_APPLICATION_NAME
, "Native client (%s)", pname
);
4992 pa_proplist_sets(data
.proplist
, "native-protocol.peer", pname
);
4993 client
= pa_client_new(p
->core
, &data
);
4994 pa_client_new_data_done(&data
);
4999 c
= pa_msgobject_new(pa_native_connection
);
5000 c
->parent
.parent
.free
= native_connection_free
;
5001 c
->parent
.process_msg
= native_connection_process_msg
;
5003 c
->options
= pa_native_options_ref(o
);
5004 c
->authorized
= FALSE
;
5006 if (o
->auth_anonymous
) {
5007 pa_log_info("Client authenticated anonymously.");
5008 c
->authorized
= TRUE
;
5011 if (!c
->authorized
&&
5013 pa_ip_acl_check(o
->auth_ip_acl
, pa_iochannel_get_recv_fd(io
)) > 0) {
5015 pa_log_info("Client authenticated by IP ACL.");
5016 c
->authorized
= TRUE
;
5020 c
->auth_timeout_event
= pa_core_rttime_new(p
->core
, pa_rtclock_now() + AUTH_TIMEOUT
, auth_timeout
, c
);
5022 c
->auth_timeout_event
= NULL
;
5024 c
->is_local
= pa_iochannel_socket_is_local(io
);
5028 c
->client
->kill
= client_kill_cb
;
5029 c
->client
->send_event
= client_send_event_cb
;
5030 c
->client
->userdata
= c
;
5032 c
->pstream
= pa_pstream_new(p
->core
->mainloop
, io
, p
->core
->mempool
);
5033 pa_pstream_set_receive_packet_callback(c
->pstream
, pstream_packet_callback
, c
);
5034 pa_pstream_set_receive_memblock_callback(c
->pstream
, pstream_memblock_callback
, c
);
5035 pa_pstream_set_die_callback(c
->pstream
, pstream_die_callback
, c
);
5036 pa_pstream_set_drain_callback(c
->pstream
, pstream_drain_callback
, c
);
5037 pa_pstream_set_revoke_callback(c
->pstream
, pstream_revoke_callback
, c
);
5038 pa_pstream_set_release_callback(c
->pstream
, pstream_release_callback
, c
);
5040 c
->pdispatch
= pa_pdispatch_new(p
->core
->mainloop
, TRUE
, command_table
, PA_COMMAND_MAX
);
5042 c
->record_streams
= pa_idxset_new(NULL
, NULL
);
5043 c
->output_streams
= pa_idxset_new(NULL
, NULL
);
5045 c
->rrobin_index
= PA_IDXSET_INVALID
;
5046 c
->subscription
= NULL
;
5048 pa_idxset_put(p
->connections
, c
, NULL
);
5051 if (pa_iochannel_creds_supported(io
))
5052 pa_iochannel_creds_enable(io
);
5055 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_CONNECTION_PUT
], c
);
5058 void pa_native_protocol_disconnect(pa_native_protocol
*p
, pa_module
*m
) {
5059 pa_native_connection
*c
;
5065 while ((c
= pa_idxset_iterate(p
->connections
, &state
, NULL
)))
5066 if (c
->options
->module
== m
)
5067 native_connection_unlink(c
);
5070 static pa_native_protocol
* native_protocol_new(pa_core
*c
) {
5071 pa_native_protocol
*p
;
5076 p
= pa_xnew(pa_native_protocol
, 1);
5079 p
->connections
= pa_idxset_new(NULL
, NULL
);
5083 p
->extensions
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
5085 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
5086 pa_hook_init(&p
->hooks
[h
], p
);
5088 pa_assert_se(pa_shared_set(c
, "native-protocol", p
) >= 0);
5093 pa_native_protocol
* pa_native_protocol_get(pa_core
*c
) {
5094 pa_native_protocol
*p
;
5096 if ((p
= pa_shared_get(c
, "native-protocol")))
5097 return pa_native_protocol_ref(p
);
5099 return native_protocol_new(c
);
5102 pa_native_protocol
* pa_native_protocol_ref(pa_native_protocol
*p
) {
5104 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5111 void pa_native_protocol_unref(pa_native_protocol
*p
) {
5112 pa_native_connection
*c
;
5116 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5118 if (PA_REFCNT_DEC(p
) > 0)
5121 while ((c
= pa_idxset_first(p
->connections
, NULL
)))
5122 native_connection_unlink(c
);
5124 pa_idxset_free(p
->connections
, NULL
);
5126 pa_strlist_free(p
->servers
);
5128 for (h
= 0; h
< PA_NATIVE_HOOK_MAX
; h
++)
5129 pa_hook_done(&p
->hooks
[h
]);
5131 pa_hashmap_free(p
->extensions
, NULL
);
5133 pa_assert_se(pa_shared_remove(p
->core
, "native-protocol") >= 0);
5138 void pa_native_protocol_add_server_string(pa_native_protocol
*p
, const char *name
) {
5140 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5143 p
->servers
= pa_strlist_prepend(p
->servers
, name
);
5145 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5148 void pa_native_protocol_remove_server_string(pa_native_protocol
*p
, const char *name
) {
5150 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5153 p
->servers
= pa_strlist_remove(p
->servers
, name
);
5155 pa_hook_fire(&p
->hooks
[PA_NATIVE_HOOK_SERVERS_CHANGED
], p
->servers
);
5158 pa_hook
*pa_native_protocol_hooks(pa_native_protocol
*p
) {
5160 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5165 pa_strlist
*pa_native_protocol_servers(pa_native_protocol
*p
) {
5167 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5172 int pa_native_protocol_install_ext(pa_native_protocol
*p
, pa_module
*m
, pa_native_protocol_ext_cb_t cb
) {
5174 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5177 pa_assert(!pa_hashmap_get(p
->extensions
, m
));
5179 pa_assert_se(pa_hashmap_put(p
->extensions
, m
, (void*) (unsigned long) cb
) == 0);
5183 void pa_native_protocol_remove_ext(pa_native_protocol
*p
, pa_module
*m
) {
5185 pa_assert(PA_REFCNT_VALUE(p
) >= 1);
5188 pa_assert_se(pa_hashmap_remove(p
->extensions
, m
));
5191 pa_native_options
* pa_native_options_new(void) {
5192 pa_native_options
*o
;
5194 o
= pa_xnew0(pa_native_options
, 1);
5200 pa_native_options
* pa_native_options_ref(pa_native_options
*o
) {
5202 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5209 void pa_native_options_unref(pa_native_options
*o
) {
5211 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5213 if (PA_REFCNT_DEC(o
) > 0)
5216 pa_xfree(o
->auth_group
);
5219 pa_ip_acl_free(o
->auth_ip_acl
);
5222 pa_auth_cookie_unref(o
->auth_cookie
);
5227 int pa_native_options_parse(pa_native_options
*o
, pa_core
*c
, pa_modargs
*ma
) {
5232 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
5235 if (pa_modargs_get_value_boolean(ma
, "auth-anonymous", &o
->auth_anonymous
) < 0) {
5236 pa_log("auth-anonymous= expects a boolean argument.");
5241 if (pa_modargs_get_value_boolean(ma
, "auth-group-enable", &enabled
) < 0) {
5242 pa_log("auth-group-enable= expects a boolean argument.");
5246 pa_xfree(o
->auth_group
);
5247 o
->auth_group
= enabled
? pa_xstrdup(pa_modargs_get_value(ma
, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP
: NULL
)) : NULL
;
5251 pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5254 if ((acl
= pa_modargs_get_value(ma
, "auth-ip-acl", NULL
))) {
5257 if (!(ipa
= pa_ip_acl_new(acl
))) {
5258 pa_log("Failed to parse IP ACL '%s'", acl
);
5263 pa_ip_acl_free(o
->auth_ip_acl
);
5265 o
->auth_ip_acl
= ipa
;
5269 if (pa_modargs_get_value_boolean(ma
, "auth-cookie-enabled", &enabled
) < 0) {
5270 pa_log("auth-cookie-enabled= expects a boolean argument.");
5275 pa_auth_cookie_unref(o
->auth_cookie
);
5280 /* The new name for this is 'auth-cookie', for compat reasons
5281 * we check the old name too */
5282 cn
= pa_modargs_get_value(ma
, "auth-cookie", NULL
);
5284 cn
= pa_modargs_get_value(ma
, "cookie", NULL
);
5287 o
->auth_cookie
= pa_auth_cookie_get(c
, cn
, TRUE
, PA_NATIVE_COOKIE_LENGTH
);
5289 o
->auth_cookie
= pa_auth_cookie_get(c
, PA_NATIVE_COOKIE_FILE
, FALSE
, PA_NATIVE_COOKIE_LENGTH
);
5290 if (!o
->auth_cookie
) {
5291 o
->auth_cookie
= pa_auth_cookie_get(c
, PA_NATIVE_COOKIE_FILE_FALLBACK
, FALSE
, PA_NATIVE_COOKIE_LENGTH
);
5293 if (!o
->auth_cookie
)
5294 o
->auth_cookie
= pa_auth_cookie_get(c
, PA_NATIVE_COOKIE_FILE
, TRUE
, PA_NATIVE_COOKIE_LENGTH
);
5298 if (!o
->auth_cookie
)
5302 o
->auth_cookie
= NULL
;
5307 pa_pstream
* pa_native_connection_get_pstream(pa_native_connection
*c
) {
5308 pa_native_connection_assert_ref(c
);
5313 pa_client
* pa_native_connection_get_client(pa_native_connection
*c
) {
5314 pa_native_connection_assert_ref(c
);