]> code.delx.au - pulseaudio/blob - src/modules/rtp/rtp.c
Merge HUGE set of changes temporarily into a branch, to allow me to move them from...
[pulseaudio] / src / modules / rtp / rtp.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2006 Lennart Poettering
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <assert.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <arpa/inet.h>
34 #include <unistd.h>
35 #include <sys/ioctl.h>
36
37 #ifdef HAVE_SYS_FILIO_H
38 #include <sys/filio.h>
39 #endif
40
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/log.h>
43
44 #include "rtp.h"
45
46 pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size) {
47 assert(c);
48 assert(fd >= 0);
49
50 c->fd = fd;
51 c->sequence = (uint16_t) (rand()*rand());
52 c->timestamp = 0;
53 c->ssrc = ssrc ? ssrc : (uint32_t) (rand()*rand());
54 c->payload = payload & 127;
55 c->frame_size = frame_size;
56
57 return c;
58 }
59
60 #define MAX_IOVECS 16
61
62 int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
63 struct iovec iov[MAX_IOVECS];
64 pa_memblock* mb[MAX_IOVECS];
65 int iov_idx = 1;
66 size_t n = 0, skip = 0;
67
68 assert(c);
69 assert(size > 0);
70 assert(q);
71
72 if (pa_memblockq_get_length(q) < size)
73 return 0;
74
75 for (;;) {
76 int r;
77 pa_memchunk chunk;
78
79 if ((r = pa_memblockq_peek(q, &chunk)) >= 0) {
80
81 size_t k = n + chunk.length > size ? size - n : chunk.length;
82
83 if (chunk.memblock) {
84 iov[iov_idx].iov_base = (void*)((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index);
85 iov[iov_idx].iov_len = k;
86 mb[iov_idx] = chunk.memblock;
87 iov_idx ++;
88
89 n += k;
90 }
91
92 skip += k;
93 pa_memblockq_drop(q, &chunk, k);
94 }
95
96 if (r < 0 || !chunk.memblock || n >= size || iov_idx >= MAX_IOVECS) {
97 uint32_t header[3];
98 struct msghdr m;
99 int k, i;
100
101 if (n > 0) {
102 header[0] = htonl(((uint32_t) 2 << 30) | ((uint32_t) c->payload << 16) | ((uint32_t) c->sequence));
103 header[1] = htonl(c->timestamp);
104 header[2] = htonl(c->ssrc);
105
106 iov[0].iov_base = (void*)header;
107 iov[0].iov_len = sizeof(header);
108
109 m.msg_name = NULL;
110 m.msg_namelen = 0;
111 m.msg_iov = iov;
112 m.msg_iovlen = iov_idx;
113 m.msg_control = NULL;
114 m.msg_controllen = 0;
115 m.msg_flags = 0;
116
117 k = sendmsg(c->fd, &m, MSG_DONTWAIT);
118
119 for (i = 1; i < iov_idx; i++) {
120 pa_memblock_release(mb[i]);
121 pa_memblock_unref(mb[i]);
122 }
123
124 c->sequence++;
125 } else
126 k = 0;
127
128 c->timestamp += skip/c->frame_size;
129
130 if (k < 0) {
131 if (errno != EAGAIN) /* If the queue is full, just ignore it */
132 pa_log("sendmsg() failed: %s", pa_cstrerror(errno));
133 return -1;
134 }
135
136 if (r < 0 || pa_memblockq_get_length(q) < size)
137 break;
138
139 n = 0;
140 skip = 0;
141 iov_idx = 1;
142 }
143 }
144
145 return 0;
146 }
147
148 pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size) {
149 assert(c);
150
151 c->fd = fd;
152 c->frame_size = frame_size;
153 return c;
154 }
155
156 int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
157 int size;
158 struct msghdr m;
159 struct iovec iov;
160 uint32_t header;
161 int cc;
162 ssize_t r;
163
164 assert(c);
165 assert(chunk);
166
167 chunk->memblock = NULL;
168
169 if (ioctl(c->fd, FIONREAD, &size) < 0) {
170 pa_log("FIONREAD failed: %s", pa_cstrerror(errno));
171 goto fail;
172 }
173
174 if (!size)
175 return 0;
176
177 chunk->memblock = pa_memblock_new(pool, size);
178
179 iov.iov_base = pa_memblock_acquire(chunk->memblock);
180 iov.iov_len = size;
181
182 m.msg_name = NULL;
183 m.msg_namelen = 0;
184 m.msg_iov = &iov;
185 m.msg_iovlen = 1;
186 m.msg_control = NULL;
187 m.msg_controllen = 0;
188 m.msg_flags = 0;
189
190 if ((r = recvmsg(c->fd, &m, 0)) != size) {
191 pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
192 goto fail;
193 }
194
195 if (size < 12) {
196 pa_log("RTP packet too short.");
197 goto fail;
198 }
199
200 memcpy(&header, iov.iov_base, sizeof(uint32_t));
201 memcpy(&c->timestamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t));
202 memcpy(&c->ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t));
203
204 header = ntohl(header);
205 c->timestamp = ntohl(c->timestamp);
206 c->ssrc = ntohl(c->ssrc);
207
208 if ((header >> 30) != 2) {
209 pa_log("Unsupported RTP version.");
210 goto fail;
211 }
212
213 if ((header >> 29) & 1) {
214 pa_log("RTP padding not supported.");
215 goto fail;
216 }
217
218 if ((header >> 28) & 1) {
219 pa_log("RTP header extensions not supported.");
220 goto fail;
221 }
222
223 cc = (header >> 24) & 0xF;
224 c->payload = (header >> 16) & 127;
225 c->sequence = header & 0xFFFF;
226
227 if (12 + cc*4 > size) {
228 pa_log("RTP packet too short. (CSRC)");
229 goto fail;
230 }
231
232 chunk->index = 12 + cc*4;
233 chunk->length = size - chunk->index;
234
235 if (chunk->length % c->frame_size != 0) {
236 pa_log("Vad RTP packet size.");
237 goto fail;
238 }
239
240 return 0;
241
242 fail:
243 if (chunk->memblock) {
244 pa_memblock_release(chunk->memblock);
245 pa_memblock_unref(chunk->memblock);
246 }
247
248 return -1;
249 }
250
251 uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) {
252 assert(ss);
253
254 if (ss->format == PA_SAMPLE_ULAW && ss->rate == 8000 && ss->channels == 1)
255 return 0;
256 if (ss->format == PA_SAMPLE_ALAW && ss->rate == 8000 && ss->channels == 1)
257 return 8;
258 if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 2)
259 return 10;
260 if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 1)
261 return 11;
262
263 return 127;
264 }
265
266 pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec *ss) {
267 assert(ss);
268
269 switch (payload) {
270 case 0:
271 ss->channels = 1;
272 ss->format = PA_SAMPLE_ULAW;
273 ss->rate = 8000;
274 break;
275
276 case 8:
277 ss->channels = 1;
278 ss->format = PA_SAMPLE_ALAW;
279 ss->rate = 8000;
280 break;
281
282 case 10:
283 ss->channels = 2;
284 ss->format = PA_SAMPLE_S16BE;
285 ss->rate = 44100;
286 break;
287
288 case 11:
289 ss->channels = 1;
290 ss->format = PA_SAMPLE_S16BE;
291 ss->rate = 44100;
292 break;
293
294 default:
295 return NULL;
296 }
297
298 return ss;
299 }
300
301 pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) {
302 assert(ss);
303
304 if (!pa_rtp_sample_spec_valid(ss))
305 ss->format = PA_SAMPLE_S16BE;
306
307 assert(pa_rtp_sample_spec_valid(ss));
308 return ss;
309 }
310
311 int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) {
312 assert(ss);
313
314 if (!pa_sample_spec_valid(ss))
315 return 0;
316
317 return
318 ss->format == PA_SAMPLE_U8 ||
319 ss->format == PA_SAMPLE_ALAW ||
320 ss->format == PA_SAMPLE_ULAW ||
321 ss->format == PA_SAMPLE_S16BE;
322 }
323
324 void pa_rtp_context_destroy(pa_rtp_context *c) {
325 assert(c);
326
327 close(c->fd);
328 }
329
330 const char* pa_rtp_format_to_string(pa_sample_format_t f) {
331 switch (f) {
332 case PA_SAMPLE_S16BE:
333 return "L16";
334 case PA_SAMPLE_U8:
335 return "L8";
336 case PA_SAMPLE_ALAW:
337 return "PCMA";
338 case PA_SAMPLE_ULAW:
339 return "PCMU";
340 default:
341 return NULL;
342 }
343 }
344
345 pa_sample_format_t pa_rtp_string_to_format(const char *s) {
346 assert(s);
347
348 if (!(strcmp(s, "L16")))
349 return PA_SAMPLE_S16BE;
350 else if (!strcmp(s, "L8"))
351 return PA_SAMPLE_U8;
352 else if (!strcmp(s, "PCMA"))
353 return PA_SAMPLE_ALAW;
354 else if (!strcmp(s, "PCMU"))
355 return PA_SAMPLE_ULAW;
356 else
357 return PA_SAMPLE_INVALID;
358 }
359