Add a preliminary RTP-over-TCP support.

This commit is contained in:
Rolf Ahrenberg 2016-12-15 08:49:47 +02:00
parent 3b89dd4b01
commit 99e366b261
13 changed files with 146 additions and 25 deletions

View File

@ -100,6 +100,11 @@ void cSatipMsearch::Process(void)
}
}
void cSatipMsearch::Process(unsigned char *dataP, int lengthP)
{
debug16("%s", __PRETTY_FUNCTION__);
}
cString cSatipMsearch::ToString(void) const
{
return "MSearch";

View File

@ -34,6 +34,7 @@ public:
public:
virtual int GetFd(void);
virtual void Process(void);
virtual void Process(unsigned char *dataP, int lengthP);
virtual cString ToString(void) const;
};

View File

@ -14,6 +14,7 @@ public:
virtual ~cSatipPollerIf() {}
virtual int GetFd(void) = 0;
virtual void Process(void) = 0;
virtual void Process(unsigned char *dataP, int lengthP) = 0;
virtual cString ToString(void) const = 0;
private:

10
rtcp.c
View File

@ -92,6 +92,16 @@ void cSatipRtcp::Process(void)
}
}
void cSatipRtcp::Process(unsigned char *dataP, int lengthP)
{
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
if (dataP && lengthP > 0) {
int offset = GetApplicationOffset(&lengthP);
if (offset >= 0)
tunerM.ProcessApplicationData(dataP + offset, lengthP);
}
}
cString cSatipRtcp::ToString(void) const
{
return cString::sprintf("RTCP [device %d]", tunerM.GetId());

1
rtcp.h
View File

@ -30,6 +30,7 @@ public:
public:
virtual int GetFd(void);
virtual void Process(void);
virtual void Process(unsigned char *dataP, int lengthP);
virtual cString ToString(void) const;
};

16
rtp.c
View File

@ -142,6 +142,22 @@ void cSatipRtp::Process(void)
}
}
void cSatipRtp::Process(unsigned char *dataP, int lengthP)
{
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
if (dataP && lengthP > 0) {
uint64_t elapsed;
cTimeMs processing(0);
int headerlen = GetHeaderLength(dataP, lengthP);
if ((headerlen >= 0) && (headerlen < lengthP))
tunerM.ProcessVideoData(dataP + headerlen, lengthP - headerlen);
elapsed = processing.Elapsed();
if (elapsed > 1)
debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, lengthP, elapsed, tunerM.GetId());
}
}
cString cSatipRtp::ToString(void) const
{
return cString::sprintf("RTP [device %d]", tunerM.GetId());

1
rtp.h
View File

@ -36,6 +36,7 @@ public:
public:
virtual int GetFd(void);
virtual void Process(void);
virtual void Process(unsigned char *dataP, int lengthP);
virtual cString ToString(void) const;
};

86
rtsp.c
View File

@ -21,7 +21,10 @@ cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP)
headerListM(NULL),
errorNoMoreM(""),
errorOutOfRangeM(""),
errorCheckSyntaxM("")
errorCheckSyntaxM(""),
modeM(cSatipConfig::eTransportModeUnicast),
interleavedRtpIdM(0),
interleavedRtcpIdM(1)
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
Create();
@ -57,6 +60,30 @@ size_t cSatipRtsp::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *d
return len;
}
size_t cSatipRtsp::InterleaveCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
{
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP);
size_t len = sizeP * nmembP;
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
if (obj && ptrP && len > 0) {
char tag = ptrP[0] & 0xFF;
if (tag == '$') {
int count = ((ptrP[2] & 0xFF) << 8) | (ptrP[3] & 0xFF);
if (count > 0) {
unsigned int channel = ptrP[1] & 0xFF;
u_char *data = (u_char *)&ptrP[4];
if (channel == obj->interleavedRtpIdM)
obj->tunerM.ProcessRtpData(data, count);
else if (channel == obj->interleavedRtcpIdM)
obj->tunerM.ProcessRtcpData(data, count);
}
}
}
return len;
}
int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP)
{
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(userPtrP);
@ -86,6 +113,21 @@ int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, s
return 0;
}
cString cSatipRtsp::GetActiveMode(void)
{
switch (modeM) {
case cSatipConfig::eTransportModeUnicast:
return "Unicast";
case cSatipConfig::eTransportModeMulticast:
return "Multicast";
case cSatipConfig::eTransportModeRtpOverTcp:
return "RTP-over-TCP";
default:
break;
}
return "";
}
cString cSatipRtsp::RtspUnescapeString(const char *strP)
{
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId());
@ -122,6 +164,9 @@ void cSatipRtsp::Create(void)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
// Limit download speed (bytes/s)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_MAX_RECV_SPEED_LARGE, eMaxDownloadSpeedMBits * 131072L);
// Set user-agent
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, tunerM.GetId()));
}
@ -189,7 +234,10 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTc
default:
// RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port>
// RTP/AVP/TCP;unicast;client_port=<client RTP port>-<client RTCP port>
transport = cString::sprintf("RTP/AVP%s;unicast;client_port=%d-%d", useTcpP ? "/TCP" : "", rtpPortP, rtcpPortP);
if (useTcpP)
transport = cString::sprintf("RTP/AVP/TCP;unicast;interleaved=%u-%u", interleavedRtpIdM, interleavedRtcpIdM);
else
transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP);
break;
}
@ -202,6 +250,9 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTc
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
SATIP_CURL_EASY_PERFORM(handleM);
// Session id is now known - disable header parsing
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
@ -309,6 +360,8 @@ bool cSatipRtsp::Teardown(const char *uriP)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
@ -351,21 +404,30 @@ void cSatipRtsp::ParseHeader(void)
FREE_POINTER(session);
}
else if (strstr(r, "Transport:")) {
CURLcode res = CURLE_OK;
int rtp = -1, rtcp = -1, ttl = -1;
char *tmp = NULL, *destination = NULL, *source = NULL;
if (sscanf(r, "Transport:%m[^;];unicast;client_port=%11d-%11d", &tmp, &rtp, &rtcp) == 3)
interleavedRtpIdM = 0;
interleavedRtcpIdM = 1;
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
if (sscanf(r, "Transport:%m[^;];unicast;client_port=%11d-%11d", &tmp, &rtp, &rtcp) == 3) {
modeM = cSatipConfig::eTransportModeUnicast;
tunerM.SetupTransport(rtp, rtcp, NULL, NULL);
}
else if (sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d;source=%m[^;]", &tmp, &destination, &rtp, &rtcp, &ttl, &source) == 6 ||
sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d", &tmp, &destination, &rtp, &rtcp, &ttl) == 5)
sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d", &tmp, &destination, &rtp, &rtcp, &ttl) == 5) {
modeM = cSatipConfig::eTransportModeMulticast;
tunerM.SetupTransport(rtp, rtcp, destination, source);
// TODO: else if (sscanf(r, "Transport:%m[^;];interleaved=%11d-%11d", &tmp, &rtp, &rtcp) == 3)
// Stream data such as RTP packets is encapsulated by an ASCII dollar
// sign (24 hexadecimal), followed by a one-byte channel identifier,
// followed by the length of the encapsulated binary data as a binary,
// two-byte integer in network byte order. The stream data follows
// immediately afterwards, without a CRLF, but including the upper-layer
// protocol headers. Each $ block contains exactly one upper-layer
// protocol data unit, e.g., one RTP packet.
}
else if (sscanf(r, "Transport:%m[^;];interleaved=%11d-%11d", &tmp, &rtp, &rtcp) == 3) {
interleavedRtpIdM = rtp;
interleavedRtcpIdM = rtcp;
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, cSatipRtsp::InterleaveCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, this);
modeM = cSatipConfig::eTransportModeRtpOverTcp;
tunerM.SetupTransport(-1, -1, NULL, NULL);
}
FREE_POINTER(tmp);
FREE_POINTER(destination);
FREE_POINTER(source);

8
rtsp.h
View File

@ -22,10 +22,12 @@ class cSatipRtsp {
private:
static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t InterleaveCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
enum {
eConnectTimeoutMs = 1500, // in milliseconds
eConnectTimeoutMs = 1500, // in milliseconds
eMaxDownloadSpeedMBits = 20, // in megabits per second
};
cSatipTunerIf &tunerM;
@ -36,6 +38,9 @@ private:
cString errorNoMoreM;
cString errorOutOfRangeM;
cString errorCheckSyntaxM;
int modeM;
unsigned int interleavedRtpIdM;
unsigned int interleavedRtcpIdM;
void Create(void);
void Destroy(void);
@ -51,6 +56,7 @@ public:
explicit cSatipRtsp(cSatipTunerIf &tunerP);
virtual ~cSatipRtsp();
cString GetActiveMode(void);
cString RtspUnescapeString(const char *strP);
void Reset(void);
bool Options(const char *uriP);

View File

@ -416,7 +416,7 @@ void cSatipPluginSetup::Setup(void)
helpM.Append(tr("Define an ill-behaving filter to be blacklisted."));
}
}
Add(new cMenuEditStraItem(tr("Transport mode"), &transportModeM, ELEMENTS(transportModeTextsM) - 1, transportModeTextsM)); // TODO: RTP-over-TCP
Add(new cMenuEditStraItem(tr("Transport mode"), &transportModeM, ELEMENTS(transportModeTextsM), transportModeTextsM));
helpM.Append(tr("Define which transport mode shall be used.\n\nUnicast, Multicast, RTP-over-TCP"));
Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false));
helpM.Append("");

36
tuner.c
View File

@ -297,6 +297,11 @@ void cSatipTuner::ProcessVideoData(u_char *bufferP, int lengthP)
reConnectM.Set(eConnectTimeoutMs);
}
void cSatipTuner::ProcessRtpData(u_char *bufferP, int lengthP)
{
rtpM.Process(bufferP, lengthP);
}
void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
{
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM);
@ -350,6 +355,11 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
reConnectM.Set(eConnectTimeoutMs);
}
void cSatipTuner::ProcessRtcpData(u_char *bufferP, int lengthP)
{
rtcpM.Process(bufferP, lengthP);
}
void cSatipTuner::SetStreamId(int streamIdP)
{
cMutexLock MutexLock(&mutexM);
@ -376,21 +386,25 @@ void cSatipTuner::SetupTransport(int rtpPortP, int rtcpPortP, const char *stream
if (multicast != rtpM.IsMulticast() || rtpPortP != rtpM.Port()) {
cSatipPoller::GetInstance()->Unregister(rtpM);
rtpM.Close();
if (multicast)
rtpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP);
else
rtpM.Open(rtpPortP);
cSatipPoller::GetInstance()->Register(rtpM);
if (rtpPortP >= 0) {
if (multicast)
rtpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP);
else
rtpM.Open(rtpPortP);
cSatipPoller::GetInstance()->Register(rtpM);
}
}
// Adapt RTCP to any transport media change
if (multicast != rtcpM.IsMulticast() || rtcpPortP != rtcpM.Port()) {
cSatipPoller::GetInstance()->Unregister(rtcpM);
rtcpM.Close();
if (multicast)
rtcpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP);
else
rtcpM.Open(rtpPortP);
cSatipPoller::GetInstance()->Register(rtcpM);
if (rtcpPortP >= 0) {
if (multicast)
rtcpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP);
else
rtcpM.Open(rtpPortP);
cSatipPoller::GetInstance()->Register(rtcpM);
}
}
}
@ -674,5 +688,5 @@ cString cSatipTuner::GetSignalStatus(void)
cString cSatipTuner::GetInformation(void)
{
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
return (currentStateM >= tsTuned) ? cString::sprintf("%s?%s [stream=%d]", *GetBaseUrl(*streamAddrM, streamPortM), *streamParamM, streamIdM) : "connection failed";
return (currentStateM >= tsTuned) ? cString::sprintf("%s?%s (%s) [stream=%d]", *GetBaseUrl(*streamAddrM, streamPortM), *streamParamM, *rtspM.GetActiveMode(), streamIdM) : "connection failed";
}

View File

@ -157,6 +157,8 @@ public:
public:
virtual void ProcessVideoData(u_char *bufferP, int lengthP);
virtual void ProcessApplicationData(u_char *bufferP, int lengthP);
virtual void ProcessRtpData(u_char *bufferP, int lengthP);
virtual void ProcessRtcpData(u_char *bufferP, int lengthP);
virtual void SetStreamId(int streamIdP);
virtual void SetSessionTimeout(const char *sessionP, int timeoutP);
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP);

View File

@ -14,6 +14,8 @@ public:
virtual ~cSatipTunerIf() {}
virtual void ProcessVideoData(u_char *bufferP, int lengthP) = 0;
virtual void ProcessApplicationData(u_char *bufferP, int lengthP) = 0;
virtual void ProcessRtpData(u_char *bufferP, int lengthP) = 0;
virtual void ProcessRtcpData(u_char *bufferP, int lengthP) = 0;
virtual void SetStreamId(int streamIdP) = 0;
virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0;
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP) = 0;