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, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/ioctl.h>
29
30 #ifdef HAVE_SYS_FILIO_H
31 #include <sys/filio.h>
32 #endif
33
34 #ifdef HAVE_SYS_UIO_H
35 #include <sys/uio.h>
36 #endif
37
38 #include <pulsecore/core-error.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/macro.h>
41 #include <pulsecore/core-util.h>
42 #include <pulsecore/arpa-inet.h>
43 #include <pulsecore/poll.h>
44
45 #include "rtp.h"
46
47 typedef struct pa_rtp_context {
48 int fd;
49 uint16_t sequence;
50 uint32_t timestamp;
51 uint32_t ssrc;
52 uint8_t payload;
53 size_t frame_size;
54 size_t mtu;
55
56 uint8_t *recv_buf;
57 size_t recv_buf_size;
58 pa_memchunk memchunk;
59 } pa_rtp_context;
60
pa_rtp_context_new_send(int fd,uint8_t payload,size_t mtu,const pa_sample_spec * ss)61 pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss) {
62 pa_rtp_context *c;
63
64 pa_assert(fd >= 0);
65
66 pa_log_info("Initialising native RTP backend for send");
67
68 c = pa_xnew0(pa_rtp_context, 1);
69
70 c->fd = fd;
71 c->sequence = (uint16_t) (rand()*rand());
72 c->timestamp = 0;
73 c->ssrc = (uint32_t) (rand()*rand());
74 c->payload = (uint8_t) (payload & 127U);
75 c->frame_size = pa_frame_size(ss);
76 c->mtu = mtu;
77
78 c->recv_buf = NULL;
79 c->recv_buf_size = 0;
80 pa_memchunk_reset(&c->memchunk);
81
82 return c;
83 }
84
85 #define MAX_IOVECS 16
86
pa_rtp_send(pa_rtp_context * c,pa_memblockq * q)87 int pa_rtp_send(pa_rtp_context *c, pa_memblockq *q) {
88 struct iovec iov[MAX_IOVECS];
89 pa_memblock* mb[MAX_IOVECS];
90 int iov_idx = 1;
91 size_t n = 0;
92
93 pa_assert(c);
94 pa_assert(q);
95
96 if (pa_memblockq_get_length(q) < c->mtu)
97 return 0;
98
99 for (;;) {
100 int r;
101 pa_memchunk chunk;
102
103 pa_memchunk_reset(&chunk);
104
105 if ((r = pa_memblockq_peek(q, &chunk)) >= 0) {
106
107 size_t k = n + chunk.length > c->mtu ? c->mtu - n : chunk.length;
108
109 pa_assert(chunk.memblock);
110
111 iov[iov_idx].iov_base = pa_memblock_acquire_chunk(&chunk);
112 iov[iov_idx].iov_len = k;
113 mb[iov_idx] = chunk.memblock;
114 iov_idx ++;
115
116 n += k;
117 pa_memblockq_drop(q, k);
118 }
119
120 pa_assert(n % c->frame_size == 0);
121
122 if (r < 0 || n >= c->mtu || iov_idx >= MAX_IOVECS) {
123 uint32_t header[3];
124 struct msghdr m;
125 ssize_t k;
126 int i;
127
128 if (n > 0) {
129 header[0] = htonl(((uint32_t) 2 << 30) | ((uint32_t) c->payload << 16) | ((uint32_t) c->sequence));
130 header[1] = htonl(c->timestamp);
131 header[2] = htonl(c->ssrc);
132
133 iov[0].iov_base = (void*)header;
134 iov[0].iov_len = sizeof(header);
135
136 m.msg_name = NULL;
137 m.msg_namelen = 0;
138 m.msg_iov = iov;
139 m.msg_iovlen = (size_t) iov_idx;
140 m.msg_control = NULL;
141 m.msg_controllen = 0;
142 m.msg_flags = 0;
143
144 k = sendmsg(c->fd, &m, MSG_DONTWAIT);
145
146 for (i = 1; i < iov_idx; i++) {
147 pa_memblock_release(mb[i]);
148 pa_memblock_unref(mb[i]);
149 }
150
151 c->sequence++;
152 } else
153 k = 0;
154
155 c->timestamp += (unsigned) (n/c->frame_size);
156
157 if (k < 0) {
158 if (errno != EAGAIN && errno != EINTR) /* If the queue is full, just ignore it */
159 pa_log("sendmsg() failed: %s", pa_cstrerror(errno));
160 return -1;
161 }
162
163 if (r < 0 || pa_memblockq_get_length(q) < c->mtu)
164 break;
165
166 n = 0;
167 iov_idx = 1;
168 }
169 }
170
171 return 0;
172 }
173
pa_rtp_context_new_recv(int fd,uint8_t payload,const pa_sample_spec * ss)174 pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample_spec *ss) {
175 pa_rtp_context *c;
176
177 pa_log_info("Initialising native RTP backend for receive");
178
179 c = pa_xnew0(pa_rtp_context, 1);
180
181 c->fd = fd;
182 c->payload = payload;
183 c->frame_size = pa_frame_size(ss);
184
185 c->recv_buf_size = 2000;
186 c->recv_buf = pa_xmalloc(c->recv_buf_size);
187 pa_memchunk_reset(&c->memchunk);
188
189 return c;
190 }
191
pa_rtp_recv(pa_rtp_context * c,pa_memchunk * chunk,pa_mempool * pool,uint32_t * rtp_tstamp,struct timeval * tstamp)192 int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_t *rtp_tstamp, struct timeval *tstamp) {
193 int size;
194 size_t audio_length;
195 size_t metadata_length;
196 struct msghdr m;
197 struct cmsghdr *cm;
198 struct iovec iov;
199 uint32_t header;
200 uint32_t ssrc;
201 uint8_t payload;
202 unsigned cc;
203 ssize_t r;
204 uint8_t aux[1024];
205 bool found_tstamp = false;
206
207 pa_assert(c);
208 pa_assert(chunk);
209
210 pa_memchunk_reset(chunk);
211
212 if (ioctl(c->fd, FIONREAD, &size) < 0) {
213 pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno));
214 goto fail;
215 }
216
217 if (size <= 0) {
218 /* size can be 0 due to any of the following reasons:
219 *
220 * 1. Somebody sent us a perfectly valid zero-length UDP packet.
221 * 2. Somebody sent us a UDP packet with a bad CRC.
222 *
223 * It is unknown whether size can actually be less than zero.
224 *
225 * In the first case, the packet has to be read out, otherwise the
226 * kernel will tell us again and again about it, thus preventing
227 * reception of any further packets. So let's just read it out
228 * now and discard it later, when comparing the number of bytes
229 * received (0) with the number of bytes wanted (1, see below).
230 *
231 * In the second case, recvmsg() will fail, thus allowing us to
232 * return the error.
233 *
234 * Just to avoid passing zero-sized memchunks and NULL pointers to
235 * recvmsg(), let's force allocation of at least one byte by setting
236 * size to 1.
237 */
238 size = 1;
239 }
240
241 if (c->recv_buf_size < (size_t) size) {
242 do
243 c->recv_buf_size *= 2;
244 while (c->recv_buf_size < (size_t) size);
245
246 c->recv_buf = pa_xrealloc(c->recv_buf, c->recv_buf_size);
247 }
248
249 pa_assert(c->recv_buf_size >= (size_t) size);
250
251 iov.iov_base = c->recv_buf;
252 iov.iov_len = (size_t) size;
253
254 m.msg_name = NULL;
255 m.msg_namelen = 0;
256 m.msg_iov = &iov;
257 m.msg_iovlen = 1;
258 m.msg_control = aux;
259 m.msg_controllen = sizeof(aux);
260 m.msg_flags = 0;
261
262 r = recvmsg(c->fd, &m, 0);
263
264 if (r != size) {
265 if (r < 0 && errno != EAGAIN && errno != EINTR)
266 pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
267
268 goto fail;
269 }
270
271 if (size < 12) {
272 pa_log_warn("RTP packet too short.");
273 goto fail;
274 }
275
276 memcpy(&header, iov.iov_base, sizeof(uint32_t));
277 memcpy(rtp_tstamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t));
278 memcpy(&ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t));
279
280 header = ntohl(header);
281 *rtp_tstamp = ntohl(*rtp_tstamp);
282 ssrc = ntohl(c->ssrc);
283
284 if ((header >> 30) != 2) {
285 pa_log_warn("Unsupported RTP version.");
286 goto fail;
287 }
288
289 if ((header >> 29) & 1) {
290 pa_log_warn("RTP padding not supported.");
291 goto fail;
292 }
293
294 if ((header >> 28) & 1) {
295 pa_log_warn("RTP header extensions not supported.");
296 goto fail;
297 }
298
299 if (ssrc != c->ssrc) {
300 pa_log_debug("Got unexpected SSRC");
301 goto fail;
302 }
303
304 cc = (header >> 24) & 0xF;
305 payload = (uint8_t) ((header >> 16) & 127U);
306 c->sequence = (uint16_t) (header & 0xFFFFU);
307
308 metadata_length = 12 + cc * 4;
309
310 if (payload != c->payload) {
311 pa_log_debug("Got unexpected payload: %u", payload);
312 goto fail;
313 }
314
315 if (metadata_length > (unsigned) size) {
316 pa_log_warn("RTP packet too short. (CSRC)");
317 goto fail;
318 }
319
320 audio_length = size - metadata_length;
321
322 if (audio_length % c->frame_size != 0) {
323 pa_log_warn("Bad RTP packet size.");
324 goto fail;
325 }
326
327 if (c->memchunk.length < (unsigned) audio_length) {
328 size_t l;
329
330 if (c->memchunk.memblock)
331 pa_memblock_unref(c->memchunk.memblock);
332
333 l = PA_MAX((size_t) audio_length, pa_mempool_block_size_max(pool));
334
335 c->memchunk.memblock = pa_memblock_new(pool, l);
336 c->memchunk.index = 0;
337 c->memchunk.length = pa_memblock_get_length(c->memchunk.memblock);
338 }
339
340 memcpy(pa_memblock_acquire_chunk(&c->memchunk), c->recv_buf + metadata_length, audio_length);
341 pa_memblock_release(c->memchunk.memblock);
342
343 chunk->memblock = pa_memblock_ref(c->memchunk.memblock);
344 chunk->index = c->memchunk.index;
345 chunk->length = audio_length;
346
347 c->memchunk.index += audio_length;
348 c->memchunk.length -= audio_length;
349
350 if (c->memchunk.length <= 0) {
351 pa_memblock_unref(c->memchunk.memblock);
352 pa_memchunk_reset(&c->memchunk);
353 }
354
355 for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
356 if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_TIMESTAMP) {
357 memcpy(tstamp, CMSG_DATA(cm), sizeof(struct timeval));
358 found_tstamp = true;
359 break;
360 }
361
362 if (!found_tstamp) {
363 pa_log_warn("Couldn't find SCM_TIMESTAMP data in auxiliary recvmsg() data!");
364 pa_zero(*tstamp);
365 }
366
367 return 0;
368
369 fail:
370 if (chunk->memblock)
371 pa_memblock_unref(chunk->memblock);
372
373 return -1;
374 }
375
pa_rtp_context_free(pa_rtp_context * c)376 void pa_rtp_context_free(pa_rtp_context *c) {
377 pa_assert(c);
378
379 pa_assert_se(pa_close(c->fd) == 0);
380
381 if (c->memchunk.memblock)
382 pa_memblock_unref(c->memchunk.memblock);
383
384 pa_xfree(c->recv_buf);
385 pa_xfree(c);
386 }
387
pa_rtp_context_get_frame_size(pa_rtp_context * c)388 size_t pa_rtp_context_get_frame_size(pa_rtp_context *c) {
389 return c->frame_size;
390 }
391
pa_rtp_context_get_rtpoll_item(pa_rtp_context * c,pa_rtpoll * rtpoll)392 pa_rtpoll_item* pa_rtp_context_get_rtpoll_item(pa_rtp_context *c, pa_rtpoll *rtpoll) {
393 pa_rtpoll_item *item;
394 struct pollfd *p;
395
396 item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_LATE, 1);
397
398 p = pa_rtpoll_item_get_pollfd(item, NULL);
399 p->fd = c->fd;
400 p->events = POLLIN;
401 p->revents = 0;
402
403 return item;
404 }
405