Remove libatomic_ops dependency
[profile/ivi/pulseaudio-panda.git] / src / modules / rtp / rtp.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 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 published
8   by the Free Software Foundation; either version 2.1 of the License,
9   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   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <sys/ioctl.h>
31
32 #ifdef HAVE_SYS_FILIO_H
33 #include <sys/filio.h>
34 #endif
35
36 #ifdef HAVE_SYS_UIO_H
37 #include <sys/uio.h>
38 #endif
39
40 #include <pulsecore/core-error.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/macro.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/arpa-inet.h>
45
46 #include "rtp.h"
47
48 pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size) {
49     pa_assert(c);
50     pa_assert(fd >= 0);
51
52     c->fd = fd;
53     c->sequence = (uint16_t) (rand()*rand());
54     c->timestamp = 0;
55     c->ssrc = ssrc ? ssrc : (uint32_t) (rand()*rand());
56     c->payload = (uint8_t) (payload & 127U);
57     c->frame_size = frame_size;
58
59     pa_memchunk_reset(&c->memchunk);
60
61     return c;
62 }
63
64 #define MAX_IOVECS 16
65
66 int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
67     struct iovec iov[MAX_IOVECS];
68     pa_memblock* mb[MAX_IOVECS];
69     int iov_idx = 1;
70     size_t n = 0;
71
72     pa_assert(c);
73     pa_assert(size > 0);
74     pa_assert(q);
75
76     if (pa_memblockq_get_length(q) < size)
77         return 0;
78
79     for (;;) {
80         int r;
81         pa_memchunk chunk;
82
83         pa_memchunk_reset(&chunk);
84
85         if ((r = pa_memblockq_peek(q, &chunk)) >= 0) {
86
87             size_t k = n + chunk.length > size ? size - n : chunk.length;
88
89             pa_assert(chunk.memblock);
90
91             iov[iov_idx].iov_base = ((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index);
92             iov[iov_idx].iov_len = k;
93             mb[iov_idx] = chunk.memblock;
94             iov_idx ++;
95
96             n += k;
97             pa_memblockq_drop(q, k);
98         }
99
100         pa_assert(n % c->frame_size == 0);
101
102         if (r < 0 || n >= size || iov_idx >= MAX_IOVECS) {
103             uint32_t header[3];
104             struct msghdr m;
105             ssize_t k;
106             int i;
107
108             if (n > 0) {
109                 header[0] = htonl(((uint32_t) 2 << 30) | ((uint32_t) c->payload << 16) | ((uint32_t) c->sequence));
110                 header[1] = htonl(c->timestamp);
111                 header[2] = htonl(c->ssrc);
112
113                 iov[0].iov_base = (void*)header;
114                 iov[0].iov_len = sizeof(header);
115
116                 m.msg_name = NULL;
117                 m.msg_namelen = 0;
118                 m.msg_iov = iov;
119                 m.msg_iovlen = (size_t) iov_idx;
120                 m.msg_control = NULL;
121                 m.msg_controllen = 0;
122                 m.msg_flags = 0;
123
124                 k = sendmsg(c->fd, &m, MSG_DONTWAIT);
125
126                 for (i = 1; i < iov_idx; i++) {
127                     pa_memblock_release(mb[i]);
128                     pa_memblock_unref(mb[i]);
129                 }
130
131                 c->sequence++;
132             } else
133                 k = 0;
134
135             c->timestamp += (unsigned) (n/c->frame_size);
136
137             if (k < 0) {
138                 if (errno != EAGAIN && errno != EINTR) /* If the queue is full, just ignore it */
139                     pa_log("sendmsg() failed: %s", pa_cstrerror(errno));
140                 return -1;
141             }
142
143             if (r < 0 || pa_memblockq_get_length(q) < size)
144                 break;
145
146             n = 0;
147             iov_idx = 1;
148         }
149     }
150
151     return 0;
152 }
153
154 pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size) {
155     pa_assert(c);
156
157     c->fd = fd;
158     c->frame_size = frame_size;
159
160     pa_memchunk_reset(&c->memchunk);
161     return c;
162 }
163
164 int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, struct timeval *tstamp) {
165     int size;
166     struct msghdr m;
167     struct cmsghdr *cm;
168     struct iovec iov;
169     uint32_t header;
170     unsigned cc;
171     ssize_t r;
172     uint8_t aux[1024];
173     pa_bool_t found_tstamp = FALSE;
174
175     pa_assert(c);
176     pa_assert(chunk);
177
178     pa_memchunk_reset(chunk);
179
180     if (ioctl(c->fd, FIONREAD, &size) < 0) {
181         pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno));
182         goto fail;
183     }
184
185     if (size <= 0)
186         return 0;
187
188     if (c->memchunk.length < (unsigned) size) {
189         size_t l;
190
191         if (c->memchunk.memblock)
192             pa_memblock_unref(c->memchunk.memblock);
193
194         l = PA_MAX((size_t) size, pa_mempool_block_size_max(pool));
195
196         c->memchunk.memblock = pa_memblock_new(pool, l);
197         c->memchunk.index = 0;
198         c->memchunk.length = pa_memblock_get_length(c->memchunk.memblock);
199     }
200
201     pa_assert(c->memchunk.length >= (size_t) size);
202
203     chunk->memblock = pa_memblock_ref(c->memchunk.memblock);
204     chunk->index = c->memchunk.index;
205
206     iov.iov_base = (uint8_t*) pa_memblock_acquire(chunk->memblock) + chunk->index;
207     iov.iov_len = (size_t) size;
208
209     m.msg_name = NULL;
210     m.msg_namelen = 0;
211     m.msg_iov = &iov;
212     m.msg_iovlen = 1;
213     m.msg_control = aux;
214     m.msg_controllen = sizeof(aux);
215     m.msg_flags = 0;
216
217     r = recvmsg(c->fd, &m, 0);
218     pa_memblock_release(chunk->memblock);
219
220     if (r != size) {
221         if (r < 0 && errno != EAGAIN && errno != EINTR)
222             pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
223
224         goto fail;
225     }
226
227     if (size < 12) {
228         pa_log_warn("RTP packet too short.");
229         goto fail;
230     }
231
232     memcpy(&header, iov.iov_base, sizeof(uint32_t));
233     memcpy(&c->timestamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t));
234     memcpy(&c->ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t));
235
236     header = ntohl(header);
237     c->timestamp = ntohl(c->timestamp);
238     c->ssrc = ntohl(c->ssrc);
239
240     if ((header >> 30) != 2) {
241         pa_log_warn("Unsupported RTP version.");
242         goto fail;
243     }
244
245     if ((header >> 29) & 1) {
246         pa_log_warn("RTP padding not supported.");
247         goto fail;
248     }
249
250     if ((header >> 28) & 1) {
251         pa_log_warn("RTP header extensions not supported.");
252         goto fail;
253     }
254
255     cc = (header >> 24) & 0xF;
256     c->payload = (uint8_t) ((header >> 16) & 127U);
257     c->sequence = (uint16_t) (header & 0xFFFFU);
258
259     if (12 + cc*4 > (unsigned) size) {
260         pa_log_warn("RTP packet too short. (CSRC)");
261         goto fail;
262     }
263
264     chunk->index += 12 + cc*4;
265     chunk->length = (size_t) size - 12 + cc*4;
266
267     if (chunk->length % c->frame_size != 0) {
268         pa_log_warn("Bad RTP packet size.");
269         goto fail;
270     }
271
272     c->memchunk.index = chunk->index + chunk->length;
273     c->memchunk.length = pa_memblock_get_length(c->memchunk.memblock) - c->memchunk.index;
274
275     if (c->memchunk.length <= 0) {
276         pa_memblock_unref(c->memchunk.memblock);
277         pa_memchunk_reset(&c->memchunk);
278     }
279
280     for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
281         if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_TIMESTAMP) {
282             memcpy(tstamp, CMSG_DATA(cm), sizeof(struct timeval));
283             found_tstamp = TRUE;
284             break;
285         }
286
287     if (!found_tstamp) {
288         pa_log_warn("Couldn't find SCM_TIMESTAMP data in auxiliary recvmsg() data!");
289         memset(tstamp, 0, sizeof(tstamp));
290     }
291
292     return 0;
293
294 fail:
295     if (chunk->memblock)
296         pa_memblock_unref(chunk->memblock);
297
298     return -1;
299 }
300
301 uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) {
302     pa_assert(ss);
303
304     if (ss->format == PA_SAMPLE_ULAW && ss->rate == 8000 && ss->channels == 1)
305         return 0;
306     if (ss->format == PA_SAMPLE_ALAW && ss->rate == 8000 && ss->channels == 1)
307         return 8;
308     if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 2)
309         return 10;
310     if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 1)
311         return 11;
312
313     return 127;
314 }
315
316 pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec *ss) {
317     pa_assert(ss);
318
319     switch (payload) {
320         case 0:
321             ss->channels = 1;
322             ss->format = PA_SAMPLE_ULAW;
323             ss->rate = 8000;
324             break;
325
326         case 8:
327             ss->channels = 1;
328             ss->format = PA_SAMPLE_ALAW;
329             ss->rate = 8000;
330             break;
331
332         case 10:
333             ss->channels = 2;
334             ss->format = PA_SAMPLE_S16BE;
335             ss->rate = 44100;
336             break;
337
338         case 11:
339             ss->channels = 1;
340             ss->format = PA_SAMPLE_S16BE;
341             ss->rate = 44100;
342             break;
343
344         default:
345             return NULL;
346     }
347
348     return ss;
349 }
350
351 pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) {
352     pa_assert(ss);
353
354     if (!pa_rtp_sample_spec_valid(ss))
355         ss->format = PA_SAMPLE_S16BE;
356
357     pa_assert(pa_rtp_sample_spec_valid(ss));
358     return ss;
359 }
360
361 int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) {
362     pa_assert(ss);
363
364     if (!pa_sample_spec_valid(ss))
365         return 0;
366
367     return
368         ss->format == PA_SAMPLE_U8 ||
369         ss->format == PA_SAMPLE_ALAW ||
370         ss->format == PA_SAMPLE_ULAW ||
371         ss->format == PA_SAMPLE_S16BE;
372 }
373
374 void pa_rtp_context_destroy(pa_rtp_context *c) {
375     pa_assert(c);
376
377     pa_assert_se(pa_close(c->fd) == 0);
378
379     if (c->memchunk.memblock)
380         pa_memblock_unref(c->memchunk.memblock);
381 }
382
383 const char* pa_rtp_format_to_string(pa_sample_format_t f) {
384     switch (f) {
385         case PA_SAMPLE_S16BE:
386             return "L16";
387         case PA_SAMPLE_U8:
388             return "L8";
389         case PA_SAMPLE_ALAW:
390             return "PCMA";
391         case PA_SAMPLE_ULAW:
392             return "PCMU";
393         default:
394             return NULL;
395     }
396 }
397
398 pa_sample_format_t pa_rtp_string_to_format(const char *s) {
399     pa_assert(s);
400
401     if (!(strcmp(s, "L16")))
402         return PA_SAMPLE_S16BE;
403     else if (!strcmp(s, "L8"))
404         return PA_SAMPLE_U8;
405     else if (!strcmp(s, "PCMA"))
406         return PA_SAMPLE_ALAW;
407     else if (!strcmp(s, "PCMU"))
408         return PA_SAMPLE_ULAW;
409     else
410         return PA_SAMPLE_INVALID;
411 }