update for beta release
[framework/uifw/e17.git] / src / modules / mixer / tag.c
1 #include "pa.h"
2
3 uint8_t *
4 tag_uint32(Pulse_Tag *tag, uint32_t val)
5 {
6    uint8_t *ret;
7
8    ret = tag->data + tag->size;
9    *ret = PA_TAG_U32;
10    val = htonl(val);
11    memcpy(ret + 1, &val, sizeof(val));
12    ret += PA_TAG_SIZE_U32;
13    tag->size = ret - tag->data;
14    return ret;
15 }
16
17 uint8_t *
18 untag_uint32(Pulse_Tag *tag, uint32_t *val)
19 {
20    uint8_t *ret;
21
22    ret = tag->data + tag->size;
23    if ((*ret != PA_TAG_U32) && (*ret != PA_TAG_VOLUME)) return 0;
24    memcpy(val, ret + 1, sizeof(uint32_t));
25    *val = ntohl(*val);
26    ret += PA_TAG_SIZE_U32;
27    tag->size = ret - tag->data;
28    return ret;
29 }
30
31 uint8_t *
32 tag_bool(Pulse_Tag *tag, Eina_Bool val)
33 {
34    uint8_t *ret;
35
36    ret = tag->data + tag->size;
37    *ret = (uint8_t)(val ? PA_TAG_BOOLEAN_TRUE : PA_TAG_BOOLEAN_FALSE);
38    ret += PA_TAG_SIZE_BOOLEAN;
39    tag->size = ret - tag->data;
40    return ret;
41 }
42
43 uint8_t *
44 untag_bool(Pulse_Tag *tag, Eina_Bool *val)
45 {
46    uint8_t *ret;
47
48    ret = tag->data + tag->size;
49    if ((*ret != PA_TAG_BOOLEAN_TRUE) && (*ret != PA_TAG_BOOLEAN_FALSE)) return 0;
50    *val = !!(*ret == PA_TAG_BOOLEAN_TRUE) ? EINA_TRUE : EINA_FALSE;
51    ret += PA_TAG_SIZE_BOOLEAN;
52    tag->size = ret - tag->data;
53    return ret;
54 }
55
56 uint8_t *
57 tag_string(Pulse_Tag *tag, const char *val)
58 {
59    uint8_t *ret;
60
61    ret = tag->data + tag->size;
62    if (val)
63      {
64         *ret = PA_TAG_STRING;
65         strcpy((char*)ret + 1, val);
66         ret += PA_TAG_SIZE_STRING + strlen(val);
67         tag->size = ret - tag->data;
68      }
69    else
70      *ret = PA_TAG_STRING_NULL, tag->size++;
71    return ret;
72 }
73
74 uint8_t *
75 untag_string(Pulse_Tag *tag, const char **val)
76 {
77    uint8_t *ret;
78
79    ret = tag->data + tag->size;
80    switch (*ret)
81      {
82       case PA_TAG_STRING:
83         eina_stringshare_replace(val, (char*)ret + 1);
84         ret += PA_TAG_SIZE_STRING + strlen(*val);
85         break;
86       case PA_TAG_STRING_NULL:
87         *val = NULL;
88         ret += PA_TAG_SIZE_STRING_NULL;
89         break;
90       default:
91         return 0;
92      }
93    tag->size = ret - tag->data;
94    return ret;
95 }
96
97 uint8_t *
98 untag_sample(Pulse_Tag *tag, pa_sample_spec *spec)
99 {
100    uint8_t *ret;
101
102    ret = tag->data + tag->size;
103    if (*ret != PA_TAG_SAMPLE_SPEC) return 0;
104
105    spec->format = ret[1];
106    spec->channels = ret[2];
107    memcpy(&spec->rate, ret + 3, sizeof(spec->rate));
108    spec->rate = ntohl(spec->rate);
109    ret += PA_TAG_SIZE_SAMPLE_SPEC, tag->size += PA_TAG_SIZE_SAMPLE_SPEC;
110    return ret;
111 }
112
113 uint8_t *
114 untag_channel_map(Pulse_Tag *tag, pa_channel_map *map)
115 {
116    uint8_t *ret;
117    unsigned int x;
118
119    ret = tag->data + tag->size;
120    if (*ret != PA_TAG_CHANNEL_MAP) return 0;
121
122    map->channels = ret[1];
123    if (map->channels > PA_CHANNELS_MAX) return 0;
124    if (map->channels + 2 + tag->size > tag->dsize) return 0;
125
126    for (ret += 2, x = 0; x < map->channels; ret++, x++)
127      map->map[x] = (int8_t)*ret;
128
129    tag->size = ret - tag->data;
130    return ret;
131 }
132
133 uint8_t *
134 untag_usec(Pulse_Tag *tag, uint64_t *val)
135 {
136    uint8_t *ret;
137    uint32_t tmp;
138
139    ret = tag->data + tag->size;
140    if (*ret != PA_TAG_USEC) return 0;
141
142    memcpy(&tmp, ret + 1, 4);
143    *val = (uint64_t)ntohl(tmp) << 32;
144    memcpy(&tmp, ret + 5, 4);
145    *val |= (uint64_t)ntohl(tmp);
146    ret += PA_TAG_SIZE_USEC;
147    tag->size = ret - tag->data;
148    return ret;
149 }
150
151 uint8_t *
152 tag_arbitrary(Pulse_Tag *tag, const void *val, uint32_t size)
153 {
154    uint8_t *ret;
155    uint32_t tmp;
156
157    ret = tag->data + tag->size;
158    *ret = PA_TAG_ARBITRARY;
159    tmp = htonl(size);
160    memcpy(ret + 1, &tmp, sizeof(uint32_t));
161    memcpy(ret + PA_TAG_SIZE_U32, val, size);
162    ret += PA_TAG_SIZE_ARBITRARY + size;
163    tag->size = ret - tag->data;
164    return ret;
165 }
166
167 uint8_t *
168 untag_arbitrary(Pulse_Tag *tag, Eina_Binbuf **val)
169 {
170    uint8_t *ret;
171    uint32_t len;
172
173    if (!untag_uint32(tag, &len)) return 0;
174    ret = tag->data + tag->size;
175    if (*ret != PA_TAG_ARBITRARY) return 0;
176    ret += PA_TAG_SIZE_ARBITRARY;
177    
178    *val = eina_binbuf_new();
179    eina_binbuf_append_length(*val, ret, len);
180    ret += len;
181    tag->size = ret - tag->data;
182    return ret;
183 }
184
185 uint8_t *
186 tag_simple_init(Pulse *conn, Pulse_Tag *tag, uint32_t val, PA_Tag type)
187 {
188    switch (type)
189      {
190       case PA_TAG_U32:
191          tag_uint32(tag, val);
192          return tag_uint32(tag, conn->tag_count++);
193       default:
194         break;
195      }
196    return NULL;
197 }
198
199 static Eina_Bool
200 tag_proplist_foreach(const Eina_Hash *h __UNUSED__, const char *key, const char *val, Pulse_Tag *tag)
201 {
202    size_t size;
203
204    tag_string(tag, key);
205    size = strlen(val) + 1;
206    tag_uint32(tag, size);
207    tag_arbitrary(tag, val, size);
208    return EINA_TRUE;
209 }
210
211 uint8_t *
212 tag_proplist(Pulse_Tag *tag)
213 {
214    uint8_t *ret;
215
216    ret = tag->data + tag->size;
217    *ret = PA_TAG_PROPLIST, tag->size++;
218    
219    eina_hash_foreach(tag->props, (Eina_Hash_Foreach)tag_proplist_foreach, tag);
220    return tag_string(tag, NULL);
221 }
222
223 uint8_t *
224 untag_proplist(Pulse_Tag *tag, Eina_Hash **props)
225 {
226    uint8_t *ret;
227
228    ret = tag->data + tag->size;
229    if (*ret != PA_TAG_PROPLIST) return 0;
230
231    *props = eina_hash_string_superfast_new((Eina_Free_Cb)eina_binbuf_free);
232    for (++tag->size; *ret != PA_TAG_STRING_NULL && tag->size < tag->dsize - 1;)
233      {
234         const char *key = NULL;
235         Eina_Binbuf *val;
236         EINA_SAFETY_ON_FALSE_GOTO(untag_string(tag, &key), error);
237         EINA_SAFETY_ON_FALSE_GOTO(untag_arbitrary(tag, &val), error);
238 #if 0
239         {
240            char buf[128];
241            snprintf(buf, sizeof(buf), "key='%%s', val='%%.%zus'", eina_binbuf_length_get(val));
242            DBG(buf, key, eina_binbuf_string_get(val));
243         }
244 #endif
245         eina_hash_add(*props, key, val);
246         eina_stringshare_del(key);
247         ret = tag->data + tag->size;
248      }
249    tag->size++;
250    return ++ret;
251 error:
252    eina_hash_free(*props);
253    return 0;
254 }
255
256 uint8_t *
257 tag_volume(Pulse_Tag *tag, uint8_t channels, double vol)
258 {
259    uint32_t pa_vol;
260    uint8_t *ret, x;
261
262    if (vol <= 0.0) pa_vol = PA_VOLUME_MUTED;
263    else pa_vol = ((vol * PA_VOLUME_NORM) - (PA_VOLUME_NORM / 2)) / 100;
264    pa_vol = htonl(pa_vol);
265    ret = tag->data + tag->size;
266    *ret++ = PA_TAG_CVOLUME;
267    *ret++ = channels;
268    for (x = 0; x < channels; x++, ret += sizeof(pa_vol))
269      memcpy(ret, &pa_vol, sizeof(pa_vol));
270    tag->size = ret - tag->data;
271    return ret;
272 }
273
274 uint8_t *
275 tag_cvol(Pulse_Tag *tag, pa_cvolume *c)
276 {
277    uint8_t *ret, x;
278    uint32_t pa_vol;
279
280    ret = tag->data + tag->size;
281    *ret++ = PA_TAG_CVOLUME;
282    *ret++ = c->channels;
283    for (x = 0; x < c->channels; x++, ret += sizeof(pa_vol))
284      {
285         pa_vol = htonl(c->values[x]);
286         memcpy(ret, &pa_vol, sizeof(pa_vol));
287      }
288    tag->size = ret - tag->data;
289    return ret;
290 }
291
292 uint8_t *
293 untag_cvol(Pulse_Tag *tag, pa_cvolume *cvol)
294 {
295    uint32_t pa_vol;
296    uint8_t *ret, x;
297
298    ret = tag->data + tag->size;
299    if (*ret != PA_TAG_CVOLUME) return 0;
300    cvol->channels = ret[1];
301    for (x = 0, ret += 2; x < cvol->channels; x++, ret += sizeof(pa_vol))
302      {
303         memcpy(&pa_vol, ret, sizeof(pa_vol));
304         cvol->values[x] = ntohl(pa_vol);
305      }
306      
307    tag->size = ret - tag->data;
308    return ret;
309 }
310
311 void
312 tag_finish(Pulse_Tag *tag)
313 {
314    EINA_SAFETY_ON_NULL_RETURN(tag);
315    tag->header[PA_PSTREAM_DESCRIPTOR_CHANNEL] = htonl((uint32_t) -1);
316    tag->header[PA_PSTREAM_DESCRIPTOR_LENGTH] = htonl(tag->dsize);
317 }
318
319 void
320 pulse_tag_free(Pulse_Tag *tag)
321 {
322    if (!tag) return;
323    free(tag->data);
324    if (tag->props) eina_hash_free(tag->props);
325    free(tag);
326 }