2014-11-14 21:28:27 +01:00
|
|
|
/*
|
|
|
|
* rtp.c: SAT>IP plugin for the Video Disk Recorder
|
|
|
|
*
|
|
|
|
* See the README file for copyright information and how to reach the author.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-12-07 19:17:30 +01:00
|
|
|
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
|
|
|
#include <inttypes.h>
|
|
|
|
|
2014-12-03 18:57:23 +01:00
|
|
|
#include "config.h"
|
2014-11-14 21:28:27 +01:00
|
|
|
#include "common.h"
|
2014-12-05 22:14:40 +01:00
|
|
|
#include "log.h"
|
2014-11-14 21:28:27 +01:00
|
|
|
#include "rtp.h"
|
|
|
|
|
2014-12-13 22:15:58 +01:00
|
|
|
cSatipRtp::cSatipRtp(cSatipTunerIf &tunerP)
|
2014-11-16 16:02:30 +01:00
|
|
|
: tunerM(tunerP),
|
2014-12-13 22:15:58 +01:00
|
|
|
bufferLenM(eRtpPacketReadCount * eMaxUdpPacketSizeB),
|
2014-11-16 09:31:34 +01:00
|
|
|
bufferM(MALLOC(unsigned char, bufferLenM)),
|
|
|
|
lastErrorReportM(0),
|
|
|
|
packetErrorsM(0),
|
|
|
|
sequenceNumberM(-1)
|
2014-11-14 21:28:27 +01:00
|
|
|
{
|
2014-12-13 22:15:58 +01:00
|
|
|
debug1("%s () [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
|
|
|
if (!bufferM)
|
|
|
|
error("Cannot create RTP buffer! [device %d]", tunerM.GetId());
|
2014-11-14 21:28:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
cSatipRtp::~cSatipRtp()
|
|
|
|
{
|
2014-12-06 16:02:45 +01:00
|
|
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
2014-11-14 21:28:27 +01:00
|
|
|
DELETE_POINTER(bufferM);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cSatipRtp::GetFd(void)
|
|
|
|
{
|
|
|
|
return Fd();
|
|
|
|
}
|
|
|
|
|
2014-11-16 09:31:34 +01:00
|
|
|
void cSatipRtp::Close(void)
|
|
|
|
{
|
2014-12-06 16:02:45 +01:00
|
|
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
2014-11-16 09:31:34 +01:00
|
|
|
|
|
|
|
cSatipSocket::Close();
|
|
|
|
|
|
|
|
sequenceNumberM = -1;
|
|
|
|
if (packetErrorsM) {
|
2014-12-05 22:02:57 +01:00
|
|
|
info("Detected %d RTP packet errors [device %d]", packetErrorsM, tunerM.GetId());
|
2014-11-16 09:31:34 +01:00
|
|
|
packetErrorsM = 0;
|
|
|
|
lastErrorReportM = time(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-14 16:58:13 +01:00
|
|
|
int cSatipRtp::GetHeaderLength(unsigned char *bufferP, unsigned int lengthP)
|
2014-11-16 09:31:34 +01:00
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, tunerM.GetId());
|
2014-11-16 09:31:34 +01:00
|
|
|
unsigned int headerlen = 0;
|
|
|
|
|
|
|
|
if (lengthP > 0) {
|
2014-12-13 22:15:58 +01:00
|
|
|
if (bufferP[0] == TS_SYNC_BYTE)
|
2014-11-16 09:31:34 +01:00
|
|
|
return headerlen;
|
|
|
|
else if (lengthP > 3) {
|
|
|
|
// http://tools.ietf.org/html/rfc3550
|
|
|
|
// http://tools.ietf.org/html/rfc2250
|
|
|
|
// Version
|
2014-12-13 22:15:58 +01:00
|
|
|
unsigned int v = (bufferP[0] >> 6) & 0x03;
|
2014-11-16 09:31:34 +01:00
|
|
|
// Extension bit
|
2014-12-13 22:15:58 +01:00
|
|
|
unsigned int x = (bufferP[0] >> 4) & 0x01;
|
2014-11-16 09:31:34 +01:00
|
|
|
// CSCR count
|
2014-12-13 22:15:58 +01:00
|
|
|
unsigned int cc = bufferP[0] & 0x0F;
|
2014-11-16 09:31:34 +01:00
|
|
|
// Payload type: MPEG2 TS = 33
|
2014-12-13 22:15:58 +01:00
|
|
|
unsigned int pt = bufferP[1] & 0x7F;
|
2014-12-07 19:17:30 +01:00
|
|
|
if (pt != 33)
|
2014-12-14 16:45:55 +01:00
|
|
|
debug7("%s (%d) Received invalid RTP payload type %d - v=%d [device %d]",
|
2014-12-13 22:15:58 +01:00
|
|
|
__PRETTY_FUNCTION__, lengthP, pt, v, tunerM.GetId());
|
2014-11-16 09:31:34 +01:00
|
|
|
// Sequence number
|
2014-12-13 22:15:58 +01:00
|
|
|
int seq = ((bufferP[2] & 0xFF) << 8) | (bufferP[3] & 0xFF);
|
2014-11-16 09:31:34 +01:00
|
|
|
if ((((sequenceNumberM + 1) % 0xFFFF) == 0) && (seq == 0xFFFF))
|
|
|
|
sequenceNumberM = -1;
|
|
|
|
else if ((sequenceNumberM >= 0) && (((sequenceNumberM + 1) % 0xFFFF) != seq)) {
|
|
|
|
packetErrorsM++;
|
|
|
|
if (time(NULL) - lastErrorReportM > eReportIntervalS) {
|
2014-11-21 22:56:03 +01:00
|
|
|
info("Detected %d RTP packet errors [device %d]", packetErrorsM, tunerM.GetId());
|
2014-11-16 09:31:34 +01:00
|
|
|
packetErrorsM = 0;
|
|
|
|
lastErrorReportM = time(NULL);
|
|
|
|
}
|
|
|
|
sequenceNumberM = seq;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sequenceNumberM = seq;
|
2015-01-14 16:58:13 +01:00
|
|
|
// Header length
|
2014-11-16 09:31:34 +01:00
|
|
|
headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
|
|
|
|
// Check if extension
|
|
|
|
if (x) {
|
|
|
|
// Extension header length
|
2014-12-13 22:15:58 +01:00
|
|
|
unsigned int ehl = (((bufferP[headerlen + 2] & 0xFF) << 8) | (bufferP[headerlen + 3] & 0xFF));
|
2014-11-16 09:31:34 +01:00
|
|
|
// Update header length
|
|
|
|
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
|
|
|
}
|
2014-11-22 13:56:20 +01:00
|
|
|
// Check for empty payload
|
|
|
|
if (lengthP == headerlen) {
|
2014-12-14 16:45:55 +01:00
|
|
|
debug7("%s (%d) Received empty RTP packet #%d [device %d]", __PRETTY_FUNCTION__, lengthP, seq, tunerM.GetId());
|
2014-11-22 13:56:20 +01:00
|
|
|
headerlen = -1;
|
|
|
|
}
|
2014-11-16 09:31:34 +01:00
|
|
|
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
2014-12-13 22:15:58 +01:00
|
|
|
else if ((v != 2) || (((lengthP - headerlen) % TS_SIZE) != 0) || (bufferP[headerlen] != TS_SYNC_BYTE)) {
|
2014-12-14 16:45:55 +01:00
|
|
|
debug7("%s (%d) Received incorrect RTP packet #%d v=%d len=%d sync=0x%02X [device %d]", __PRETTY_FUNCTION__,
|
2014-12-13 22:15:58 +01:00
|
|
|
lengthP, seq, v, headerlen, bufferP[headerlen], tunerM.GetId());
|
2014-11-16 09:31:34 +01:00
|
|
|
headerlen = -1;
|
|
|
|
}
|
2014-12-07 19:17:30 +01:00
|
|
|
else
|
2014-12-14 16:45:55 +01:00
|
|
|
debug7("%s (%d) Received RTP packet #%d v=%d len=%d sync=0x%02X [device %d]", __PRETTY_FUNCTION__,
|
2014-12-13 22:15:58 +01:00
|
|
|
lengthP, seq, v, headerlen, bufferP[headerlen], tunerM.GetId());
|
2014-11-16 09:31:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return headerlen;
|
|
|
|
}
|
|
|
|
|
2014-11-25 21:04:34 +01:00
|
|
|
void cSatipRtp::Process(void)
|
2014-11-14 21:28:27 +01:00
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
2014-11-14 21:28:27 +01:00
|
|
|
if (bufferM) {
|
2014-12-13 22:15:58 +01:00
|
|
|
unsigned int lenMsg[eRtpPacketReadCount];
|
2014-12-07 19:17:30 +01:00
|
|
|
uint64_t elapsed;
|
2014-12-13 22:15:58 +01:00
|
|
|
int count = 0;
|
2014-12-07 19:17:30 +01:00
|
|
|
cTimeMs processing(0);
|
|
|
|
|
2014-12-13 22:15:58 +01:00
|
|
|
do {
|
|
|
|
count = ReadMulti(bufferM, lenMsg, eRtpPacketReadCount, eMaxUdpPacketSizeB);
|
|
|
|
for (int i = 0; i < count; ++i) {
|
|
|
|
unsigned char *p = &bufferM[i * eMaxUdpPacketSizeB];
|
2015-01-14 16:58:13 +01:00
|
|
|
int headerlen = GetHeaderLength(p, lenMsg[i]);
|
2014-12-13 22:15:58 +01:00
|
|
|
if ((headerlen >= 0) && (headerlen < (int)lenMsg[i]))
|
|
|
|
tunerM.ProcessVideoData(p + headerlen, lenMsg[i] - headerlen);
|
2014-11-27 21:03:56 +01:00
|
|
|
}
|
2014-12-13 22:15:58 +01:00
|
|
|
} while (count >= eRtpPacketReadCount);
|
|
|
|
|
2014-11-27 21:03:56 +01:00
|
|
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
2014-12-05 22:02:57 +01:00
|
|
|
error("Error %d reading in %s [device %d]", errno, *ToString(), tunerM.GetId());
|
2014-12-07 19:17:30 +01:00
|
|
|
|
|
|
|
elapsed = processing.Elapsed();
|
|
|
|
if (elapsed > 1)
|
|
|
|
debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, count, elapsed, tunerM.GetId());
|
2014-11-14 21:28:27 +01:00
|
|
|
}
|
|
|
|
}
|
2014-11-29 13:44:30 +01:00
|
|
|
|
|
|
|
cString cSatipRtp::ToString(void) const
|
|
|
|
{
|
|
|
|
return cString::sprintf("RTP [device %d]", tunerM.GetId());
|
|
|
|
}
|