Fix indent
[platform/upstream/pulseaudio.git] / src / pulsecore / protocol-native.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31
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>
39
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>
60
61 #include "protocol-native.h"
62
63 #ifdef USE_SECURITY
64 #include <pulsecore/cynara.h>
65 #include <pulsecore/iochannel.h>
66 #endif
67
68 /* #define PROTOCOL_NATIVE_DEBUG */
69
70 /* Kick a client if it doesn't authenticate within this time */
71 #define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
72
73 /* Don't accept more connection than this */
74 #define MAX_CONNECTIONS 64
75
76 #define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
77 #define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
78 #define DEFAULT_PROCESS_MSEC 20   /* 20ms */
79 #define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
80
81 #ifdef __TIZEN__
82 #define DEVICE_BUS_BUILTIN "builtin"
83 #endif
84
85 struct pa_native_protocol;
86
87 typedef struct record_stream {
88     pa_msgobject parent;
89
90     pa_native_connection *connection;
91     uint32_t index;
92
93     pa_source_output *source_output;
94     pa_memblockq *memblockq;
95
96     bool adjust_latency:1;
97     bool early_requests:1;
98
99     /* Requested buffer attributes */
100     pa_buffer_attr buffer_attr_req;
101     /* Fixed-up and adjusted buffer attributes */
102     pa_buffer_attr buffer_attr;
103
104     pa_atomic_t on_the_fly;
105     pa_usec_t configured_source_latency;
106     size_t drop_initial;
107
108     /* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
109     size_t on_the_fly_snapshot;
110     pa_usec_t current_monitor_latency;
111     pa_usec_t current_source_latency;
112 } record_stream;
113
114 #define RECORD_STREAM(o) (record_stream_cast(o))
115 PA_DEFINE_PRIVATE_CLASS(record_stream, pa_msgobject);
116
117 typedef struct output_stream {
118     pa_msgobject parent;
119 } output_stream;
120
121 #define OUTPUT_STREAM(o) (output_stream_cast(o))
122 PA_DEFINE_PRIVATE_CLASS(output_stream, pa_msgobject);
123
124 typedef struct playback_stream {
125     output_stream parent;
126
127     pa_native_connection *connection;
128     uint32_t index;
129
130     pa_sink_input *sink_input;
131     pa_memblockq *memblockq;
132
133     bool adjust_latency:1;
134     bool early_requests:1;
135
136     bool is_underrun:1;
137     bool drain_request:1;
138     uint32_t drain_tag;
139     uint32_t syncid;
140
141     /* Optimization to avoid too many rewinds with a lot of small blocks */
142     pa_atomic_t seek_or_post_in_queue;
143     int64_t seek_windex;
144
145     pa_atomic_t missing;
146     pa_usec_t configured_sink_latency;
147     /* Requested buffer attributes */
148     pa_buffer_attr buffer_attr_req;
149     /* Fixed-up and adjusted buffer attributes */
150     pa_buffer_attr buffer_attr;
151
152     /* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
153     int64_t read_index, write_index;
154     size_t render_memblockq_length;
155     pa_usec_t current_sink_latency;
156     uint64_t playing_for, underrun_for;
157 } playback_stream;
158
159 #define PLAYBACK_STREAM(o) (playback_stream_cast(o))
160 PA_DEFINE_PRIVATE_CLASS(playback_stream, output_stream);
161
162 typedef struct upload_stream {
163     output_stream parent;
164
165     pa_native_connection *connection;
166     uint32_t index;
167
168     pa_memchunk memchunk;
169     size_t length;
170     char *name;
171     pa_sample_spec sample_spec;
172     pa_channel_map channel_map;
173     pa_proplist *proplist;
174 } upload_stream;
175
176 #define UPLOAD_STREAM(o) (upload_stream_cast(o))
177 PA_DEFINE_PRIVATE_CLASS(upload_stream, output_stream);
178
179 struct pa_native_connection {
180     pa_msgobject parent;
181     pa_native_protocol *protocol;
182     pa_native_options *options;
183     bool authorized:1;
184     bool is_local:1;
185     uint32_t version;
186     pa_client *client;
187     pa_pstream *pstream;
188     pa_pdispatch *pdispatch;
189     pa_idxset *record_streams, *output_streams;
190     uint32_t rrobin_index;
191     pa_subscription *subscription;
192     pa_time_event *auth_timeout_event;
193 };
194
195 #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
196 PA_DEFINE_PRIVATE_CLASS(pa_native_connection, pa_msgobject);
197
198 struct pa_native_protocol {
199     PA_REFCNT_DECLARE;
200
201     pa_core *core;
202     pa_idxset *connections;
203
204     pa_strlist *servers;
205     pa_hook hooks[PA_NATIVE_HOOK_MAX];
206
207     pa_hashmap *extensions;
208 };
209
210 enum {
211     SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
212 };
213
214 enum {
215     SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
216     SINK_INPUT_MESSAGE_DRAIN, /* disabled prebuf, get playback started. */
217     SINK_INPUT_MESSAGE_FLUSH,
218     SINK_INPUT_MESSAGE_TRIGGER,
219     SINK_INPUT_MESSAGE_SEEK,
220     SINK_INPUT_MESSAGE_PREBUF_FORCE,
221     SINK_INPUT_MESSAGE_UPDATE_LATENCY,
222     SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
223 };
224
225 enum {
226     PLAYBACK_STREAM_MESSAGE_REQUEST_DATA,      /* data requested from sink input from the main loop */
227     PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
228     PLAYBACK_STREAM_MESSAGE_OVERFLOW,
229     PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
230     PLAYBACK_STREAM_MESSAGE_STARTED,
231     PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH,
232 #ifdef __TIZEN__
233     PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT
234 #endif
235 };
236
237 enum {
238     RECORD_STREAM_MESSAGE_POST_DATA         /* data from source output to main loop */
239 };
240
241 enum {
242     CONNECTION_MESSAGE_RELEASE,
243     CONNECTION_MESSAGE_REVOKE
244 };
245
246 static bool sink_input_process_underrun_cb(pa_sink_input *i);
247 static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk);
248 static void sink_input_kill_cb(pa_sink_input *i);
249 static void sink_input_suspend_cb(pa_sink_input *i, bool suspend);
250 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest);
251 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes);
252 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes);
253 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes);
254 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl);
255
256 static void native_connection_send_memblock(pa_native_connection *c);
257 static void playback_stream_request_bytes(struct playback_stream*s);
258
259 static void source_output_kill_cb(pa_source_output *o);
260 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk);
261 static void source_output_suspend_cb(pa_source_output *o, bool suspend);
262 static void source_output_moving_cb(pa_source_output *o, pa_source *dest);
263 static pa_usec_t source_output_get_latency_cb(pa_source_output *o);
264 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl);
265
266 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
267 static int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk);
268
269 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
270 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
271 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
272 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
273 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
274 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
275 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
276 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
277 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
278 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
279 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
280 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
281 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
282 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
283 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
284 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
285 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
286 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
287 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
288 static void command_set_volume(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
289 static void command_set_mute(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
290 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
291 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
292 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
293 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
294 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
295 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
296 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
297 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
298 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
299 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
300 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
301 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
302 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
303 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
304 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
305 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
306 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
307 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
308 static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
309 static void command_set_volume_ramp(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
310 #ifdef USE_SECURITY
311 static void command_check_privilege(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
312 #endif
313
314 static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
315     [PA_COMMAND_ERROR] = NULL,
316     [PA_COMMAND_TIMEOUT] = NULL,
317     [PA_COMMAND_REPLY] = NULL,
318     [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream,
319     [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream,
320     [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream,
321     [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream,
322     [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream,
323     [PA_COMMAND_AUTH] = command_auth,
324     [PA_COMMAND_REQUEST] = NULL,
325     [PA_COMMAND_EXIT] = command_exit,
326     [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name,
327     [PA_COMMAND_LOOKUP_SINK] = command_lookup,
328     [PA_COMMAND_LOOKUP_SOURCE] = command_lookup,
329     [PA_COMMAND_STAT] = command_stat,
330     [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency,
331     [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency,
332     [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream,
333     [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream,
334     [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream,
335     [PA_COMMAND_PLAY_SAMPLE] = command_play_sample,
336     [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample,
337     [PA_COMMAND_GET_SINK_INFO] = command_get_info,
338     [PA_COMMAND_GET_SOURCE_INFO] = command_get_info,
339     [PA_COMMAND_GET_CLIENT_INFO] = command_get_info,
340     [PA_COMMAND_GET_CARD_INFO] = command_get_info,
341     [PA_COMMAND_GET_MODULE_INFO] = command_get_info,
342     [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info,
343     [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info,
344     [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info,
345     [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list,
346     [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list,
347     [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list,
348     [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list,
349     [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list,
350     [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list,
351     [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list,
352     [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list,
353     [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info,
354     [PA_COMMAND_SUBSCRIBE] = command_subscribe,
355
356     [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume,
357     [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume,
358     [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume,
359     [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume,
360
361     [PA_COMMAND_SET_SINK_MUTE] = command_set_mute,
362     [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute,
363     [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute,
364     [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute,
365
366     [PA_COMMAND_SUSPEND_SINK] = command_suspend,
367     [PA_COMMAND_SUSPEND_SOURCE] = command_suspend,
368
369     [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream,
370     [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
371     [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
372     [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream,
373
374     [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream,
375     [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream,
376
377     [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source,
378     [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source,
379     [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name,
380     [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name,
381     [PA_COMMAND_KILL_CLIENT] = command_kill,
382     [PA_COMMAND_KILL_SINK_INPUT] = command_kill,
383     [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill,
384     [PA_COMMAND_LOAD_MODULE] = command_load_module,
385     [PA_COMMAND_UNLOAD_MODULE] = command_unload_module,
386
387     [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL,
388     [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL,
389     [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL,
390     [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL,
391
392     [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream,
393     [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream,
394
395     [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
396     [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr,
397
398     [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
399     [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate,
400
401     [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist,
402     [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist,
403     [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist,
404
405     [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist,
406     [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist,
407     [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist,
408
409     [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
410
411     [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
412     [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
413
414     [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = command_set_port_latency_offset,
415
416     [PA_COMMAND_SET_SINK_VOLUME_RAMP] = command_set_volume_ramp,
417     [PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP] = command_set_volume_ramp,
418 #ifdef __TIZEN__
419     [PA_COMMAND_CHECK_PRIVILEGE] = command_check_privilege,
420 #endif
421
422     [PA_COMMAND_EXTENSION] = command_extension
423 };
424
425 /* structure management */
426
427 #ifdef USE_SECURITY
428 static int _get_connection_out_fd(pa_native_connection *c) {
429     return pa_iochannel_get_send_fd(pa_pstream_get_iochannel(pa_native_connection_get_pstream(c)));
430 }
431 #endif
432
433 /* Called from main context */
434 static void upload_stream_unlink(upload_stream *s) {
435     pa_assert(s);
436
437     if (!s->connection)
438         return;
439
440     pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
441     s->connection = NULL;
442     upload_stream_unref(s);
443 }
444
445 /* Called from main context */
446 static void upload_stream_free(pa_object *o) {
447     upload_stream *s = UPLOAD_STREAM(o);
448     pa_assert(s);
449
450     upload_stream_unlink(s);
451
452     pa_xfree(s->name);
453
454     if (s->proplist)
455         pa_proplist_free(s->proplist);
456
457     if (s->memchunk.memblock)
458         pa_memblock_unref(s->memchunk.memblock);
459
460     pa_xfree(s);
461 }
462
463 /* Called from main context */
464 static upload_stream* upload_stream_new(
465         pa_native_connection *c,
466         const pa_sample_spec *ss,
467         const pa_channel_map *map,
468         const char *name,
469         size_t length,
470         pa_proplist *p) {
471
472     upload_stream *s;
473
474     pa_assert(c);
475     pa_assert(ss);
476     pa_assert(name);
477     pa_assert(length > 0);
478     pa_assert(p);
479
480     s = pa_msgobject_new(upload_stream);
481     s->parent.parent.parent.free = upload_stream_free;
482     s->connection = c;
483     s->sample_spec = *ss;
484     s->channel_map = *map;
485     s->name = pa_xstrdup(name);
486     pa_memchunk_reset(&s->memchunk);
487     s->length = length;
488     s->proplist = pa_proplist_copy(p);
489     pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist);
490
491     pa_idxset_put(c->output_streams, s, &s->index);
492
493     return s;
494 }
495
496 /* Called from main context */
497 static void record_stream_unlink(record_stream *s) {
498     pa_assert(s);
499
500     if (!s->connection)
501         return;
502
503     if (s->source_output) {
504         pa_source_output_unlink(s->source_output);
505         pa_source_output_unref(s->source_output);
506         s->source_output = NULL;
507     }
508
509     pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s);
510     s->connection = NULL;
511     record_stream_unref(s);
512 }
513
514 /* Called from main context */
515 static void record_stream_free(pa_object *o) {
516     record_stream *s = RECORD_STREAM(o);
517     pa_assert(s);
518
519     record_stream_unlink(s);
520
521     pa_memblockq_free(s->memblockq);
522     pa_xfree(s);
523 }
524
525 /* Called from main context */
526 static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
527     record_stream *s = RECORD_STREAM(o);
528     record_stream_assert_ref(s);
529
530     if (!s->connection)
531         return -1;
532
533     switch (code) {
534
535         case RECORD_STREAM_MESSAGE_POST_DATA:
536
537             /* We try to keep up to date with how many bytes are
538              * currently on the fly */
539             pa_atomic_sub(&s->on_the_fly, chunk->length);
540
541             if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
542 /*                 pa_log_warn("Failed to push data into output queue."); */
543                 return -1;
544             }
545
546             if (!pa_pstream_is_pending(s->connection->pstream))
547                 native_connection_send_memblock(s->connection);
548
549             break;
550     }
551
552     return 0;
553 }
554
555 /* Called from main context */
556 static void fix_record_buffer_attr_pre(record_stream *s) {
557
558     size_t frame_size;
559     pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
560
561     pa_assert(s);
562
563     /* This function will be called from the main thread, before as
564      * well as after the source output has been activated using
565      * pa_source_output_put()! That means it may not touch any
566      * ->thread_info data! */
567
568     frame_size = pa_frame_size(&s->source_output->sample_spec);
569     s->buffer_attr = s->buffer_attr_req;
570
571     if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
572         s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
573     if (s->buffer_attr.maxlength <= 0)
574         s->buffer_attr.maxlength = (uint32_t) frame_size;
575
576     if (s->buffer_attr.fragsize == (uint32_t) -1)
577         s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
578     if (s->buffer_attr.fragsize <= 0)
579         s->buffer_attr.fragsize = (uint32_t) frame_size;
580
581     orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
582
583     if (s->early_requests) {
584
585         /* In early request mode we need to emulate the classic
586          * fragment-based playback model. We do this setting the source
587          * latency to the fragment size. */
588
589         source_usec = fragsize_usec;
590
591     } else if (s->adjust_latency) {
592
593         /* So, the user asked us to adjust the latency according to
594          * what the source can provide. Half the latency will be
595          * spent on the hw buffer, half of it in the async buffer
596          * queue we maintain for each client. */
597
598         source_usec = fragsize_usec/2;
599
600     } else {
601
602         /* Ok, the user didn't ask us to adjust the latency, hence we
603          * don't */
604
605         source_usec = (pa_usec_t) -1;
606     }
607
608     if (source_usec != (pa_usec_t) -1)
609         s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec);
610     else
611         s->configured_source_latency = 0;
612
613     if (s->early_requests) {
614
615         /* Ok, we didn't necessarily get what we were asking for, so
616          * let's tell the user */
617
618         fragsize_usec = s->configured_source_latency;
619
620     } else if (s->adjust_latency) {
621
622         /* Now subtract what we actually got */
623
624         if (fragsize_usec >= s->configured_source_latency*2)
625             fragsize_usec -= s->configured_source_latency;
626         else
627             fragsize_usec = s->configured_source_latency;
628     }
629
630     if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
631         pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
632
633         s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
634
635     if (s->buffer_attr.fragsize <= 0)
636         s->buffer_attr.fragsize = (uint32_t) frame_size;
637 }
638
639 /* Called from main context */
640 static void fix_record_buffer_attr_post(record_stream *s) {
641     size_t base;
642
643     pa_assert(s);
644
645     /* This function will be called from the main thread, before as
646      * well as after the source output has been activated using
647      * pa_source_output_put()! That means it may not touch and
648      * ->thread_info data! */
649
650     base = pa_frame_size(&s->source_output->sample_spec);
651
652     s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
653     if (s->buffer_attr.fragsize <= 0)
654         s->buffer_attr.fragsize = base;
655
656     if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
657         s->buffer_attr.fragsize = s->buffer_attr.maxlength;
658 }
659
660 #ifdef __TIZEN__
661 static int update_buffer_attr(pa_proplist* proplist, pa_buffer_attr* ret_attr, bool is_playback_stream) {
662     const char* _propStr = NULL;
663
664     pa_assert(ret_attr);
665
666     if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_MAXLENGTH)) == NULL) {
667         pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_MAXLENGTH);
668         return -1;
669     }
670     if (pa_atoi(_propStr, &ret_attr->maxlength)) {
671         pa_log_error("failed to pa_atoi for maxlength");
672         return -1;
673     }
674
675     if (is_playback_stream) {
676         /* for playback */
677         if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_TLENGTH)) == NULL) {
678             pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_TLENGTH);
679             return -1;
680         }
681         if (pa_atoi(_propStr, &ret_attr->tlength)) {
682             pa_log_error("failed to pa_atoi for tlength");
683             return -1;
684         }
685
686         if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_PREBUF)) == NULL) {
687             pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_PREBUF);
688             return -1;
689         }
690         if (pa_atoi(_propStr, &ret_attr->prebuf)) {
691             pa_log_error("failed to pa_atoi for prebuf");
692             return -1;
693         }
694
695         if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_MINREQ)) == NULL) {
696             pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_MINREQ);
697             return -1;
698         }
699         if (pa_atoi(_propStr, &ret_attr->minreq)) {
700             pa_log_error("failed to pa_atoi for minreq");
701             return -1;
702         }
703
704         pa_log_info(" - props: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
705                     ret_attr->maxlength, ret_attr->tlength, ret_attr->prebuf, ret_attr->minreq);
706
707     } else {
708         /* for recording */
709         if ((_propStr = pa_proplist_gets(proplist, PA_PROP_BUFFER_ATTR_FRAGSIZE)) == NULL) {
710             pa_log_error("failed to get %s", PA_PROP_BUFFER_ATTR_FRAGSIZE);
711             return -1;
712         }
713         if (pa_atoi(_propStr, &ret_attr->fragsize)) {
714             pa_log_error("failed to pa_atoi for fragsize");
715             return -1;
716         }
717
718         pa_log_info(" - props: maxlength(%d), fragsize(%d)", ret_attr->maxlength, ret_attr->fragsize);
719     }
720
721     return 0;
722 }
723 #endif
724
725 /* Called from main context */
726 static record_stream* record_stream_new(
727         pa_native_connection *c,
728         pa_source *source,
729         pa_sample_spec *ss,
730         pa_channel_map *map,
731         pa_idxset *formats,
732         pa_buffer_attr *attr,
733         pa_cvolume *volume,
734         bool muted,
735         bool muted_set,
736         pa_source_output_flags_t flags,
737         pa_proplist *p,
738         bool adjust_latency,
739         bool early_requests,
740         bool relative_volume,
741         bool peak_detect,
742         pa_sink_input *direct_on_input,
743         int *ret) {
744
745     record_stream *s;
746     pa_source_output *source_output = NULL;
747     pa_source_output_new_data data;
748     char *memblockq_name;
749
750     pa_assert(c);
751     pa_assert(ss);
752     pa_assert(p);
753     pa_assert(ret);
754
755     pa_source_output_new_data_init(&data);
756
757     pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
758     data.driver = __FILE__;
759     data.module = c->options->module;
760     data.client = c->client;
761     if (source)
762         pa_source_output_new_data_set_source(&data, source, false);
763     if (pa_sample_spec_valid(ss))
764         pa_source_output_new_data_set_sample_spec(&data, ss);
765     if (pa_channel_map_valid(map))
766         pa_source_output_new_data_set_channel_map(&data, map);
767     if (formats)
768         pa_source_output_new_data_set_formats(&data, formats);
769     data.direct_on_input = direct_on_input;
770     if (volume) {
771         pa_source_output_new_data_set_volume(&data, volume, relative_volume);
772         data.save_volume = false;
773     }
774     if (muted_set) {
775         pa_source_output_new_data_set_muted(&data, muted);
776         data.save_muted = false;
777     }
778     if (peak_detect)
779         data.resample_method = PA_RESAMPLER_PEAKS;
780     data.flags = flags;
781
782     *ret = -pa_source_output_new(&source_output, c->protocol->core, &data);
783
784 #ifdef __TIZEN__
785     {
786         pa_buffer_attr buffer_attr;
787         pa_log_info("*** update buffer attributes - record_stream_new()");
788         if (source_output && !update_buffer_attr(source_output->proplist, &buffer_attr, false)) {
789             pa_log_info(" - origins: maxlength(%d), fragsize(%d)", attr->maxlength, attr->fragsize);
790             if ((int)attr->maxlength >= 0)
791                 buffer_attr.maxlength = attr->maxlength;
792             if ((int)attr->fragsize >= 0)
793                 buffer_attr.fragsize = attr->fragsize;
794             *attr = buffer_attr;
795             pa_log_info(" - updated: maxlength(%d), fragsize(%d)", attr->maxlength, attr->fragsize);
796         }
797     }
798 #endif
799
800     pa_source_output_new_data_done(&data);
801
802     if (!source_output)
803         return NULL;
804
805     s = pa_msgobject_new(record_stream);
806     s->parent.parent.free = record_stream_free;
807     s->parent.process_msg = record_stream_process_msg;
808     s->connection = c;
809     s->source_output = source_output;
810     s->buffer_attr_req = *attr;
811     s->adjust_latency = adjust_latency;
812     s->early_requests = early_requests;
813     pa_atomic_store(&s->on_the_fly, 0);
814
815     s->source_output->parent.process_msg = source_output_process_msg;
816     s->source_output->push = source_output_push_cb;
817     s->source_output->kill = source_output_kill_cb;
818     s->source_output->get_latency = source_output_get_latency_cb;
819     s->source_output->moving = source_output_moving_cb;
820     s->source_output->suspend = source_output_suspend_cb;
821     s->source_output->send_event = source_output_send_event_cb;
822     s->source_output->userdata = s;
823
824     fix_record_buffer_attr_pre(s);
825
826     memblockq_name = pa_sprintf_malloc("native protocol record stream memblockq [%u]", s->source_output->index);
827     s->memblockq = pa_memblockq_new(
828             memblockq_name,
829             0,
830             s->buffer_attr.maxlength,
831             0,
832             &source_output->sample_spec,
833             1,
834             0,
835             0,
836             NULL);
837     pa_xfree(memblockq_name);
838
839     pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
840     fix_record_buffer_attr_post(s);
841
842     *ss = s->source_output->sample_spec;
843     *map = s->source_output->channel_map;
844
845     pa_idxset_put(c->record_streams, s, &s->index);
846
847     pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
848                 ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC,
849                 (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
850                 (double) s->configured_source_latency / PA_USEC_PER_MSEC);
851
852     pa_source_output_put(s->source_output);
853     return s;
854 }
855
856 /* Called from main context */
857 static void record_stream_send_killed(record_stream *r) {
858     pa_tagstruct *t;
859     record_stream_assert_ref(r);
860
861     t = pa_tagstruct_new(NULL, 0);
862     pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED);
863     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
864     pa_tagstruct_putu32(t, r->index);
865     pa_pstream_send_tagstruct(r->connection->pstream, t);
866 }
867
868 /* Called from main context */
869 static void playback_stream_unlink(playback_stream *s) {
870     pa_assert(s);
871
872     if (!s->connection)
873         return;
874
875     if (s->sink_input) {
876         pa_sink_input_unlink(s->sink_input);
877         pa_sink_input_unref(s->sink_input);
878         s->sink_input = NULL;
879     }
880
881     if (s->drain_request)
882         pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY);
883
884     pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s);
885     s->connection = NULL;
886     playback_stream_unref(s);
887 }
888
889 /* Called from main context */
890 static void playback_stream_free(pa_object* o) {
891     playback_stream *s = PLAYBACK_STREAM(o);
892     pa_assert(s);
893
894     playback_stream_unlink(s);
895
896     pa_memblockq_free(s->memblockq);
897     pa_xfree(s);
898 }
899
900 /* Called from main context */
901 static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
902     playback_stream *s = PLAYBACK_STREAM(o);
903     playback_stream_assert_ref(s);
904
905     if (!s->connection)
906         return -1;
907
908     switch (code) {
909
910         case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: {
911             pa_tagstruct *t;
912             int l = 0;
913
914             for (;;) {
915                 if ((l = pa_atomic_load(&s->missing)) <= 0)
916                     return 0;
917
918                 if (pa_atomic_cmpxchg(&s->missing, l, 0))
919                     break;
920             }
921
922             t = pa_tagstruct_new(NULL, 0);
923             pa_tagstruct_putu32(t, PA_COMMAND_REQUEST);
924             pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
925             pa_tagstruct_putu32(t, s->index);
926             pa_tagstruct_putu32(t, (uint32_t) l);
927             pa_pstream_send_tagstruct(s->connection->pstream, t);
928
929 #ifdef PROTOCOL_NATIVE_DEBUG
930             pa_log("Requesting %lu bytes", (unsigned long) l);
931 #endif
932             break;
933         }
934
935         case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: {
936             pa_tagstruct *t;
937
938 #ifdef PROTOCOL_NATIVE_DEBUG
939             pa_log("signalling underflow");
940 #endif
941
942             /* Report that we're empty */
943             t = pa_tagstruct_new(NULL, 0);
944             pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
945             pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
946             pa_tagstruct_putu32(t, s->index);
947             if (s->connection->version >= 23)
948                 pa_tagstruct_puts64(t, offset);
949             pa_pstream_send_tagstruct(s->connection->pstream, t);
950             break;
951         }
952
953         case PLAYBACK_STREAM_MESSAGE_OVERFLOW: {
954             pa_tagstruct *t;
955
956             /* Notify the user we're overflowed*/
957             t = pa_tagstruct_new(NULL, 0);
958             pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW);
959             pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
960             pa_tagstruct_putu32(t, s->index);
961             pa_pstream_send_tagstruct(s->connection->pstream, t);
962             break;
963         }
964
965         case PLAYBACK_STREAM_MESSAGE_STARTED:
966
967             if (s->connection->version >= 13) {
968                 pa_tagstruct *t;
969
970                 /* Notify the user we started playback */
971                 t = pa_tagstruct_new(NULL, 0);
972                 pa_tagstruct_putu32(t, PA_COMMAND_STARTED);
973                 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
974                 pa_tagstruct_putu32(t, s->index);
975                 pa_pstream_send_tagstruct(s->connection->pstream, t);
976             }
977
978             break;
979
980 #ifdef __TIZEN__
981         case PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT: {
982                 pa_tagstruct *t;
983                 pa_proplist* pl = pa_proplist_new();
984
985                 pa_log_info("received : PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT, send PA_COMMAND_PLAYBACK_STREAM_EVENT(%s)",
986                     PA_STREAM_EVENT_POP_TIMEOUT);
987
988                 t = pa_tagstruct_new(NULL, 0);
989                 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
990                 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
991                 pa_tagstruct_putu32(t, s->index);
992                 pa_tagstruct_puts(t, PA_STREAM_EVENT_POP_TIMEOUT);
993                 pa_tagstruct_put_proplist(t, pl);
994                 pa_pstream_send_tagstruct(s->connection->pstream, t);
995
996                 pa_proplist_free(pl);
997               }
998               break;
999 #endif
1000
1001         case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
1002             pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
1003             break;
1004
1005         case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH:
1006
1007             s->buffer_attr.tlength = (uint32_t) offset;
1008
1009             if (s->connection->version >= 15) {
1010                 pa_tagstruct *t;
1011
1012                 t = pa_tagstruct_new(NULL, 0);
1013                 pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
1014                 pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1015                 pa_tagstruct_putu32(t, s->index);
1016                 pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1017                 pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1018                 pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1019                 pa_tagstruct_putu32(t, s->buffer_attr.minreq);
1020                 pa_tagstruct_put_usec(t, s->configured_sink_latency);
1021                 pa_pstream_send_tagstruct(s->connection->pstream, t);
1022             }
1023
1024             break;
1025     }
1026
1027     return 0;
1028 }
1029
1030 /* Called from main context */
1031 static void fix_playback_buffer_attr(playback_stream *s) {
1032     size_t frame_size, max_prebuf;
1033     pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
1034
1035     pa_assert(s);
1036
1037 #ifdef PROTOCOL_NATIVE_DEBUG
1038     pa_log("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes",
1039            (long) s->buffer_attr_req.maxlength,
1040            (long) s->buffer_attr_req.tlength,
1041            (long) s->buffer_attr_req.minreq,
1042            (long) s->buffer_attr_req.prebuf);
1043
1044     pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
1045            (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1046            (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1047            (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1048            (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC));
1049 #endif
1050
1051     /* This function will be called from the main thread, before as
1052      * well as after the sink input has been activated using
1053      * pa_sink_input_put()! That means it may not touch any
1054      * ->thread_info data, such as the memblockq! */
1055
1056     frame_size = pa_frame_size(&s->sink_input->sample_spec);
1057     s->buffer_attr = s->buffer_attr_req;
1058
1059     if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
1060         s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
1061     if (s->buffer_attr.maxlength <= 0)
1062         s->buffer_attr.maxlength = (uint32_t) frame_size;
1063
1064     if (s->buffer_attr.tlength == (uint32_t) -1)
1065         s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
1066     if (s->buffer_attr.tlength <= 0)
1067         s->buffer_attr.tlength = (uint32_t) frame_size;
1068     if (s->buffer_attr.tlength > s->buffer_attr.maxlength)
1069         s->buffer_attr.tlength = s->buffer_attr.maxlength;
1070
1071     if (s->buffer_attr.minreq == (uint32_t) -1) {
1072         uint32_t process = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
1073         /* With low-latency, tlength/4 gives a decent default in all of traditional, adjust latency and early request modes. */
1074         uint32_t m = s->buffer_attr.tlength / 4;
1075         if (frame_size)
1076             m -= m % frame_size;
1077         s->buffer_attr.minreq = PA_MIN(process, m);
1078     }
1079     if (s->buffer_attr.minreq <= 0)
1080         s->buffer_attr.minreq = (uint32_t) frame_size;
1081
1082     if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
1083         s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
1084
1085     orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
1086     orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
1087
1088     pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
1089                 (double) tlength_usec / PA_USEC_PER_MSEC,
1090                 (double) minreq_usec / PA_USEC_PER_MSEC);
1091
1092     if (s->early_requests) {
1093
1094         /* In early request mode we need to emulate the classic
1095          * fragment-based playback model. We do this setting the sink
1096          * latency to the fragment size. */
1097
1098         sink_usec = minreq_usec;
1099         pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
1100
1101     } else if (s->adjust_latency) {
1102
1103         /* So, the user asked us to adjust the latency of the stream
1104          * buffer according to the what the sink can provide. The
1105          * tlength passed in shall be the overall latency. Roughly
1106          * half the latency will be spent on the hw buffer, the other
1107          * half of it in the async buffer queue we maintain for each
1108          * client. In between we'll have a safety space of size
1109          * 2*minreq. Why the 2*minreq? When the hw buffer is completely
1110          * empty and needs to be filled, then our buffer must have
1111          * enough data to fulfill this request immediately and thus
1112          * have at least the same tlength as the size of the hw
1113          * buffer. It additionally needs space for 2 times minreq
1114          * because if the buffer ran empty and a partial fillup
1115          * happens immediately on the next iteration we need to be
1116          * able to fulfill it and give the application also minreq
1117          * time to fill it up again for the next request Makes 2 times
1118          * minreq in plus.. */
1119
1120         if (tlength_usec > minreq_usec*2)
1121             sink_usec = (tlength_usec - minreq_usec*2)/2;
1122         else
1123             sink_usec = 0;
1124
1125         pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency.");
1126
1127     } else {
1128
1129         /* Ok, the user didn't ask us to adjust the latency, but we
1130          * still need to make sure that the parameters from the user
1131          * do make sense. */
1132
1133         if (tlength_usec > minreq_usec*2)
1134             sink_usec = (tlength_usec - minreq_usec*2);
1135         else
1136             sink_usec = 0;
1137
1138         pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq.");
1139     }
1140
1141     s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
1142
1143     if (s->early_requests) {
1144
1145         /* Ok, we didn't necessarily get what we were asking for, so
1146          * let's tell the user */
1147
1148         minreq_usec = s->configured_sink_latency;
1149
1150     } else if (s->adjust_latency) {
1151
1152         /* Ok, we didn't necessarily get what we were asking for, so
1153          * let's subtract from what we asked for for the remaining
1154          * buffer space */
1155
1156         if (tlength_usec >= s->configured_sink_latency)
1157             tlength_usec -= s->configured_sink_latency;
1158     }
1159
1160     pa_log_debug("Requested latency=%0.2f ms, Received latency=%0.2f ms",
1161                  (double) sink_usec / PA_USEC_PER_MSEC,
1162                  (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1163
1164     /* FIXME: This is actually larger than necessary, since not all of
1165      * the sink latency is actually rewritable. */
1166     if (tlength_usec < s->configured_sink_latency + 2*minreq_usec)
1167         tlength_usec = s->configured_sink_latency + 2*minreq_usec;
1168
1169     if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
1170         pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
1171         s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
1172
1173     if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
1174         pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
1175         s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
1176
1177     if (s->buffer_attr.minreq <= 0) {
1178         s->buffer_attr.minreq = (uint32_t) frame_size;
1179         s->buffer_attr.tlength += (uint32_t) frame_size*2;
1180     }
1181
1182     if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
1183         s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
1184
1185     max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq;
1186
1187     if (s->buffer_attr.prebuf == (uint32_t) -1 ||
1188         s->buffer_attr.prebuf > max_prebuf)
1189         s->buffer_attr.prebuf = max_prebuf;
1190
1191 #ifdef PROTOCOL_NATIVE_DEBUG
1192     pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms",
1193            (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1194            (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1195            (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC),
1196            (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC));
1197 #endif
1198 }
1199
1200 /* Called from main context */
1201 static playback_stream* playback_stream_new(
1202         pa_native_connection *c,
1203         pa_sink *sink,
1204         pa_sample_spec *ss,
1205         pa_channel_map *map,
1206         pa_idxset *formats,
1207         pa_buffer_attr *a,
1208         pa_cvolume *volume,
1209         bool muted,
1210         bool muted_set,
1211         pa_sink_input_flags_t flags,
1212         pa_proplist *p,
1213         bool adjust_latency,
1214         bool early_requests,
1215         bool relative_volume,
1216         uint32_t syncid,
1217         uint32_t *missing,
1218         int *ret) {
1219
1220     /* Note: This function takes ownership of the 'formats' param, so we need
1221      * to take extra care to not leak it */
1222
1223     playback_stream *ssync;
1224     playback_stream *s = NULL;
1225     pa_sink_input *sink_input = NULL;
1226     pa_memchunk silence;
1227     uint32_t idx;
1228     int64_t start_index;
1229     pa_sink_input_new_data data;
1230     char *memblockq_name;
1231
1232     pa_assert(c);
1233     pa_assert(ss);
1234     pa_assert(missing);
1235     pa_assert(p);
1236     pa_assert(ret);
1237
1238     /* Find syncid group */
1239     PA_IDXSET_FOREACH(ssync, c->output_streams, idx) {
1240
1241         if (!playback_stream_isinstance(ssync))
1242             continue;
1243
1244         if (ssync->syncid == syncid)
1245             break;
1246     }
1247
1248     /* Synced streams must connect to the same sink */
1249     if (ssync) {
1250
1251         if (!sink)
1252             sink = ssync->sink_input->sink;
1253         else if (sink != ssync->sink_input->sink) {
1254             *ret = PA_ERR_INVALID;
1255             goto out;
1256         }
1257     }
1258
1259     pa_sink_input_new_data_init(&data);
1260
1261     pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p);
1262     data.driver = __FILE__;
1263     data.module = c->options->module;
1264     data.client = c->client;
1265     if (sink)
1266         pa_sink_input_new_data_set_sink(&data, sink, false);
1267     if (pa_sample_spec_valid(ss))
1268         pa_sink_input_new_data_set_sample_spec(&data, ss);
1269     if (pa_channel_map_valid(map))
1270         pa_sink_input_new_data_set_channel_map(&data, map);
1271     if (formats) {
1272         pa_sink_input_new_data_set_formats(&data, formats);
1273         /* Ownership transferred to new_data, so we don't free it ourselves */
1274         formats = NULL;
1275     }
1276     if (volume) {
1277         pa_sink_input_new_data_set_volume(&data, volume, relative_volume);
1278         data.save_volume = false;
1279     }
1280     if (muted_set) {
1281         pa_sink_input_new_data_set_muted(&data, muted);
1282         data.save_muted = false;
1283     }
1284     data.sync_base = ssync ? ssync->sink_input : NULL;
1285     data.flags = flags;
1286
1287     *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data);
1288
1289 #ifdef __TIZEN__
1290     {
1291         pa_buffer_attr buffer_attr;
1292         pa_log_info("*** update buffer attributes - playback_stream_new()");
1293         if (sink_input && !update_buffer_attr(sink_input->proplist, &buffer_attr, true)) {
1294             pa_log_info(" - origins: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
1295                         a->maxlength, a->tlength, a->prebuf, a->minreq);
1296             if ((int)a->maxlength >= 0)
1297                 buffer_attr.maxlength = a->maxlength;
1298             /* "tlength" is always set to default value from pa_stream_new_with_proplist_internal() in stream.c.
1299                but here we use tlength from stream-map.json except -1. */
1300             if ((int)buffer_attr.tlength == -1)
1301                 buffer_attr.tlength = a->tlength;
1302             if ((int)a->prebuf >= 0)
1303                 buffer_attr.prebuf = a->prebuf;
1304             if ((int)a->minreq >= 0)
1305                 buffer_attr.minreq = a->minreq;
1306             *a = buffer_attr;
1307             pa_log_info(" - updated: maxlength(%d), tlength(%d), prebuf(%d), minreq(%d)",
1308                         a->maxlength, a->tlength, a->prebuf, a->minreq);
1309         }
1310     }
1311 #endif
1312
1313     pa_sink_input_new_data_done(&data);
1314
1315     if (!sink_input)
1316         goto out;
1317
1318     s = pa_msgobject_new(playback_stream);
1319     s->parent.parent.parent.free = playback_stream_free;
1320     s->parent.parent.process_msg = playback_stream_process_msg;
1321     s->connection = c;
1322     s->syncid = syncid;
1323     s->sink_input = sink_input;
1324     s->is_underrun = true;
1325     s->drain_request = false;
1326     pa_atomic_store(&s->missing, 0);
1327     s->buffer_attr_req = *a;
1328     s->adjust_latency = adjust_latency;
1329     s->early_requests = early_requests;
1330     pa_atomic_store(&s->seek_or_post_in_queue, 0);
1331     s->seek_windex = -1;
1332
1333     s->sink_input->parent.process_msg = sink_input_process_msg;
1334     s->sink_input->pop = sink_input_pop_cb;
1335     s->sink_input->process_underrun = sink_input_process_underrun_cb;
1336     s->sink_input->process_rewind = sink_input_process_rewind_cb;
1337     s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1338     s->sink_input->update_max_request = sink_input_update_max_request_cb;
1339     s->sink_input->kill = sink_input_kill_cb;
1340     s->sink_input->moving = sink_input_moving_cb;
1341     s->sink_input->suspend = sink_input_suspend_cb;
1342     s->sink_input->send_event = sink_input_send_event_cb;
1343     s->sink_input->userdata = s;
1344
1345     start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
1346
1347     fix_playback_buffer_attr(s);
1348
1349     pa_sink_input_get_silence(sink_input, &silence);
1350     memblockq_name = pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s->sink_input->index);
1351     s->memblockq = pa_memblockq_new(
1352             memblockq_name,
1353             start_index,
1354             s->buffer_attr.maxlength,
1355             s->buffer_attr.tlength,
1356             &sink_input->sample_spec,
1357             s->buffer_attr.prebuf,
1358             s->buffer_attr.minreq,
1359             0,
1360             &silence);
1361     pa_xfree(memblockq_name);
1362     pa_memblock_unref(silence.memblock);
1363
1364     pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1365
1366     *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
1367
1368 #ifdef PROTOCOL_NATIVE_DEBUG
1369     pa_log("missing original: %li", (long int) *missing);
1370 #endif
1371
1372     *ss = s->sink_input->sample_spec;
1373     *map = s->sink_input->channel_map;
1374
1375     pa_idxset_put(c->output_streams, s, &s->index);
1376
1377     pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
1378                 ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC,
1379                 (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1380                 (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
1381                 (double) s->configured_sink_latency / PA_USEC_PER_MSEC);
1382
1383     pa_sink_input_put(s->sink_input);
1384
1385 out:
1386     if (formats)
1387         pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
1388
1389     return s;
1390 }
1391
1392 /* Called from IO context */
1393 static void playback_stream_request_bytes(playback_stream *s) {
1394     size_t m, minreq;
1395     int previous_missing;
1396
1397     playback_stream_assert_ref(s);
1398
1399     m = pa_memblockq_pop_missing(s->memblockq);
1400
1401     /* pa_log("request_bytes(%lu) (tlength=%lu minreq=%lu length=%lu really missing=%lli)", */
1402     /*        (unsigned long) m, */
1403     /*        pa_memblockq_get_tlength(s->memblockq), */
1404     /*        pa_memblockq_get_minreq(s->memblockq), */
1405     /*        pa_memblockq_get_length(s->memblockq), */
1406     /*        (long long) pa_memblockq_get_tlength(s->memblockq) - (long long) pa_memblockq_get_length(s->memblockq)); */
1407
1408     if (m <= 0)
1409         return;
1410
1411 #ifdef PROTOCOL_NATIVE_DEBUG
1412     pa_log("request_bytes(%lu)", (unsigned long) m);
1413 #endif
1414
1415     previous_missing = pa_atomic_add(&s->missing, (int) m);
1416     minreq = pa_memblockq_get_minreq(s->memblockq);
1417
1418     if (pa_memblockq_prebuf_active(s->memblockq) ||
1419         (previous_missing < (int) minreq && previous_missing + (int) m >= (int) minreq))
1420         pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
1421 }
1422
1423 /* Called from main context */
1424 static void playback_stream_send_killed(playback_stream *p) {
1425     pa_tagstruct *t;
1426     playback_stream_assert_ref(p);
1427
1428     t = pa_tagstruct_new(NULL, 0);
1429     pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED);
1430     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1431     pa_tagstruct_putu32(t, p->index);
1432     pa_pstream_send_tagstruct(p->connection->pstream, t);
1433 }
1434
1435 /* Called from main context */
1436 static int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
1437     pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1438     pa_native_connection_assert_ref(c);
1439
1440     if (!c->protocol)
1441         return -1;
1442
1443     switch (code) {
1444
1445         case CONNECTION_MESSAGE_REVOKE:
1446             pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata));
1447             break;
1448
1449         case CONNECTION_MESSAGE_RELEASE:
1450             pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata));
1451             break;
1452     }
1453
1454     return 0;
1455 }
1456
1457 /* Called from main context */
1458 static void native_connection_unlink(pa_native_connection *c) {
1459     record_stream *r;
1460     output_stream *o;
1461
1462     pa_assert(c);
1463
1464     if (!c->protocol)
1465         return;
1466
1467     pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c);
1468
1469     if (c->options)
1470         pa_native_options_unref(c->options);
1471
1472     while ((r = pa_idxset_first(c->record_streams, NULL)))
1473         record_stream_unlink(r);
1474
1475     while ((o = pa_idxset_first(c->output_streams, NULL)))
1476         if (playback_stream_isinstance(o))
1477             playback_stream_unlink(PLAYBACK_STREAM(o));
1478         else
1479             upload_stream_unlink(UPLOAD_STREAM(o));
1480
1481     if (c->subscription)
1482         pa_subscription_free(c->subscription);
1483
1484     if (c->pstream)
1485         pa_pstream_unlink(c->pstream);
1486
1487     if (c->auth_timeout_event) {
1488         c->protocol->core->mainloop->time_free(c->auth_timeout_event);
1489         c->auth_timeout_event = NULL;
1490     }
1491
1492     pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
1493     c->protocol = NULL;
1494     pa_native_connection_unref(c);
1495 }
1496
1497 /* Called from main context */
1498 static void native_connection_free(pa_object *o) {
1499     pa_native_connection *c = PA_NATIVE_CONNECTION(o);
1500
1501     pa_assert(c);
1502
1503     native_connection_unlink(c);
1504
1505     pa_idxset_free(c->record_streams, NULL);
1506     pa_idxset_free(c->output_streams, NULL);
1507
1508     pa_pdispatch_unref(c->pdispatch);
1509     pa_pstream_unref(c->pstream);
1510     pa_client_free(c->client);
1511
1512     pa_xfree(c);
1513 }
1514
1515 /* Called from main context */
1516 static void native_connection_send_memblock(pa_native_connection *c) {
1517     uint32_t start;
1518     record_stream *r;
1519
1520     start = PA_IDXSET_INVALID;
1521     for (;;) {
1522         pa_memchunk chunk;
1523
1524         if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index))))
1525             return;
1526
1527         if (start == PA_IDXSET_INVALID)
1528             start = c->rrobin_index;
1529         else if (start == c->rrobin_index)
1530             return;
1531
1532         if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
1533             pa_memchunk schunk = chunk;
1534
1535             if (schunk.length > r->buffer_attr.fragsize)
1536                 schunk.length = r->buffer_attr.fragsize;
1537
1538             pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
1539
1540             pa_memblockq_drop(r->memblockq, schunk.length);
1541             pa_memblock_unref(schunk.memblock);
1542
1543             return;
1544         }
1545     }
1546 }
1547
1548 /*** sink input callbacks ***/
1549
1550 /* Called from thread context */
1551 static void handle_seek(playback_stream *s, int64_t indexw) {
1552     playback_stream_assert_ref(s);
1553
1554 /*     pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
1555
1556     if (s->sink_input->thread_info.underrun_for > 0) {
1557
1558 /*         pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
1559
1560         if (pa_memblockq_is_readable(s->memblockq)) {
1561
1562             /* We just ended an underrun, let's ask the sink
1563              * for a complete rewind rewrite */
1564
1565             pa_log_debug("Requesting rewind due to end of underrun.");
1566             pa_sink_input_request_rewind(s->sink_input,
1567                                          (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 :
1568                                                    s->sink_input->thread_info.underrun_for),
1569                                          false, true, false);
1570         }
1571
1572     } else {
1573         int64_t indexr;
1574
1575         indexr = pa_memblockq_get_read_index(s->memblockq);
1576
1577         if (indexw < indexr) {
1578             /* OK, the sink already asked for this data, so
1579              * let's have it ask us again */
1580
1581             pa_log_debug("Requesting rewind due to rewrite.");
1582             pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), true, false, false);
1583         }
1584     }
1585
1586     playback_stream_request_bytes(s);
1587 }
1588
1589 static void flush_write_no_account(pa_memblockq *q) {
1590     pa_memblockq_flush_write(q, false);
1591 }
1592
1593 /* Called from thread context */
1594 static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1595     pa_sink_input *i = PA_SINK_INPUT(o);
1596     playback_stream *s;
1597
1598     pa_sink_input_assert_ref(i);
1599     s = PLAYBACK_STREAM(i->userdata);
1600     playback_stream_assert_ref(s);
1601
1602     switch (code) {
1603
1604         case SINK_INPUT_MESSAGE_SEEK:
1605         case SINK_INPUT_MESSAGE_POST_DATA: {
1606             int64_t windex = pa_memblockq_get_write_index(s->memblockq);
1607
1608             if (code == SINK_INPUT_MESSAGE_SEEK) {
1609                 /* The client side is incapable of accounting correctly
1610                  * for seeks of a type != PA_SEEK_RELATIVE. We need to be
1611                  * able to deal with that. */
1612
1613                 pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
1614                 windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
1615             }
1616
1617             if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
1618                 if (pa_log_ratelimit(PA_LOG_WARN))
1619                     pa_log_warn("Failed to push data into queue");
1620                 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
1621                 pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, true);
1622             }
1623
1624             /* If more data is in queue, we rewind later instead. */
1625             if (s->seek_windex != -1)
1626                 windex = PA_MIN(windex, s->seek_windex);
1627             if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
1628                 s->seek_windex = windex;
1629             else {
1630                 s->seek_windex = -1;
1631                 handle_seek(s, windex);
1632             }
1633             return 0;
1634         }
1635
1636         case SINK_INPUT_MESSAGE_DRAIN:
1637         case SINK_INPUT_MESSAGE_FLUSH:
1638         case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1639         case SINK_INPUT_MESSAGE_TRIGGER: {
1640
1641             int64_t windex;
1642             pa_sink_input *isync;
1643             void (*func)(pa_memblockq *bq);
1644
1645             switch (code) {
1646                 case SINK_INPUT_MESSAGE_FLUSH:
1647                     func = flush_write_no_account;
1648                     break;
1649
1650                 case SINK_INPUT_MESSAGE_PREBUF_FORCE:
1651                     func = pa_memblockq_prebuf_force;
1652                     break;
1653
1654                 case SINK_INPUT_MESSAGE_DRAIN:
1655                 case SINK_INPUT_MESSAGE_TRIGGER:
1656                     func = pa_memblockq_prebuf_disable;
1657                     break;
1658
1659                 default:
1660                     pa_assert_not_reached();
1661             }
1662
1663             windex = pa_memblockq_get_write_index(s->memblockq);
1664             func(s->memblockq);
1665             handle_seek(s, windex);
1666
1667             /* Do the same for all other members in the sync group */
1668             for (isync = i->sync_prev; isync; isync = isync->sync_prev) {
1669                 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1670                 windex = pa_memblockq_get_write_index(ssync->memblockq);
1671                 func(ssync->memblockq);
1672                 handle_seek(ssync, windex);
1673             }
1674
1675             for (isync = i->sync_next; isync; isync = isync->sync_next) {
1676                 playback_stream *ssync = PLAYBACK_STREAM(isync->userdata);
1677                 windex = pa_memblockq_get_write_index(ssync->memblockq);
1678                 func(ssync->memblockq);
1679                 handle_seek(ssync, windex);
1680             }
1681
1682 #ifdef __TIZEN__
1683             if (code == SINK_INPUT_MESSAGE_FLUSH) {
1684                 pa_log_debug("Requesting rewind due to rewrite. Flush old data in sink");
1685                 pa_sink_input_request_rewind(s->sink_input, 0, FALSE, TRUE, FALSE);
1686             }
1687 #endif
1688
1689             if (code == SINK_INPUT_MESSAGE_DRAIN) {
1690                 if (!pa_memblockq_is_readable(s->memblockq))
1691                     pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL);
1692                 else {
1693                     s->drain_tag = PA_PTR_TO_UINT(userdata);
1694                     s->drain_request = true;
1695                 }
1696             }
1697
1698             return 0;
1699         }
1700
1701         case SINK_INPUT_MESSAGE_UPDATE_LATENCY:
1702             /* Atomically get a snapshot of all timing parameters... */
1703             s->read_index = pa_memblockq_get_read_index(s->memblockq);
1704             s->write_index = pa_memblockq_get_write_index(s->memblockq);
1705             s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq);
1706             s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink);
1707             s->underrun_for = s->sink_input->thread_info.underrun_for;
1708             s->playing_for = s->sink_input->thread_info.playing_for;
1709
1710             return 0;
1711
1712         case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1713             int64_t windex;
1714
1715             windex = pa_memblockq_get_write_index(s->memblockq);
1716
1717             /* We enable prebuffering so that after CORKED -> RUNNING
1718              * transitions we don't have trouble with underruns in case the
1719              * buffer has too little data. This must not be done when draining
1720              * has been requested, however, otherwise the buffered audio would
1721              * never play. */
1722             if (!s->drain_request)
1723                 pa_memblockq_prebuf_force(s->memblockq);
1724
1725             handle_seek(s, windex);
1726
1727             /* Fall through to the default handler */
1728             break;
1729         }
1730
1731         case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1732             pa_usec_t *r = userdata;
1733
1734             *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
1735
1736             /* Fall through, the default handler will add in the extra
1737              * latency added by the resampler */
1738             break;
1739         }
1740
1741         case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
1742             pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1743             pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1744             return 0;
1745         }
1746     }
1747
1748     return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
1749 }
1750
1751 static bool handle_input_underrun(playback_stream *s, bool force) {
1752     bool send_drain;
1753
1754     if (pa_memblockq_is_readable(s->memblockq))
1755         return false;
1756
1757     if (!s->is_underrun)
1758         pa_log_debug("%s %s of '%s'", force ? "Actual" : "Implicit",
1759             s->drain_request ? "drain" : "underrun", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME)));
1760
1761     send_drain = s->drain_request && (force || pa_sink_input_safe_to_remove(s->sink_input));
1762
1763     if (send_drain) {
1764          s->drain_request = false;
1765          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);
1766          pa_log_debug("Drain acknowledged of '%s'", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME)));
1767     } else if (!s->is_underrun) {
1768          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);
1769     }
1770     s->is_underrun = true;
1771     playback_stream_request_bytes(s);
1772     return true;
1773 }
1774
1775 /* Called from thread context */
1776 static bool sink_input_process_underrun_cb(pa_sink_input *i) {
1777     playback_stream *s;
1778
1779     pa_sink_input_assert_ref(i);
1780     s = PLAYBACK_STREAM(i->userdata);
1781     playback_stream_assert_ref(s);
1782
1783     return handle_input_underrun(s, true);
1784 }
1785
1786 #ifdef __TIZEN__
1787 static void _check_zero_pop_timeout(pa_sink_input *i) {
1788     uint32_t zero_pop_time = 0;
1789     playback_stream *s = PLAYBACK_STREAM(i->userdata);
1790
1791     if (pa_memblockq_get_length(s->memblockq) == 0) {
1792         if (i->zero_pop_start_time) {
1793             /* calculate zero pop time in seconds */
1794             zero_pop_time = (uint32_t)((pa_rtclock_now() - i->zero_pop_start_time) / PA_USEC_PER_SEC);
1795
1796             /* check only once per seconds */
1797             if (zero_pop_time > i->old_zero_pop_time) {
1798                 pa_log_debug("zero pop (no sink-input data) for [%u] sec., timeout in [%u] sec.",
1799                              zero_pop_time, i->core->zero_pop_threshold);
1800
1801                 if (zero_pop_time >= i->core->zero_pop_threshold) {
1802                     pa_log_warn("async msgq post : PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT");
1803                     pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s),
1804                                       PLAYBACK_STREAM_MESSAGE_POP_TIMEOUT, NULL, 0, NULL, NULL);
1805                     i->zero_pop_start_time = 0; /* this will make reset count */
1806                 } else {
1807                     i->old_zero_pop_time = zero_pop_time;
1808                 }
1809             }
1810         } else {
1811             pa_log_debug("zero pop start!!!");
1812             i->zero_pop_start_time = pa_rtclock_now();
1813             i->old_zero_pop_time = 0;
1814         }
1815     } else {
1816         if (i->zero_pop_start_time) {
1817             pa_log_debug("zero pop end...");
1818             i->zero_pop_start_time = 0;
1819         }
1820     }
1821 }
1822 #endif
1823
1824 /* Called from thread context */
1825 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
1826     playback_stream *s;
1827
1828     pa_sink_input_assert_ref(i);
1829     s = PLAYBACK_STREAM(i->userdata);
1830     playback_stream_assert_ref(s);
1831     pa_assert(chunk);
1832
1833 #ifdef PROTOCOL_NATIVE_DEBUG
1834     pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq));
1835 #endif
1836
1837 #ifdef __TIZEN__
1838     /* If zero pops exceeds certain threshold, send message to client to handle this situation */
1839     /* FIXME: maybe we can use s->is_underrun to check.... */
1840     if (!i->is_virtual) /* skip for virtual stream */
1841         _check_zero_pop_timeout(i);
1842 #endif
1843
1844     if (!handle_input_underrun(s, false))
1845         s->is_underrun = false;
1846
1847     /* This call will not fail with prebuf=0, hence we check for
1848        underrun explicitly in handle_input_underrun */
1849     if (pa_memblockq_peek(s->memblockq, chunk) < 0)
1850         return -1;
1851
1852     chunk->length = PA_MIN(nbytes, chunk->length);
1853
1854     if (i->thread_info.underrun_for > 0)
1855         pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL);
1856
1857     pa_memblockq_drop(s->memblockq, chunk->length);
1858     playback_stream_request_bytes(s);
1859
1860     return 0;
1861 }
1862
1863 /* Called from thread context */
1864 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
1865     playback_stream *s;
1866
1867     pa_sink_input_assert_ref(i);
1868     s = PLAYBACK_STREAM(i->userdata);
1869     playback_stream_assert_ref(s);
1870
1871     /* If we are in an underrun, then we don't rewind */
1872     if (i->thread_info.underrun_for > 0)
1873         return;
1874
1875     pa_memblockq_rewind(s->memblockq, nbytes);
1876 }
1877
1878 /* Called from thread context */
1879 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
1880     playback_stream *s;
1881
1882     pa_sink_input_assert_ref(i);
1883     s = PLAYBACK_STREAM(i->userdata);
1884     playback_stream_assert_ref(s);
1885
1886     pa_memblockq_set_maxrewind(s->memblockq, nbytes);
1887 }
1888
1889 /* Called from thread context */
1890 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
1891     playback_stream *s;
1892     size_t new_tlength, old_tlength;
1893
1894     pa_sink_input_assert_ref(i);
1895     s = PLAYBACK_STREAM(i->userdata);
1896     playback_stream_assert_ref(s);
1897
1898     old_tlength = pa_memblockq_get_tlength(s->memblockq);
1899     new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
1900
1901     if (old_tlength < new_tlength) {
1902         pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, new_tlength);
1903         pa_memblockq_set_tlength(s->memblockq, new_tlength);
1904         new_tlength = pa_memblockq_get_tlength(s->memblockq);
1905
1906         if (new_tlength == old_tlength)
1907             pa_log_debug("Failed to increase tlength");
1908         else {
1909             pa_log_debug("Notifying client about increased tlength");
1910             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);
1911         }
1912     }
1913 }
1914
1915 /* Called from main context */
1916 static void sink_input_kill_cb(pa_sink_input *i) {
1917     playback_stream *s;
1918
1919     pa_sink_input_assert_ref(i);
1920     s = PLAYBACK_STREAM(i->userdata);
1921     playback_stream_assert_ref(s);
1922
1923     playback_stream_send_killed(s);
1924     playback_stream_unlink(s);
1925 }
1926
1927 /* Called from main context */
1928 static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) {
1929     playback_stream *s;
1930     pa_tagstruct *t;
1931
1932     pa_sink_input_assert_ref(i);
1933     s = PLAYBACK_STREAM(i->userdata);
1934     playback_stream_assert_ref(s);
1935
1936     if (s->connection->version < 15)
1937       return;
1938
1939     t = pa_tagstruct_new(NULL, 0);
1940     pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT);
1941     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1942     pa_tagstruct_putu32(t, s->index);
1943     pa_tagstruct_puts(t, event);
1944     pa_tagstruct_put_proplist(t, pl);
1945     pa_pstream_send_tagstruct(s->connection->pstream, t);
1946 }
1947
1948 /* Called from main context */
1949 static void sink_input_suspend_cb(pa_sink_input *i, bool suspend) {
1950     playback_stream *s;
1951     pa_tagstruct *t;
1952
1953     pa_sink_input_assert_ref(i);
1954     s = PLAYBACK_STREAM(i->userdata);
1955     playback_stream_assert_ref(s);
1956
1957     if (s->connection->version < 12)
1958       return;
1959
1960     t = pa_tagstruct_new(NULL, 0);
1961     pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED);
1962     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1963     pa_tagstruct_putu32(t, s->index);
1964     pa_tagstruct_put_boolean(t, suspend);
1965     pa_pstream_send_tagstruct(s->connection->pstream, t);
1966 }
1967
1968 /* Called from main context */
1969 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1970     playback_stream *s;
1971     pa_tagstruct *t;
1972
1973     pa_sink_input_assert_ref(i);
1974     s = PLAYBACK_STREAM(i->userdata);
1975     playback_stream_assert_ref(s);
1976
1977     if (!dest)
1978         return;
1979
1980     fix_playback_buffer_attr(s);
1981     pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
1982     pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
1983
1984     if (s->connection->version < 12)
1985       return;
1986
1987     t = pa_tagstruct_new(NULL, 0);
1988     pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED);
1989     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
1990     pa_tagstruct_putu32(t, s->index);
1991     pa_tagstruct_putu32(t, dest->index);
1992     pa_tagstruct_puts(t, dest->name);
1993     pa_tagstruct_put_boolean(t, pa_sink_get_state(dest) == PA_SINK_SUSPENDED);
1994
1995     if (s->connection->version >= 13) {
1996         pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
1997         pa_tagstruct_putu32(t, s->buffer_attr.tlength);
1998         pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
1999         pa_tagstruct_putu32(t, s->buffer_attr.minreq);
2000         pa_tagstruct_put_usec(t, s->configured_sink_latency);
2001     }
2002
2003     pa_pstream_send_tagstruct(s->connection->pstream, t);
2004 }
2005
2006 /*** source_output callbacks ***/
2007
2008 /* Called from thread context */
2009 static int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
2010     pa_source_output *o = PA_SOURCE_OUTPUT(_o);
2011     record_stream *s;
2012
2013     pa_source_output_assert_ref(o);
2014     s = RECORD_STREAM(o->userdata);
2015     record_stream_assert_ref(s);
2016
2017     switch (code) {
2018         case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY:
2019             /* Atomically get a snapshot of all timing parameters... */
2020             s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of) : 0;
2021             s->current_source_latency = pa_source_get_latency_within_thread(o->source);
2022             s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly);
2023             return 0;
2024     }
2025
2026     return pa_source_output_process_msg(_o, code, userdata, offset, chunk);
2027 }
2028
2029 /* Called from thread context */
2030 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
2031     record_stream *s;
2032
2033     pa_source_output_assert_ref(o);
2034     s = RECORD_STREAM(o->userdata);
2035     record_stream_assert_ref(s);
2036     pa_assert(chunk);
2037
2038     pa_atomic_add(&s->on_the_fly, chunk->length);
2039     pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
2040 }
2041
2042 static void source_output_kill_cb(pa_source_output *o) {
2043     record_stream *s;
2044
2045     pa_source_output_assert_ref(o);
2046     s = RECORD_STREAM(o->userdata);
2047     record_stream_assert_ref(s);
2048
2049     record_stream_send_killed(s);
2050     record_stream_unlink(s);
2051 }
2052
2053 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
2054     record_stream *s;
2055
2056     pa_source_output_assert_ref(o);
2057     s = RECORD_STREAM(o->userdata);
2058     record_stream_assert_ref(s);
2059
2060     /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
2061
2062     return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec);
2063 }
2064
2065 /* Called from main context */
2066 static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) {
2067     record_stream *s;
2068     pa_tagstruct *t;
2069
2070     pa_source_output_assert_ref(o);
2071     s = RECORD_STREAM(o->userdata);
2072     record_stream_assert_ref(s);
2073
2074     if (s->connection->version < 15)
2075       return;
2076
2077     t = pa_tagstruct_new(NULL, 0);
2078     pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT);
2079     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
2080     pa_tagstruct_putu32(t, s->index);
2081     pa_tagstruct_puts(t, event);
2082     pa_tagstruct_put_proplist(t, pl);
2083     pa_pstream_send_tagstruct(s->connection->pstream, t);
2084 }
2085
2086 /* Called from main context */
2087 static void source_output_suspend_cb(pa_source_output *o, bool suspend) {
2088     record_stream *s;
2089     pa_tagstruct *t;
2090
2091     pa_source_output_assert_ref(o);
2092     s = RECORD_STREAM(o->userdata);
2093     record_stream_assert_ref(s);
2094
2095     if (s->connection->version < 12)
2096       return;
2097
2098     t = pa_tagstruct_new(NULL, 0);
2099     pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED);
2100     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
2101     pa_tagstruct_putu32(t, s->index);
2102     pa_tagstruct_put_boolean(t, suspend);
2103     pa_pstream_send_tagstruct(s->connection->pstream, t);
2104 }
2105
2106 /* Called from main context */
2107 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
2108     record_stream *s;
2109     pa_tagstruct *t;
2110
2111     pa_source_output_assert_ref(o);
2112     s = RECORD_STREAM(o->userdata);
2113     record_stream_assert_ref(s);
2114
2115     if (!dest)
2116         return;
2117
2118     fix_record_buffer_attr_pre(s);
2119     pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
2120     pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
2121     fix_record_buffer_attr_post(s);
2122
2123     if (s->connection->version < 12)
2124       return;
2125
2126     t = pa_tagstruct_new(NULL, 0);
2127     pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED);
2128     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
2129     pa_tagstruct_putu32(t, s->index);
2130     pa_tagstruct_putu32(t, dest->index);
2131     pa_tagstruct_puts(t, dest->name);
2132     pa_tagstruct_put_boolean(t, pa_source_get_state(dest) == PA_SOURCE_SUSPENDED);
2133
2134     if (s->connection->version >= 13) {
2135         pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
2136         pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
2137         pa_tagstruct_put_usec(t, s->configured_source_latency);
2138     }
2139
2140     pa_pstream_send_tagstruct(s->connection->pstream, t);
2141 }
2142
2143 /*** pdispatch callbacks ***/
2144
2145 static void protocol_error(pa_native_connection *c) {
2146     pa_log("protocol error, kicking client");
2147     native_connection_unlink(c);
2148 }
2149
2150 #define CHECK_VALIDITY(pstream, expression, tag, error) do { \
2151 if (!(expression)) { \
2152     pa_pstream_send_error((pstream), (tag), (error)); \
2153     return; \
2154 } \
2155 } while(0);
2156
2157 #define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \
2158 if (!(expression)) { \
2159     pa_pstream_send_error((pstream), (tag), (error)); \
2160     goto label; \
2161 } \
2162 } while(0);
2163
2164 static pa_tagstruct *reply_new(uint32_t tag) {
2165     pa_tagstruct *reply;
2166
2167     reply = pa_tagstruct_new(NULL, 0);
2168     pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
2169     pa_tagstruct_putu32(reply, tag);
2170     return reply;
2171 }
2172
2173 static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2174     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2175     playback_stream *s;
2176     uint32_t sink_index, syncid, missing = 0;
2177     pa_buffer_attr attr;
2178     const char *name = NULL, *sink_name;
2179     pa_sample_spec ss;
2180     pa_channel_map map;
2181     pa_tagstruct *reply;
2182     pa_sink *sink = NULL;
2183     pa_cvolume volume;
2184     bool
2185         corked = false,
2186         no_remap = false,
2187         no_remix = false,
2188         fix_format = false,
2189         fix_rate = false,
2190         fix_channels = false,
2191         no_move = false,
2192         variable_rate = false,
2193         muted = false,
2194         adjust_latency = false,
2195         early_requests = false,
2196         dont_inhibit_auto_suspend = false,
2197         volume_set = true,
2198         muted_set = false,
2199         fail_on_suspend = false,
2200         relative_volume = false,
2201         passthrough = false,
2202         ramp_muted = false;
2203
2204     pa_sink_input_flags_t flags = 0;
2205     pa_proplist *p = NULL;
2206     int ret = PA_ERR_INVALID;
2207     uint8_t n_formats = 0;
2208     pa_format_info *format;
2209     pa_idxset *formats = NULL;
2210     uint32_t i;
2211
2212     pa_native_connection_assert_ref(c);
2213     pa_assert(t);
2214     memset(&attr, 0, sizeof(attr));
2215
2216     if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2217         pa_tagstruct_get(
2218                 t,
2219                 PA_TAG_SAMPLE_SPEC, &ss,
2220                 PA_TAG_CHANNEL_MAP, &map,
2221                 PA_TAG_U32, &sink_index,
2222                 PA_TAG_STRING, &sink_name,
2223                 PA_TAG_U32, &attr.maxlength,
2224                 PA_TAG_BOOLEAN, &corked,
2225                 PA_TAG_U32, &attr.tlength,
2226                 PA_TAG_U32, &attr.prebuf,
2227                 PA_TAG_U32, &attr.minreq,
2228                 PA_TAG_U32, &syncid,
2229                 PA_TAG_CVOLUME, &volume,
2230                 PA_TAG_INVALID) < 0) {
2231
2232         protocol_error(c);
2233         goto finish;
2234     }
2235
2236     CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2237     CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish);
2238     CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish);
2239     CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2240     CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2241
2242     p = pa_proplist_new();
2243
2244     if (name)
2245         pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2246
2247     if (c->version >= 12) {
2248         /* Since 0.9.8 the user can ask for a couple of additional flags */
2249
2250         if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2251             pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2252             pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2253             pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2254             pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2255             pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2256             pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2257
2258             protocol_error(c);
2259             goto finish;
2260         }
2261     }
2262
2263     if (c->version >= 13) {
2264
2265         if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
2266             pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2267             pa_tagstruct_get_proplist(t, p) < 0) {
2268
2269             protocol_error(c);
2270             goto finish;
2271         }
2272     }
2273
2274     if (c->version >= 14) {
2275
2276         if (pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2277             pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2278
2279             protocol_error(c);
2280             goto finish;
2281         }
2282     }
2283
2284     if (c->version >= 15) {
2285
2286         if (pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2287             pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2288             pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2289
2290             protocol_error(c);
2291             goto finish;
2292         }
2293     }
2294
2295     if (c->version >= 17) {
2296
2297         if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) {
2298
2299             protocol_error(c);
2300             goto finish;
2301         }
2302     }
2303
2304     if (c->version >= 18) {
2305
2306         if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) {
2307             protocol_error(c);
2308             goto finish;
2309         }
2310     }
2311
2312     if (c->version >= 21) {
2313
2314         if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2315             protocol_error(c);
2316             goto finish;
2317         }
2318
2319         if (n_formats)
2320             formats = pa_idxset_new(NULL, NULL);
2321
2322         for (i = 0; i < n_formats; i++) {
2323             format = pa_format_info_new();
2324             if (pa_tagstruct_get_format_info(t, format) < 0) {
2325                 protocol_error(c);
2326                 goto finish;
2327             }
2328             pa_idxset_put(formats, format, NULL);
2329         }
2330
2331     }
2332
2333     if (n_formats == 0) {
2334         CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2335         CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2336         CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2337     } else {
2338         PA_IDXSET_FOREACH(format, formats, i) {
2339             CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2340         }
2341     }
2342
2343     if (pa_tagstruct_get_boolean(t, &ramp_muted) < 0 ) {
2344         protocol_error(c);
2345         goto finish;
2346     }
2347
2348     if (!pa_tagstruct_eof(t)) {
2349         protocol_error(c);
2350         goto finish;
2351     }
2352
2353     if (sink_index != PA_INVALID_INDEX) {
2354
2355         if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) {
2356             pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2357             goto finish;
2358         }
2359
2360     } else if (sink_name) {
2361
2362         if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) {
2363             pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2364             goto finish;
2365         }
2366     }
2367
2368     flags =
2369         (corked ? PA_SINK_INPUT_START_CORKED : 0) |
2370         (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) |
2371         (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) |
2372         (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) |
2373         (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) |
2374         (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) |
2375         (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
2376         (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) |
2377         (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2378         (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) |
2379         (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0) |
2380         (ramp_muted ? PA_SINK_INPUT_START_RAMP_MUTED : 0);
2381
2382     /* Only since protocol version 15 there's a separate muted_set
2383      * flag. For older versions we synthesize it here */
2384     muted_set = muted_set || muted;
2385
2386     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);
2387     /* We no longer own the formats idxset */
2388     formats = NULL;
2389
2390     CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2391
2392     reply = reply_new(tag);
2393     pa_tagstruct_putu32(reply, s->index);
2394     pa_assert(s->sink_input);
2395     pa_tagstruct_putu32(reply, s->sink_input->index);
2396     pa_tagstruct_putu32(reply, missing);
2397
2398 #ifdef PROTOCOL_NATIVE_DEBUG
2399     pa_log("initial request is %u", missing);
2400 #endif
2401
2402     if (c->version >= 9) {
2403         /* Since 0.9.0 we support sending the buffer metrics back to the client */
2404
2405         pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2406         pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
2407         pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
2408         pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
2409     }
2410
2411     if (c->version >= 12) {
2412         /* Since 0.9.8 we support sending the chosen sample
2413          * spec/channel map/device/suspend status back to the
2414          * client */
2415
2416         pa_tagstruct_put_sample_spec(reply, &ss);
2417         pa_tagstruct_put_channel_map(reply, &map);
2418
2419         pa_tagstruct_putu32(reply, s->sink_input->sink->index);
2420         pa_tagstruct_puts(reply, s->sink_input->sink->name);
2421
2422         pa_tagstruct_put_boolean(reply, pa_sink_get_state(s->sink_input->sink) == PA_SINK_SUSPENDED);
2423     }
2424
2425     if (c->version >= 13)
2426         pa_tagstruct_put_usec(reply, s->configured_sink_latency);
2427
2428     if (c->version >= 21) {
2429         /* Send back the format we negotiated */
2430         if (s->sink_input->format)
2431             pa_tagstruct_put_format_info(reply, s->sink_input->format);
2432         else {
2433             pa_format_info *f = pa_format_info_new();
2434             pa_tagstruct_put_format_info(reply, f);
2435             pa_format_info_free(f);
2436         }
2437     }
2438
2439     pa_pstream_send_tagstruct(c->pstream, reply);
2440
2441 finish:
2442     if (p)
2443         pa_proplist_free(p);
2444     if (formats)
2445         pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
2446 }
2447
2448 static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2449     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2450     uint32_t channel;
2451
2452     pa_native_connection_assert_ref(c);
2453     pa_assert(t);
2454
2455     if (pa_tagstruct_getu32(t, &channel) < 0 ||
2456         !pa_tagstruct_eof(t)) {
2457         protocol_error(c);
2458         return;
2459     }
2460
2461     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2462
2463     switch (command) {
2464
2465         case PA_COMMAND_DELETE_PLAYBACK_STREAM: {
2466             playback_stream *s;
2467             if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) {
2468                 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2469                 return;
2470             }
2471
2472             playback_stream_unlink(s);
2473             break;
2474         }
2475
2476         case PA_COMMAND_DELETE_RECORD_STREAM: {
2477             record_stream *s;
2478             if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) {
2479                 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2480                 return;
2481             }
2482
2483             record_stream_unlink(s);
2484             break;
2485         }
2486
2487         case PA_COMMAND_DELETE_UPLOAD_STREAM: {
2488             upload_stream *s;
2489
2490             if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) {
2491                 pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST);
2492                 return;
2493             }
2494
2495             upload_stream_unlink(s);
2496             break;
2497         }
2498
2499         default:
2500             pa_assert_not_reached();
2501     }
2502
2503     pa_pstream_send_simple_ack(c->pstream, tag);
2504 }
2505
2506 #ifdef __TIZEN__
2507 static void command_check_privilege(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2508     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2509     const char *privilege;
2510
2511     pa_native_connection_assert_ref(c);
2512     pa_assert(t);
2513
2514     if (pa_tagstruct_gets(t, &privilege) < 0) {
2515         protocol_error(c);
2516         return;
2517     }
2518
2519 #ifdef USE_SECURITY
2520     CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), privilege), tag, PA_ERR_ACCESS);
2521 #else
2522     pa_log_warn("Cannot check privilege %s", privilege);
2523 #endif
2524     pa_pstream_send_simple_ack(c->pstream, tag);
2525 }
2526 #endif
2527
2528 static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2529     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2530     record_stream *s;
2531     pa_buffer_attr attr;
2532     uint32_t source_index;
2533     const char *name = NULL, *source_name;
2534     pa_sample_spec ss;
2535     pa_channel_map map;
2536     pa_tagstruct *reply;
2537     pa_source *source = NULL;
2538     pa_cvolume volume;
2539     bool
2540         corked = false,
2541         no_remap = false,
2542         no_remix = false,
2543         fix_format = false,
2544         fix_rate = false,
2545         fix_channels = false,
2546         no_move = false,
2547         variable_rate = false,
2548         muted = false,
2549         adjust_latency = false,
2550         peak_detect = false,
2551         early_requests = false,
2552         dont_inhibit_auto_suspend = false,
2553         volume_set = false,
2554         muted_set = false,
2555         fail_on_suspend = false,
2556         relative_volume = false,
2557         passthrough = false;
2558
2559     pa_source_output_flags_t flags = 0;
2560     pa_proplist *p = NULL;
2561     uint32_t direct_on_input_idx = PA_INVALID_INDEX;
2562     pa_sink_input *direct_on_input = NULL;
2563     int ret = PA_ERR_INVALID;
2564     uint8_t n_formats = 0;
2565     pa_format_info *format;
2566     pa_idxset *formats = NULL;
2567     uint32_t i;
2568
2569 #ifdef USE_SECURITY
2570     bool is_virtual_stream = false;
2571 #endif
2572
2573     pa_native_connection_assert_ref(c);
2574     pa_assert(t);
2575
2576     memset(&attr, 0, sizeof(attr));
2577
2578     if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
2579         pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
2580         pa_tagstruct_get_channel_map(t, &map) < 0 ||
2581         pa_tagstruct_getu32(t, &source_index) < 0 ||
2582         pa_tagstruct_gets(t, &source_name) < 0 ||
2583         pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
2584         pa_tagstruct_get_boolean(t, &corked) < 0 ||
2585         pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
2586
2587         protocol_error(c);
2588         goto finish;
2589     }
2590
2591     CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish);
2592     CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish);
2593     CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish);
2594     CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish);
2595
2596 #ifdef USE_SECURITY
2597     pa_tagstruct_get_boolean(t, &is_virtual_stream);
2598     pa_log_info("is virtual stream : %s", pa_yes_no(is_virtual_stream));
2599     if (!is_virtual_stream) {
2600         CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), RECORDER_PRIVILEGE),
2601                        tag, PA_ERR_ACCESS);
2602     }
2603 #endif /* USE_SECURITY */
2604
2605     p = pa_proplist_new();
2606
2607     if (name)
2608         pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2609
2610     if (c->version >= 12) {
2611         /* Since 0.9.8 the user can ask for a couple of additional flags */
2612
2613         if (pa_tagstruct_get_boolean(t, &no_remap) < 0 ||
2614             pa_tagstruct_get_boolean(t, &no_remix) < 0 ||
2615             pa_tagstruct_get_boolean(t, &fix_format) < 0 ||
2616             pa_tagstruct_get_boolean(t, &fix_rate) < 0 ||
2617             pa_tagstruct_get_boolean(t, &fix_channels) < 0 ||
2618             pa_tagstruct_get_boolean(t, &no_move) < 0 ||
2619             pa_tagstruct_get_boolean(t, &variable_rate) < 0) {
2620
2621             protocol_error(c);
2622             goto finish;
2623         }
2624     }
2625
2626     if (c->version >= 13) {
2627
2628         if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
2629             pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
2630             pa_tagstruct_get_proplist(t, p) < 0 ||
2631             pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) {
2632
2633             protocol_error(c);
2634             goto finish;
2635         }
2636     }
2637
2638     if (c->version >= 14) {
2639
2640         if (pa_tagstruct_get_boolean(t, &early_requests) < 0) {
2641             protocol_error(c);
2642             goto finish;
2643         }
2644     }
2645
2646     if (c->version >= 15) {
2647
2648         if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 ||
2649             pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) {
2650
2651             protocol_error(c);
2652             goto finish;
2653         }
2654     }
2655
2656     if (c->version >= 22) {
2657         /* For newer client versions (with per-source-output volumes), we try
2658          * to make the behaviour for playback and record streams the same. */
2659         volume_set = true;
2660
2661         if (pa_tagstruct_getu8(t, &n_formats) < 0) {
2662             protocol_error(c);
2663             goto finish;
2664         }
2665
2666         if (n_formats)
2667             formats = pa_idxset_new(NULL, NULL);
2668
2669         for (i = 0; i < n_formats; i++) {
2670             format = pa_format_info_new();
2671             if (pa_tagstruct_get_format_info(t, format) < 0) {
2672                 protocol_error(c);
2673                 goto finish;
2674             }
2675             pa_idxset_put(formats, format, NULL);
2676         }
2677
2678         if (pa_tagstruct_get_cvolume(t, &volume) < 0 ||
2679             pa_tagstruct_get_boolean(t, &muted) < 0 ||
2680             pa_tagstruct_get_boolean(t, &volume_set) < 0 ||
2681             pa_tagstruct_get_boolean(t, &muted_set) < 0 ||
2682             pa_tagstruct_get_boolean(t, &relative_volume) < 0 ||
2683             pa_tagstruct_get_boolean(t, &passthrough) < 0) {
2684
2685             protocol_error(c);
2686             goto finish;
2687         }
2688
2689         CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish);
2690     }
2691
2692     if (n_formats == 0) {
2693         CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish);
2694         CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID, finish);
2695         CHECK_VALIDITY_GOTO(c->pstream, c->version < 22 || (volume.channels == ss.channels), tag, PA_ERR_INVALID, finish);
2696         CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish);
2697     } else {
2698         PA_IDXSET_FOREACH(format, formats, i) {
2699             CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish);
2700         }
2701     }
2702
2703     if (!pa_tagstruct_eof(t)) {
2704         protocol_error(c);
2705         goto finish;
2706     }
2707
2708     if (source_index != PA_INVALID_INDEX) {
2709
2710         if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) {
2711             pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2712             goto finish;
2713         }
2714
2715     } else if (source_name) {
2716
2717         if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
2718             pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2719             goto finish;
2720         }
2721     }
2722
2723     if (direct_on_input_idx != PA_INVALID_INDEX) {
2724
2725         if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) {
2726             pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
2727             goto finish;
2728         }
2729     }
2730
2731     flags =
2732         (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) |
2733         (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) |
2734         (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) |
2735         (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) |
2736         (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) |
2737         (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) |
2738         (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
2739         (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) |
2740         (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
2741         (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) |
2742         (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0);
2743
2744     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);
2745
2746     CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish);
2747
2748     reply = reply_new(tag);
2749     pa_tagstruct_putu32(reply, s->index);
2750     pa_assert(s->source_output);
2751     pa_tagstruct_putu32(reply, s->source_output->index);
2752
2753     if (c->version >= 9) {
2754         /* Since 0.9 we support sending the buffer metrics back to the client */
2755
2756         pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
2757         pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
2758     }
2759
2760     if (c->version >= 12) {
2761         /* Since 0.9.8 we support sending the chosen sample
2762          * spec/channel map/device/suspend status back to the
2763          * client */
2764
2765         pa_tagstruct_put_sample_spec(reply, &ss);
2766         pa_tagstruct_put_channel_map(reply, &map);
2767
2768         pa_tagstruct_putu32(reply, s->source_output->source->index);
2769         pa_tagstruct_puts(reply, s->source_output->source->name);
2770
2771         pa_tagstruct_put_boolean(reply, pa_source_get_state(s->source_output->source) == PA_SOURCE_SUSPENDED);
2772     }
2773
2774     if (c->version >= 13)
2775         pa_tagstruct_put_usec(reply, s->configured_source_latency);
2776
2777     if (c->version >= 22) {
2778         /* Send back the format we negotiated */
2779         if (s->source_output->format)
2780             pa_tagstruct_put_format_info(reply, s->source_output->format);
2781         else {
2782             pa_format_info *f = pa_format_info_new();
2783             pa_tagstruct_put_format_info(reply, f);
2784             pa_format_info_free(f);
2785         }
2786     }
2787
2788     pa_pstream_send_tagstruct(c->pstream, reply);
2789
2790 finish:
2791     if (p)
2792         pa_proplist_free(p);
2793     if (formats)
2794         pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
2795 }
2796
2797 static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2798     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2799     int ret;
2800
2801     pa_native_connection_assert_ref(c);
2802     pa_assert(t);
2803
2804     if (!pa_tagstruct_eof(t)) {
2805         protocol_error(c);
2806         return;
2807     }
2808
2809     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
2810     ret = pa_core_exit(c->protocol->core, false, 0);
2811     CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS);
2812
2813     pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
2814
2815     pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */
2816 }
2817
2818 static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2819     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2820     const void*cookie;
2821     pa_tagstruct *reply;
2822     bool shm_on_remote = false, do_shm;
2823
2824     pa_native_connection_assert_ref(c);
2825     pa_assert(t);
2826
2827     if (pa_tagstruct_getu32(t, &c->version) < 0 ||
2828         pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 ||
2829         !pa_tagstruct_eof(t)) {
2830         protocol_error(c);
2831         return;
2832     }
2833
2834     /* Minimum supported version */
2835     if (c->version < 8) {
2836         pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION);
2837         return;
2838     }
2839
2840     /* Starting with protocol version 13 the MSB of the version tag
2841        reflects if shm is available for this pa_native_connection or
2842        not. */
2843     if (c->version >= 13) {
2844         shm_on_remote = !!(c->version & 0x80000000U);
2845         c->version &= 0x7FFFFFFFU;
2846     }
2847
2848     pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);
2849
2850     pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version);
2851
2852     if (!c->authorized) {
2853         bool success = false;
2854
2855 #ifdef HAVE_CREDS
2856         const pa_creds *creds;
2857
2858         if ((creds = pa_pdispatch_creds(pd))) {
2859             if (creds->uid == getuid())
2860                 success = true;
2861             else if (c->options->auth_group) {
2862                 int r;
2863                 gid_t gid;
2864
2865                 if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1)
2866                     pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group);
2867                 else if (gid == creds->gid)
2868                     success = true;
2869
2870                 if (!success) {
2871                     if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0)
2872                         pa_log_warn("Failed to check group membership.");
2873                     else if (r > 0)
2874                         success = true;
2875                 }
2876             }
2877
2878             pa_log_info("Got credentials: uid=%lu gid=%lu success=%i",
2879                         (unsigned long) creds->uid,
2880                         (unsigned long) creds->gid,
2881                         (int) success);
2882         }
2883 #endif
2884
2885         if (!success && c->options->auth_cookie) {
2886             const uint8_t *ac;
2887
2888             if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH)))
2889                 if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0)
2890                     success = true;
2891         }
2892
2893         if (!success) {
2894             pa_log_warn("Denied access to client with invalid authorization data.");
2895             pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS);
2896             return;
2897         }
2898
2899         c->authorized = true;
2900         if (c->auth_timeout_event) {
2901             c->protocol->core->mainloop->time_free(c->auth_timeout_event);
2902             c->auth_timeout_event = NULL;
2903         }
2904     }
2905
2906     /* Enable shared memory support if possible */
2907     do_shm =
2908         pa_mempool_is_shared(c->protocol->core->mempool) &&
2909         c->is_local;
2910
2911     pa_log_debug("SHM possible: %s", pa_yes_no(do_shm));
2912
2913     if (do_shm)
2914         if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
2915             do_shm = false;
2916
2917 #ifdef HAVE_CREDS
2918     if (do_shm) {
2919         /* Only enable SHM if both sides are owned by the same
2920          * user. This is a security measure because otherwise data
2921          * private to the user might leak. */
2922
2923         const pa_creds *creds;
2924         if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
2925             do_shm = false;
2926     }
2927 #endif
2928
2929     pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
2930     pa_pstream_enable_shm(c->pstream, do_shm);
2931
2932     reply = reply_new(tag);
2933     pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0));
2934
2935 #ifdef HAVE_CREDS
2936 {
2937     /* SHM support is only enabled after both sides made sure they are the same user. */
2938
2939     pa_creds ucred;
2940
2941     ucred.uid = getuid();
2942     ucred.gid = getgid();
2943
2944     pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred);
2945 }
2946 #else
2947     pa_pstream_send_tagstruct(c->pstream, reply);
2948 #endif
2949 }
2950
2951 static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2952     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2953     const char *name = NULL;
2954     pa_proplist *p;
2955     pa_tagstruct *reply;
2956
2957     pa_native_connection_assert_ref(c);
2958     pa_assert(t);
2959
2960     p = pa_proplist_new();
2961
2962     if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) ||
2963         (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
2964         !pa_tagstruct_eof(t)) {
2965
2966         protocol_error(c);
2967         pa_proplist_free(p);
2968         return;
2969     }
2970
2971     if (name)
2972         if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) {
2973             pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
2974             pa_proplist_free(p);
2975             return;
2976         }
2977
2978     pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p);
2979     pa_proplist_free(p);
2980
2981     reply = reply_new(tag);
2982
2983     if (c->version >= 13)
2984         pa_tagstruct_putu32(reply, c->client->index);
2985
2986     pa_pstream_send_tagstruct(c->pstream, reply);
2987 }
2988
2989 static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2990     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
2991     const char *name;
2992     uint32_t idx = PA_IDXSET_INVALID;
2993
2994     pa_native_connection_assert_ref(c);
2995     pa_assert(t);
2996
2997     if (pa_tagstruct_gets(t, &name) < 0 ||
2998         !pa_tagstruct_eof(t)) {
2999         protocol_error(c);
3000         return;
3001     }
3002
3003     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3004     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);
3005
3006     if (command == PA_COMMAND_LOOKUP_SINK) {
3007         pa_sink *sink;
3008         if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK)))
3009             idx = sink->index;
3010     } else {
3011         pa_source *source;
3012         pa_assert(command == PA_COMMAND_LOOKUP_SOURCE);
3013         if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE)))
3014             idx = source->index;
3015     }
3016
3017     if (idx == PA_IDXSET_INVALID)
3018         pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3019     else {
3020         pa_tagstruct *reply;
3021         reply = reply_new(tag);
3022         pa_tagstruct_putu32(reply, idx);
3023         pa_pstream_send_tagstruct(c->pstream, reply);
3024     }
3025 }
3026
3027 static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3028     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3029     uint32_t idx;
3030     playback_stream *s;
3031
3032     pa_native_connection_assert_ref(c);
3033     pa_assert(t);
3034
3035     if (pa_tagstruct_getu32(t, &idx) < 0 ||
3036         !pa_tagstruct_eof(t)) {
3037         protocol_error(c);
3038         return;
3039     }
3040
3041     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3042     s = pa_idxset_get_by_index(c->output_streams, idx);
3043     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3044     CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3045
3046     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);
3047 }
3048
3049 static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3050     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3051     pa_tagstruct *reply;
3052     const pa_mempool_stat *stat;
3053
3054     pa_native_connection_assert_ref(c);
3055     pa_assert(t);
3056
3057     if (!pa_tagstruct_eof(t)) {
3058         protocol_error(c);
3059         return;
3060     }
3061
3062     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3063
3064     stat = pa_mempool_get_stat(c->protocol->core->mempool);
3065
3066     reply = reply_new(tag);
3067     pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated));
3068     pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size));
3069     pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated));
3070     pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size));
3071     pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core));
3072     pa_pstream_send_tagstruct(c->pstream, reply);
3073 }
3074
3075 static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3076     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3077     pa_tagstruct *reply;
3078     playback_stream *s;
3079     struct timeval tv, now;
3080     uint32_t idx;
3081
3082     pa_native_connection_assert_ref(c);
3083     pa_assert(t);
3084
3085     if (pa_tagstruct_getu32(t, &idx) < 0 ||
3086         pa_tagstruct_get_timeval(t, &tv) < 0 ||
3087         !pa_tagstruct_eof(t)) {
3088         protocol_error(c);
3089         return;
3090     }
3091
3092     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3093     s = pa_idxset_get_by_index(c->output_streams, idx);
3094     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3095     CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3096
3097     /* Get an atomic snapshot of all timing parameters */
3098     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);
3099
3100     reply = reply_new(tag);
3101     pa_tagstruct_put_usec(reply,
3102                           s->current_sink_latency +
3103                           pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec));
3104     pa_tagstruct_put_usec(reply, 0);
3105     pa_tagstruct_put_boolean(reply,
3106                              s->playing_for > 0 &&
3107                              pa_sink_get_state(s->sink_input->sink) == PA_SINK_RUNNING &&
3108                              pa_sink_input_get_state(s->sink_input) == PA_SINK_INPUT_RUNNING);
3109     pa_tagstruct_put_timeval(reply, &tv);
3110     pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
3111     pa_tagstruct_puts64(reply, s->write_index);
3112     pa_tagstruct_puts64(reply, s->read_index);
3113
3114     if (c->version >= 13) {
3115         pa_tagstruct_putu64(reply, s->underrun_for);
3116         pa_tagstruct_putu64(reply, s->playing_for);
3117     }
3118
3119     pa_pstream_send_tagstruct(c->pstream, reply);
3120 }
3121
3122 static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3123     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3124     pa_tagstruct *reply;
3125     record_stream *s;
3126     struct timeval tv, now;
3127     uint32_t idx;
3128
3129     pa_native_connection_assert_ref(c);
3130     pa_assert(t);
3131
3132     if (pa_tagstruct_getu32(t, &idx) < 0 ||
3133         pa_tagstruct_get_timeval(t, &tv) < 0 ||
3134         !pa_tagstruct_eof(t)) {
3135         protocol_error(c);
3136         return;
3137     }
3138
3139     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3140     s = pa_idxset_get_by_index(c->record_streams, idx);
3141     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3142
3143     /* Get an atomic snapshot of all timing parameters */
3144     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);
3145
3146     reply = reply_new(tag);
3147     pa_tagstruct_put_usec(reply, s->current_monitor_latency);
3148     pa_tagstruct_put_usec(reply,
3149                           s->current_source_latency +
3150                           pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->source->sample_spec));
3151     pa_tagstruct_put_boolean(reply,
3152                              pa_source_get_state(s->source_output->source) == PA_SOURCE_RUNNING &&
3153                              pa_source_output_get_state(s->source_output) == PA_SOURCE_OUTPUT_RUNNING);
3154     pa_tagstruct_put_timeval(reply, &tv);
3155     pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
3156     pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
3157     pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq));
3158     pa_pstream_send_tagstruct(c->pstream, reply);
3159 }
3160
3161 static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3162     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3163     upload_stream *s;
3164     uint32_t length;
3165     const char *name = NULL;
3166     pa_sample_spec ss;
3167     pa_channel_map map;
3168     pa_tagstruct *reply;
3169     pa_proplist *p;
3170
3171     pa_native_connection_assert_ref(c);
3172     pa_assert(t);
3173
3174     if (pa_tagstruct_gets(t, &name) < 0 ||
3175         pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
3176         pa_tagstruct_get_channel_map(t, &map) < 0 ||
3177         pa_tagstruct_getu32(t, &length) < 0) {
3178         protocol_error(c);
3179         return;
3180     }
3181
3182     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3183     CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
3184     CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
3185     CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
3186     CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID);
3187     CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE);
3188
3189     p = pa_proplist_new();
3190
3191     if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
3192         !pa_tagstruct_eof(t)) {
3193
3194         protocol_error(c);
3195         pa_proplist_free(p);
3196         return;
3197     }
3198
3199     if (c->version < 13)
3200         pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
3201     else if (!name)
3202         if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID)))
3203             name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME);
3204
3205     if (!name || !pa_namereg_is_valid_name(name)) {
3206         pa_proplist_free(p);
3207         CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID);
3208     }
3209
3210     s = upload_stream_new(c, &ss, &map, name, length, p);
3211     pa_proplist_free(p);
3212
3213     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
3214
3215     reply = reply_new(tag);
3216     pa_tagstruct_putu32(reply, s->index);
3217     pa_tagstruct_putu32(reply, length);
3218     pa_pstream_send_tagstruct(c->pstream, reply);
3219 }
3220
3221 static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3222     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3223     uint32_t channel;
3224     upload_stream *s;
3225     uint32_t idx;
3226
3227     pa_native_connection_assert_ref(c);
3228     pa_assert(t);
3229
3230     if (pa_tagstruct_getu32(t, &channel) < 0 ||
3231         !pa_tagstruct_eof(t)) {
3232         protocol_error(c);
3233         return;
3234     }
3235
3236     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3237
3238     s = pa_idxset_get_by_index(c->output_streams, channel);
3239     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
3240     CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY);
3241
3242     if (!s->memchunk.memblock)
3243         pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE);
3244     else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0)
3245         pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL);
3246     else
3247         pa_pstream_send_simple_ack(c->pstream, tag);
3248
3249     upload_stream_unlink(s);
3250 }
3251
3252 static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3253     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3254     uint32_t sink_index;
3255     pa_volume_t volume;
3256     pa_sink *sink;
3257     const char *name, *sink_name;
3258     uint32_t idx;
3259     pa_proplist *p;
3260     pa_tagstruct *reply;
3261
3262     pa_native_connection_assert_ref(c);
3263     pa_assert(t);
3264
3265     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3266
3267     if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
3268         pa_tagstruct_gets(t, &sink_name) < 0 ||
3269         pa_tagstruct_getu32(t, &volume) < 0 ||
3270         pa_tagstruct_gets(t, &name) < 0) {
3271         protocol_error(c);
3272         return;
3273     }
3274
3275     CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID);
3276     CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID);
3277     CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
3278     CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3279
3280     if (sink_index != PA_INVALID_INDEX)
3281         sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index);
3282     else
3283         sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK);
3284
3285     CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
3286
3287     p = pa_proplist_new();
3288
3289     if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) ||
3290         !pa_tagstruct_eof(t)) {
3291         protocol_error(c);
3292         pa_proplist_free(p);
3293         return;
3294     }
3295
3296     pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist);
3297
3298     if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) {
3299         pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3300         pa_proplist_free(p);
3301         return;
3302     }
3303
3304     pa_proplist_free(p);
3305
3306     reply = reply_new(tag);
3307
3308     if (c->version >= 13)
3309         pa_tagstruct_putu32(reply, idx);
3310
3311     pa_pstream_send_tagstruct(c->pstream, reply);
3312 }
3313
3314 static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3315     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3316     const char *name;
3317
3318     pa_native_connection_assert_ref(c);
3319     pa_assert(t);
3320
3321     if (pa_tagstruct_gets(t, &name) < 0 ||
3322         !pa_tagstruct_eof(t)) {
3323         protocol_error(c);
3324         return;
3325     }
3326
3327     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3328     CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3329
3330     if (pa_scache_remove_item(c->protocol->core, name) < 0) {
3331         pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3332         return;
3333     }
3334
3335     pa_pstream_send_simple_ack(c->pstream, tag);
3336 }
3337
3338 static void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) {
3339     pa_assert(c);
3340     pa_assert(fixed);
3341     pa_assert(original);
3342
3343     *fixed = *original;
3344
3345     if (c->version < 12) {
3346         /* Before protocol version 12 we didn't support S32 samples,
3347          * so we need to lie about this to the client */
3348
3349         if (fixed->format == PA_SAMPLE_S32LE)
3350             fixed->format = PA_SAMPLE_FLOAT32LE;
3351         if (fixed->format == PA_SAMPLE_S32BE)
3352             fixed->format = PA_SAMPLE_FLOAT32BE;
3353     }
3354
3355     if (c->version < 15) {
3356         if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE)
3357             fixed->format = PA_SAMPLE_FLOAT32LE;
3358         if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE)
3359             fixed->format = PA_SAMPLE_FLOAT32BE;
3360     }
3361 }
3362
3363 static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) {
3364     pa_sample_spec fixed_ss;
3365
3366     pa_assert(t);
3367     pa_sink_assert_ref(sink);
3368
3369     fixup_sample_spec(c, &fixed_ss, &sink->sample_spec);
3370
3371     pa_tagstruct_put(
3372         t,
3373         PA_TAG_U32, sink->index,
3374         PA_TAG_STRING, sink->name,
3375         PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3376         PA_TAG_SAMPLE_SPEC, &fixed_ss,
3377         PA_TAG_CHANNEL_MAP, &sink->channel_map,
3378         PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX,
3379         PA_TAG_CVOLUME, pa_sink_get_volume(sink, false),
3380         PA_TAG_BOOLEAN, pa_sink_get_mute(sink, false),
3381         PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
3382         PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL,
3383         PA_TAG_USEC, pa_sink_get_latency(sink),
3384         PA_TAG_STRING, sink->driver,
3385         PA_TAG_U32, sink->flags & PA_SINK_CLIENT_FLAGS_MASK,
3386         PA_TAG_INVALID);
3387
3388     if (c->version >= 13) {
3389         pa_tagstruct_put_proplist(t, sink->proplist);
3390         pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink));
3391     }
3392
3393     if (c->version >= 15) {
3394         pa_tagstruct_put_volume(t, sink->base_volume);
3395         if (PA_UNLIKELY(pa_sink_get_state(sink) == PA_SINK_INVALID_STATE))
3396             pa_log_error("Internal sink state is invalid.");
3397         pa_tagstruct_putu32(t, pa_sink_get_state(sink));
3398         pa_tagstruct_putu32(t, sink->n_volume_steps);
3399         pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
3400     }
3401
3402     if (c->version >= 16) {
3403         void *state;
3404         pa_device_port *p;
3405
3406         pa_tagstruct_putu32(t, pa_hashmap_size(sink->ports));
3407
3408         PA_HASHMAP_FOREACH(p, sink->ports, state) {
3409             pa_tagstruct_puts(t, p->name);
3410             pa_tagstruct_puts(t, p->description);
3411             pa_tagstruct_putu32(t, p->priority);
3412             if (c->version >= 24)
3413                 pa_tagstruct_putu32(t, p->available);
3414         }
3415
3416         pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
3417     }
3418
3419     if (c->version >= 21) {
3420         uint32_t i;
3421         pa_format_info *f;
3422         pa_idxset *formats = pa_sink_get_formats(sink);
3423
3424         pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3425         PA_IDXSET_FOREACH(f, formats, i) {
3426             pa_tagstruct_put_format_info(t, f);
3427         }
3428
3429         pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
3430     }
3431 }
3432
3433 static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
3434     pa_sample_spec fixed_ss;
3435
3436     pa_assert(t);
3437     pa_source_assert_ref(source);
3438
3439     fixup_sample_spec(c, &fixed_ss, &source->sample_spec);
3440
3441     pa_tagstruct_put(
3442         t,
3443         PA_TAG_U32, source->index,
3444         PA_TAG_STRING, source->name,
3445         PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)),
3446         PA_TAG_SAMPLE_SPEC, &fixed_ss,
3447         PA_TAG_CHANNEL_MAP, &source->channel_map,
3448         PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX,
3449         PA_TAG_CVOLUME, pa_source_get_volume(source, false),
3450         PA_TAG_BOOLEAN, pa_source_get_mute(source, false),
3451         PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX,
3452         PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL,
3453         PA_TAG_USEC, pa_source_get_latency(source),
3454         PA_TAG_STRING, source->driver,
3455         PA_TAG_U32, source->flags & PA_SOURCE_CLIENT_FLAGS_MASK,
3456         PA_TAG_INVALID);
3457
3458     if (c->version >= 13) {
3459         pa_tagstruct_put_proplist(t, source->proplist);
3460         pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source));
3461     }
3462
3463     if (c->version >= 15) {
3464         pa_tagstruct_put_volume(t, source->base_volume);
3465         if (PA_UNLIKELY(pa_source_get_state(source) == PA_SOURCE_INVALID_STATE))
3466             pa_log_error("Internal source state is invalid.");
3467         pa_tagstruct_putu32(t, pa_source_get_state(source));
3468         pa_tagstruct_putu32(t, source->n_volume_steps);
3469         pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
3470     }
3471
3472     if (c->version >= 16) {
3473         void *state;
3474         pa_device_port *p;
3475
3476         pa_tagstruct_putu32(t, pa_hashmap_size(source->ports));
3477
3478         PA_HASHMAP_FOREACH(p, source->ports, state) {
3479             pa_tagstruct_puts(t, p->name);
3480             pa_tagstruct_puts(t, p->description);
3481             pa_tagstruct_putu32(t, p->priority);
3482             if (c->version >= 24)
3483                 pa_tagstruct_putu32(t, p->available);
3484         }
3485
3486         pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
3487     }
3488
3489     if (c->version >= 22) {
3490         uint32_t i;
3491         pa_format_info *f;
3492         pa_idxset *formats = pa_source_get_formats(source);
3493
3494         pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats));
3495         PA_IDXSET_FOREACH(f, formats, i) {
3496             pa_tagstruct_put_format_info(t, f);
3497         }
3498
3499         pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
3500     }
3501 }
3502
3503 static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
3504     pa_assert(t);
3505     pa_assert(client);
3506
3507     pa_tagstruct_putu32(t, client->index);
3508     pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME)));
3509     pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX);
3510     pa_tagstruct_puts(t, client->driver);
3511
3512     if (c->version >= 13)
3513         pa_tagstruct_put_proplist(t, client->proplist);
3514 }
3515
3516 static void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) {
3517     void *state = NULL;
3518     pa_card_profile *p;
3519     pa_device_port *port;
3520
3521     pa_assert(t);
3522     pa_assert(card);
3523
3524     pa_tagstruct_putu32(t, card->index);
3525     pa_tagstruct_puts(t, card->name);
3526     pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX);
3527     pa_tagstruct_puts(t, card->driver);
3528
3529     pa_tagstruct_putu32(t, pa_hashmap_size(card->profiles));
3530
3531     PA_HASHMAP_FOREACH(p, card->profiles, state) {
3532         pa_tagstruct_puts(t, p->name);
3533         pa_tagstruct_puts(t, p->description);
3534         pa_tagstruct_putu32(t, p->n_sinks);
3535         pa_tagstruct_putu32(t, p->n_sources);
3536         pa_tagstruct_putu32(t, p->priority);
3537
3538         if (c->version >= 29)
3539             pa_tagstruct_putu32(t, (p->available != PA_AVAILABLE_NO));
3540     }
3541
3542     pa_tagstruct_puts(t, card->active_profile->name);
3543     pa_tagstruct_put_proplist(t, card->proplist);
3544
3545     if (c->version < 26)
3546         return;
3547
3548     pa_tagstruct_putu32(t, pa_hashmap_size(card->ports));
3549
3550     PA_HASHMAP_FOREACH(port, card->ports, state) {
3551         void *state2;
3552
3553         pa_tagstruct_puts(t, port->name);
3554         pa_tagstruct_puts(t, port->description);
3555         pa_tagstruct_putu32(t, port->priority);
3556         pa_tagstruct_putu32(t, port->available);
3557         pa_tagstruct_putu8(t, port->direction);
3558         pa_tagstruct_put_proplist(t, port->proplist);
3559
3560         pa_tagstruct_putu32(t, pa_hashmap_size(port->profiles));
3561
3562         PA_HASHMAP_FOREACH(p, port->profiles, state2)
3563             pa_tagstruct_puts(t, p->name);
3564
3565         if (c->version >= 27)
3566             pa_tagstruct_puts64(t, port->latency_offset);
3567     }
3568 }
3569
3570 static void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) {
3571     pa_assert(t);
3572     pa_assert(module);
3573
3574     pa_tagstruct_putu32(t, module->index);
3575     pa_tagstruct_puts(t, module->name);
3576     pa_tagstruct_puts(t, module->argument);
3577     pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module));
3578
3579     if (c->version < 15)
3580         pa_tagstruct_put_boolean(t, false); /* autoload is obsolete */
3581
3582     if (c->version >= 15)
3583         pa_tagstruct_put_proplist(t, module->proplist);
3584 }
3585
3586 static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) {
3587     pa_sample_spec fixed_ss;
3588     pa_usec_t sink_latency;
3589     pa_cvolume v;
3590     bool has_volume = false;
3591
3592     pa_assert(t);
3593     pa_sink_input_assert_ref(s);
3594
3595     fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3596
3597     has_volume = pa_sink_input_is_volume_readable(s);
3598     if (has_volume)
3599         pa_sink_input_get_volume(s, &v, true);
3600     else
3601         pa_cvolume_reset(&v, fixed_ss.channels);
3602
3603     pa_tagstruct_putu32(t, s->index);
3604     pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3605     pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3606     pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3607     pa_tagstruct_putu32(t, s->sink->index);
3608     pa_tagstruct_put_sample_spec(t, &fixed_ss);
3609     pa_tagstruct_put_channel_map(t, &s->channel_map);
3610     pa_tagstruct_put_cvolume(t, &v);
3611     pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency));
3612     pa_tagstruct_put_usec(t, sink_latency);
3613     pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s)));
3614     pa_tagstruct_puts(t, s->driver);
3615     if (c->version >= 11)
3616         pa_tagstruct_put_boolean(t, s->muted);
3617     if (c->version >= 13)
3618         pa_tagstruct_put_proplist(t, s->proplist);
3619     if (c->version >= 19)
3620         pa_tagstruct_put_boolean(t, (pa_sink_input_get_state(s) == PA_SINK_INPUT_CORKED));
3621     if (c->version >= 20) {
3622         pa_tagstruct_put_boolean(t, has_volume);
3623         pa_tagstruct_put_boolean(t, s->volume_writable);
3624     }
3625     if (c->version >= 21)
3626         pa_tagstruct_put_format_info(t, s->format);
3627 }
3628
3629 static void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) {
3630     pa_sample_spec fixed_ss;
3631     pa_usec_t source_latency;
3632     pa_cvolume v;
3633     bool has_volume = false;
3634
3635     pa_assert(t);
3636     pa_source_output_assert_ref(s);
3637
3638     fixup_sample_spec(c, &fixed_ss, &s->sample_spec);
3639
3640     has_volume = pa_source_output_is_volume_readable(s);
3641     if (has_volume)
3642         pa_source_output_get_volume(s, &v, true);
3643     else
3644         pa_cvolume_reset(&v, fixed_ss.channels);
3645
3646     pa_tagstruct_putu32(t, s->index);
3647     pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)));
3648     pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX);
3649     pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX);
3650     pa_tagstruct_putu32(t, s->source->index);
3651     pa_tagstruct_put_sample_spec(t, &fixed_ss);
3652     pa_tagstruct_put_channel_map(t, &s->channel_map);
3653     pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency));
3654     pa_tagstruct_put_usec(t, source_latency);
3655     pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s)));
3656     pa_tagstruct_puts(t, s->driver);
3657     if (c->version >= 13)
3658         pa_tagstruct_put_proplist(t, s->proplist);
3659     if (c->version >= 19)
3660         pa_tagstruct_put_boolean(t, (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_CORKED));
3661     if (c->version >= 22) {
3662         pa_tagstruct_put_cvolume(t, &v);
3663         pa_tagstruct_put_boolean(t, s->muted);
3664         pa_tagstruct_put_boolean(t, has_volume);
3665         pa_tagstruct_put_boolean(t, s->volume_writable);
3666         pa_tagstruct_put_format_info(t, s->format);
3667     }
3668 }
3669
3670 static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) {
3671     pa_sample_spec fixed_ss;
3672     pa_cvolume v;
3673
3674     pa_assert(t);
3675     pa_assert(e);
3676
3677     if (e->memchunk.memblock)
3678         fixup_sample_spec(c, &fixed_ss, &e->sample_spec);
3679     else
3680         memset(&fixed_ss, 0, sizeof(fixed_ss));
3681
3682     pa_tagstruct_putu32(t, e->index);
3683     pa_tagstruct_puts(t, e->name);
3684
3685     if (e->volume_is_set)
3686         v = e->volume;
3687     else
3688         pa_cvolume_init(&v);
3689
3690     pa_tagstruct_put_cvolume(t, &v);
3691     pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0);
3692     pa_tagstruct_put_sample_spec(t, &fixed_ss);
3693     pa_tagstruct_put_channel_map(t, &e->channel_map);
3694     pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length);
3695     pa_tagstruct_put_boolean(t, e->lazy);
3696     pa_tagstruct_puts(t, e->filename);
3697
3698     if (c->version >= 13)
3699         pa_tagstruct_put_proplist(t, e->proplist);
3700 }
3701
3702 static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3703     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3704     uint32_t idx;
3705     pa_sink *sink = NULL;
3706     pa_source *source = NULL;
3707     pa_client *client = NULL;
3708     pa_card *card = NULL;
3709     pa_module *module = NULL;
3710     pa_sink_input *si = NULL;
3711     pa_source_output *so = NULL;
3712     pa_scache_entry *sce = NULL;
3713     const char *name = NULL;
3714     pa_tagstruct *reply;
3715
3716     pa_native_connection_assert_ref(c);
3717     pa_assert(t);
3718
3719     if (pa_tagstruct_getu32(t, &idx) < 0 ||
3720         (command != PA_COMMAND_GET_CLIENT_INFO &&
3721          command != PA_COMMAND_GET_MODULE_INFO &&
3722          command != PA_COMMAND_GET_SINK_INPUT_INFO &&
3723          command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO &&
3724          pa_tagstruct_gets(t, &name) < 0) ||
3725         !pa_tagstruct_eof(t)) {
3726         protocol_error(c);
3727         return;
3728     }
3729
3730     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3731     CHECK_VALIDITY(c->pstream, !name ||
3732                    (command == PA_COMMAND_GET_SINK_INFO &&
3733                     pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) ||
3734                    (command == PA_COMMAND_GET_SOURCE_INFO &&
3735                     pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) ||
3736                    pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
3737     CHECK_VALIDITY(c->pstream, command == PA_COMMAND_GET_SINK_INFO ||
3738                    command == PA_COMMAND_GET_SOURCE_INFO ||
3739                    (idx != PA_INVALID_INDEX || name), tag, PA_ERR_INVALID);
3740     CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
3741
3742     if (command == PA_COMMAND_GET_SINK_INFO) {
3743         if (idx != PA_INVALID_INDEX)
3744             sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3745         else
3746             sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3747     } else if (command == PA_COMMAND_GET_SOURCE_INFO) {
3748         if (idx != PA_INVALID_INDEX)
3749             source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
3750         else
3751             source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
3752     } else if (command == PA_COMMAND_GET_CARD_INFO) {
3753         if (idx != PA_INVALID_INDEX)
3754             card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
3755         else
3756             card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
3757     } else if (command == PA_COMMAND_GET_CLIENT_INFO)
3758         client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
3759     else if (command == PA_COMMAND_GET_MODULE_INFO)
3760         module = pa_idxset_get_by_index(c->protocol->core->modules, idx);
3761     else if (command == PA_COMMAND_GET_SINK_INPUT_INFO)
3762         si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
3763     else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO)
3764         so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
3765     else {
3766         pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO);
3767         if (idx != PA_INVALID_INDEX)
3768             sce = pa_idxset_get_by_index(c->protocol->core->scache, idx);
3769         else
3770             sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE);
3771     }
3772
3773     if (!sink && !source && !client && !card && !module && !si && !so && !sce) {
3774         pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY);
3775         return;
3776     }
3777
3778     reply = reply_new(tag);
3779     if (sink)
3780         sink_fill_tagstruct(c, reply, sink);
3781     else if (source)
3782         source_fill_tagstruct(c, reply, source);
3783     else if (client)
3784         client_fill_tagstruct(c, reply, client);
3785     else if (card)
3786         card_fill_tagstruct(c, reply, card);
3787     else if (module)
3788         module_fill_tagstruct(c, reply, module);
3789     else if (si)
3790         sink_input_fill_tagstruct(c, reply, si);
3791     else if (so)
3792         source_output_fill_tagstruct(c, reply, so);
3793     else
3794         scache_fill_tagstruct(c, reply, sce);
3795     pa_pstream_send_tagstruct(c->pstream, reply);
3796 }
3797
3798 static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3799     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3800     pa_idxset *i;
3801     uint32_t idx;
3802     void *p;
3803     pa_tagstruct *reply;
3804
3805     pa_native_connection_assert_ref(c);
3806     pa_assert(t);
3807
3808     if (!pa_tagstruct_eof(t)) {
3809         protocol_error(c);
3810         return;
3811     }
3812
3813     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3814
3815     reply = reply_new(tag);
3816
3817     if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3818         i = c->protocol->core->sinks;
3819     else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3820         i = c->protocol->core->sources;
3821     else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3822         i = c->protocol->core->clients;
3823     else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3824         i = c->protocol->core->cards;
3825     else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3826         i = c->protocol->core->modules;
3827     else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3828         i = c->protocol->core->sink_inputs;
3829     else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3830         i = c->protocol->core->source_outputs;
3831     else {
3832         pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3833         i = c->protocol->core->scache;
3834     }
3835
3836     if (i) {
3837         PA_IDXSET_FOREACH(p, i, idx) {
3838             if (command == PA_COMMAND_GET_SINK_INFO_LIST)
3839                 sink_fill_tagstruct(c, reply, p);
3840             else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST)
3841                 source_fill_tagstruct(c, reply, p);
3842             else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST)
3843                 client_fill_tagstruct(c, reply, p);
3844             else if (command == PA_COMMAND_GET_CARD_INFO_LIST)
3845                 card_fill_tagstruct(c, reply, p);
3846             else if (command == PA_COMMAND_GET_MODULE_INFO_LIST)
3847                 module_fill_tagstruct(c, reply, p);
3848             else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST)
3849                 sink_input_fill_tagstruct(c, reply, p);
3850             else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST)
3851                 source_output_fill_tagstruct(c, reply, p);
3852             else {
3853                 pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST);
3854                 scache_fill_tagstruct(c, reply, p);
3855             }
3856         }
3857     }
3858
3859     pa_pstream_send_tagstruct(c->pstream, reply);
3860 }
3861
3862 static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3863     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3864     pa_tagstruct *reply;
3865     pa_sink *def_sink;
3866     pa_source *def_source;
3867     pa_sample_spec fixed_ss;
3868     char *h, *u;
3869
3870     pa_native_connection_assert_ref(c);
3871     pa_assert(t);
3872
3873     if (!pa_tagstruct_eof(t)) {
3874         protocol_error(c);
3875         return;
3876     }
3877
3878     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3879
3880     reply = reply_new(tag);
3881     pa_tagstruct_puts(reply, PACKAGE_NAME);
3882     pa_tagstruct_puts(reply, PACKAGE_VERSION);
3883
3884     u = pa_get_user_name_malloc();
3885     pa_tagstruct_puts(reply, u);
3886     pa_xfree(u);
3887
3888     h = pa_get_host_name_malloc();
3889     pa_tagstruct_puts(reply, h);
3890     pa_xfree(h);
3891
3892     fixup_sample_spec(c, &fixed_ss, &c->protocol->core->default_sample_spec);
3893     pa_tagstruct_put_sample_spec(reply, &fixed_ss);
3894
3895     def_sink = pa_namereg_get_default_sink(c->protocol->core);
3896     pa_tagstruct_puts(reply, def_sink ? def_sink->name : NULL);
3897     def_source = pa_namereg_get_default_source(c->protocol->core);
3898     pa_tagstruct_puts(reply, def_source ? def_source->name : NULL);
3899
3900     pa_tagstruct_putu32(reply, c->protocol->core->cookie);
3901
3902     if (c->version >= 15)
3903         pa_tagstruct_put_channel_map(reply, &c->protocol->core->default_channel_map);
3904
3905     pa_pstream_send_tagstruct(c->pstream, reply);
3906 }
3907
3908 static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) {
3909     pa_tagstruct *t;
3910     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3911
3912     pa_native_connection_assert_ref(c);
3913
3914     t = pa_tagstruct_new(NULL, 0);
3915     pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT);
3916     pa_tagstruct_putu32(t, (uint32_t) -1);
3917     pa_tagstruct_putu32(t, e);
3918     pa_tagstruct_putu32(t, idx);
3919     pa_pstream_send_tagstruct(c->pstream, t);
3920 }
3921
3922 static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
3923     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3924     pa_subscription_mask_t m;
3925
3926     pa_native_connection_assert_ref(c);
3927     pa_assert(t);
3928
3929     if (pa_tagstruct_getu32(t, &m) < 0 ||
3930         !pa_tagstruct_eof(t)) {
3931         protocol_error(c);
3932         return;
3933     }
3934
3935     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3936     CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID);
3937
3938     if (c->subscription)
3939         pa_subscription_free(c->subscription);
3940
3941     if (m != 0) {
3942         c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c);
3943         pa_assert(c->subscription);
3944     } else
3945         c->subscription = NULL;
3946
3947     pa_pstream_send_simple_ack(c->pstream, tag);
3948 }
3949
3950 static void command_set_volume(
3951         pa_pdispatch *pd,
3952         uint32_t command,
3953         uint32_t tag,
3954         pa_tagstruct *t,
3955         void *userdata) {
3956
3957     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
3958     uint32_t idx;
3959     pa_cvolume volume;
3960     pa_sink *sink = NULL;
3961     pa_source *source = NULL;
3962     pa_sink_input *si = NULL;
3963     pa_source_output *so = NULL;
3964     const char *name = NULL;
3965     const char *client_name;
3966
3967     pa_native_connection_assert_ref(c);
3968     pa_assert(t);
3969
3970     if (pa_tagstruct_getu32(t, &idx) < 0 ||
3971         (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3972         (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) ||
3973         pa_tagstruct_get_cvolume(t, &volume) ||
3974         !pa_tagstruct_eof(t)) {
3975         protocol_error(c);
3976         return;
3977     }
3978
3979     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
3980     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);
3981     CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
3982     CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
3983
3984 #ifdef USE_SECURITY
3985     CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), VOLUME_SET_PRIVILEGE),
3986                    tag, PA_ERR_ACCESS);
3987 #endif /* USE_SECURITY */
3988
3989     switch (command) {
3990
3991         case PA_COMMAND_SET_SINK_VOLUME:
3992             if (idx != PA_INVALID_INDEX)
3993                 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
3994             else
3995                 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
3996             break;
3997
3998         case PA_COMMAND_SET_SOURCE_VOLUME:
3999             if (idx != PA_INVALID_INDEX)
4000                 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4001             else
4002                 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4003             break;
4004
4005         case PA_COMMAND_SET_SINK_INPUT_VOLUME:
4006             si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4007             break;
4008
4009         case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME:
4010             so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4011             break;
4012
4013         default:
4014             pa_assert_not_reached();
4015     }
4016
4017     CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
4018
4019     client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4020
4021     if (sink) {
4022         CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID);
4023
4024         pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name);
4025         pa_sink_set_volume(sink, &volume, true, true);
4026     } else if (source) {
4027         CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID);
4028
4029         pa_log_debug("Client %s changes volume of source %s.", client_name, source->name);
4030         pa_source_set_volume(source, &volume, true, true);
4031     } else if (si) {
4032         CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE);
4033         CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID);
4034
4035         pa_log_debug("Client %s changes volume of sink input %s.",
4036                      client_name,
4037                      pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
4038         pa_sink_input_set_volume(si, &volume, true, true);
4039     } else if (so) {
4040         CHECK_VALIDITY(c->pstream, so->volume_writable, tag, PA_ERR_BADSTATE);
4041         CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID);
4042
4043         pa_log_debug("Client %s changes volume of source output %s.",
4044                      client_name,
4045                      pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
4046         pa_source_output_set_volume(so, &volume, true, true);
4047     }
4048
4049     pa_pstream_send_simple_ack(c->pstream, tag);
4050 }
4051
4052 static void command_set_volume_ramp(
4053         pa_pdispatch *pd,
4054         uint32_t command,
4055         uint32_t tag,
4056         pa_tagstruct *t,
4057         void *userdata) {
4058
4059     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4060     uint32_t idx;
4061     pa_cvolume_ramp ramp;
4062     pa_sink *sink = NULL;
4063     pa_sink_input *si = NULL;
4064     const char *name = NULL;
4065     const char *client_name;
4066
4067     pa_native_connection_assert_ref(c);
4068     pa_assert(t);
4069
4070     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4071         (command == PA_COMMAND_SET_SINK_VOLUME_RAMP && pa_tagstruct_gets(t, &name) < 0) ||
4072         (command == PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP && pa_tagstruct_gets(t, &name) < 0) ||
4073         pa_tagstruct_get_cvolume_ramp(t, &ramp) ||
4074         !pa_tagstruct_eof(t)) {
4075         protocol_error(c);
4076         return;
4077     }
4078
4079     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4080     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);
4081     CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
4082     CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
4083     CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4084 #ifdef USE_SECURITY
4085     CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), VOLUME_SET_PRIVILEGE),
4086                    tag, PA_ERR_ACCESS);
4087 #endif /* USE_SECURITY */
4088
4089     switch (command) {
4090
4091         case PA_COMMAND_SET_SINK_VOLUME_RAMP:
4092             if (idx != PA_INVALID_INDEX)
4093                 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4094             else
4095                 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4096             break;
4097
4098         case PA_COMMAND_SET_SINK_INPUT_VOLUME_RAMP:
4099             si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4100             break;
4101
4102         default:
4103             pa_assert_not_reached();
4104     }
4105
4106     CHECK_VALIDITY(c->pstream, sink || si, tag, PA_ERR_NOENTITY);
4107
4108     client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4109
4110     if (sink) {
4111         pa_log_debug("Client %s changes volume ramp of sink %s.", client_name, sink->name);
4112         pa_sink_set_volume_ramp(sink, &ramp, TRUE, TRUE);
4113     } else if (si) {
4114         pa_log_debug("Client %s changes volume ramp of sink input %s.", client_name, pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
4115         pa_sink_input_set_volume_ramp(si, &ramp, TRUE, TRUE);
4116     }
4117
4118     pa_pstream_send_simple_ack(c->pstream, tag);
4119 }
4120
4121 static void command_set_mute(
4122         pa_pdispatch *pd,
4123         uint32_t command,
4124         uint32_t tag,
4125         pa_tagstruct *t,
4126         void *userdata) {
4127
4128     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4129     uint32_t idx;
4130     bool mute;
4131     pa_sink *sink = NULL;
4132     pa_source *source = NULL;
4133     pa_sink_input *si = NULL;
4134     pa_source_output *so = NULL;
4135     const char *name = NULL, *client_name;
4136
4137     pa_native_connection_assert_ref(c);
4138     pa_assert(t);
4139
4140     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4141         (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
4142         (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) ||
4143         pa_tagstruct_get_boolean(t, &mute) ||
4144         !pa_tagstruct_eof(t)) {
4145         protocol_error(c);
4146         return;
4147     }
4148
4149     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4150     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);
4151     CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
4152 #ifdef USE_SECURITY
4153     CHECK_VALIDITY(c->pstream, cynara_check_privilege(_get_connection_out_fd(c), VOLUME_SET_PRIVILEGE),
4154                    tag, PA_ERR_ACCESS);
4155 #endif /* USE_SECURITY */
4156
4157     switch (command) {
4158
4159         case PA_COMMAND_SET_SINK_MUTE:
4160             if (idx != PA_INVALID_INDEX)
4161                 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
4162             else
4163                 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
4164
4165             break;
4166
4167         case PA_COMMAND_SET_SOURCE_MUTE:
4168             if (idx != PA_INVALID_INDEX)
4169                 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
4170             else
4171                 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
4172
4173             break;
4174
4175         case PA_COMMAND_SET_SINK_INPUT_MUTE:
4176             si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4177             break;
4178
4179         case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE:
4180             so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4181             break;
4182
4183         default:
4184             pa_assert_not_reached();
4185     }
4186
4187     CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY);
4188
4189     client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
4190
4191     if (sink) {
4192         pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name);
4193         pa_sink_set_mute(sink, mute, true);
4194     } else if (source) {
4195         pa_log_debug("Client %s changes mute of source %s.", client_name, source->name);
4196         pa_source_set_mute(source, mute, true);
4197     } else if (si) {
4198         pa_log_debug("Client %s changes mute of sink input %s.",
4199                      client_name,
4200                      pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
4201         pa_sink_input_set_mute(si, mute, true);
4202     } else if (so) {
4203         pa_log_debug("Client %s changes mute of source output %s.",
4204                      client_name,
4205                      pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME)));
4206         pa_source_output_set_mute(so, mute, true);
4207     }
4208
4209     pa_pstream_send_simple_ack(c->pstream, tag);
4210 }
4211
4212 static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4213     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4214     uint32_t idx;
4215     bool b;
4216     playback_stream *s;
4217
4218     pa_native_connection_assert_ref(c);
4219     pa_assert(t);
4220
4221     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4222         pa_tagstruct_get_boolean(t, &b) < 0 ||
4223         !pa_tagstruct_eof(t)) {
4224         protocol_error(c);
4225         return;
4226     }
4227
4228     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4229     CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4230     s = pa_idxset_get_by_index(c->output_streams, idx);
4231     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4232     CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4233
4234     pa_sink_input_cork(s->sink_input, b);
4235
4236     if (b)
4237         s->is_underrun = true;
4238
4239     pa_pstream_send_simple_ack(c->pstream, tag);
4240 }
4241
4242 static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4243     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4244     uint32_t idx;
4245     playback_stream *s;
4246
4247     pa_native_connection_assert_ref(c);
4248     pa_assert(t);
4249
4250     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4251         !pa_tagstruct_eof(t)) {
4252         protocol_error(c);
4253         return;
4254     }
4255
4256     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4257     CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4258     s = pa_idxset_get_by_index(c->output_streams, idx);
4259     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4260     CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4261
4262     switch (command) {
4263         case PA_COMMAND_FLUSH_PLAYBACK_STREAM:
4264             pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL);
4265             break;
4266
4267         case PA_COMMAND_PREBUF_PLAYBACK_STREAM:
4268             pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL);
4269             break;
4270
4271         case PA_COMMAND_TRIGGER_PLAYBACK_STREAM:
4272             pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL);
4273             break;
4274
4275         default:
4276             pa_assert_not_reached();
4277     }
4278
4279     pa_pstream_send_simple_ack(c->pstream, tag);
4280 }
4281
4282 static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4283     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4284     uint32_t idx;
4285     record_stream *s;
4286     bool b;
4287
4288     pa_native_connection_assert_ref(c);
4289     pa_assert(t);
4290
4291     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4292         pa_tagstruct_get_boolean(t, &b) < 0 ||
4293         !pa_tagstruct_eof(t)) {
4294         protocol_error(c);
4295         return;
4296     }
4297
4298     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4299     s = pa_idxset_get_by_index(c->record_streams, idx);
4300     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4301
4302     pa_source_output_cork(s->source_output, b);
4303     pa_memblockq_prebuf_force(s->memblockq);
4304     pa_pstream_send_simple_ack(c->pstream, tag);
4305 }
4306
4307 static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4308     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4309     uint32_t idx;
4310     record_stream *s;
4311
4312     pa_native_connection_assert_ref(c);
4313     pa_assert(t);
4314
4315     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4316         !pa_tagstruct_eof(t)) {
4317         protocol_error(c);
4318         return;
4319     }
4320
4321     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4322     s = pa_idxset_get_by_index(c->record_streams, idx);
4323     CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4324
4325     pa_memblockq_flush_read(s->memblockq);
4326     pa_pstream_send_simple_ack(c->pstream, tag);
4327 }
4328
4329 static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4330     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4331     uint32_t idx;
4332     pa_buffer_attr a;
4333     pa_tagstruct *reply;
4334
4335     pa_native_connection_assert_ref(c);
4336     pa_assert(t);
4337
4338     memset(&a, 0, sizeof(a));
4339
4340     if (pa_tagstruct_getu32(t, &idx) < 0) {
4341         protocol_error(c);
4342         return;
4343     }
4344
4345     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4346
4347     if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
4348         playback_stream *s;
4349         bool adjust_latency = false, early_requests = false;
4350
4351         s = pa_idxset_get_by_index(c->output_streams, idx);
4352         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4353         CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4354
4355         if (pa_tagstruct_get(
4356                     t,
4357                     PA_TAG_U32, &a.maxlength,
4358                     PA_TAG_U32, &a.tlength,
4359                     PA_TAG_U32, &a.prebuf,
4360                     PA_TAG_U32, &a.minreq,
4361                     PA_TAG_INVALID) < 0 ||
4362             (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
4363             (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
4364             !pa_tagstruct_eof(t)) {
4365             protocol_error(c);
4366             return;
4367         }
4368
4369         s->adjust_latency = adjust_latency;
4370         s->early_requests = early_requests;
4371         s->buffer_attr_req = a;
4372
4373         fix_playback_buffer_attr(s);
4374         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);
4375
4376         reply = reply_new(tag);
4377         pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4378         pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
4379         pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
4380         pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
4381
4382         if (c->version >= 13)
4383             pa_tagstruct_put_usec(reply, s->configured_sink_latency);
4384
4385     } else {
4386         record_stream *s;
4387         bool adjust_latency = false, early_requests = false;
4388         pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
4389
4390         s = pa_idxset_get_by_index(c->record_streams, idx);
4391         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4392
4393         if (pa_tagstruct_get(
4394                     t,
4395                     PA_TAG_U32, &a.maxlength,
4396                     PA_TAG_U32, &a.fragsize,
4397                     PA_TAG_INVALID) < 0 ||
4398             (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
4399             (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
4400             !pa_tagstruct_eof(t)) {
4401             protocol_error(c);
4402             return;
4403         }
4404
4405         s->adjust_latency = adjust_latency;
4406         s->early_requests = early_requests;
4407         s->buffer_attr_req = a;
4408
4409         fix_record_buffer_attr_pre(s);
4410         pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
4411         pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
4412         fix_record_buffer_attr_post(s);
4413
4414         reply = reply_new(tag);
4415         pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
4416         pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
4417
4418         if (c->version >= 13)
4419             pa_tagstruct_put_usec(reply, s->configured_source_latency);
4420     }
4421
4422     pa_pstream_send_tagstruct(c->pstream, reply);
4423 }
4424
4425 static void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4426     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4427     uint32_t idx;
4428     uint32_t rate;
4429
4430     pa_native_connection_assert_ref(c);
4431     pa_assert(t);
4432
4433     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4434         pa_tagstruct_getu32(t, &rate) < 0 ||
4435         !pa_tagstruct_eof(t)) {
4436         protocol_error(c);
4437         return;
4438     }
4439
4440     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4441     CHECK_VALIDITY(c->pstream, pa_sample_rate_valid(rate), tag, PA_ERR_INVALID);
4442
4443     if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) {
4444         playback_stream *s;
4445
4446         s = pa_idxset_get_by_index(c->output_streams, idx);
4447         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4448         CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4449
4450         pa_sink_input_set_rate(s->sink_input, rate);
4451
4452     } else {
4453         record_stream *s;
4454         pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE);
4455
4456         s = pa_idxset_get_by_index(c->record_streams, idx);
4457         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4458
4459         pa_source_output_set_rate(s->source_output, rate);
4460     }
4461
4462     pa_pstream_send_simple_ack(c->pstream, tag);
4463 }
4464
4465 static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4466     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4467     uint32_t idx;
4468     uint32_t mode;
4469     pa_proplist *p;
4470
4471     pa_native_connection_assert_ref(c);
4472     pa_assert(t);
4473
4474     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4475
4476     p = pa_proplist_new();
4477
4478     if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) {
4479
4480         if (pa_tagstruct_getu32(t, &mode) < 0 ||
4481             pa_tagstruct_get_proplist(t, p) < 0 ||
4482             !pa_tagstruct_eof(t)) {
4483             protocol_error(c);
4484             pa_proplist_free(p);
4485             return;
4486         }
4487
4488     } else {
4489
4490         if (pa_tagstruct_getu32(t, &idx) < 0 ||
4491             pa_tagstruct_getu32(t, &mode) < 0 ||
4492             pa_tagstruct_get_proplist(t, p) < 0 ||
4493             !pa_tagstruct_eof(t)) {
4494             protocol_error(c);
4495             pa_proplist_free(p);
4496             return;
4497         }
4498     }
4499
4500     if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) {
4501         pa_proplist_free(p);
4502         CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID);
4503     }
4504
4505     if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) {
4506         playback_stream *s;
4507
4508         s = pa_idxset_get_by_index(c->output_streams, idx);
4509         if (!s || !playback_stream_isinstance(s)) {
4510             pa_proplist_free(p);
4511             CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY);
4512         }
4513         pa_sink_input_update_proplist(s->sink_input, mode, p);
4514
4515     } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) {
4516         record_stream *s;
4517
4518         if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) {
4519             pa_proplist_free(p);
4520             CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY);
4521         }
4522         pa_source_output_update_proplist(s->source_output, mode, p);
4523
4524     } else {
4525         pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST);
4526
4527         pa_client_update_proplist(c->client, mode, p);
4528     }
4529
4530     pa_pstream_send_simple_ack(c->pstream, tag);
4531     pa_proplist_free(p);
4532 }
4533
4534 static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4535     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4536     uint32_t idx;
4537     unsigned changed = 0;
4538     pa_proplist *p;
4539     pa_strlist *l = NULL;
4540
4541     pa_native_connection_assert_ref(c);
4542     pa_assert(t);
4543
4544     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4545
4546     if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) {
4547
4548         if (pa_tagstruct_getu32(t, &idx) < 0) {
4549             protocol_error(c);
4550             return;
4551         }
4552     }
4553
4554     if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4555         playback_stream *s;
4556
4557         s = pa_idxset_get_by_index(c->output_streams, idx);
4558         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4559         CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4560
4561         p = s->sink_input->proplist;
4562
4563     } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4564         record_stream *s;
4565
4566         s = pa_idxset_get_by_index(c->record_streams, idx);
4567         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4568
4569         p = s->source_output->proplist;
4570     } else {
4571         pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4572
4573         p = c->client->proplist;
4574     }
4575
4576     for (;;) {
4577         const char *k;
4578
4579         if (pa_tagstruct_gets(t, &k) < 0) {
4580             protocol_error(c);
4581             pa_strlist_free(l);
4582             return;
4583         }
4584
4585         if (!k)
4586             break;
4587
4588         l = pa_strlist_prepend(l, k);
4589     }
4590
4591     if (!pa_tagstruct_eof(t)) {
4592         protocol_error(c);
4593         pa_strlist_free(l);
4594         return;
4595     }
4596
4597     for (;;) {
4598         char *z;
4599
4600         l = pa_strlist_pop(l, &z);
4601
4602         if (!z)
4603             break;
4604
4605         changed += (unsigned) (pa_proplist_unset(p, z) >= 0);
4606         pa_xfree(z);
4607     }
4608
4609     pa_pstream_send_simple_ack(c->pstream, tag);
4610
4611     if (changed) {
4612         if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) {
4613             playback_stream *s;
4614
4615             s = pa_idxset_get_by_index(c->output_streams, idx);
4616             pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index);
4617
4618         } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) {
4619             record_stream *s;
4620
4621             s = pa_idxset_get_by_index(c->record_streams, idx);
4622             pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index);
4623
4624         } else {
4625             pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST);
4626             pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
4627         }
4628     }
4629 }
4630
4631 static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4632     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4633     const char *s;
4634
4635     pa_native_connection_assert_ref(c);
4636     pa_assert(t);
4637
4638     if (pa_tagstruct_gets(t, &s) < 0 ||
4639         !pa_tagstruct_eof(t)) {
4640         protocol_error(c);
4641         return;
4642     }
4643
4644     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4645     CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4646
4647     if (command == PA_COMMAND_SET_DEFAULT_SOURCE) {
4648         pa_source *source;
4649
4650         source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE);
4651         CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
4652
4653         pa_namereg_set_default_source(c->protocol->core, source);
4654     } else {
4655         pa_sink *sink;
4656         pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK);
4657
4658         sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK);
4659         CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4660
4661         pa_namereg_set_default_sink(c->protocol->core, sink);
4662     }
4663
4664     pa_pstream_send_simple_ack(c->pstream, tag);
4665 }
4666
4667 #ifdef __TIZEN__
4668 static void command_set_default_sink_by_api_bus(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4669     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4670     pa_sink *sink;
4671     pa_bool_t found = FALSE;
4672     const char *api, *bus;
4673     const char *api_string, *bus_string, *form_factor;
4674     uint32_t idx;
4675
4676     pa_native_connection_assert_ref(c);
4677     pa_assert(t);
4678
4679     if (pa_tagstruct_gets(t, &api) < 0 ||
4680             pa_tagstruct_gets(t, &bus) < 0 ||
4681             !pa_tagstruct_eof(t)) {
4682         protocol_error(c);
4683         return;
4684     }
4685
4686     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4687     CHECK_VALIDITY(c->pstream, !api || pa_utf8_valid(api), tag, PA_ERR_INVALID);
4688     CHECK_VALIDITY(c->pstream, !bus || pa_utf8_valid(bus), tag, PA_ERR_INVALID);
4689
4690     pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK_BY_API_BUS);
4691
4692     PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
4693         if (sink && sink->proplist) {
4694         api_string = pa_proplist_gets(sink->proplist, "device.api");
4695         if (api_string) {
4696             pa_log_debug("Found api = [%s]\n", api_string);
4697             if (!strcmp(api, api_string)) {
4698                 bus_string = pa_proplist_gets(sink->proplist, "device.bus");
4699                 if (bus_string) {
4700                     pa_log_debug("Found bus = [%s]\n", bus_string);
4701                     if(!strcmp(bus, bus_string)) {
4702                         pa_log_debug("  ** FOUND!!! set default sink to [%s]\n", sink->name);
4703                         found = TRUE;
4704                         break;
4705                     } else {
4706                         pa_log_debug("No string [%s] match, match with form_factor = internal\n", bus);
4707                         form_factor = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_FORM_FACTOR );
4708                         if (form_factor) {
4709                             if(!strcmp(form_factor, "internal")) {
4710                                 pa_log_debug("Found internal device(sink) , set (%s) as default sink", sink->name);
4711                                 found = TRUE;
4712                                 break;
4713                             }
4714                         }
4715                         else {
4716                             pa_log_debug("This device doesn't have form factor property");
4717                         }
4718                     }
4719                 } else {
4720                     pa_log_debug(" Found no bus ");
4721                     if (!strcmp(DEVICE_BUS_BUILTIN, bus)) {
4722                         pa_log_debug(" searching bus was builtin, then select this");
4723                         found = TRUE;
4724                         break;
4725                     }
4726                 }
4727             } else {
4728                 pa_log_debug("No string [%s] match!!!!\n", api);
4729             }
4730         }
4731
4732         }
4733     }
4734
4735     if (!found)
4736         sink = NULL;
4737
4738     CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4739
4740     pa_namereg_set_default_sink(c->protocol->core, sink);
4741
4742     pa_pstream_send_simple_ack(c->pstream, tag);
4743 }
4744
4745 static void command_set_default_sink_for_usb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4746     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4747     pa_sink *sink;
4748     pa_bool_t found = FALSE;
4749     const char *serial;
4750     const char *s;
4751     uint32_t idx;
4752
4753     pa_native_connection_assert_ref(c);
4754     pa_assert(t);
4755
4756     if (pa_tagstruct_gets(t, &s) < 0 ||
4757         !pa_tagstruct_eof(t)) {
4758         protocol_error(c);
4759         return;
4760     }
4761
4762     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4763     CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID);
4764
4765     pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK_FOR_USB);
4766
4767     PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
4768         if (sink && sink->card && sink->card->proplist) {
4769             if ((serial = pa_proplist_gets(sink->card->proplist, PA_PROP_DEVICE_SERIAL)) == NULL) {
4770                 pa_log_warn("  ** No serial for this sink [%s]", sink->name);
4771                 continue;
4772             }
4773
4774             if ((found = pa_streq(serial, s))) {
4775                 pa_log_info("  ** serial [%s] for sink [%s] is matched, set as default sink\n", serial, sink->name);
4776                 break;
4777             } else {
4778                 pa_log_debug("  ** serial [%s] for sink [%s] is not matched...", serial, sink->name);
4779             }
4780         }
4781     }
4782
4783     if (!found)
4784         sink = NULL;
4785
4786     CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
4787
4788     pa_namereg_set_default_sink(c->protocol->core, sink);
4789
4790     pa_pstream_send_simple_ack(c->pstream, tag);
4791 }
4792
4793 #endif /* __TIZEN__ */
4794
4795 static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4796     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4797     uint32_t idx;
4798     const char *name;
4799
4800     pa_native_connection_assert_ref(c);
4801     pa_assert(t);
4802
4803     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4804         pa_tagstruct_gets(t, &name) < 0 ||
4805         !pa_tagstruct_eof(t)) {
4806         protocol_error(c);
4807         return;
4808     }
4809
4810     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4811     CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID);
4812
4813     if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) {
4814         playback_stream *s;
4815
4816         s = pa_idxset_get_by_index(c->output_streams, idx);
4817         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4818         CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY);
4819
4820         pa_sink_input_set_name(s->sink_input, name);
4821
4822     } else {
4823         record_stream *s;
4824         pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME);
4825
4826         s = pa_idxset_get_by_index(c->record_streams, idx);
4827         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4828
4829         pa_source_output_set_name(s->source_output, name);
4830     }
4831
4832     pa_pstream_send_simple_ack(c->pstream, tag);
4833 }
4834
4835 static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4836     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4837     uint32_t idx;
4838
4839     pa_native_connection_assert_ref(c);
4840     pa_assert(t);
4841
4842     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4843         !pa_tagstruct_eof(t)) {
4844         protocol_error(c);
4845         return;
4846     }
4847
4848     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4849
4850     if (command == PA_COMMAND_KILL_CLIENT) {
4851         pa_client *client;
4852
4853         client = pa_idxset_get_by_index(c->protocol->core->clients, idx);
4854         CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY);
4855
4856         pa_native_connection_ref(c);
4857         pa_client_kill(client);
4858
4859     } else if (command == PA_COMMAND_KILL_SINK_INPUT) {
4860         pa_sink_input *s;
4861
4862         s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4863         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4864
4865         pa_native_connection_ref(c);
4866         pa_sink_input_kill(s);
4867     } else {
4868         pa_source_output *s;
4869
4870         pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT);
4871
4872         s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4873         CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
4874
4875         pa_native_connection_ref(c);
4876         pa_source_output_kill(s);
4877     }
4878
4879     pa_pstream_send_simple_ack(c->pstream, tag);
4880     pa_native_connection_unref(c);
4881 }
4882
4883 static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4884     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4885     pa_module *m;
4886     const char *name, *argument;
4887     pa_tagstruct *reply;
4888
4889     pa_native_connection_assert_ref(c);
4890     pa_assert(t);
4891
4892     if (pa_tagstruct_gets(t, &name) < 0 ||
4893         pa_tagstruct_gets(t, &argument) < 0 ||
4894         !pa_tagstruct_eof(t)) {
4895         protocol_error(c);
4896         return;
4897     }
4898
4899     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4900     CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID);
4901     CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID);
4902
4903     if (!(m = pa_module_load(c->protocol->core, name, argument))) {
4904         pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED);
4905         return;
4906     }
4907
4908     reply = reply_new(tag);
4909     pa_tagstruct_putu32(reply, m->index);
4910     pa_pstream_send_tagstruct(c->pstream, reply);
4911 }
4912
4913 static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4914     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4915     uint32_t idx;
4916     pa_module *m;
4917
4918     pa_native_connection_assert_ref(c);
4919     pa_assert(t);
4920
4921     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4922         !pa_tagstruct_eof(t)) {
4923         protocol_error(c);
4924         return;
4925     }
4926
4927     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4928     m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
4929     CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY);
4930
4931     pa_module_unload_request(m, false);
4932     pa_pstream_send_simple_ack(c->pstream, tag);
4933 }
4934
4935 static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4936     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
4937     uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX;
4938     const char *name_device = NULL;
4939
4940     pa_native_connection_assert_ref(c);
4941     pa_assert(t);
4942
4943     if (pa_tagstruct_getu32(t, &idx) < 0 ||
4944         pa_tagstruct_getu32(t, &idx_device) < 0 ||
4945         pa_tagstruct_gets(t, &name_device) < 0 ||
4946         !pa_tagstruct_eof(t)) {
4947         protocol_error(c);
4948         return;
4949     }
4950
4951     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
4952     CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
4953
4954     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);
4955     CHECK_VALIDITY(c->pstream, (idx_device != PA_INVALID_INDEX) ^ (name_device != NULL), tag, PA_ERR_INVALID);
4956
4957     if (command == PA_COMMAND_MOVE_SINK_INPUT) {
4958         pa_sink_input *si = NULL;
4959         pa_sink *sink = NULL;
4960
4961         si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx);
4962
4963         if (idx_device != PA_INVALID_INDEX)
4964             sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device);
4965         else
4966             sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK);
4967
4968         CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY);
4969
4970         if (pa_sink_input_move_to(si, sink, true) < 0) {
4971             pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4972             return;
4973         }
4974     } else {
4975         pa_source_output *so = NULL;
4976         pa_source *source;
4977
4978         pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT);
4979
4980         so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx);
4981
4982         if (idx_device != PA_INVALID_INDEX)
4983             source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device);
4984         else
4985             source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE);
4986
4987         CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY);
4988
4989         if (pa_source_output_move_to(so, source, true) < 0) {
4990             pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
4991             return;
4992         }
4993     }
4994
4995     pa_pstream_send_simple_ack(c->pstream, tag);
4996 }
4997
4998 static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
4999     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5000     uint32_t idx = PA_INVALID_INDEX;
5001     const char *name = NULL;
5002     bool b;
5003
5004     pa_native_connection_assert_ref(c);
5005     pa_assert(t);
5006
5007     if (pa_tagstruct_getu32(t, &idx) < 0 ||
5008         pa_tagstruct_gets(t, &name) < 0 ||
5009         pa_tagstruct_get_boolean(t, &b) < 0 ||
5010         !pa_tagstruct_eof(t)) {
5011         protocol_error(c);
5012         return;
5013     }
5014
5015     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5016     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);
5017     CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5018
5019     if (command == PA_COMMAND_SUSPEND_SINK) {
5020
5021         if (idx == PA_INVALID_INDEX && name && !*name) {
5022
5023             pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
5024
5025             if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
5026                 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
5027                 return;
5028             }
5029         } else {
5030             pa_sink *sink = NULL;
5031
5032             if (idx != PA_INVALID_INDEX)
5033                 sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
5034             else
5035                 sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
5036
5037             CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
5038
5039             pa_log_debug("%s of sink %s requested by client %" PRIu32 ".",
5040                          b ? "Suspending" : "Resuming", sink->name, c->client->index);
5041
5042             if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
5043                 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
5044                 return;
5045             }
5046         }
5047     } else {
5048
5049         pa_assert(command == PA_COMMAND_SUSPEND_SOURCE);
5050
5051         if (idx == PA_INVALID_INDEX && name && !*name) {
5052
5053             pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
5054
5055             if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
5056                 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
5057                 return;
5058             }
5059
5060         } else {
5061             pa_source *source;
5062
5063             if (idx != PA_INVALID_INDEX)
5064                 source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
5065             else
5066                 source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
5067
5068             CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
5069
5070             pa_log_debug("%s of source %s requested by client %" PRIu32 ".",
5071                          b ? "Suspending" : "Resuming", source->name, c->client->index);
5072
5073             if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
5074                 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
5075                 return;
5076             }
5077         }
5078     }
5079
5080     pa_pstream_send_simple_ack(c->pstream, tag);
5081 }
5082
5083 static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5084     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5085     uint32_t idx = PA_INVALID_INDEX;
5086     const char *name = NULL;
5087     pa_module *m;
5088     pa_native_protocol_ext_cb_t cb;
5089
5090     pa_native_connection_assert_ref(c);
5091     pa_assert(t);
5092
5093     if (pa_tagstruct_getu32(t, &idx) < 0 ||
5094         pa_tagstruct_gets(t, &name) < 0) {
5095         protocol_error(c);
5096         return;
5097     }
5098
5099     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5100     CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID);
5101     CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5102
5103     if (idx != PA_INVALID_INDEX)
5104         m = pa_idxset_get_by_index(c->protocol->core->modules, idx);
5105     else
5106         PA_IDXSET_FOREACH(m, c->protocol->core->modules, idx)
5107             if (pa_streq(name, m->name))
5108                 break;
5109
5110     CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION);
5111     CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID);
5112
5113     cb = (pa_native_protocol_ext_cb_t) (unsigned long) pa_hashmap_get(c->protocol->extensions, m);
5114     CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION);
5115
5116     if (cb(c->protocol, m, c, tag, t) < 0)
5117         protocol_error(c);
5118 }
5119
5120 static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5121     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5122     uint32_t idx = PA_INVALID_INDEX;
5123     const char *name = NULL, *profile_name = NULL;
5124     pa_card *card = NULL;
5125     pa_card_profile *profile;
5126     int ret;
5127
5128     pa_native_connection_assert_ref(c);
5129     pa_assert(t);
5130
5131     if (pa_tagstruct_getu32(t, &idx) < 0 ||
5132         pa_tagstruct_gets(t, &name) < 0 ||
5133         pa_tagstruct_gets(t, &profile_name) < 0 ||
5134         !pa_tagstruct_eof(t)) {
5135         protocol_error(c);
5136         return;
5137     }
5138
5139     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5140     CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
5141     CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5142     CHECK_VALIDITY(c->pstream, profile_name, tag, PA_ERR_INVALID);
5143
5144     if (idx != PA_INVALID_INDEX)
5145         card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
5146     else
5147         card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD);
5148
5149     CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
5150
5151     profile = pa_hashmap_get(card->profiles, profile_name);
5152
5153     CHECK_VALIDITY(c->pstream, profile, tag, PA_ERR_NOENTITY);
5154
5155     if ((ret = pa_card_set_profile(card, profile, true)) < 0) {
5156         pa_pstream_send_error(c->pstream, tag, -ret);
5157         return;
5158     }
5159
5160     pa_pstream_send_simple_ack(c->pstream, tag);
5161 }
5162
5163 static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5164     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5165     uint32_t idx = PA_INVALID_INDEX;
5166     const char *name = NULL, *port = NULL;
5167     int ret;
5168
5169     pa_native_connection_assert_ref(c);
5170     pa_assert(t);
5171
5172     if (pa_tagstruct_getu32(t, &idx) < 0 ||
5173         pa_tagstruct_gets(t, &name) < 0 ||
5174         pa_tagstruct_gets(t, &port) < 0 ||
5175         !pa_tagstruct_eof(t)) {
5176         protocol_error(c);
5177         return;
5178     }
5179
5180     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5181     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);
5182     CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID);
5183     CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_INVALID);
5184
5185     if (command == PA_COMMAND_SET_SINK_PORT) {
5186         pa_sink *sink;
5187
5188         if (idx != PA_INVALID_INDEX)
5189             sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
5190         else
5191             sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
5192
5193         CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
5194
5195         if ((ret = pa_sink_set_port(sink, port, true)) < 0) {
5196             pa_pstream_send_error(c->pstream, tag, -ret);
5197             return;
5198         }
5199     } else {
5200         pa_source *source;
5201
5202         pa_assert(command == PA_COMMAND_SET_SOURCE_PORT);
5203
5204         if (idx != PA_INVALID_INDEX)
5205             source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
5206         else
5207             source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
5208
5209         CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
5210
5211         if ((ret = pa_source_set_port(source, port, true)) < 0) {
5212             pa_pstream_send_error(c->pstream, tag, -ret);
5213             return;
5214         }
5215     }
5216
5217     pa_pstream_send_simple_ack(c->pstream, tag);
5218 }
5219
5220 static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
5221     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5222     const char *port_name, *card_name;
5223     uint32_t idx = PA_INVALID_INDEX;
5224     int64_t offset;
5225     pa_card *card = NULL;
5226     pa_device_port *port = NULL;
5227
5228     pa_native_connection_assert_ref(c);
5229     pa_assert(t);
5230
5231     if (pa_tagstruct_getu32(t, &idx) < 0 ||
5232         pa_tagstruct_gets(t, &card_name) < 0 ||
5233         pa_tagstruct_gets(t, &port_name) < 0 ||
5234         pa_tagstruct_gets64(t, &offset) < 0 ||
5235         !pa_tagstruct_eof(t)) {
5236         protocol_error(c);
5237         return;
5238     }
5239
5240     CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
5241     CHECK_VALIDITY(c->pstream, !card_name || pa_namereg_is_valid_name(card_name), tag, PA_ERR_INVALID);
5242     CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (card_name != NULL), tag, PA_ERR_INVALID);
5243     CHECK_VALIDITY(c->pstream, port_name, tag, PA_ERR_INVALID);
5244
5245     if (idx != PA_INVALID_INDEX)
5246         card = pa_idxset_get_by_index(c->protocol->core->cards, idx);
5247     else
5248         card = pa_namereg_get(c->protocol->core, card_name, PA_NAMEREG_CARD);
5249
5250     CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
5251
5252     port = pa_hashmap_get(card->ports, port_name);
5253     CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_NOENTITY);
5254
5255     pa_device_port_set_latency_offset(port, offset);
5256
5257     pa_pstream_send_simple_ack(c->pstream, tag);
5258 }
5259
5260 /*** pstream callbacks ***/
5261
5262 static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
5263     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5264
5265     pa_assert(p);
5266     pa_assert(packet);
5267     pa_native_connection_assert_ref(c);
5268
5269     if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) {
5270         pa_log("invalid packet.");
5271         native_connection_unlink(c);
5272     }
5273 }
5274
5275 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) {
5276     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5277     output_stream *stream;
5278
5279     pa_assert(p);
5280     pa_assert(chunk);
5281     pa_native_connection_assert_ref(c);
5282
5283     if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) {
5284         pa_log_debug("Client sent block for invalid stream.");
5285         /* Ignoring */
5286         return;
5287     }
5288
5289 #ifdef PROTOCOL_NATIVE_DEBUG
5290     pa_log("got %lu bytes from client", (unsigned long) chunk->length);
5291 #endif
5292
5293     if (playback_stream_isinstance(stream)) {
5294         playback_stream *ps = PLAYBACK_STREAM(stream);
5295
5296         pa_atomic_inc(&ps->seek_or_post_in_queue);
5297         if (chunk->memblock) {
5298             if (seek != PA_SEEK_RELATIVE || offset != 0)
5299                 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);
5300             else
5301                 pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
5302         } else
5303             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);
5304
5305     } else {
5306         upload_stream *u = UPLOAD_STREAM(stream);
5307         size_t l;
5308
5309         if (!u->memchunk.memblock) {
5310             if (u->length == chunk->length && chunk->memblock) {
5311                 u->memchunk = *chunk;
5312                 pa_memblock_ref(u->memchunk.memblock);
5313                 u->length = 0;
5314             } else {
5315                 u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length);
5316                 u->memchunk.index = u->memchunk.length = 0;
5317             }
5318         }
5319
5320         pa_assert(u->memchunk.memblock);
5321
5322         l = u->length;
5323         if (l > chunk->length)
5324             l = chunk->length;
5325
5326         if (l > 0) {
5327             void *dst;
5328             dst = pa_memblock_acquire(u->memchunk.memblock);
5329
5330             if (chunk->memblock) {
5331                 void *src;
5332                 src = pa_memblock_acquire(chunk->memblock);
5333
5334                 memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length,
5335                        (uint8_t*) src + chunk->index, l);
5336
5337                 pa_memblock_release(chunk->memblock);
5338             } else
5339                 pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec);
5340
5341             pa_memblock_release(u->memchunk.memblock);
5342
5343             u->memchunk.length += l;
5344             u->length -= l;
5345         }
5346     }
5347 }
5348
5349 static void pstream_die_callback(pa_pstream *p, void *userdata) {
5350     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5351
5352     pa_assert(p);
5353     pa_native_connection_assert_ref(c);
5354
5355     native_connection_unlink(c);
5356     pa_log_info("Connection died.");
5357 }
5358
5359 static void pstream_drain_callback(pa_pstream *p, void *userdata) {
5360     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5361
5362     pa_assert(p);
5363     pa_native_connection_assert_ref(c);
5364
5365     native_connection_send_memblock(c);
5366 }
5367
5368 static void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
5369     pa_thread_mq *q;
5370
5371     if (!(q = pa_thread_mq_get()))
5372         pa_pstream_send_revoke(p, block_id);
5373     else
5374         pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
5375 }
5376
5377 static void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) {
5378     pa_thread_mq *q;
5379
5380     if (!(q = pa_thread_mq_get()))
5381         pa_pstream_send_release(p, block_id);
5382     else
5383         pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL);
5384 }
5385
5386 /*** client callbacks ***/
5387
5388 static void client_kill_cb(pa_client *c) {
5389     pa_assert(c);
5390
5391     native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata));
5392     pa_log_info("Connection killed.");
5393 }
5394
5395 static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) {
5396     pa_tagstruct *t;
5397     pa_native_connection *c;
5398
5399     pa_assert(client);
5400     c = PA_NATIVE_CONNECTION(client->userdata);
5401     pa_native_connection_assert_ref(c);
5402
5403     if (c->version < 15)
5404       return;
5405
5406     t = pa_tagstruct_new(NULL, 0);
5407     pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT);
5408     pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
5409     pa_tagstruct_puts(t, event);
5410     pa_tagstruct_put_proplist(t, pl);
5411     pa_pstream_send_tagstruct(c->pstream, t);
5412 }
5413
5414 /*** module entry points ***/
5415
5416 static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
5417     pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
5418
5419     pa_assert(m);
5420     pa_native_connection_assert_ref(c);
5421     pa_assert(c->auth_timeout_event == e);
5422
5423     if (!c->authorized) {
5424         native_connection_unlink(c);
5425         pa_log_info("Connection terminated due to authentication timeout.");
5426     }
5427 }
5428
5429 void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
5430     pa_native_connection *c;
5431     char pname[128];
5432     pa_client *client;
5433     pa_client_new_data data;
5434
5435     pa_assert(p);
5436     pa_assert(io);
5437     pa_assert(o);
5438
5439     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
5440         pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
5441         pa_iochannel_free(io);
5442         return;
5443     }
5444
5445     pa_client_new_data_init(&data);
5446     data.module = o->module;
5447     data.driver = __FILE__;
5448     pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
5449     pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
5450     pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
5451     client = pa_client_new(p->core, &data);
5452     pa_client_new_data_done(&data);
5453
5454     if (!client)
5455         return;
5456
5457     c = pa_msgobject_new(pa_native_connection);
5458     c->parent.parent.free = native_connection_free;
5459     c->parent.process_msg = native_connection_process_msg;
5460     c->protocol = p;
5461     c->options = pa_native_options_ref(o);
5462     c->authorized = false;
5463
5464     if (o->auth_anonymous) {
5465         pa_log_info("Client authenticated anonymously.");
5466         c->authorized = true;
5467     }
5468
5469     if (!c->authorized &&
5470         o->auth_ip_acl &&
5471         pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) {
5472
5473         pa_log_info("Client authenticated by IP ACL.");
5474         c->authorized = true;
5475     }
5476
5477     if (!c->authorized)
5478         c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
5479     else
5480         c->auth_timeout_event = NULL;
5481
5482     c->is_local = pa_iochannel_socket_is_local(io);
5483     c->version = 8;
5484
5485     c->client = client;
5486     c->client->kill = client_kill_cb;
5487     c->client->send_event = client_send_event_cb;
5488     c->client->userdata = c;
5489
5490     c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
5491     pa_pstream_set_receive_packet_callback(c->pstream, pstream_packet_callback, c);
5492     pa_pstream_set_receive_memblock_callback(c->pstream, pstream_memblock_callback, c);
5493     pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
5494     pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
5495     pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
5496     pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
5497
5498     c->pdispatch = pa_pdispatch_new(p->core->mainloop, true, command_table, PA_COMMAND_MAX);
5499
5500     c->record_streams = pa_idxset_new(NULL, NULL);
5501     c->output_streams = pa_idxset_new(NULL, NULL);
5502
5503     c->rrobin_index = PA_IDXSET_INVALID;
5504     c->subscription = NULL;
5505
5506     pa_idxset_put(p->connections, c, NULL);
5507
5508 #ifdef HAVE_CREDS
5509     if (pa_iochannel_creds_supported(io))
5510         pa_iochannel_creds_enable(io);
5511 #endif
5512
5513     pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c);
5514 }
5515
5516 void pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) {
5517     pa_native_connection *c;
5518     void *state = NULL;
5519
5520     pa_assert(p);
5521     pa_assert(m);
5522
5523     while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
5524         if (c->options->module == m)
5525             native_connection_unlink(c);
5526 }
5527
5528 static pa_native_protocol* native_protocol_new(pa_core *c) {
5529     pa_native_protocol *p;
5530     pa_native_hook_t h;
5531
5532     pa_assert(c);
5533
5534     p = pa_xnew(pa_native_protocol, 1);
5535     PA_REFCNT_INIT(p);
5536     p->core = c;
5537     p->connections = pa_idxset_new(NULL, NULL);
5538
5539     p->servers = NULL;
5540
5541     p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
5542
5543     for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5544         pa_hook_init(&p->hooks[h], p);
5545
5546     pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0);
5547
5548     return p;
5549 }
5550
5551 pa_native_protocol* pa_native_protocol_get(pa_core *c) {
5552     pa_native_protocol *p;
5553
5554     if ((p = pa_shared_get(c, "native-protocol")))
5555         return pa_native_protocol_ref(p);
5556
5557     return native_protocol_new(c);
5558 }
5559
5560 pa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) {
5561     pa_assert(p);
5562     pa_assert(PA_REFCNT_VALUE(p) >= 1);
5563
5564     PA_REFCNT_INC(p);
5565
5566     return p;
5567 }
5568
5569 void pa_native_protocol_unref(pa_native_protocol *p) {
5570     pa_native_connection *c;
5571     pa_native_hook_t h;
5572
5573     pa_assert(p);
5574     pa_assert(PA_REFCNT_VALUE(p) >= 1);
5575
5576     if (PA_REFCNT_DEC(p) > 0)
5577         return;
5578
5579     while ((c = pa_idxset_first(p->connections, NULL)))
5580         native_connection_unlink(c);
5581
5582     pa_idxset_free(p->connections, NULL);
5583
5584     pa_strlist_free(p->servers);
5585
5586     for (h = 0; h < PA_NATIVE_HOOK_MAX; h++)
5587         pa_hook_done(&p->hooks[h]);
5588
5589     pa_hashmap_free(p->extensions);
5590
5591     pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0);
5592
5593     pa_xfree(p);
5594 }
5595
5596 void pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) {
5597     pa_assert(p);
5598     pa_assert(PA_REFCNT_VALUE(p) >= 1);
5599     pa_assert(name);
5600
5601     p->servers = pa_strlist_prepend(p->servers, name);
5602
5603     pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5604 }
5605
5606 void pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) {
5607     pa_assert(p);
5608     pa_assert(PA_REFCNT_VALUE(p) >= 1);
5609     pa_assert(name);
5610
5611     p->servers = pa_strlist_remove(p->servers, name);
5612
5613     pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers);
5614 }
5615
5616 pa_hook *pa_native_protocol_hooks(pa_native_protocol *p) {
5617     pa_assert(p);
5618     pa_assert(PA_REFCNT_VALUE(p) >= 1);
5619
5620     return p->hooks;
5621 }
5622
5623 pa_strlist *pa_native_protocol_servers(pa_native_protocol *p) {
5624     pa_assert(p);
5625     pa_assert(PA_REFCNT_VALUE(p) >= 1);
5626
5627     return p->servers;
5628 }
5629
5630 int pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) {
5631     pa_assert(p);
5632     pa_assert(PA_REFCNT_VALUE(p) >= 1);
5633     pa_assert(m);
5634     pa_assert(cb);
5635     pa_assert(!pa_hashmap_get(p->extensions, m));
5636
5637     pa_assert_se(pa_hashmap_put(p->extensions, m, (void*) (unsigned long) cb) == 0);
5638     return 0;
5639 }
5640
5641 void pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) {
5642     pa_assert(p);
5643     pa_assert(PA_REFCNT_VALUE(p) >= 1);
5644     pa_assert(m);
5645
5646     pa_assert_se(pa_hashmap_remove(p->extensions, m));
5647 }
5648
5649 pa_native_options* pa_native_options_new(void) {
5650     pa_native_options *o;
5651
5652     o = pa_xnew0(pa_native_options, 1);
5653     PA_REFCNT_INIT(o);
5654
5655     return o;
5656 }
5657
5658 pa_native_options* pa_native_options_ref(pa_native_options *o) {
5659     pa_assert(o);
5660     pa_assert(PA_REFCNT_VALUE(o) >= 1);
5661
5662     PA_REFCNT_INC(o);
5663
5664     return o;
5665 }
5666
5667 void pa_native_options_unref(pa_native_options *o) {
5668     pa_assert(o);
5669     pa_assert(PA_REFCNT_VALUE(o) >= 1);
5670
5671     if (PA_REFCNT_DEC(o) > 0)
5672         return;
5673
5674     pa_xfree(o->auth_group);
5675
5676     if (o->auth_ip_acl)
5677         pa_ip_acl_free(o->auth_ip_acl);
5678
5679     if (o->auth_cookie)
5680         pa_auth_cookie_unref(o->auth_cookie);
5681
5682     pa_xfree(o);
5683 }
5684
5685 int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) {
5686     bool enabled;
5687     const char *acl;
5688
5689     pa_assert(o);
5690     pa_assert(PA_REFCNT_VALUE(o) >= 1);
5691     pa_assert(ma);
5692
5693     if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) {
5694         pa_log("auth-anonymous= expects a boolean argument.");
5695         return -1;
5696     }
5697
5698     enabled = true;
5699     if (pa_modargs_get_value_boolean(ma, "auth-group-enable", &enabled) < 0) {
5700         pa_log("auth-group-enable= expects a boolean argument.");
5701         return -1;
5702     }
5703
5704     pa_xfree(o->auth_group);
5705     o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL;
5706
5707 #ifndef HAVE_CREDS
5708     if (o->auth_group)
5709         pa_log_warn("Authentication group configured, but not available on local system. Ignoring.");
5710 #endif
5711
5712     if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) {
5713         pa_ip_acl *ipa;
5714
5715         if (!(ipa = pa_ip_acl_new(acl))) {
5716             pa_log("Failed to parse IP ACL '%s'", acl);
5717             return -1;
5718         }
5719
5720         if (o->auth_ip_acl)
5721             pa_ip_acl_free(o->auth_ip_acl);
5722
5723         o->auth_ip_acl = ipa;
5724     }
5725
5726     enabled = true;
5727     if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) {
5728         pa_log("auth-cookie-enabled= expects a boolean argument.");
5729         return -1;
5730     }
5731
5732     if (o->auth_cookie)
5733         pa_auth_cookie_unref(o->auth_cookie);
5734
5735     if (enabled) {
5736         const char *cn;
5737
5738         /* The new name for this is 'auth-cookie', for compat reasons
5739          * we check the old name too */
5740         cn = pa_modargs_get_value(ma, "auth-cookie", NULL);
5741         if (!cn)
5742             cn = pa_modargs_get_value(ma, "cookie", NULL);
5743
5744         if (cn)
5745             o->auth_cookie = pa_auth_cookie_get(c, cn, true, PA_NATIVE_COOKIE_LENGTH);
5746         else {
5747             o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, false, PA_NATIVE_COOKIE_LENGTH);
5748             if (!o->auth_cookie) {
5749                 o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE_FALLBACK, false, PA_NATIVE_COOKIE_LENGTH);
5750
5751                 if (!o->auth_cookie)
5752                     o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, true, PA_NATIVE_COOKIE_LENGTH);
5753             }
5754         }
5755
5756         if (!o->auth_cookie)
5757             return -1;
5758
5759     } else
5760           o->auth_cookie = NULL;
5761
5762     return 0;
5763 }
5764
5765 pa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) {
5766     pa_native_connection_assert_ref(c);
5767
5768     return c->pstream;
5769 }
5770
5771 pa_client* pa_native_connection_get_client(pa_native_connection *c) {
5772     pa_native_connection_assert_ref(c);
5773
5774     return c->client;
5775 }