mirror of
https://github.com/rofafor/vdr-plugin-satip.git
synced 2023-10-10 13:37:42 +02:00
Add a preliminary RTP-over-TCP support.
This commit is contained in:
parent
af64cb3011
commit
a5d57e9390
@ -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";
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
10
rtcp.c
@ -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
1
rtcp.h
@ -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
16
rtp.c
@ -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
1
rtp.h
@ -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
86
rtsp.c
@ -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);
|
||||
|
6
rtsp.h
6
rtsp.h
@ -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
|
||||
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);
|
||||
|
2
setup.c
2
setup.c
@ -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("");
|
||||
|
16
tuner.c
16
tuner.c
@ -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,22 +386,26 @@ void cSatipTuner::SetupTransport(int rtpPortP, int rtcpPortP, const char *stream
|
||||
if (multicast != rtpM.IsMulticast() || rtpPortP != rtpM.Port()) {
|
||||
cSatipPoller::GetInstance()->Unregister(rtpM);
|
||||
rtpM.Close();
|
||||
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 (rtcpPortP >= 0) {
|
||||
if (multicast)
|
||||
rtcpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP);
|
||||
else
|
||||
rtcpM.Open(rtpPortP);
|
||||
cSatipPoller::GetInstance()->Register(rtcpM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cString cSatipTuner::GetBaseUrl(const char *addressP, const int portP)
|
||||
@ -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";
|
||||
}
|
||||
|
2
tuner.h
2
tuner.h
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user