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