2006-04-14 23:47:33 +00:00
|
|
|
/***
|
2006-06-19 21:53:48 +00:00
|
|
|
This file is part of PulseAudio.
|
2007-02-13 15:35:19 +00:00
|
|
|
|
|
|
|
|
Copyright 2006 Lennart Poettering
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2006-06-19 21:53:48 +00:00
|
|
|
PulseAudio is free software; you can redistribute it and/or modify
|
2006-04-14 23:47:33 +00:00
|
|
|
it under the terms of the GNU Lesser General Public License as published
|
2009-03-03 20:23:02 +00:00
|
|
|
by the Free Software Foundation; either version 2.1 of the License,
|
2006-04-14 23:47:33 +00:00
|
|
|
or (at your option) any later version.
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2006-06-19 21:53:48 +00:00
|
|
|
PulseAudio is distributed in the hope that it will be useful, but
|
2006-04-14 23:47:33 +00:00
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
General Public License for more details.
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2014-11-26 14:14:51 +01:00
|
|
|
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
2006-04-14 23:47:33 +00:00
|
|
|
***/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <unistd.h>
|
2006-04-16 00:16:53 +00:00
|
|
|
#include <sys/ioctl.h>
|
2006-04-14 23:47:33 +00:00
|
|
|
|
2006-04-18 14:09:56 +00:00
|
|
|
#ifdef HAVE_SYS_FILIO_H
|
|
|
|
|
#include <sys/filio.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-01-22 01:37:19 +01:00
|
|
|
#ifdef HAVE_SYS_UIO_H
|
|
|
|
|
#include <sys/uio.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2006-06-19 21:53:48 +00:00
|
|
|
#include <pulsecore/core-error.h>
|
|
|
|
|
#include <pulsecore/log.h>
|
2007-10-28 19:13:50 +00:00
|
|
|
#include <pulsecore/macro.h>
|
|
|
|
|
#include <pulsecore/core-util.h>
|
2011-03-01 16:06:19 +01:00
|
|
|
#include <pulsecore/arpa-inet.h>
|
2016-05-12 17:59:55 +05:30
|
|
|
#include <pulsecore/poll.h>
|
2006-04-14 23:47:33 +00:00
|
|
|
|
|
|
|
|
#include "rtp.h"
|
|
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
typedef struct pa_rtp_context {
|
|
|
|
|
int fd;
|
|
|
|
|
uint16_t sequence;
|
|
|
|
|
uint32_t timestamp;
|
|
|
|
|
uint32_t ssrc;
|
|
|
|
|
uint8_t payload;
|
|
|
|
|
size_t frame_size;
|
|
|
|
|
size_t mtu;
|
|
|
|
|
|
|
|
|
|
uint8_t *recv_buf;
|
|
|
|
|
size_t recv_buf_size;
|
|
|
|
|
pa_memchunk memchunk;
|
|
|
|
|
} pa_rtp_context;
|
|
|
|
|
|
2016-05-12 19:26:55 +05:30
|
|
|
pa_rtp_context* pa_rtp_context_new_send(int fd, uint8_t payload, size_t mtu, const pa_sample_spec *ss) {
|
2016-05-12 17:59:55 +05:30
|
|
|
pa_rtp_context *c;
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(fd >= 0);
|
2006-04-14 23:47:33 +00:00
|
|
|
|
2019-07-05 06:21:07 +05:30
|
|
|
pa_log_info("Initialising native RTP backend for send");
|
|
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
c = pa_xnew0(pa_rtp_context, 1);
|
|
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
c->fd = fd;
|
|
|
|
|
c->sequence = (uint16_t) (rand()*rand());
|
|
|
|
|
c->timestamp = 0;
|
2016-05-12 17:56:51 +05:30
|
|
|
c->ssrc = (uint32_t) (rand()*rand());
|
2008-08-19 22:39:54 +02:00
|
|
|
c->payload = (uint8_t) (payload & 127U);
|
2016-05-12 19:26:55 +05:30
|
|
|
c->frame_size = pa_frame_size(ss);
|
2016-05-12 17:57:04 +05:30
|
|
|
c->mtu = mtu;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
c->recv_buf = NULL;
|
|
|
|
|
c->recv_buf_size = 0;
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_memchunk_reset(&c->memchunk);
|
|
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
return c;
|
2006-04-14 23:47:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MAX_IOVECS 16
|
|
|
|
|
|
2016-05-12 17:57:04 +05:30
|
|
|
int pa_rtp_send(pa_rtp_context *c, pa_memblockq *q) {
|
2006-04-14 23:47:33 +00:00
|
|
|
struct iovec iov[MAX_IOVECS];
|
|
|
|
|
pa_memblock* mb[MAX_IOVECS];
|
|
|
|
|
int iov_idx = 1;
|
2007-10-28 19:13:50 +00:00
|
|
|
size_t n = 0;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(c);
|
|
|
|
|
pa_assert(q);
|
2006-04-14 23:47:33 +00:00
|
|
|
|
2016-05-12 17:57:04 +05:30
|
|
|
if (pa_memblockq_get_length(q) < c->mtu)
|
2006-04-14 23:47:33 +00:00
|
|
|
return 0;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
for (;;) {
|
|
|
|
|
int r;
|
|
|
|
|
pa_memchunk chunk;
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_memchunk_reset(&chunk);
|
|
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
if ((r = pa_memblockq_peek(q, &chunk)) >= 0) {
|
|
|
|
|
|
2016-05-12 17:57:04 +05:30
|
|
|
size_t k = n + chunk.length > c->mtu ? c->mtu - n : chunk.length;
|
2006-04-14 23:47:33 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(chunk.memblock);
|
2006-04-14 23:47:33 +00:00
|
|
|
|
2012-08-17 18:09:34 +03:00
|
|
|
iov[iov_idx].iov_base = pa_memblock_acquire_chunk(&chunk);
|
2007-10-28 19:13:50 +00:00
|
|
|
iov[iov_idx].iov_len = k;
|
|
|
|
|
mb[iov_idx] = chunk.memblock;
|
|
|
|
|
iov_idx ++;
|
2006-04-14 23:47:33 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
n += k;
|
|
|
|
|
pa_memblockq_drop(q, k);
|
2006-04-14 23:47:33 +00:00
|
|
|
}
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(n % c->frame_size == 0);
|
|
|
|
|
|
2016-05-12 17:57:04 +05:30
|
|
|
if (r < 0 || n >= c->mtu || iov_idx >= MAX_IOVECS) {
|
2006-04-14 23:47:33 +00:00
|
|
|
uint32_t header[3];
|
|
|
|
|
struct msghdr m;
|
2008-08-19 22:39:54 +02:00
|
|
|
ssize_t k;
|
|
|
|
|
int i;
|
2006-04-14 23:47:33 +00:00
|
|
|
|
|
|
|
|
if (n > 0) {
|
|
|
|
|
header[0] = htonl(((uint32_t) 2 << 30) | ((uint32_t) c->payload << 16) | ((uint32_t) c->sequence));
|
|
|
|
|
header[1] = htonl(c->timestamp);
|
|
|
|
|
header[2] = htonl(c->ssrc);
|
|
|
|
|
|
2006-04-18 14:09:56 +00:00
|
|
|
iov[0].iov_base = (void*)header;
|
2006-04-14 23:47:33 +00:00
|
|
|
iov[0].iov_len = sizeof(header);
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
m.msg_name = NULL;
|
|
|
|
|
m.msg_namelen = 0;
|
|
|
|
|
m.msg_iov = iov;
|
2008-08-19 22:39:54 +02:00
|
|
|
m.msg_iovlen = (size_t) iov_idx;
|
2006-04-14 23:47:33 +00:00
|
|
|
m.msg_control = NULL;
|
|
|
|
|
m.msg_controllen = 0;
|
|
|
|
|
m.msg_flags = 0;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
k = sendmsg(c->fd, &m, MSG_DONTWAIT);
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
for (i = 1; i < iov_idx; i++) {
|
|
|
|
|
pa_memblock_release(mb[i]);
|
2006-04-14 23:47:33 +00:00
|
|
|
pa_memblock_unref(mb[i]);
|
2007-10-28 19:13:50 +00:00
|
|
|
}
|
2006-04-14 23:47:33 +00:00
|
|
|
|
|
|
|
|
c->sequence++;
|
|
|
|
|
} else
|
|
|
|
|
k = 0;
|
|
|
|
|
|
2008-08-19 22:39:54 +02:00
|
|
|
c->timestamp += (unsigned) (n/c->frame_size);
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
if (k < 0) {
|
2007-10-28 19:13:50 +00:00
|
|
|
if (errno != EAGAIN && errno != EINTR) /* If the queue is full, just ignore it */
|
2006-08-18 21:38:40 +00:00
|
|
|
pa_log("sendmsg() failed: %s", pa_cstrerror(errno));
|
2006-04-14 23:47:33 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2016-05-12 17:57:04 +05:30
|
|
|
if (r < 0 || pa_memblockq_get_length(q) < c->mtu)
|
2006-04-14 23:47:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
|
iov_idx = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 19:26:55 +05:30
|
|
|
pa_rtp_context* pa_rtp_context_new_recv(int fd, uint8_t payload, const pa_sample_spec *ss) {
|
2016-05-12 17:59:55 +05:30
|
|
|
pa_rtp_context *c;
|
|
|
|
|
|
2019-07-05 06:21:07 +05:30
|
|
|
pa_log_info("Initialising native RTP backend for receive");
|
|
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
c = pa_xnew0(pa_rtp_context, 1);
|
2006-04-14 23:47:33 +00:00
|
|
|
|
|
|
|
|
c->fd = fd;
|
2016-05-12 17:59:55 +05:30
|
|
|
c->payload = payload;
|
2016-05-12 19:26:55 +05:30
|
|
|
c->frame_size = pa_frame_size(ss);
|
2008-05-15 23:34:41 +00:00
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
c->recv_buf_size = 2000;
|
|
|
|
|
c->recv_buf = pa_xmalloc(c->recv_buf_size);
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_memchunk_reset(&c->memchunk);
|
2016-05-12 17:59:55 +05:30
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_t *rtp_tstamp, struct timeval *tstamp) {
|
2006-04-16 00:16:53 +00:00
|
|
|
int size;
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
size_t audio_length;
|
|
|
|
|
size_t metadata_length;
|
2006-04-16 00:16:53 +00:00
|
|
|
struct msghdr m;
|
2009-04-07 00:50:47 +02:00
|
|
|
struct cmsghdr *cm;
|
2006-04-16 00:16:53 +00:00
|
|
|
struct iovec iov;
|
|
|
|
|
uint32_t header;
|
2016-05-12 17:59:55 +05:30
|
|
|
uint32_t ssrc;
|
|
|
|
|
uint8_t payload;
|
2008-08-19 22:39:54 +02:00
|
|
|
unsigned cc;
|
2006-04-16 00:16:53 +00:00
|
|
|
ssize_t r;
|
2009-04-07 00:50:47 +02:00
|
|
|
uint8_t aux[1024];
|
2013-06-27 19:28:09 +02:00
|
|
|
bool found_tstamp = false;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(c);
|
|
|
|
|
pa_assert(chunk);
|
2006-04-14 23:47:33 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_memchunk_reset(chunk);
|
2006-04-16 00:16:53 +00:00
|
|
|
|
|
|
|
|
if (ioctl(c->fd, FIONREAD, &size) < 0) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno));
|
2006-04-16 00:16:53 +00:00
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 22:29:25 +06:00
|
|
|
if (size <= 0) {
|
|
|
|
|
/* size can be 0 due to any of the following reasons:
|
|
|
|
|
*
|
|
|
|
|
* 1. Somebody sent us a perfectly valid zero-length UDP packet.
|
|
|
|
|
* 2. Somebody sent us a UDP packet with a bad CRC.
|
|
|
|
|
*
|
|
|
|
|
* It is unknown whether size can actually be less than zero.
|
|
|
|
|
*
|
|
|
|
|
* In the first case, the packet has to be read out, otherwise the
|
|
|
|
|
* kernel will tell us again and again about it, thus preventing
|
|
|
|
|
* reception of any further packets. So let's just read it out
|
|
|
|
|
* now and discard it later, when comparing the number of bytes
|
|
|
|
|
* received (0) with the number of bytes wanted (1, see below).
|
|
|
|
|
*
|
|
|
|
|
* In the second case, recvmsg() will fail, thus allowing us to
|
|
|
|
|
* return the error.
|
|
|
|
|
*
|
|
|
|
|
* Just to avoid passing zero-sized memchunks and NULL pointers to
|
|
|
|
|
* recvmsg(), let's force allocation of at least one byte by setting
|
|
|
|
|
* size to 1.
|
|
|
|
|
*/
|
|
|
|
|
size = 1;
|
|
|
|
|
}
|
2006-04-16 00:16:53 +00:00
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
if (c->recv_buf_size < (size_t) size) {
|
|
|
|
|
do
|
|
|
|
|
c->recv_buf_size *= 2;
|
|
|
|
|
while (c->recv_buf_size < (size_t) size);
|
2008-05-15 23:34:41 +00:00
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
c->recv_buf = pa_xrealloc(c->recv_buf, c->recv_buf_size);
|
2008-05-15 23:34:41 +00:00
|
|
|
}
|
|
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
pa_assert(c->recv_buf_size >= (size_t) size);
|
2008-05-15 23:34:41 +00:00
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
iov.iov_base = c->recv_buf;
|
2008-08-19 22:39:54 +02:00
|
|
|
iov.iov_len = (size_t) size;
|
2006-04-16 00:16:53 +00:00
|
|
|
|
|
|
|
|
m.msg_name = NULL;
|
|
|
|
|
m.msg_namelen = 0;
|
|
|
|
|
m.msg_iov = &iov;
|
|
|
|
|
m.msg_iovlen = 1;
|
2009-04-07 00:50:47 +02:00
|
|
|
m.msg_control = aux;
|
|
|
|
|
m.msg_controllen = sizeof(aux);
|
2006-04-16 00:16:53 +00:00
|
|
|
m.msg_flags = 0;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
r = recvmsg(c->fd, &m, 0);
|
|
|
|
|
|
|
|
|
|
if (r != size) {
|
|
|
|
|
if (r < 0 && errno != EAGAIN && errno != EINTR)
|
|
|
|
|
pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
|
|
|
|
|
|
2006-04-16 00:16:53 +00:00
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (size < 12) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_log_warn("RTP packet too short.");
|
2006-04-16 00:16:53 +00:00
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
memcpy(&header, iov.iov_base, sizeof(uint32_t));
|
2016-05-12 17:59:55 +05:30
|
|
|
memcpy(rtp_tstamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t));
|
|
|
|
|
memcpy(&ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t));
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2006-04-16 00:16:53 +00:00
|
|
|
header = ntohl(header);
|
2016-05-12 17:59:55 +05:30
|
|
|
*rtp_tstamp = ntohl(*rtp_tstamp);
|
|
|
|
|
ssrc = ntohl(c->ssrc);
|
2006-04-16 00:16:53 +00:00
|
|
|
|
|
|
|
|
if ((header >> 30) != 2) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_log_warn("Unsupported RTP version.");
|
2006-04-16 00:16:53 +00:00
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((header >> 29) & 1) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_log_warn("RTP padding not supported.");
|
2006-04-16 00:16:53 +00:00
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((header >> 28) & 1) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_log_warn("RTP header extensions not supported.");
|
2006-04-16 00:16:53 +00:00
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
if (ssrc != c->ssrc) {
|
|
|
|
|
pa_log_debug("Got unexpected SSRC");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-16 00:16:53 +00:00
|
|
|
cc = (header >> 24) & 0xF;
|
2016-05-12 17:59:55 +05:30
|
|
|
payload = (uint8_t) ((header >> 16) & 127U);
|
2008-08-19 22:39:54 +02:00
|
|
|
c->sequence = (uint16_t) (header & 0xFFFFU);
|
2006-04-16 00:16:53 +00:00
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
metadata_length = 12 + cc * 4;
|
|
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
if (payload != c->payload) {
|
|
|
|
|
pa_log_debug("Got unexpected payload: %u", payload);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
if (metadata_length > (unsigned) size) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_log_warn("RTP packet too short. (CSRC)");
|
2006-04-16 00:16:53 +00:00
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
audio_length = size - metadata_length;
|
2006-04-16 00:16:53 +00:00
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
if (audio_length % c->frame_size != 0) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_log_warn("Bad RTP packet size.");
|
2006-04-16 00:16:53 +00:00
|
|
|
goto fail;
|
|
|
|
|
}
|
2007-05-29 17:24:48 +00:00
|
|
|
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
if (c->memchunk.length < (unsigned) audio_length) {
|
|
|
|
|
size_t l;
|
|
|
|
|
|
|
|
|
|
if (c->memchunk.memblock)
|
|
|
|
|
pa_memblock_unref(c->memchunk.memblock);
|
|
|
|
|
|
|
|
|
|
l = PA_MAX((size_t) audio_length, pa_mempool_block_size_max(pool));
|
|
|
|
|
|
|
|
|
|
c->memchunk.memblock = pa_memblock_new(pool, l);
|
|
|
|
|
c->memchunk.index = 0;
|
|
|
|
|
c->memchunk.length = pa_memblock_get_length(c->memchunk.memblock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(pa_memblock_acquire_chunk(&c->memchunk), c->recv_buf + metadata_length, audio_length);
|
|
|
|
|
pa_memblock_release(c->memchunk.memblock);
|
|
|
|
|
|
|
|
|
|
chunk->memblock = pa_memblock_ref(c->memchunk.memblock);
|
|
|
|
|
chunk->index = c->memchunk.index;
|
|
|
|
|
chunk->length = audio_length;
|
|
|
|
|
|
|
|
|
|
c->memchunk.index += audio_length;
|
|
|
|
|
c->memchunk.length -= audio_length;
|
2008-05-15 23:34:41 +00:00
|
|
|
|
|
|
|
|
if (c->memchunk.length <= 0) {
|
|
|
|
|
pa_memblock_unref(c->memchunk.memblock);
|
|
|
|
|
pa_memchunk_reset(&c->memchunk);
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-08 13:47:19 +01:00
|
|
|
for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm))
|
2011-11-14 11:44:43 +01:00
|
|
|
if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_TIMESTAMP) {
|
2009-04-07 00:50:47 +02:00
|
|
|
memcpy(tstamp, CMSG_DATA(cm), sizeof(struct timeval));
|
2013-06-27 19:28:09 +02:00
|
|
|
found_tstamp = true;
|
2009-04-07 00:50:47 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found_tstamp) {
|
2011-11-14 11:44:43 +01:00
|
|
|
pa_log_warn("Couldn't find SCM_TIMESTAMP data in auxiliary recvmsg() data!");
|
2013-05-22 13:26:24 +02:00
|
|
|
pa_zero(*tstamp);
|
2009-04-07 00:50:47 +02:00
|
|
|
}
|
|
|
|
|
|
2006-04-14 23:47:33 +00:00
|
|
|
return 0;
|
2006-04-16 00:16:53 +00:00
|
|
|
|
|
|
|
|
fail:
|
2006-11-06 13:06:01 +00:00
|
|
|
if (chunk->memblock)
|
2006-04-16 00:16:53 +00:00
|
|
|
pa_memblock_unref(chunk->memblock);
|
|
|
|
|
|
|
|
|
|
return -1;
|
2006-04-14 23:47:33 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
void pa_rtp_context_free(pa_rtp_context *c) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(c);
|
2006-04-14 23:47:33 +00:00
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_assert_se(pa_close(c->fd) == 0);
|
|
|
|
|
|
|
|
|
|
if (c->memchunk.memblock)
|
|
|
|
|
pa_memblock_unref(c->memchunk.memblock);
|
rtp: don't use memblocks for non-audio data
pa_memblockq_push() expects all memchunks to be aligned to PCM frame
boundaries, and that means both the index and length fields of
pa_memchunk. pa_rtp_recv(), however, used a memblock for storing both
the RTP packet metadata and the actual audio data. The metadata was
"removed" from the audio data by setting the memchunk index
appropriately, so the metadata stayed in the memblock, but it was not
played back. The metadata length is not necessarily divisible by the PCM
frame size, which caused pa_memblock_push() to crash in an assertion
with some sample specs, because the memchunk index was not properly
aligned. In my tests the metadata length was 12, so it was compatible
with many configurations, but eight-channel audio didn't work.
This patch adds a separate buffer for receiving the RTP packets. As a
result, an extra memcpy is needed for moving the audio data from the
receive buffer to the memblock buffer.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=96612
2016-09-20 12:59:04 +03:00
|
|
|
|
|
|
|
|
pa_xfree(c->recv_buf);
|
2016-05-12 17:59:55 +05:30
|
|
|
pa_xfree(c);
|
2006-04-14 23:47:33 +00:00
|
|
|
}
|
2006-04-16 00:16:53 +00:00
|
|
|
|
2016-05-12 17:59:55 +05:30
|
|
|
size_t pa_rtp_context_get_frame_size(pa_rtp_context *c) {
|
|
|
|
|
return c->frame_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_rtpoll_item* pa_rtp_context_get_rtpoll_item(pa_rtp_context *c, pa_rtpoll *rtpoll) {
|
|
|
|
|
pa_rtpoll_item *item;
|
|
|
|
|
struct pollfd *p;
|
|
|
|
|
|
|
|
|
|
item = pa_rtpoll_item_new(rtpoll, PA_RTPOLL_LATE, 1);
|
|
|
|
|
|
|
|
|
|
p = pa_rtpoll_item_get_pollfd(item, NULL);
|
|
|
|
|
p->fd = c->fd;
|
|
|
|
|
p->events = POLLIN;
|
|
|
|
|
p->revents = 0;
|
|
|
|
|
|
|
|
|
|
return item;
|
|
|
|
|
}
|