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