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