2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
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.
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.
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
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
36 #include <pulse/xmalloc.h>
38 #include <pulsecore/socket.h>
39 #include <pulsecore/macro.h>
41 #include "tagstruct.h"
43 #define MAX_TAG_SIZE (64*1024)
47 size_t length, allocated;
53 pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) {
56 pa_assert(!data || (data && length));
58 t = pa_xnew(pa_tagstruct, 1);
59 t->data = (uint8_t*) data;
60 t->allocated = t->length = data ? length : 0;
67 void pa_tagstruct_free(pa_tagstruct*t) {
75 uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
79 pa_assert(t->dynamic);
88 static void extend(pa_tagstruct*t, size_t l) {
90 pa_assert(t->dynamic);
92 if (t->length+l <= t->allocated)
95 t->data = pa_xrealloc(t->data, t->allocated = t->length+l+100);
98 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
105 t->data[t->length] = PA_TAG_STRING;
106 strcpy((char*) (t->data+t->length+1), s);
110 t->data[t->length] = PA_TAG_STRING_NULL;
115 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
119 t->data[t->length] = PA_TAG_U32;
121 memcpy(t->data+t->length+1, &i, 4);
125 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
129 t->data[t->length] = PA_TAG_U8;
130 *(t->data+t->length+1) = c;
134 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
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);
149 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
156 t->data[t->length] = PA_TAG_ARBITRARY;
157 tmp = htonl((uint32_t) length);
158 memcpy(t->data+t->length+1, &tmp, 4);
160 memcpy(t->data+t->length+5, p, length);
161 t->length += 5+length;
164 void pa_tagstruct_put_boolean(pa_tagstruct*t, pa_bool_t b) {
168 t->data[t->length] = (uint8_t) (b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE);
172 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
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);
185 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
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);
199 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
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);
213 void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
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);
227 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
232 extend(t, 2 + (size_t) map->channels);
234 t->data[t->length++] = PA_TAG_CHANNEL_MAP;
235 t->data[t->length++] = map->channels;
237 for (i = 0; i < map->channels; i ++)
238 t->data[t->length++] = (uint8_t) map->map[i];
241 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
247 extend(t, 2 + cvolume->channels * sizeof(pa_volume_t));
249 t->data[t->length++] = PA_TAG_CVOLUME;
250 t->data[t->length++] = cvolume->channels;
252 for (i = 0; i < cvolume->channels; i ++) {
253 vol = htonl(cvolume->values[i]);
254 memcpy(t->data + t->length, &vol, sizeof(pa_volume_t));
255 t->length += sizeof(pa_volume_t);
259 void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t vol) {
264 t->data[t->length] = PA_TAG_VOLUME;
265 u = htonl((uint32_t) vol);
266 memcpy(t->data+t->length+1, &u, 4);
270 void pa_tagstruct_put_proplist(pa_tagstruct *t, pa_proplist *p) {
277 t->data[t->length++] = PA_TAG_PROPLIST;
284 if (!(k = pa_proplist_iterate(p, &state)))
287 pa_tagstruct_puts(t, k);
288 pa_assert_se(pa_proplist_get(p, k, &d, &l) >= 0);
289 pa_tagstruct_putu32(t, (uint32_t) l);
290 pa_tagstruct_put_arbitrary(t, d, l);
293 pa_tagstruct_puts(t, NULL);
296 void pa_tagstruct_put_format_info(pa_tagstruct *t, pa_format_info *f) {
302 t->data[t->length++] = PA_TAG_FORMAT_INFO;
303 pa_tagstruct_putu8(t, (uint8_t) f->encoding);
304 pa_tagstruct_put_proplist(t, f->plist);
307 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
315 if (t->rindex+1 > t->length)
318 if (t->data[t->rindex] == PA_TAG_STRING_NULL) {
324 if (t->rindex+2 > t->length)
327 if (t->data[t->rindex] != PA_TAG_STRING)
331 for (n = 0, c = (char*) (t->data+t->rindex+1); t->rindex+1+n < t->length; n++, c++)
340 *s = (char*) (t->data+t->rindex+1);
346 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
350 if (t->rindex+5 > t->length)
353 if (t->data[t->rindex] != PA_TAG_U32)
356 memcpy(i, t->data+t->rindex+1, 4);
362 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
366 if (t->rindex+2 > t->length)
369 if (t->data[t->rindex] != PA_TAG_U8)
372 *c = t->data[t->rindex+1];
377 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
381 if (t->rindex+7 > t->length)
384 if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
387 ss->format = t->data[t->rindex+1];
388 ss->channels = t->data[t->rindex+2];
389 memcpy(&ss->rate, t->data+t->rindex+3, 4);
390 ss->rate = ntohl(ss->rate);
396 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
402 if (t->rindex+5+length > t->length)
405 if (t->data[t->rindex] != PA_TAG_ARBITRARY)
408 memcpy(&len, t->data+t->rindex+1, 4);
409 if (ntohl(len) != length)
412 *p = t->data+t->rindex+5;
413 t->rindex += 5+length;
417 int pa_tagstruct_eof(pa_tagstruct*t) {
420 return t->rindex >= t->length;
423 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
425 pa_assert(t->dynamic);
432 int pa_tagstruct_get_boolean(pa_tagstruct*t, pa_bool_t *b) {
436 if (t->rindex+1 > t->length)
439 if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
441 else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
450 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
455 if (t->rindex+9 > t->length)
458 if (t->data[t->rindex] != PA_TAG_TIMEVAL)
461 memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
462 tv->tv_sec = (time_t) ntohl((uint32_t) tv->tv_sec);
463 memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
464 tv->tv_usec = (suseconds_t) ntohl((uint32_t) tv->tv_usec);
469 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
475 if (t->rindex+9 > t->length)
478 if (t->data[t->rindex] != PA_TAG_USEC)
481 memcpy(&tmp, t->data+t->rindex+1, 4);
482 *u = (pa_usec_t) ntohl(tmp) << 32;
483 memcpy(&tmp, t->data+t->rindex+5, 4);
484 *u |= (pa_usec_t) ntohl(tmp);
489 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
495 if (t->rindex+9 > t->length)
498 if (t->data[t->rindex] != PA_TAG_U64)
501 memcpy(&tmp, t->data+t->rindex+1, 4);
502 *u = (uint64_t) ntohl(tmp) << 32;
503 memcpy(&tmp, t->data+t->rindex+5, 4);
504 *u |= (uint64_t) ntohl(tmp);
509 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
515 if (t->rindex+9 > t->length)
518 if (t->data[t->rindex] != PA_TAG_S64)
521 memcpy(&tmp, t->data+t->rindex+1, 4);
522 *u = (int64_t) ((uint64_t) ntohl(tmp) << 32);
523 memcpy(&tmp, t->data+t->rindex+5, 4);
524 *u |= (int64_t) ntohl(tmp);
529 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
535 if (t->rindex+2 > t->length)
538 if (t->data[t->rindex] != PA_TAG_CHANNEL_MAP)
541 if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
544 if (t->rindex+2+map->channels > t->length)
547 for (i = 0; i < map->channels; i ++)
548 map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
550 t->rindex += 2 + (size_t) map->channels;
554 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
561 if (t->rindex+2 > t->length)
564 if (t->data[t->rindex] != PA_TAG_CVOLUME)
567 if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX)
570 if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
573 for (i = 0; i < cvolume->channels; i ++) {
574 memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t));
575 cvolume->values[i] = (pa_volume_t) ntohl(vol);
578 t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t);
582 int pa_tagstruct_get_volume(pa_tagstruct*t, pa_volume_t *vol) {
588 if (t->rindex+5 > t->length)
591 if (t->data[t->rindex] != PA_TAG_VOLUME)
594 memcpy(&u, t->data+t->rindex+1, 4);
595 *vol = (pa_volume_t) ntohl(u);
601 int pa_tagstruct_get_proplist(pa_tagstruct *t, pa_proplist *p) {
606 if (t->rindex+1 > t->length)
609 if (t->data[t->rindex] != PA_TAG_PROPLIST)
612 saved_rindex = t->rindex;
620 if (pa_tagstruct_gets(t, &k) < 0)
626 if (!pa_proplist_key_valid(k))
629 if (pa_tagstruct_getu32(t, &length) < 0)
632 if (length > MAX_TAG_SIZE)
635 if (pa_tagstruct_get_arbitrary(t, &d, length) < 0)
639 pa_assert_se(pa_proplist_set(p, k, d, length) >= 0);
645 t->rindex = saved_rindex;
649 int pa_tagstruct_get_format_info(pa_tagstruct *t, pa_format_info *f) {
656 if (t->rindex+1 > t->length)
659 if (t->data[t->rindex] != PA_TAG_FORMAT_INFO)
662 saved_rindex = t->rindex;
665 if (pa_tagstruct_getu8(t, &encoding) < 0)
668 f->encoding = encoding;
670 if (pa_tagstruct_get_proplist(t, f->plist) < 0)
676 t->rindex = saved_rindex;
680 void pa_tagstruct_put(pa_tagstruct *t, ...) {
687 int tag = va_arg(va, int);
689 if (tag == PA_TAG_INVALID)
694 case PA_TAG_STRING_NULL:
695 pa_tagstruct_puts(t, va_arg(va, char*));
699 pa_tagstruct_putu32(t, va_arg(va, uint32_t));
703 pa_tagstruct_putu8(t, (uint8_t) va_arg(va, int));
707 pa_tagstruct_putu64(t, va_arg(va, uint64_t));
710 case PA_TAG_SAMPLE_SPEC:
711 pa_tagstruct_put_sample_spec(t, va_arg(va, pa_sample_spec*));
714 case PA_TAG_ARBITRARY: {
715 void *p = va_arg(va, void*);
716 size_t size = va_arg(va, size_t);
717 pa_tagstruct_put_arbitrary(t, p, size);
721 case PA_TAG_BOOLEAN_TRUE:
722 case PA_TAG_BOOLEAN_FALSE:
723 pa_tagstruct_put_boolean(t, va_arg(va, int));
727 pa_tagstruct_put_timeval(t, va_arg(va, struct timeval*));
731 pa_tagstruct_put_usec(t, va_arg(va, pa_usec_t));
734 case PA_TAG_CHANNEL_MAP:
735 pa_tagstruct_put_channel_map(t, va_arg(va, pa_channel_map *));
739 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
743 pa_tagstruct_put_volume(t, va_arg(va, pa_volume_t));
746 case PA_TAG_PROPLIST:
747 pa_tagstruct_put_proplist(t, va_arg(va, pa_proplist *));
751 pa_assert_not_reached();
758 int pa_tagstruct_get(pa_tagstruct *t, ...) {
766 int tag = va_arg(va, int);
768 if (tag == PA_TAG_INVALID)
773 case PA_TAG_STRING_NULL:
774 ret = pa_tagstruct_gets(t, va_arg(va, const char**));
778 ret = pa_tagstruct_getu32(t, va_arg(va, uint32_t*));
782 ret = pa_tagstruct_getu8(t, va_arg(va, uint8_t*));
786 ret = pa_tagstruct_getu64(t, va_arg(va, uint64_t*));
789 case PA_TAG_SAMPLE_SPEC:
790 ret = pa_tagstruct_get_sample_spec(t, va_arg(va, pa_sample_spec*));
793 case PA_TAG_ARBITRARY: {
794 const void **p = va_arg(va, const void**);
795 size_t size = va_arg(va, size_t);
796 ret = pa_tagstruct_get_arbitrary(t, p, size);
800 case PA_TAG_BOOLEAN_TRUE:
801 case PA_TAG_BOOLEAN_FALSE:
802 ret = pa_tagstruct_get_boolean(t, va_arg(va, pa_bool_t*));
806 ret = pa_tagstruct_get_timeval(t, va_arg(va, struct timeval*));
810 ret = pa_tagstruct_get_usec(t, va_arg(va, pa_usec_t*));
813 case PA_TAG_CHANNEL_MAP:
814 ret = pa_tagstruct_get_channel_map(t, va_arg(va, pa_channel_map *));
818 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
822 ret = pa_tagstruct_get_volume(t, va_arg(va, pa_volume_t *));
825 case PA_TAG_PROPLIST:
826 ret = pa_tagstruct_get_proplist(t, va_arg(va, pa_proplist *));
830 pa_assert_not_reached();