]> code.delx.au - pulseaudio/blob - src/pulsecore/tagstruct.c
remap: make the MMX code pretier
[pulseaudio] / 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/winsock.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 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
295 int error = 0;
296 size_t n;
297 char *c;
298
299 pa_assert(t);
300 pa_assert(s);
301
302 if (t->rindex+1 > t->length)
303 return -1;
304
305 if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
306 t->rindex++;
307 *s = NULL;
308 return 0;
309 }
310
311 if (t->rindex+2 > t->length)
312 return -1;
313
314 if (t->data[t->rindex] != PA_TAG_STRING)
315 return -1;
316
317 error = 1;
318 for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++)
319 if (!*c) {
320 error = 0;
321 break;
322 }
323
324 if (error)
325 return -1;
326
327 *s = (char*) (t->data+t->rindex+1);
328
329 t->rindex += n+2;
330 return 0;
331 }
332
333 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
334 pa_assert(t);
335 pa_assert(i);
336
337 if (t->rindex+5 > t->length)
338 return -1;
339
340 if (t->data[t->rindex] != PA_TAG_U32)
341 return -1;
342
343 memcpy(i, t->data+t->rindex+1, 4);
344 *i = ntohl(*i);
345 t->rindex += 5;
346 return 0;
347 }
348
349 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
350 pa_assert(t);
351 pa_assert(c);
352
353 if (t->rindex+2 > t->length)
354 return -1;
355
356 if (t->data[t->rindex] != PA_TAG_U8)
357 return -1;
358
359 *c = t->data[t->rindex+1];
360 t->rindex +=2;
361 return 0;
362 }
363
364 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
365 pa_assert(t);
366 pa_assert(ss);
367
368 if (t->rindex+7 > t->length)
369 return -1;
370
371 if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
372 return -1;
373
374 ss->format = t->data[t->rindex+1];
375 ss->channels = t->data[t->rindex+2];
376 memcpy(&ss->rate, t->data+t->rindex+3, 4);
377 ss->rate = ntohl(ss->rate);
378
379 t->rindex += 7;
380 return 0;
381 }
382
383 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
384 uint32_t len;
385
386 pa_assert(t);
387 pa_assert(p);
388
389 if (t->rindex+5+length > t->length)
390 return -1;
391
392 if (t->data[t->rindex] != PA_TAG_ARBITRARY)
393 return -1;
394
395 memcpy(&len, t->data+t->rindex+1, 4);
396 if (ntohl(len) != length)
397 return -1;
398
399 *p = t->data+t->rindex+5;
400 t->rindex += 5+length;
401 return 0;
402 }
403
404 int pa_tagstruct_eof(pa_tagstruct*t) {
405 pa_assert(t);
406
407 return t->rindex >= t->length;
408 }
409
410 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
411 pa_assert(t);
412 pa_assert(t->dynamic);
413 pa_assert(l);
414
415 *l = t->length;
416 return t->data;
417 }
418
419 int pa_tagstruct_get_boolean(pa_tagstruct*t, pa_bool_t *b) {
420 pa_assert(t);
421 pa_assert(b);
422
423 if (t->rindex+1 > t->length)
424 return -1;
425
426 if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
427 *b = TRUE;
428 else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
429 *b = FALSE;
430 else
431 return -1;
432
433 t->rindex +=1;
434 return 0;
435 }
436
437 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
438
439 pa_assert(t);
440 pa_assert(tv);
441
442 if (t->rindex+9 > t->length)
443 return -1;
444
445 if (t->data[t->rindex] != PA_TAG_TIMEVAL)
446 return -1;
447
448 memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
449 tv->tv_sec = (time_t) ntohl((uint32_t) tv->tv_sec);
450 memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
451 tv->tv_usec = (suseconds_t) ntohl((uint32_t) tv->tv_usec);
452 t->rindex += 9;
453 return 0;
454 }
455
456 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
457 uint32_t tmp;
458
459 pa_assert(t);
460 pa_assert(u);
461
462 if (t->rindex+9 > t->length)
463 return -1;
464
465 if (t->data[t->rindex] != PA_TAG_USEC)
466 return -1;
467
468 memcpy(&tmp, t->data+t->rindex+1, 4);
469 *u = (pa_usec_t) ntohl(tmp) << 32;
470 memcpy(&tmp, t->data+t->rindex+5, 4);
471 *u |= (pa_usec_t) ntohl(tmp);
472 t->rindex +=9;
473 return 0;
474 }
475
476 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
477 uint32_t tmp;
478
479 pa_assert(t);
480 pa_assert(u);
481
482 if (t->rindex+9 > t->length)
483 return -1;
484
485 if (t->data[t->rindex] != PA_TAG_U64)
486 return -1;
487
488 memcpy(&tmp, t->data+t->rindex+1, 4);
489 *u = (uint64_t) ntohl(tmp) << 32;
490 memcpy(&tmp, t->data+t->rindex+5, 4);
491 *u |= (uint64_t) ntohl(tmp);
492 t->rindex +=9;
493 return 0;
494 }
495
496 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
497 uint32_t tmp;
498
499 pa_assert(t);
500 pa_assert(u);
501
502 if (t->rindex+9 > t->length)
503 return -1;
504
505 if (t->data[t->rindex] != PA_TAG_S64)
506 return -1;
507
508 memcpy(&tmp, t->data+t->rindex+1, 4);
509 *u = (int64_t) ((uint64_t) ntohl(tmp) << 32);
510 memcpy(&tmp, t->data+t->rindex+5, 4);
511 *u |= (int64_t) ntohl(tmp);
512 t->rindex +=9;
513 return 0;
514 }
515
516 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
517 unsigned i;
518
519 pa_assert(t);
520 pa_assert(map);
521
522 if (t->rindex+2 > t->length)
523 return -1;
524
525 if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP)
526 return -1;
527
528 if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
529 return -1;
530
531 if (t->rindex+2+map->channels > t->length)
532 return -1;
533
534 for (i = 0; i < map->channels; i ++)
535 map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
536
537 t->rindex += 2 + (size_t) map->channels;
538 return 0;
539 }
540
541 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
542 unsigned i;
543 pa_volume_t vol;
544
545 pa_assert(t);
546 pa_assert(cvolume);
547
548 if (t->rindex+2 > t->length)
549 return -1;
550
551 if (t->data[t->rindex] != PA_TAG_CVOLUME)
552 return -1;
553
554 if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
555 return -1;
556
557 if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
558 return -1;
559
560 for (i = 0; i < cvolume->channels; i ++) {
561 memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t));
562 cvolume->values[i] = (pa_volume_t) ntohl(vol);
563 }
564
565 t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t);
566 return 0;
567 }
568
569 int pa_tagstruct_get_volume(pa_tagstruct*t, pa_volume_t *vol) {
570 uint32_t u;
571
572 pa_assert(t);
573 pa_assert(vol);
574
575 if (t->rindex+5 > t->length)
576 return -1;
577
578 if (t->data[t->rindex] != PA_TAG_VOLUME)
579 return -1;
580
581 memcpy(&u, t->data+t->rindex+1, 4);
582 *vol = (pa_volume_t) ntohl(u);
583
584 t->rindex += 5;
585 return 0;
586 }
587
588 int pa_tagstruct_get_proplist(pa_tagstruct *t, pa_proplist *p) {
589 size_t saved_rindex;
590
591 pa_assert(t);
592 pa_assert(p);
593
594 if (t->rindex+1 > t->length)
595 return -1;
596
597 if (t->data[t->rindex] != PA_TAG_PROPLIST)
598 return -1;
599
600 saved_rindex = t->rindex;
601 t->rindex++;
602
603 for (;;) {
604 const char *k;
605 const void *d;
606 uint32_t length;
607
608 if (pa_tagstruct_gets(t, &k) < 0)
609 goto fail;
610
611 if (!k)
612 break;
613
614 if (pa_tagstruct_getu32(t, &length) < 0)
615 goto fail;
616
617 if (length > MAX_TAG_SIZE)
618 goto fail;
619
620 if (pa_tagstruct_get_arbitrary(t, &d, length) < 0)
621 goto fail;
622
623 if (pa_proplist_set(p, k, d, length) < 0)
624 goto fail;
625 }
626
627 return 0;
628
629 fail:
630 t->rindex = saved_rindex;
631 return -1;
632 }
633
634 void pa_tagstruct_put(pa_tagstruct *t, ...) {
635 va_list va;
636 pa_assert(t);
637
638 va_start(va, t);
639
640 for (;;) {
641 int tag = va_arg(va, int);
642
643 if (tag == PA_TAG_INVALID)
644 break;
645
646 switch (tag) {
647 case PA_TAG_STRING:
648 case PA_TAG_STRING_NULL:
649 pa_tagstruct_puts(t, va_arg(va, char*));
650 break;
651
652 case PA_TAG_U32:
653 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
654 break;
655
656 case PA_TAG_U8:
657 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
658 break;
659
660 case PA_TAG_U64:
661 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
662 break;
663
664 case PA_TAG_SAMPLE_SPEC:
665 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
666 break;
667
668 case PA_TAG_ARBITRARY: {
669 void *p = va_arg(va, void*);
670 size_t size = va_arg(va, size_t);
671 pa_tagstruct_put_arbitrary(t, p, size);
672 break;
673 }
674
675 case PA_TAG_BOOLEAN_TRUE:
676 case PA_TAG_BOOLEAN_FALSE:
677 pa_tagstruct_put_boolean(t, va_arg(va, int));
678 break;
679
680 case PA_TAG_TIMEVAL:
681 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
682 break;
683
684 case PA_TAG_USEC:
685 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
686 break;
687
688 case PA_TAG_CHANNEL_MAP:
689 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
690 break;
691
692 case PA_TAG_CVOLUME:
693 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
694 break;
695
696 case PA_TAG_VOLUME:
697 pa_tagstruct_put_volume(t, va_arg(va, pa_volume_t));
698 break;
699
700 case PA_TAG_PROPLIST:
701 pa_tagstruct_put_proplist(t, va_arg(va, pa_proplist *));
702 break;
703
704 default:
705 pa_assert_not_reached();
706 }
707 }
708
709 va_end(va);
710 }
711
712 int pa_tagstruct_get(pa_tagstruct *t, ...) {
713 va_list va;
714 int ret = 0;
715
716 pa_assert(t);
717
718 va_start(va, t);
719 while (ret == 0) {
720 int tag = va_arg(va, int);
721
722 if (tag == PA_TAG_INVALID)
723 break;
724
725 switch (tag) {
726 case PA_TAG_STRING:
727 case PA_TAG_STRING_NULL:
728 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
729 break;
730
731 case PA_TAG_U32:
732 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
733 break;
734
735 case PA_TAG_U8:
736 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
737 break;
738
739 case PA_TAG_U64:
740 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
741 break;
742
743 case PA_TAG_SAMPLE_SPEC:
744 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
745 break;
746
747 case PA_TAG_ARBITRARY: {
748 const void **p = va_arg(va, const void**);
749 size_t size = va_arg(va, size_t);
750 ret = pa_tagstruct_get_arbitrary(t, p, size);
751 break;
752 }
753
754 case PA_TAG_BOOLEAN_TRUE:
755 case PA_TAG_BOOLEAN_FALSE:
756 ret = pa_tagstruct_get_boolean(t, va_arg(va, pa_bool_t*));
757 break;
758
759 case PA_TAG_TIMEVAL:
760 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
761 break;
762
763 case PA_TAG_USEC:
764 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
765 break;
766
767 case PA_TAG_CHANNEL_MAP:
768 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
769 break;
770
771 case PA_TAG_CVOLUME:
772 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
773 break;
774
775 case PA_TAG_VOLUME:
776 ret = pa_tagstruct_get_volume(t, va_arg(va, pa_volume_t *));
777 break;
778
779 case PA_TAG_PROPLIST:
780 ret = pa_tagstruct_get_proplist(t, va_arg(va, pa_proplist *));
781 break;
782
783 default:
784 pa_assert_not_reached();
785 }
786
787 }
788
789 va_end(va);
790 return ret;
791 }