volume ramp: additions to the low level infra
[platform/upstream/pulseaudio.git] / src / pulsecore / tagstruct.c
index 11e85c1..e51fcf2 100644 (file)
@@ -1,18 +1,18 @@
-/* $Id$ */
-
 /***
   This file is part of PulseAudio.
+
+  Copyright 2004-2006 Lennart Poettering
+
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation; either version 2.1 of the
   License, or (at your option) any later version.
+
   PulseAudio is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   Lesser General Public License for more details.
+
   You should have received a copy of the GNU Lesser General Public
   License along with PulseAudio; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 #include <string.h>
 #include <unistd.h>
 #include <sys/time.h>
-#include <assert.h>
 #include <stdarg.h>
 
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
 
-#include "winsock.h"
-
 #include <pulse/xmalloc.h>
 
+#include <pulsecore/socket.h>
+#include <pulsecore/macro.h>
+
 #include "tagstruct.h"
 
+#define MAX_TAG_SIZE (64*1024)
 
 struct pa_tagstruct {
     uint8_t *data;
     size_t length, allocated;
     size_t rindex;
 
-    int dynamic;
+    bool dynamic;
 };
 
 pa_tagstruct *pa_tagstruct_new(const uint8_t* data, size_t length) {
     pa_tagstruct*t;
 
-    assert(!data || (data && length));
-    
-    t = pa_xmalloc(sizeof(pa_tagstruct));
+    pa_assert(!data || (data && length));
+
+    t = pa_xnew(pa_tagstruct, 1);
     t->data = (uint8_t*) data;
     t->allocated = t->length = data ? length : 0;
     t->rindex = 0;
     t->dynamic = !data;
+
     return t;
 }
-    
+
 void pa_tagstruct_free(pa_tagstruct*t) {
-    assert(t);
+    pa_assert(t);
+
     if (t->dynamic)
         pa_xfree(t->data);
     pa_xfree(t);
@@ -71,7 +74,11 @@ void pa_tagstruct_free(pa_tagstruct*t) {
 
 uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
     uint8_t *p;
-    assert(t && t->dynamic && l);
+
+    pa_assert(t);
+    pa_assert(t->dynamic);
+    pa_assert(l);
+
     p = t->data;
     *l = t->length;
     pa_xfree(t);
@@ -79,8 +86,8 @@ uint8_t* pa_tagstruct_free_data(pa_tagstruct*t, size_t *l) {
 }
 
 static void extend(pa_tagstruct*t, size_t l) {
-    assert(t);
-    assert(t->dynamic);
+    pa_assert(t);
+    pa_assert(t->dynamic);
 
     if (t->length+l <= t->allocated)
         return;
@@ -90,7 +97,8 @@ static void extend(pa_tagstruct*t, size_t l) {
 
 void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
     size_t l;
-    assert(t);
+    pa_assert(t);
+
     if (s) {
         l = strlen(s)+2;
         extend(t, l);
@@ -105,7 +113,8 @@ void pa_tagstruct_puts(pa_tagstruct*t, const char *s) {
 }
 
 void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
-    assert(t);
+    pa_assert(t);
+
     extend(t, 5);
     t->data[t->length] = PA_TAG_U32;
     i = htonl(i);
@@ -114,7 +123,8 @@ void pa_tagstruct_putu32(pa_tagstruct*t, uint32_t i) {
 }
 
 void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
-    assert(t);
+    pa_assert(t);
+
     extend(t, 2);
     t->data[t->length] = PA_TAG_U8;
     *(t->data+t->length+1) = c;
@@ -123,7 +133,10 @@ void pa_tagstruct_putu8(pa_tagstruct*t, uint8_t c) {
 
 void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
     uint32_t rate;
-    assert(t && ss);
+
+    pa_assert(t);
+    pa_assert(ss);
+
     extend(t, 7);
     t->data[t->length] = PA_TAG_SAMPLE_SPEC;
     t->data[t->length+1] = (uint8_t) ss->format;
@@ -135,39 +148,45 @@ void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss) {
 
 void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
     uint32_t tmp;
-    assert(t && p);
+
+    pa_assert(t);
+    pa_assert(p);
 
     extend(t, 5+length);
     t->data[t->length] = PA_TAG_ARBITRARY;
-    tmp = htonl(length);
+    tmp = htonl((uint32_t) length);
     memcpy(t->data+t->length+1, &tmp, 4);
     if (length)
         memcpy(t->data+t->length+5, p, length);
     t->length += 5+length;
 }
 
-void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) {
-    assert(t);
+void pa_tagstruct_put_boolean(pa_tagstruct*t, bool b) {
+    pa_assert(t);
+
     extend(t, 1);
-    t->data[t->length] = b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE;
+    t->data[t->length] = (uint8_t) (b ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE);
     t->length += 1;
 }
 
 void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv) {
     uint32_t tmp;
-    assert(t);
+    pa_assert(t);
+
     extend(t, 9);
     t->data[t->length] = PA_TAG_TIMEVAL;
-    tmp = htonl(tv->tv_sec);
+    tmp = htonl((uint32_t) tv->tv_sec);
     memcpy(t->data+t->length+1, &tmp, 4);
-    tmp = htonl(tv->tv_usec);
+    tmp = htonl((uint32_t) tv->tv_usec);
     memcpy(t->data+t->length+5, &tmp, 4);
     t->length += 9;
 }
 
 void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
     uint32_t tmp;
-    assert(t);
+
+    pa_assert(t);
+
     extend(t, 9);
     t->data[t->length] = PA_TAG_USEC;
     tmp = htonl((uint32_t) (u >> 32));
@@ -179,7 +198,9 @@ void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u) {
 
 void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
     uint32_t tmp;
-    assert(t);
+
+    pa_assert(t);
+
     extend(t, 9);
     t->data[t->length] = PA_TAG_U64;
     tmp = htonl((uint32_t) (u >> 32));
@@ -191,7 +212,9 @@ void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) {
 
 void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
     uint32_t tmp;
-    assert(t);
+
+    pa_assert(t);
+
     extend(t, 9);
     t->data[t->length] = PA_TAG_S64;
     tmp = htonl((uint32_t) ((uint64_t) u >> 32));
@@ -203,13 +226,14 @@ void pa_tagstruct_puts64(pa_tagstruct*t, int64_t u) {
 
 void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
     unsigned i;
-    
-    assert(t);
-    extend(t, 2 + map->channels);
+
+    pa_assert(t);
+    pa_assert(map);
+    extend(t, 2 + (size_t) map->channels);
 
     t->data[t->length++] = PA_TAG_CHANNEL_MAP;
     t->data[t->length++] = map->channels;
-    
+
     for (i = 0; i < map->channels; i ++)
         t->data[t->length++] = (uint8_t) map->map[i];
 }
@@ -217,13 +241,14 @@ void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) {
 void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
     unsigned i;
     pa_volume_t vol;
-    
-    assert(t);
+
+    pa_assert(t);
+    pa_assert(cvolume);
     extend(t, 2 + cvolume->channels * sizeof(pa_volume_t));
 
     t->data[t->length++] = PA_TAG_CVOLUME;
     t->data[t->length++] = cvolume->channels;
-    
+
     for (i = 0; i < cvolume->channels; i ++) {
         vol = htonl(cvolume->values[i]);
         memcpy(t->data + t->length, &vol, sizeof(pa_volume_t));
@@ -231,11 +256,61 @@ void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) {
     }
 }
 
+void pa_tagstruct_put_volume(pa_tagstruct *t, pa_volume_t vol) {
+    uint32_t u;
+    pa_assert(t);
+
+    extend(t, 5);
+    t->data[t->length] = PA_TAG_VOLUME;
+    u = htonl((uint32_t) vol);
+    memcpy(t->data+t->length+1, &u, 4);
+    t->length += 5;
+}
+
+void pa_tagstruct_put_proplist(pa_tagstruct *t, pa_proplist *p) {
+    void *state = NULL;
+    pa_assert(t);
+    pa_assert(p);
+
+    extend(t, 1);
+
+    t->data[t->length++] = PA_TAG_PROPLIST;
+
+    for (;;) {
+        const char *k;
+        const void *d;
+        size_t l;
+
+        if (!(k = pa_proplist_iterate(p, &state)))
+            break;
+
+        pa_tagstruct_puts(t, k);
+        pa_assert_se(pa_proplist_get(p, k, &d, &l) >= 0);
+        pa_tagstruct_putu32(t, (uint32_t) l);
+        pa_tagstruct_put_arbitrary(t, d, l);
+    }
+
+    pa_tagstruct_puts(t, NULL);
+}
+
+void pa_tagstruct_put_format_info(pa_tagstruct *t, pa_format_info *f) {
+    pa_assert(t);
+    pa_assert(f);
+
+    extend(t, 1);
+
+    t->data[t->length++] = PA_TAG_FORMAT_INFO;
+    pa_tagstruct_putu8(t, (uint8_t) f->encoding);
+    pa_tagstruct_put_proplist(t, f->plist);
+}
+
 int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
     int error = 0;
     size_t n;
     char *c;
-    assert(t && s);
+
+    pa_assert(t);
+    pa_assert(s);
 
     if (t->rindex+1 > t->length)
         return -1;
@@ -245,10 +320,10 @@ int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
         *s = NULL;
         return 0;
     }
-    
+
     if (t->rindex+2 > t->length)
         return -1;
-    
+
     if (t->data[t->rindex] != PA_TAG_STRING)
         return -1;
 
@@ -269,7 +344,8 @@ int pa_tagstruct_gets(pa_tagstruct*t, const char **s) {
 }
 
 int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
-    assert(t && i);
+    pa_assert(t);
+    pa_assert(i);
 
     if (t->rindex+5 > t->length)
         return -1;
@@ -284,7 +360,8 @@ int pa_tagstruct_getu32(pa_tagstruct*t, uint32_t *i) {
 }
 
 int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
-    assert(t && c);
+    pa_assert(t);
+    pa_assert(c);
 
     if (t->rindex+2 > t->length)
         return -1;
@@ -298,14 +375,15 @@ int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c) {
 }
 
 int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
-    assert(t && ss);
+    pa_assert(t);
+    pa_assert(ss);
 
     if (t->rindex+7 > t->length)
         return -1;
 
     if (t->data[t->rindex] != PA_TAG_SAMPLE_SPEC)
         return -1;
-    
+
     ss->format = t->data[t->rindex+1];
     ss->channels = t->data[t->rindex+2];
     memcpy(&ss->rate, t->data+t->rindex+3, 4);
@@ -317,8 +395,10 @@ int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) {
 
 int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
     uint32_t len;
-    assert(t && p);
-    
+
+    pa_assert(t);
+    pa_assert(p);
+
     if (t->rindex+5+length > t->length)
         return -1;
 
@@ -335,35 +415,43 @@ int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length) {
 }
 
 int pa_tagstruct_eof(pa_tagstruct*t) {
-    assert(t);
+    pa_assert(t);
+
     return t->rindex >= t->length;
 }
 
 const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
-    assert(t && t->dynamic && l);
+    pa_assert(t);
+    pa_assert(t->dynamic);
+    pa_assert(l);
+
     *l = t->length;
     return t->data;
 }
 
-int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
-    assert(t && b);
+int pa_tagstruct_get_boolean(pa_tagstruct*t, bool *b) {
+    pa_assert(t);
+    pa_assert(b);
 
     if (t->rindex+1 > t->length)
         return -1;
 
     if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
-        *b = 1;
+        *b = true;
     else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
-        *b = 0;
+        *b = false;
     else
         return -1;
-    
+
     t->rindex +=1;
     return 0;
 }
 
 int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
 
+    pa_assert(t);
+    pa_assert(tv);
+
     if (t->rindex+9 > t->length)
         return -1;
 
@@ -371,16 +459,18 @@ int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv) {
         return -1;
 
     memcpy(&tv->tv_sec, t->data+t->rindex+1, 4);
-    tv->tv_sec = ntohl(tv->tv_sec);
+    tv->tv_sec = (time_t) ntohl((uint32_t) tv->tv_sec);
     memcpy(&tv->tv_usec, t->data+t->rindex+5, 4);
-    tv->tv_usec = ntohl(tv->tv_usec);
+    tv->tv_usec = (suseconds_t) ntohl((uint32_t) tv->tv_usec);
     t->rindex += 9;
     return 0;
 }
 
 int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
     uint32_t tmp;
-    assert(t && u);
+
+    pa_assert(t);
+    pa_assert(u);
 
     if (t->rindex+9 > t->length)
         return -1;
@@ -398,7 +488,9 @@ int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u) {
 
 int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
     uint32_t tmp;
-    assert(t && u);
+
+    pa_assert(t);
+    pa_assert(u);
 
     if (t->rindex+9 > t->length)
         return -1;
@@ -416,7 +508,9 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) {
 
 int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
     uint32_t tmp;
-    assert(t && u);
+
+    pa_assert(t);
+    pa_assert(u);
 
     if (t->rindex+9 > t->length)
         return -1;
@@ -434,9 +528,9 @@ int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *u) {
 
 int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
     unsigned i;
-    
-    assert(t);
-    assert(map);
+
+    pa_assert(t);
+    pa_assert(map);
 
     if (t->rindex+2 > t->length)
         return -1;
@@ -449,20 +543,20 @@ int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) {
 
     if (t->rindex+2+map->channels > t->length)
         return -1;
-    
+
     for (i = 0; i < map->channels; i ++)
         map->map[i] = (int8_t) t->data[t->rindex + 2 + i];
 
-    t->rindex += 2 + map->channels;
+    t->rindex += 2 + (size_t) map->channels;
     return 0;
 }
 
 int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
     unsigned i;
     pa_volume_t vol;
-    
-    assert(t);
-    assert(cvolume);
+
+    pa_assert(t);
+    pa_assert(cvolume);
 
     if (t->rindex+2 > t->length)
         return -1;
@@ -475,7 +569,7 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
 
     if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length)
         return -1;
-    
+
     for (i = 0; i < cvolume->channels; i ++) {
         memcpy(&vol, t->data + t->rindex + 2 + i * sizeof(pa_volume_t), sizeof(pa_volume_t));
         cvolume->values[i] = (pa_volume_t) ntohl(vol);
@@ -485,10 +579,108 @@ int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) {
     return 0;
 }
 
+int pa_tagstruct_get_volume(pa_tagstruct*t, pa_volume_t *vol) {
+    uint32_t u;
+
+    pa_assert(t);
+    pa_assert(vol);
+
+    if (t->rindex+5 > t->length)
+        return -1;
+
+    if (t->data[t->rindex] != PA_TAG_VOLUME)
+        return -1;
+
+    memcpy(&u, t->data+t->rindex+1, 4);
+    *vol = (pa_volume_t) ntohl(u);
+
+    t->rindex += 5;
+    return 0;
+}
+
+int pa_tagstruct_get_proplist(pa_tagstruct *t, pa_proplist *p) {
+    size_t saved_rindex;
+
+    pa_assert(t);
+
+    if (t->rindex+1 > t->length)
+        return -1;
+
+    if (t->data[t->rindex] != PA_TAG_PROPLIST)
+        return -1;
+
+    saved_rindex = t->rindex;
+    t->rindex++;
+
+    for (;;) {
+        const char *k;
+        const void *d;
+        uint32_t length;
+
+        if (pa_tagstruct_gets(t, &k) < 0)
+            goto fail;
+
+        if (!k)
+            break;
+
+        if (!pa_proplist_key_valid(k))
+            goto fail;
+
+        if (pa_tagstruct_getu32(t, &length) < 0)
+            goto fail;
+
+        if (length > MAX_TAG_SIZE)
+            goto fail;
+
+        if (pa_tagstruct_get_arbitrary(t, &d, length) < 0)
+            goto fail;
+
+        if (p)
+            pa_assert_se(pa_proplist_set(p, k, d, length) >= 0);
+    }
+
+    return 0;
+
+fail:
+    t->rindex = saved_rindex;
+    return -1;
+}
+
+int pa_tagstruct_get_format_info(pa_tagstruct *t, pa_format_info *f) {
+    size_t saved_rindex;
+    uint8_t encoding;
+
+    pa_assert(t);
+    pa_assert(f);
+
+    if (t->rindex+1 > t->length)
+        return -1;
+
+    if (t->data[t->rindex] != PA_TAG_FORMAT_INFO)
+        return -1;
+
+    saved_rindex = t->rindex;
+    t->rindex++;
+
+    if (pa_tagstruct_getu8(t, &encoding) < 0)
+        goto fail;
+
+    f->encoding = encoding;
+
+    if (pa_tagstruct_get_proplist(t, f->plist) < 0)
+        goto fail;
+
+    return 0;
+
+fail:
+    t->rindex = saved_rindex;
+    return -1;
+}
+
 void pa_tagstruct_put(pa_tagstruct *t, ...) {
     va_list va;
-    assert(t);
-    
+    pa_assert(t);
+
     va_start(va, t);
 
     for (;;) {
@@ -547,20 +739,28 @@ void pa_tagstruct_put(pa_tagstruct *t, ...) {
                 pa_tagstruct_put_cvolume(t, va_arg(va, pa_cvolume *));
                 break;
 
+            case PA_TAG_VOLUME:
+                pa_tagstruct_put_volume(t, va_arg(va, pa_volume_t));
+                break;
+
+            case PA_TAG_PROPLIST:
+                pa_tagstruct_put_proplist(t, va_arg(va, pa_proplist *));
+                break;
+
             default:
-                abort();
+                pa_assert_not_reached();
         }
     }
-    
+
     va_end(va);
 }
 
 int pa_tagstruct_get(pa_tagstruct *t, ...) {
     va_list va;
     int ret = 0;
-    
-    assert(t);
-    
+
+    pa_assert(t);
+
     va_start(va, t);
     while (ret == 0) {
         int tag = va_arg(va, int);
@@ -599,7 +799,7 @@ int pa_tagstruct_get(pa_tagstruct *t, ...) {
 
             case PA_TAG_BOOLEAN_TRUE:
             case PA_TAG_BOOLEAN_FALSE:
-                ret = pa_tagstruct_get_boolean(t, va_arg(va, int*));
+                ret = pa_tagstruct_get_boolean(t, va_arg(va, bool*));
                 break;
 
             case PA_TAG_TIMEVAL:
@@ -618,11 +818,18 @@ int pa_tagstruct_get(pa_tagstruct *t, ...) {
                 ret = pa_tagstruct_get_cvolume(t, va_arg(va, pa_cvolume *));
                 break;
 
-            
+            case PA_TAG_VOLUME:
+                ret = pa_tagstruct_get_volume(t, va_arg(va, pa_volume_t *));
+                break;
+
+            case PA_TAG_PROPLIST:
+                ret = pa_tagstruct_get_proplist(t, va_arg(va, pa_proplist *));
+                break;
+
             default:
-                abort();
+                pa_assert_not_reached();
         }
-        
+
     }
 
     va_end(va);