Merge branch 'passthrough'
[platform/upstream/pulseaudio.git] / src / pulsecore / tagstruct.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/time.h>
30 #include <stdarg.h>
31
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
34 #endif
35
36 #include <pulse/xmalloc.h>
37
38 #include <pulsecore/socket.h>
39 #include <pulsecore/macro.h>
40
41 #include "tagstruct.h"
42
43 #define MAX_TAG_SIZE (64*1024)
44
45 struct pa_tagstruct {
46     uint8_t *data;
47     size_t length, allocated;
48     size_t rindex;
49
50     pa_bool_t dynamic;
51 };
52
53 pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) {
54     pa_tagstruct*t;
55
56     pa_assert(!data || (data && length));
57
58     t = pa_xnew(pa_tagstruct, 1);
59     t->data = (uint8_t*) data;
60     t->allocated = t->length = data ? length : 0;
61     t->rindex = 0;
62     t->dynamic = !data;
63
64     return t;
65 }
66
67 void pa_tagstruct_free(pa_tagstruct*t) {
68     pa_assert(t);
69
70     if (t->dynamic)
71         pa_xfree(t->data);
72     pa_xfree(t);
73 }
74
75 uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
76     uint8_t *p;
77
78     pa_assert(t);
79     pa_assert(t->dynamic);
80     pa_assert(l);
81
82     p = t->data;
83     *l = t->length;
84     pa_xfree(t);
85     return p;
86 }
87
88 static void extend(pa_tagstruct*t, size_t l) {
89     pa_assert(t);
90     pa_assert(t->dynamic);
91
92     if (t->length+l <= t->allocated)
93         return;
94
95     t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100);
96 }
97
98 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
99     size_t l;
100     pa_assert(t);
101
102     if (s) {
103         l = strlen(s)+2;
104         extend(t, l);
105         t->data[t->length] = PA_TAG_STRING;
106         strcpy((char*) (t->data+t->length+1), s);
107         t->length += l;
108     } else {
109         extend(t, 1);
110         t->data[t->length] = PA_TAG_STRING_NULL;
111         t->length += 1;
112     }
113 }
114
115 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
116     pa_assert(t);
117
118     extend(t, 5);
119     t->data[t->length] = PA_TAG_U32;
120     i = htonl(i);
121     memcpy(t->data+t->length+1, &i, 4);
122     t->length += 5;
123 }
124
125 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
126     pa_assert(t);
127
128     extend(t, 2);
129     t->data[t->length] = PA_TAG_U8;
130     *(t->data+t->length+1) = c;
131     t->length += 2;
132 }
133
134 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
135     uint32_t rate;
136
137     pa_assert(t);
138     pa_assert(ss);
139
140     extend(t, 7);
141     t->data[t->length] = PA_TAG_SAMPLE_SPEC;
142     t->data[t->length+1] = (uint8_t) ss->format;
143     t->data[t->length+2] = ss->channels;
144     rate = htonl(ss->rate);
145     memcpy(t->data+t->length+3, &rate, 4);
146     t->length += 7;
147 }
148
149 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
150     uint32_t tmp;
151
152     pa_assert(t);
153     pa_assert(p);
154
155     extend(t, 5+length);
156     t->data[t->length] = PA_TAG_ARBITRARY;
157     tmp = htonl((uint32_t) length);
158     memcpy(t->data+t->length+1, &tmp, 4);
159     if (length)
160         memcpy(t->data+t->length+5, p, length);
161     t->length += 5+length;
162 }
163
164 void pa_tagstruct_put_boolean(pa_tagstruct*t, pa_bool_t b) {
165     pa_assert(t);
166
167     extend(t, 1);
168     t->data[t->length] = (uint8_t) (b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE);
169     t->length += 1;
170 }
171
172 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
173     uint32_t tmp;
174     pa_assert(t);
175
176     extend(t, 9);
177     t->data[t->length] = PA_TAG_TIMEVAL;
178     tmp = htonl((uint32_t) tv->tv_sec);
179     memcpy(t->data+t->length+1, &tmp, 4);
180     tmp = htonl((uint32_t) tv->tv_usec);
181     memcpy(t->data+t->length+5, &tmp, 4);
182     t->length += 9;
183 }
184
185 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
186     uint32_t tmp;
187
188     pa_assert(t);
189
190     extend(t, 9);
191     t->data[t->length] = PA_TAG_USEC;
192     tmp = htonl((uint32_t) (u >> 32));
193     memcpy(t->data+t->length+1, &tmp, 4);
194     tmp = htonl((uint32_t) u);
195     memcpy(t->data+t->length+5, &tmp, 4);
196     t->length += 9;
197 }
198
199 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
200     uint32_t tmp;
201
202     pa_assert(t);
203
204     extend(t, 9);
205     t->data[t->length] = PA_TAG_U64;
206     tmp = htonl((uint32_t) (u >> 32));
207     memcpy(t->data+t->length+1, &tmp, 4);
208     tmp = htonl((uint32_t) u);
209     memcpy(t->data+t->length+5, &tmp, 4);
210     t->length += 9;
211 }
212
213 void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
214     uint32_t tmp;
215
216     pa_assert(t);
217
218     extend(t, 9);
219     t->data[t->length] = PA_TAG_S64;
220     tmp = htonl((uint32_t) ((uint64_t) u >> 32));
221     memcpy(t->data+t->length+1, &tmp, 4);
222     tmp = htonl((uint32_t) ((uint64_t) u));
223     memcpy(t->data+t->length+5, &tmp, 4);
224     t->length += 9;
225 }
226
227 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
228     unsigned i;
229
230     pa_assert(t);
231     extend(t, 2 + (size_t) map->channels);
232
233     t->data[t->length++] = PA_TAG_CHANNEL_MAP;
234     t->data[t->length++] = map->channels;
235
236     for (i = 0; i < map->channels; i ++)
237         t->data[t->length++] = (uint8_t) map->map[i];
238 }
239
240 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
241     unsigned i;
242     pa_volume_t vol;
243
244     pa_assert(t);
245     extend(t, 2 + cvolume->channels * sizeof(pa_volume_t));
246
247     t->data[t->length++] = PA_TAG_CVOLUME;
248     t->data[t->length++] = cvolume->channels;
249
250     for (i = 0; i < cvolume->channels; i ++) {
251         vol = htonl(cvolume->values[i]);
252         memcpy(t->data + t->length, &vol, sizeof(pa_volume_t));
253         t->length += sizeof(pa_volume_t);
254     }
255 }
256
257 void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t vol) {
258     uint32_t u;
259     pa_assert(t);
260
261     extend(t, 5);
262     t->data[t->length] = PA_TAG_VOLUME;
263     u = htonl((uint32_t) vol);
264     memcpy(t->data+t->length+1, &u, 4);
265     t->length += 5;
266 }
267
268 void pa_tagstruct_put_proplist(pa_tagstruct *t, pa_proplist *p) {
269     void *state = NULL;
270     pa_assert(t);
271     pa_assert(p);
272
273     extend(t, 1);
274
275     t->data[t->length++] = PA_TAG_PROPLIST;
276
277     for (;;) {
278         const char *k;
279         const void *d;
280         size_t l;
281
282         if (!(k = pa_proplist_iterate(p, &state)))
283             break;
284
285         pa_tagstruct_puts(t, k);
286         pa_assert_se(pa_proplist_get(p, k, &d, &l) >= 0);
287         pa_tagstruct_putu32(t, (uint32_t) l);
288         pa_tagstruct_put_arbitrary(t, d, l);
289     }
290
291     pa_tagstruct_puts(t, NULL);
292 }
293
294 void pa_tagstruct_put_format_info(pa_tagstruct *t, pa_format_info *f) {
295     pa_assert(t);
296     pa_assert(f);
297
298     extend(t, 1);
299
300     t->data[t->length++] = PA_TAG_FORMAT_INFO;
301     pa_tagstruct_putu8(t, (uint8_t) f->encoding);
302     pa_tagstruct_put_proplist(t, f->plist);
303 }
304
305 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
306     int error = 0;
307     size_t n;
308     char *c;
309
310     pa_assert(t);
311     pa_assert(s);
312
313     if (t->rindex+1 > t->length)
314         return -1;
315
316     if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
317         t->rindex++;
318         *s = NULL;
319         return 0;
320     }
321
322     if (t->rindex+2 > t->length)
323         return -1;
324
325     if (t->data[t->rindex] != PA_TAG_STRING)
326         return -1;
327
328     error = 1;
329     for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++)
330         if (!*c) {
331             error = 0;
332             break;
333         }
334
335     if (error)
336         return -1;
337
338     *s = (char*) (t->data+t->rindex+1);
339
340     t->rindex += n+2;
341     return 0;
342 }
343
344 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
345     pa_assert(t);
346     pa_assert(i);
347
348     if (t->rindex+5 > t->length)
349         return -1;
350
351     if (t->data[t->rindex] != PA_TAG_U32)
352         return -1;
353
354     memcpy(i, t->data+t->rindex+1, 4);
355     *i = ntohl(*i);
356     t->rindex += 5;
357     return 0;
358 }
359
360 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
361     pa_assert(t);
362     pa_assert(c);
363
364     if (t->rindex+2 > t->length)
365         return -1;
366
367     if (t->data[t->rindex] != PA_TAG_U8)
368         return -1;
369
370     *c = t->data[t->rindex+1];
371     t->rindex +=2;
372     return 0;
373 }
374
375 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
376     pa_assert(t);
377     pa_assert(ss);
378
379     if (t->rindex+7 > t->length)
380         return -1;
381
382     if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
383         return -1;
384
385     ss->format = t->data[t->rindex+1];
386     ss->channels = t->data[t->rindex+2];
387     memcpy(&ss->rate, t->data+t->rindex+3, 4);
388     ss->rate = ntohl(ss->rate);
389
390     t->rindex += 7;
391     return 0;
392 }
393
394 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
395     uint32_t len;
396
397     pa_assert(t);
398     pa_assert(p);
399
400     if (t->rindex+5+length > t->length)
401         return -1;
402
403     if (t->data[t->rindex] != PA_TAG_ARBITRARY)
404         return -1;
405
406     memcpy(&len, t->data+t->rindex+1, 4);
407     if (ntohl(len) != length)
408         return -1;
409
410     *p = t->data+t->rindex+5;
411     t->rindex += 5+length;
412     return 0;
413 }
414
415 int pa_tagstruct_eof(pa_tagstruct*t) {
416     pa_assert(t);
417
418     return t->rindex >= t->length;
419 }
420
421 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
422     pa_assert(t);
423     pa_assert(t->dynamic);
424     pa_assert(l);
425
426     *l = t->length;
427     return t->data;
428 }
429
430 int pa_tagstruct_get_boolean(pa_tagstruct*t, pa_bool_t *b) {
431     pa_assert(t);
432     pa_assert(b);
433
434     if (t->rindex+1 > t->length)
435         return -1;
436
437     if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
438         *b = TRUE;
439     else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
440         *b = FALSE;
441     else
442         return -1;
443
444     t->rindex +=1;
445     return 0;
446 }
447
448 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
449
450     pa_assert(t);
451     pa_assert(tv);
452
453     if (t->rindex+9 > t->length)
454         return -1;
455
456     if (t->data[t->rindex] != PA_TAG_TIMEVAL)
457         return -1;
458
459     memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
460     tv->tv_sec = (time_t) ntohl((uint32_t) tv->tv_sec);
461     memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
462     tv->tv_usec = (suseconds_t) ntohl((uint32_t) tv->tv_usec);
463     t->rindex += 9;
464     return 0;
465 }
466
467 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
468     uint32_t tmp;
469
470     pa_assert(t);
471     pa_assert(u);
472
473     if (t->rindex+9 > t->length)
474         return -1;
475
476     if (t->data[t->rindex] != PA_TAG_USEC)
477         return -1;
478
479     memcpy(&tmp, t->data+t->rindex+1, 4);
480     *u = (pa_usec_t) ntohl(tmp) << 32;
481     memcpy(&tmp, t->data+t->rindex+5, 4);
482     *u |= (pa_usec_t) ntohl(tmp);
483     t->rindex +=9;
484     return 0;
485 }
486
487 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
488     uint32_t tmp;
489
490     pa_assert(t);
491     pa_assert(u);
492
493     if (t->rindex+9 > t->length)
494         return -1;
495
496     if (t->data[t->rindex] != PA_TAG_U64)
497         return -1;
498
499     memcpy(&tmp, t->data+t->rindex+1, 4);
500     *u = (uint64_t) ntohl(tmp) << 32;
501     memcpy(&tmp, t->data+t->rindex+5, 4);
502     *u |= (uint64_t) ntohl(tmp);
503     t->rindex +=9;
504     return 0;
505 }
506
507 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
508     uint32_t tmp;
509
510     pa_assert(t);
511     pa_assert(u);
512
513     if (t->rindex+9 > t->length)
514         return -1;
515
516     if (t->data[t->rindex] != PA_TAG_S64)
517         return -1;
518
519     memcpy(&tmp, t->data+t->rindex+1, 4);
520     *u = (int64_t) ((uint64_t) ntohl(tmp) << 32);
521     memcpy(&tmp, t->data+t->rindex+5, 4);
522     *u |= (int64_t) ntohl(tmp);
523     t->rindex +=9;
524     return 0;
525 }
526
527 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
528     unsigned i;
529
530     pa_assert(t);
531     pa_assert(map);
532
533     if (t->rindex+2 > t->length)
534         return -1;
535
536     if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP)
537         return -1;
538
539     if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
540         return -1;
541
542     if (t->rindex+2+map->channels > t->length)
543         return -1;
544
545     for (i = 0; i < map->channels; i ++)
546         map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
547
548     t->rindex += 2 + (size_t) map->channels;
549     return 0;
550 }
551
552 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
553     unsigned i;
554     pa_volume_t vol;
555
556     pa_assert(t);
557     pa_assert(cvolume);
558
559     if (t->rindex+2 > t->length)
560         return -1;
561
562     if (t->data[t->rindex] != PA_TAG_CVOLUME)
563         return -1;
564
565     if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
566         return -1;
567
568     if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
569         return -1;
570
571     for (i = 0; i < cvolume->channels; i ++) {
572         memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t));
573         cvolume->values[i] = (pa_volume_t) ntohl(vol);
574     }
575
576     t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t);
577     return 0;
578 }
579
580 int pa_tagstruct_get_volume(pa_tagstruct*t, pa_volume_t *vol) {
581     uint32_t u;
582
583     pa_assert(t);
584     pa_assert(vol);
585
586     if (t->rindex+5 > t->length)
587         return -1;
588
589     if (t->data[t->rindex] != PA_TAG_VOLUME)
590         return -1;
591
592     memcpy(&u, t->data+t->rindex+1, 4);
593     *vol = (pa_volume_t) ntohl(u);
594
595     t->rindex += 5;
596     return 0;
597 }
598
599 int pa_tagstruct_get_proplist(pa_tagstruct *t, pa_proplist *p) {
600     size_t saved_rindex;
601
602     pa_assert(t);
603     pa_assert(p);
604
605     if (t->rindex+1 > t->length)
606         return -1;
607
608     if (t->data[t->rindex] != PA_TAG_PROPLIST)
609         return -1;
610
611     saved_rindex = t->rindex;
612     t->rindex++;
613
614     for (;;) {
615         const char *k;
616         const void *d;
617         uint32_t length;
618
619         if (pa_tagstruct_gets(t, &k) < 0)
620             goto fail;
621
622         if (!k)
623             break;
624
625         if (pa_tagstruct_getu32(t, &length) < 0)
626             goto fail;
627
628         if (length > MAX_TAG_SIZE)
629             goto fail;
630
631         if (pa_tagstruct_get_arbitrary(t, &d, length) < 0)
632             goto fail;
633
634         if (pa_proplist_set(p, k, d, length) < 0)
635             goto fail;
636     }
637
638     return 0;
639
640 fail:
641     t->rindex = saved_rindex;
642     return -1;
643 }
644
645 int pa_tagstruct_get_format_info(pa_tagstruct *t, pa_format_info *f) {
646     size_t saved_rindex;
647     uint8_t encoding;
648
649     pa_assert(t);
650     pa_assert(f);
651
652     if (t->rindex+1 > t->length)
653         return -1;
654
655     if (t->data[t->rindex] != PA_TAG_FORMAT_INFO)
656         return -1;
657
658     saved_rindex = t->rindex;
659     t->rindex++;
660
661     if (pa_tagstruct_getu8(t, &encoding) < 0)
662         goto fail;
663
664     f->encoding = encoding;
665
666     if (pa_tagstruct_get_proplist(t, f->plist) < 0)
667         goto fail;
668
669     return 0;
670
671 fail:
672     t->rindex = saved_rindex;
673     return -1;
674 }
675
676 void pa_tagstruct_put(pa_tagstruct *t, ...) {
677     va_list va;
678     pa_assert(t);
679
680     va_start(va, t);
681
682     for (;;) {
683         int tag = va_arg(va, int);
684
685         if (tag == PA_TAG_INVALID)
686             break;
687
688         switch (tag) {
689             case PA_TAG_STRING:
690             case PA_TAG_STRING_NULL:
691                 pa_tagstruct_puts(t, va_arg(va, char*));
692                 break;
693
694             case PA_TAG_U32:
695                 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
696                 break;
697
698             case PA_TAG_U8:
699                 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
700                 break;
701
702             case PA_TAG_U64:
703                 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
704                 break;
705
706             case PA_TAG_SAMPLE_SPEC:
707                 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
708                 break;
709
710             case PA_TAG_ARBITRARY: {
711                 void *p = va_arg(va, void*);
712                 size_t size = va_arg(va, size_t);
713                 pa_tagstruct_put_arbitrary(t, p, size);
714                 break;
715             }
716
717             case PA_TAG_BOOLEAN_TRUE:
718             case PA_TAG_BOOLEAN_FALSE:
719                 pa_tagstruct_put_boolean(t, va_arg(va, int));
720                 break;
721
722             case PA_TAG_TIMEVAL:
723                 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
724                 break;
725
726             case PA_TAG_USEC:
727                 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
728                 break;
729
730             case PA_TAG_CHANNEL_MAP:
731                 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
732                 break;
733
734             case PA_TAG_CVOLUME:
735                 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
736                 break;
737
738             case PA_TAG_VOLUME:
739                 pa_tagstruct_put_volume(t, va_arg(va, pa_volume_t));
740                 break;
741
742             case PA_TAG_PROPLIST:
743                 pa_tagstruct_put_proplist(t, va_arg(va, pa_proplist *));
744                 break;
745
746             default:
747                 pa_assert_not_reached();
748         }
749     }
750
751     va_end(va);
752 }
753
754 int pa_tagstruct_get(pa_tagstruct *t, ...) {
755     va_list va;
756     int ret = 0;
757
758     pa_assert(t);
759
760     va_start(va, t);
761     while (ret == 0) {
762         int tag = va_arg(va, int);
763
764         if (tag == PA_TAG_INVALID)
765             break;
766
767         switch (tag) {
768             case PA_TAG_STRING:
769             case PA_TAG_STRING_NULL:
770                 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
771                 break;
772
773             case PA_TAG_U32:
774                 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
775                 break;
776
777             case PA_TAG_U8:
778                 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
779                 break;
780
781             case PA_TAG_U64:
782                 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
783                 break;
784
785             case PA_TAG_SAMPLE_SPEC:
786                 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
787                 break;
788
789             case PA_TAG_ARBITRARY: {
790                 const void **p = va_arg(va, const void**);
791                 size_t size = va_arg(va, size_t);
792                 ret = pa_tagstruct_get_arbitrary(t, p, size);
793                 break;
794             }
795
796             case PA_TAG_BOOLEAN_TRUE:
797             case PA_TAG_BOOLEAN_FALSE:
798                 ret = pa_tagstruct_get_boolean(t, va_arg(va, pa_bool_t*));
799                 break;
800
801             case PA_TAG_TIMEVAL:
802                 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
803                 break;
804
805             case PA_TAG_USEC:
806                 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
807                 break;
808
809             case PA_TAG_CHANNEL_MAP:
810                 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
811                 break;
812
813             case PA_TAG_CVOLUME:
814                 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
815                 break;
816
817             case PA_TAG_VOLUME:
818                 ret = pa_tagstruct_get_volume(t, va_arg(va, pa_volume_t *));
819                 break;
820
821             case PA_TAG_PROPLIST:
822                 ret = pa_tagstruct_get_proplist(t, va_arg(va, pa_proplist *));
823                 break;
824
825             default:
826                 pa_assert_not_reached();
827         }
828
829     }
830
831     va_end(va);
832     return ret;
833 }