1
0
mirror of https://github.com/rofafor/vdr-plugin-satip.git synced 2023-10-10 13:37:42 +02:00

Merge branch 'vdr-2.2.x' of https://github.com/rofafor/vdr-plugin-satip into vdr-2.2.x

This commit is contained in:
REELcoder 2016-12-16 09:02:06 +01:00
commit 462d83d0fd
30 changed files with 470 additions and 74 deletions

8
README
View File

@ -116,6 +116,11 @@ Setup menu:
"Disable filter" options which allow you "Disable filter" options which allow you
to disable the individual section filters. to disable the individual section filters.
Valid range: "none" = 0 ... 7 Valid range: "none" = 0 ... 7
- Transport mode = unicast If you want to use the non-standard
multicast RTP-over-TCP transport mode, set this option
rtp-o-tcp accordingly. Otherwise, the transport
mode will be RTP-over-UDP via unicast or
multicast.
- [Red:Scan] Forces network scanning of SAT>IP hardware. - [Red:Scan] Forces network scanning of SAT>IP hardware.
- [Yellow:Devices] Opens SAT>IP device status menu. - [Yellow:Devices] Opens SAT>IP device status menu.
- [Blue:Info] Opens SAT>IP information/statistics menu. - [Blue:Info] Opens SAT>IP information/statistics menu.
@ -131,6 +136,9 @@ Information menu:
Notes: Notes:
- If you are having problems receiving DVB-S2 channels, make sure your
channels.conf entry contains correct pilot tone setting.
- The stream id "-1" states about unsuccessful tuning. This might be a - The stream id "-1" states about unsuccessful tuning. This might be a
result of invalid channel parameters or lack of free SAT>IP tuners. result of invalid channel parameters or lack of free SAT>IP tuners.

View File

@ -19,7 +19,7 @@ cSatipConfig::cSatipConfig(void)
useBytesM(1), useBytesM(1),
portRangeStartM(0), portRangeStartM(0),
portRangeStopM(0), portRangeStopM(0),
useRtpOverTcpM(false), transportModeM(eTransportModeUnicast),
detachedModeM(false), detachedModeM(false),
disableServerQuirksM(false), disableServerQuirksM(false),
useSingleModelServersM(false) useSingleModelServersM(false)

View File

@ -21,7 +21,7 @@ private:
unsigned int useBytesM; unsigned int useBytesM;
unsigned int portRangeStartM; unsigned int portRangeStartM;
unsigned int portRangeStopM; unsigned int portRangeStopM;
bool useRtpOverTcpM; unsigned int transportModeM;
bool detachedModeM; bool detachedModeM;
bool disableServerQuirksM; bool disableServerQuirksM;
bool useSingleModelServersM; bool useSingleModelServersM;
@ -37,6 +37,12 @@ public:
eOperatingModeHigh, eOperatingModeHigh,
eOperatingModeCount eOperatingModeCount
}; };
enum eTransportMode {
eTransportModeUnicast = 0,
eTransportModeMulticast,
eTransportModeRtpOverTcp,
eTransportModeCount
};
enum eTraceMode { enum eTraceMode {
eTraceModeNormal = 0x0000, eTraceModeNormal = 0x0000,
eTraceModeDebug1 = 0x0001, eTraceModeDebug1 = 0x0001,
@ -70,7 +76,10 @@ public:
int GetCICAM(unsigned int indexP) const; int GetCICAM(unsigned int indexP) const;
unsigned int GetEITScan(void) const { return eitScanM; } unsigned int GetEITScan(void) const { return eitScanM; }
unsigned int GetUseBytes(void) const { return useBytesM; } unsigned int GetUseBytes(void) const { return useBytesM; }
bool GetUseRtpOverTcp(void) const { return useRtpOverTcpM; } unsigned int GetTransportMode(void) const { return transportModeM; }
bool IsTransportModeUnicast(void) const { return (transportModeM == eTransportModeUnicast); }
bool IsTransportModeRtpOverTcp(void) const { return (transportModeM == eTransportModeRtpOverTcp); }
bool IsTransportModeMulticast(void) const { return (transportModeM == eTransportModeMulticast); }
bool GetDetachedMode(void) const { return detachedModeM; } bool GetDetachedMode(void) const { return detachedModeM; }
bool GetDisableServerQuirks(void) const { return disableServerQuirksM; } bool GetDisableServerQuirks(void) const { return disableServerQuirksM; }
bool GetUseSingleModelServers(void) const { return useSingleModelServersM; } bool GetUseSingleModelServers(void) const { return useSingleModelServersM; }
@ -87,7 +96,7 @@ public:
void SetCICAM(unsigned int indexP, int cicamP); void SetCICAM(unsigned int indexP, int cicamP);
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; } void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; }
void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; } void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; }
void SetUseRtpOverTcp(bool onOffP) { useRtpOverTcpM = onOffP; } void SetTransportMode(unsigned int transportModeP) { transportModeM = transportModeP; }
void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; } void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; }
void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; } void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; }
void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; } void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; }

View File

@ -22,8 +22,7 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)), deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)),
channelM(), channelM(),
createdM(0), createdM(0),
mutexM(), mutexM()
fixedPidsM()
{ {
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE; unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
bufsize -= (bufsize % TS_SIZE); bufsize -= (bufsize % TS_SIZE);
@ -141,7 +140,7 @@ cString cSatipDevice::GetGeneralInformation(void)
#if defined(APIVERSNUM) && APIVERSNUM >= 20301 #if defined(APIVERSNUM) && APIVERSNUM >= 20301
LOCK_CHANNELS_READ; LOCK_CHANNELS_READ;
#endif #endif
return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s", return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s\n",
deviceIndexM, CardIndex(), deviceIndexM, CardIndex(),
pTunerM ? *pTunerM->GetInformation() : "", pTunerM ? *pTunerM->GetInformation() : "",
pTunerM ? *pTunerM->GetSignalStatus() : "", pTunerM ? *pTunerM->GetSignalStatus() : "",
@ -372,17 +371,11 @@ bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
{ {
debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP ? handleP->pid : -1, typeP, onP, deviceIndexM); debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP ? handleP->pid : -1, typeP, onP, deviceIndexM);
if (pTunerM && handleP && handleP->pid >= 0) { if (pTunerM && handleP && handleP->pid >= 0) {
if (onP) { if (onP)
fixedPidsM.AddPid(handleP->pid);
debug12("%s A%d fixedPidsM=%s [device %d]", __PRETTY_FUNCTION__, handleP->pid, *fixedPidsM.ListPids(), deviceIndexM);
return pTunerM->SetPid(handleP->pid, typeP, true); return pTunerM->SetPid(handleP->pid, typeP, true);
} else if (!handleP->used && pSectionFilterHandlerM && !pSectionFilterHandlerM->Exists(handleP->pid))
else if (!handleP->used) {
fixedPidsM.RemovePid(handleP->pid);
debug12("%s R%d fixedPidsM=%s [device %d]", __PRETTY_FUNCTION__, handleP->pid, *fixedPidsM.ListPids(), deviceIndexM);
return pTunerM->SetPid(handleP->pid, typeP, false); return pTunerM->SetPid(handleP->pid, typeP, false);
} }
}
return true; return true;
} }
@ -403,7 +396,7 @@ void cSatipDevice::CloseFilter(int handleP)
if (pSectionFilterHandlerM) { if (pSectionFilterHandlerM) {
int pid = pSectionFilterHandlerM->GetPid(handleP); int pid = pSectionFilterHandlerM->GetPid(handleP);
debug12("%s (%d) [device %u]", __PRETTY_FUNCTION__, pid, deviceIndexM); debug12("%s (%d) [device %u]", __PRETTY_FUNCTION__, pid, deviceIndexM);
if (pTunerM && fixedPidsM.IndexOf(pid) == -1) if (pTunerM)
pTunerM->SetPid(pid, ptOther, false); pTunerM->SetPid(pid, ptOther, false);
pSectionFilterHandlerM->Close(handleP); pSectionFilterHandlerM->Close(handleP);
} }
@ -417,7 +410,6 @@ bool cSatipDevice::OpenDvr(void)
if (pTunerM) if (pTunerM)
pTunerM->Open(); pTunerM->Open();
isOpenDvrM = true; isOpenDvrM = true;
fixedPidsM.Clear();
return true; return true;
} }
@ -562,8 +554,8 @@ bool cSatipDevice::GetTSPacket(uchar *&dataP)
if (dataP && (dataP[4] == 0x00) && (dataP[5] == 0x02) && ((dataP[6] & 0xfc) == 0xb0)) { if (dataP && (dataP[4] == 0x00) && (dataP[5] == 0x02) && ((dataP[6] & 0xfc) == 0xb0)) {
int pidA = ((dataP[1] & 0x1f) << 8) | dataP[2]; int pidA = ((dataP[1] & 0x1f) << 8) | dataP[2];
int pidB = GetPmtPid(); int pidB = GetPmtPid();
debug12("%s PID %d/%d 0x%02x%02x%02x%02x%02x%02x%02x %d", __PRETTY_FUNCTION__, debug12("%s PID %d/%d 0x%02x%02x%02x%02x%02x%02x%02x", __PRETTY_FUNCTION__,
pidA, pidB, dataP[0], dataP[1], dataP[2], dataP[3], dataP[4], dataP[5], dataP[6], fixedPidsM.IndexOf(pidA)); pidA, pidB, dataP[0], dataP[1], dataP[2], dataP[3], dataP[4], dataP[5], dataP[6]);
} }
return true; return true;

View File

@ -40,7 +40,6 @@ private:
cSatipSectionFilterHandler *pSectionFilterHandlerM; cSatipSectionFilterHandler *pSectionFilterHandlerM;
cTimeMs createdM; cTimeMs createdM;
cMutex mutexM; cMutex mutexM;
cSatipPid fixedPidsM;
// constructor & destructor // constructor & destructor
public: public:

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 cString cSatipMsearch::ToString(void) const
{ {
return "MSearch"; return "MSearch";

View File

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

View File

@ -1,5 +1,5 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007-2015 Rolf Ahrenberg # Copyright (C) 2007-2016 Rolf Ahrenberg
# This file is distributed under the same license as the satip package. # This file is distributed under the same license as the satip package.
# Gabriel Bonich, 2014-2015 # Gabriel Bonich, 2014-2015
# #
@ -85,6 +85,15 @@ msgstr "Normal"
msgid "high" msgid "high"
msgstr "Alt" msgstr "Alt"
msgid "Unicast"
msgstr ""
msgid "Multicast"
msgstr ""
msgid "RTP-over-TCP"
msgstr ""
msgid "Button$Devices" msgid "Button$Devices"
msgstr "Dispositius" msgstr "Dispositius"
@ -178,13 +187,13 @@ msgstr "Filtra"
msgid "Define an ill-behaving filter to be blacklisted." msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Definir un filtre mal comportar a la llista negra." msgstr "Definir un filtre mal comportar a la llista negra."
msgid "Use RTP-over-TCP mode" msgid "Transport mode"
msgstr "" msgstr ""
msgid "" msgid ""
"Define whether the RTP-over-TCP mode shall be used.\n" "Define which transport mode shall be used.\n"
"\n" "\n"
"This setting affects only SAT>IP devices supporting the feature." "Unicast, Multicast, RTP-over-TCP"
msgstr "" msgstr ""
msgid "Active SAT>IP servers:" msgid "Active SAT>IP servers:"

View File

@ -1,7 +1,7 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007-2015 Rolf Ahrenberg # Copyright (C) 2007-2016 Rolf Ahrenberg
# This file is distributed under the same license as the satip package. # This file is distributed under the same license as the satip package.
# Frank Neumann, 2014-2015 # Frank Neumann, 2014-2016
# #
msgid "" msgid ""
msgstr "" msgstr ""
@ -85,11 +85,20 @@ msgstr "normal"
msgid "high" msgid "high"
msgstr "hoch" msgstr "hoch"
msgid "Unicast"
msgstr "Unicast"
msgid "Multicast"
msgstr "Multicast"
msgid "RTP-over-TCP"
msgstr "RTP-over-TCP"
msgid "Button$Devices" msgid "Button$Devices"
msgstr "Geräte" msgstr "Geräte"
msgid "Operating mode" msgid "Operating mode"
msgstr "Betriebsmodus" msgstr "Betriebsart"
msgid "" msgid ""
"Define the used operating mode for all SAT>IP devices:\n" "Define the used operating mode for all SAT>IP devices:\n"
@ -99,7 +108,7 @@ msgid ""
"normal - devices are working within normal parameters\n" "normal - devices are working within normal parameters\n"
"high - devices are working at the highest priority" "high - devices are working at the highest priority"
msgstr "" msgstr ""
"Bestimme den Betriebsmodus für alle SAT>IP Geräte:\n" "Bestimme die Betriebsart für alle SAT>IP Geräte:\n"
"\n" "\n"
"aus - Geräte sind abgeschaltet\n" "aus - Geräte sind abgeschaltet\n"
"niedrig - Geräte arbeiten mit geringster Priorität\n" "niedrig - Geräte arbeiten mit geringster Priorität\n"
@ -170,22 +179,25 @@ msgid ""
msgstr "" msgstr ""
"Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\n" "Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\n"
"\n" "\n"
"Bestimmte Abschnittsfilter können unerwünschtes Verhalten mit VDR, z.B. falsche Zeit-Synchronisation, verursachen. Durch das Ausblenden einzelner Filter können nützliche Daten dieser Abschnitte für den VDR erhalten werden." "Bestimmte Abschnittsfilter können unerwünschtes Verhalten mit VDR, z.B. falsche Zeit-Synchronisation, verursachen. Durch das Ausblenden einzelner Filter können nützliche Daten dieser Abschnitte für den VDR erhalten bleiben."
msgid "Filter" msgid "Filter"
msgstr "Filter" msgstr "Filter"
msgid "Define an ill-behaving filter to be blacklisted." msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Bestimme einen fehlerhaften Filter der ausgeblendet werden soll." msgstr "Bestimme fehlerhafte Filter die ausgeblendet werden sollen."
msgid "Use RTP-over-TCP mode" msgid "Transport mode"
msgstr "" msgstr "Übertragungsart"
msgid "" msgid ""
"Define whether the RTP-over-TCP mode shall be used.\n" "Define which transport mode shall be used.\n"
"\n" "\n"
"This setting affects only SAT>IP devices supporting the feature." "Unicast, Multicast, RTP-over-TCP"
msgstr "" msgstr ""
"Lege die gewünschte Übertragungsart fest.\n"
"\n"
"Unicast, Multicast, RTP-over-TCP"
msgid "Active SAT>IP servers:" msgid "Active SAT>IP servers:"
msgstr "Aktive SAT>IP Server:" msgstr "Aktive SAT>IP Server:"

View File

@ -1,5 +1,5 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007-2015 Rolf Ahrenberg # Copyright (C) 2007-2016 Rolf Ahrenberg
# This file is distributed under the same license as the satip package. # This file is distributed under the same license as the satip package.
# Gabriel Bonich, 2014-2015 # Gabriel Bonich, 2014-2015
# #
@ -85,6 +85,15 @@ msgstr "Normal"
msgid "high" msgid "high"
msgstr "Alto" msgstr "Alto"
msgid "Unicast"
msgstr ""
msgid "Multicast"
msgstr ""
msgid "RTP-over-TCP"
msgstr ""
msgid "Button$Devices" msgid "Button$Devices"
msgstr "Dispositivos" msgstr "Dispositivos"
@ -178,13 +187,13 @@ msgstr "Filtra"
msgid "Define an ill-behaving filter to be blacklisted." msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Define un filtro para poner en la lista negra." msgstr "Define un filtro para poner en la lista negra."
msgid "Use RTP-over-TCP mode" msgid "Transport mode"
msgstr "" msgstr ""
msgid "" msgid ""
"Define whether the RTP-over-TCP mode shall be used.\n" "Define which transport mode shall be used.\n"
"\n" "\n"
"This setting affects only SAT>IP devices supporting the feature." "Unicast, Multicast, RTP-over-TCP"
msgstr "" msgstr ""
msgid "Active SAT>IP servers:" msgid "Active SAT>IP servers:"

View File

@ -1,7 +1,7 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007-2015 Rolf Ahrenberg # Copyright (C) 2007-2016 Rolf Ahrenberg
# This file is distributed under the same license as the satip package. # This file is distributed under the same license as the satip package.
# Rolf Ahrenberg, 2015 # Rolf Ahrenberg, 2015-2016
# #
msgid "" msgid ""
msgstr "" msgstr ""
@ -85,6 +85,15 @@ msgstr "normaali"
msgid "high" msgid "high"
msgstr "korkea" msgstr "korkea"
msgid "Unicast"
msgstr "Unicast"
msgid "Multicast"
msgstr "Multicast"
msgid "RTP-over-TCP"
msgstr "RTP-over-TCP"
msgid "Button$Devices" msgid "Button$Devices"
msgstr "Laitteet" msgstr "Laitteet"
@ -177,17 +186,17 @@ msgstr "Suodatin"
msgid "Define an ill-behaving filter to be blacklisted." msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle." msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle."
msgid "Use RTP-over-TCP mode" msgid "Transport mode"
msgstr "Käytä RTP-over-TCP -moodia" msgstr "Siirtoyhteystapa"
msgid "" msgid ""
"Define whether the RTP-over-TCP mode shall be used.\n" "Define which transport mode shall be used.\n"
"\n" "\n"
"This setting affects only SAT>IP devices supporting the feature." "Unicast, Multicast, RTP-over-TCP"
msgstr "" msgstr ""
"Määrittele RTP-over-TCP -moodin käyttöönotto.\n" "Määrittele käytettävä siirtoyhteystapa.\n"
"\n" "\n"
"Tämä asetus vaikuttaa vain SAT>IP-laitteisiin, jotka tukevat kyseistä ominaisuutta." "Unicast, Multicast, RTP-over-TCP"
msgid "Active SAT>IP servers:" msgid "Active SAT>IP servers:"
msgstr "Aktiiviset SAT>IP-palvelimet:" msgstr "Aktiiviset SAT>IP-palvelimet:"

View File

@ -14,6 +14,7 @@ public:
virtual ~cSatipPollerIf() {} virtual ~cSatipPollerIf() {}
virtual int GetFd(void) = 0; virtual int GetFd(void) = 0;
virtual void Process(void) = 0; virtual void Process(void) = 0;
virtual void Process(unsigned char *dataP, int lengthP) = 0;
virtual cString ToString(void) const = 0; virtual cString ToString(void) const = 0;
private: 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 cString cSatipRtcp::ToString(void) const
{ {
return cString::sprintf("RTCP [device %d]", tunerM.GetId()); return cString::sprintf("RTCP [device %d]", tunerM.GetId());

1
rtcp.h
View File

@ -30,6 +30,7 @@ public:
public: public:
virtual int GetFd(void); virtual int GetFd(void);
virtual void Process(void); virtual void Process(void);
virtual void Process(unsigned char *dataP, int lengthP);
virtual cString ToString(void) const; 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 cString cSatipRtp::ToString(void) const
{ {
return cString::sprintf("RTP [device %d]", tunerM.GetId()); return cString::sprintf("RTP [device %d]", tunerM.GetId());

1
rtp.h
View File

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

96
rtsp.c
View File

@ -17,12 +17,14 @@ cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP)
: tunerM(tunerP), : tunerM(tunerP),
headerBufferM(), headerBufferM(),
dataBufferM(), dataBufferM(),
modeM(cmUnicast),
handleM(NULL), handleM(NULL),
headerListM(NULL), headerListM(NULL),
errorNoMoreM(""), errorNoMoreM(""),
errorOutOfRangeM(""), errorOutOfRangeM(""),
errorCheckSyntaxM("") errorCheckSyntaxM(""),
modeM(cSatipConfig::eTransportModeUnicast),
interleavedRtpIdM(0),
interleavedRtcpIdM(1)
{ {
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
Create(); Create();
@ -58,6 +60,30 @@ size_t cSatipRtsp::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *d
return len; 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) int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP)
{ {
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(userPtrP); cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(userPtrP);
@ -87,6 +113,21 @@ int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, s
return 0; 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) cString cSatipRtsp::RtspUnescapeString(const char *strP)
{ {
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId()); debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId());
@ -123,6 +164,9 @@ void cSatipRtsp::Create(void)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_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 // Set user-agent
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, tunerM.GetId())); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, tunerM.GetId()));
} }
@ -182,16 +226,18 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTc
cTimeMs processing(0); cTimeMs processing(0);
CURLcode res = CURLE_OK; CURLcode res = CURLE_OK;
switch (modeM) { switch (SatipConfig.GetTransportMode()) {
case cmMulticast: case cSatipConfig::eTransportModeMulticast:
// RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl> // RTP/AVP;multicast;destination=<multicast group address>;port=<RTP port>-<RTCP port>;ttl=<ttl>[;source=<multicast source address>]
transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP); transport = cString::sprintf("RTP/AVP;multicast");
break; break;
default: default:
case cmUnicast:
// RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port> // RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port>
// RTP/AVP/TCP;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; break;
} }
@ -204,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_WRITEHEADER, this);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); 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_PERFORM(handleM);
// Session id is now known - disable header parsing // Session id is now known - disable header parsing
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
@ -311,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_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); 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_PERFORM(handleM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
@ -352,6 +403,35 @@ void cSatipRtsp::ParseHeader(void)
tunerM.SetSessionTimeout(skipspace(session), -1); tunerM.SetSessionTimeout(skipspace(session), -1);
FREE_POINTER(session); 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;
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) {
modeM = cSatipConfig::eTransportModeMulticast;
tunerM.SetupTransport(rtp, rtcp, destination, source);
}
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);
}
r = strtok_r(NULL, "\r\n", &s); r = strtok_r(NULL, "\r\n", &s);
} }
} }

8
rtsp.h
View File

@ -22,22 +22,25 @@ class cSatipRtsp {
private: private:
static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); 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 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); static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
enum { enum {
eConnectTimeoutMs = 1500, // in milliseconds eConnectTimeoutMs = 1500, // in milliseconds
eMaxDownloadSpeedMBits = 20, // in megabits per second
}; };
enum eCommunicationMode { cmUnicast, cmMulticast };
cSatipTunerIf &tunerM; cSatipTunerIf &tunerM;
cSatipMemoryBuffer headerBufferM; cSatipMemoryBuffer headerBufferM;
cSatipMemoryBuffer dataBufferM; cSatipMemoryBuffer dataBufferM;
eCommunicationMode modeM;
CURL *handleM; CURL *handleM;
struct curl_slist *headerListM; struct curl_slist *headerListM;
cString errorNoMoreM; cString errorNoMoreM;
cString errorOutOfRangeM; cString errorOutOfRangeM;
cString errorCheckSyntaxM; cString errorCheckSyntaxM;
int modeM;
unsigned int interleavedRtpIdM;
unsigned int interleavedRtcpIdM;
void Create(void); void Create(void);
void Destroy(void); void Destroy(void);
@ -53,6 +56,7 @@ public:
explicit cSatipRtsp(cSatipTunerIf &tunerP); explicit cSatipRtsp(cSatipTunerIf &tunerP);
virtual ~cSatipRtsp(); virtual ~cSatipRtsp();
cString GetActiveMode(void);
cString RtspUnescapeString(const char *strP); cString RtspUnescapeString(const char *strP);
void Reset(void); void Reset(void);
bool Options(const char *uriP); bool Options(const char *uriP);

11
satip.c
View File

@ -305,7 +305,12 @@ void cPluginSatip::ParsePortRange(const char *paramP)
rangeStart = 0; rangeStart = 0;
rangeStop = 0; rangeStop = 0;
} }
if (rangeStop - rangeStart + 1 < deviceCountM * 2) { if (rangeStart % 2) {
error("The given range start port must be even!");
rangeStart = 0;
rangeStop = 0;
}
else if (rangeStop - rangeStart + 1 < deviceCountM * 2) {
error("The given port range is to small: %d < %d!", rangeStop - rangeStart + 1, deviceCountM * 2); error("The given port range is to small: %d < %d!", rangeStop - rangeStart + 1, deviceCountM * 2);
rangeStart = 0; rangeStart = 0;
rangeStop = 0; rangeStop = 0;
@ -401,8 +406,8 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
for (unsigned int i = 0; i < DisabledFiltersCount; ++i) for (unsigned int i = 0; i < DisabledFiltersCount; ++i)
SatipConfig.SetDisabledFilters(i, DisabledFilters[i]); SatipConfig.SetDisabledFilters(i, DisabledFilters[i]);
} }
else if (!strcasecmp(nameP, "UseRtpOverTcp")) else if (!strcasecmp(nameP, "TransportMode"))
SatipConfig.SetUseRtpOverTcp(atoi(valueP)); SatipConfig.SetTransportMode(atoi(valueP));
else else
return false; return false;
return true; return true;

View File

@ -338,6 +338,19 @@ cString cSatipSectionFilterHandler::GetInformation(void)
return s; return s;
} }
bool cSatipSectionFilterHandler::Exists(u_short pidP)
{
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM);
cMutexLock MutexLock(&mutexM);
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i] && (pidP == filtersM[i]->GetPid())) {
debug12("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM);
return true;
}
}
return false;
}
bool cSatipSectionFilterHandler::Delete(unsigned int indexP) bool cSatipSectionFilterHandler::Delete(unsigned int indexP)
{ {
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM); debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);

View File

@ -80,6 +80,7 @@ public:
cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP); cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP);
virtual ~cSatipSectionFilterHandler(); virtual ~cSatipSectionFilterHandler();
cString GetInformation(void); cString GetInformation(void);
bool Exists(u_short pidP);
int Open(u_short pidP, u_char tidP, u_char maskP); int Open(u_short pidP, u_char tidP, u_char maskP);
void Close(int handleP); void Close(int handleP);
int GetPid(int handleP); int GetPid(int handleP);

View File

@ -147,6 +147,13 @@ cSatipServer::cSatipServer(const char *addressP, const int portP, const char *mo
if (strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server if (strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
) )
quirkM |= eSatipQuirkCiTnr; quirkM |= eSatipQuirkCiTnr;
// These devices don't support auto-detection of pilot tones
if (strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
strstr(*descriptionM, "DIGIBIT") || // Telestar Digibit R1
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
// Kathrein ExIP 414/E
)
quirkM |= eSatipQuirkForcePilot;
} }
if ((quirkM & eSatipQuirkMask) & eSatipQuirkSessionId) if ((quirkM & eSatipQuirkMask) & eSatipQuirkSessionId)
quirksM = cString::sprintf("%s%sSessionId", *quirksM, isempty(*quirksM) ? "" : ","); quirksM = cString::sprintf("%s%sSessionId", *quirksM, isempty(*quirksM) ? "" : ",");
@ -160,6 +167,8 @@ cSatipServer::cSatipServer(const char *addressP, const int portP, const char *mo
quirksM = cString::sprintf("%s%sCiXpmt", *quirksM, isempty(*quirksM) ? "" : ","); quirksM = cString::sprintf("%s%sCiXpmt", *quirksM, isempty(*quirksM) ? "" : ",");
if ((quirkM & eSatipQuirkMask) & eSatipQuirkCiTnr) if ((quirkM & eSatipQuirkMask) & eSatipQuirkCiTnr)
quirksM = cString::sprintf("%s%sCiTnr", *quirksM, isempty(*quirksM) ? "" : ","); quirksM = cString::sprintf("%s%sCiTnr", *quirksM, isempty(*quirksM) ? "" : ",");
if ((quirkM & eSatipQuirkMask) & eSatipQuirkForcePilot)
quirksM = cString::sprintf("%s%sForcePilot", *quirksM, isempty(*quirksM) ? "" : ",");
debug3("%s description=%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM, *quirksM); debug3("%s description=%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM, *quirksM);
// These devices support external CI // These devices support external CI
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet

View File

@ -81,6 +81,7 @@ public:
eSatipQuirkRtpOverTcp = 0x08, eSatipQuirkRtpOverTcp = 0x08,
eSatipQuirkCiXpmt = 0x10, eSatipQuirkCiXpmt = 0x10,
eSatipQuirkCiTnr = 0x20, eSatipQuirkCiTnr = 0x20,
eSatipQuirkForcePilot = 0x40,
eSatipQuirkMask = 0xFF eSatipQuirkMask = 0xFF
}; };
cSatipServer(const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP); cSatipServer(const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP);

13
setup.c
View File

@ -344,8 +344,8 @@ eOSState cSatipMenuInfo::ProcessKey(eKeys keyP)
cSatipPluginSetup::cSatipPluginSetup() cSatipPluginSetup::cSatipPluginSetup()
: detachedModeM(SatipConfig.GetDetachedMode()), : detachedModeM(SatipConfig.GetDetachedMode()),
deviceCountM(0), deviceCountM(0),
useRtpOverTcpM(SatipConfig.GetUseRtpOverTcp()),
operatingModeM(SatipConfig.GetOperatingMode()), operatingModeM(SatipConfig.GetOperatingMode()),
transportModeM(SatipConfig.GetTransportMode()),
ciExtensionM(SatipConfig.GetCIExtension()), ciExtensionM(SatipConfig.GetCIExtension()),
eitScanM(SatipConfig.GetEITScan()), eitScanM(SatipConfig.GetEITScan()),
numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()), numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()),
@ -356,6 +356,9 @@ cSatipPluginSetup::cSatipPluginSetup()
operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low"); operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low");
operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal"); operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal");
operatingModeTextsM[cSatipConfig::eOperatingModeHigh] = tr("high"); operatingModeTextsM[cSatipConfig::eOperatingModeHigh] = tr("high");
transportModeTextsM[cSatipConfig::eTransportModeUnicast] = tr("Unicast");
transportModeTextsM[cSatipConfig::eTransportModeMulticast] = tr("Multicast");
transportModeTextsM[cSatipConfig::eTransportModeRtpOverTcp] = tr("RTP-over-TCP");
for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i) for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i)
cicamsM[i] = SatipConfig.GetCICAM(i); cicamsM[i] = SatipConfig.GetCICAM(i);
for (unsigned int i = 0; i < ELEMENTS(ca_systems_table); ++i) for (unsigned int i = 0; i < ELEMENTS(ca_systems_table); ++i)
@ -413,8 +416,8 @@ void cSatipPluginSetup::Setup(void)
helpM.Append(tr("Define an ill-behaving filter to be blacklisted.")); helpM.Append(tr("Define an ill-behaving filter to be blacklisted."));
} }
} }
Add(new cMenuEditBoolItem(tr("Use RTP-over-TCP mode"), &useRtpOverTcpM)); Add(new cMenuEditStraItem(tr("Transport mode"), &transportModeM, ELEMENTS(transportModeTextsM), transportModeTextsM));
helpM.Append(tr("Define whether the RTP-over-TCP mode shall be used.\n\nThis setting affects only SAT>IP devices supporting the feature.")); 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)); Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false));
helpM.Append(""); helpM.Append("");
@ -563,16 +566,16 @@ void cSatipPluginSetup::StoreFilters(const char *nameP, int *valuesP)
void cSatipPluginSetup::Store(void) void cSatipPluginSetup::Store(void)
{ {
// Store values into setup.conf // Store values into setup.conf
SetupStore("UseRtpOverTcp", useRtpOverTcpM);
SetupStore("OperatingMode", operatingModeM); SetupStore("OperatingMode", operatingModeM);
SetupStore("TransportMode", transportModeM);
SetupStore("EnableCIExtension", ciExtensionM); SetupStore("EnableCIExtension", ciExtensionM);
SetupStore("EnableEITScan", eitScanM); SetupStore("EnableEITScan", eitScanM);
StoreCicams("CICAM", cicamsM); StoreCicams("CICAM", cicamsM);
StoreSources("DisabledSources", disabledSourcesM); StoreSources("DisabledSources", disabledSourcesM);
StoreFilters("DisabledFilters", disabledFilterIndexesM); StoreFilters("DisabledFilters", disabledFilterIndexesM);
// Update global config // Update global config
SatipConfig.SetUseRtpOverTcp(useRtpOverTcpM);
SatipConfig.SetOperatingMode(operatingModeM); SatipConfig.SetOperatingMode(operatingModeM);
SatipConfig.SetTransportMode(transportModeM);
SatipConfig.SetCIExtension(ciExtensionM); SatipConfig.SetCIExtension(ciExtensionM);
SatipConfig.SetEITScan(eitScanM); SatipConfig.SetEITScan(eitScanM);
for (int i = 0; i < MAX_CICAM_COUNT; ++i) for (int i = 0; i < MAX_CICAM_COUNT; ++i)

View File

@ -17,9 +17,10 @@ class cSatipPluginSetup : public cMenuSetupPage
private: private:
bool detachedModeM; bool detachedModeM;
int deviceCountM; int deviceCountM;
int useRtpOverTcpM;
int operatingModeM; int operatingModeM;
int transportModeM;
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount]; const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];
const char *transportModeTextsM[cSatipConfig::eTransportModeCount];
int ciExtensionM; int ciExtensionM;
int cicamsM[MAX_CICAM_COUNT]; int cicamsM[MAX_CICAM_COUNT];
const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE]; const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE];

141
socket.c
View File

@ -21,7 +21,11 @@
cSatipSocket::cSatipSocket() cSatipSocket::cSatipSocket()
: socketPortM(0), : socketPortM(0),
socketDescM(-1) socketDescM(-1),
isMulticastM(false),
useSsmM(false),
streamAddrM(htonl(INADDR_ANY)),
sourceAddrM(htonl(INADDR_ANY))
{ {
debug1("%s", __PRETTY_FUNCTION__); debug1("%s", __PRETTY_FUNCTION__);
memset(&sockAddrM, 0, sizeof(sockAddrM)); memset(&sockAddrM, 0, sizeof(sockAddrM));
@ -36,6 +40,12 @@ cSatipSocket::~cSatipSocket()
bool cSatipSocket::Open(const int portP, const bool reuseP) bool cSatipSocket::Open(const int portP, const bool reuseP)
{ {
// If socket is there already and it is bound to a different port, it must
// be closed first
if (portP != socketPortM) {
debug1("%s (%d, %d) Socket tear-down", __PRETTY_FUNCTION__, portP, reuseP);
Close();
}
// Bind to the socket if it is not active already // Bind to the socket if it is not active already
if (socketDescM < 0) { if (socketDescM < 0) {
int yes; int yes;
@ -55,6 +65,11 @@ bool cSatipSocket::Open(const int portP, const bool reuseP)
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0 && errno != ENOPROTOOPT, ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0 && errno != ENOPROTOOPT,
"setsockopt(SO_REUSEPORT)", Close(), return false); "setsockopt(SO_REUSEPORT)", Close(), return false);
#endif #endif
#ifndef __FreeBSD__
// Allow packet information to be fetched
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0,
"setsockopt(IP_PKTINFO)", Close(), return false);
#endif // __FreeBSD__
// Bind socket // Bind socket
memset(&sockAddrM, 0, sizeof(sockAddrM)); memset(&sockAddrM, 0, sizeof(sockAddrM));
sockAddrM.sin_family = AF_INET; sockAddrM.sin_family = AF_INET;
@ -66,20 +81,38 @@ bool cSatipSocket::Open(const int portP, const bool reuseP)
ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0, ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0,
"getsockname()", Close(), return false); "getsockname()", Close(), return false);
socketPortM = ntohs(sockAddrM.sin_port); socketPortM = ntohs(sockAddrM.sin_port);
isMulticastM = false;
} }
debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM); debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM);
return true; return true;
} }
bool cSatipSocket::OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP)
{
debug1("%s (%d, %s, %s)", __PRETTY_FUNCTION__, portP, streamAddrP, sourceAddrP);
if (Open(portP)) {
CheckAddress(streamAddrP, &streamAddrM);
if (!isempty(sourceAddrP))
useSsmM = CheckAddress(sourceAddrP, &sourceAddrM);
return Join();
}
return false;
}
void cSatipSocket::Close(void) void cSatipSocket::Close(void)
{ {
debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM); debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM);
// Check if socket exists // Check if socket exists
if (socketDescM >= 0) { if (socketDescM >= 0) {
Leave();
close(socketDescM); close(socketDescM);
socketDescM = -1; socketDescM = -1;
socketPortM = 0; socketPortM = 0;
memset(&sockAddrM, 0, sizeof(sockAddrM)); memset(&sockAddrM, 0, sizeof(sockAddrM));
streamAddrM = htonl(INADDR_ANY);
sourceAddrM = htonl(INADDR_ANY);
isMulticastM = false;
useSsmM = false;
} }
} }
@ -102,6 +135,96 @@ bool cSatipSocket::Flush(void)
return false; return false;
} }
bool cSatipSocket::CheckAddress(const char *addrP, in_addr_t *inAddrP)
{
if (inAddrP) {
// First try only the IP address
*inAddrP = inet_addr(addrP);
if (*inAddrP == htonl(INADDR_NONE)) {
debug1("%s (%s, ) Cannot convert to address", __PRETTY_FUNCTION__, addrP);
// It may be a host name, get the name
struct hostent *host = gethostbyname(addrP);
if (!host) {
char tmp[64];
error("gethostbyname() failed: %s is not valid address: %s", addrP,
strerror_r(h_errno, tmp, sizeof(tmp)));
return false;
}
*inAddrP = inet_addr(*host->h_addr_list);
}
return true;
}
return false;
}
bool cSatipSocket::Join(void)
{
debug1("%s", __PRETTY_FUNCTION__);
// Check if socket exists
if (socketDescM >= 0 && !isMulticastM) {
// Join a new multicast group
if (useSsmM) {
// Source-specific multicast (SSM) is used
struct group_source_req gsr;
struct sockaddr_in *grp;
struct sockaddr_in *src;
gsr.gsr_interface = 0; // if_nametoindex("any") ?
grp = (struct sockaddr_in*)&gsr.gsr_group;
grp->sin_family = AF_INET;
grp->sin_addr.s_addr = streamAddrM;
grp->sin_port = 0;
src = (struct sockaddr_in*)&gsr.gsr_source;
src->sin_family = AF_INET;
src->sin_addr.s_addr = sourceAddrM;
src->sin_port = 0;
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_JOIN_SOURCE_GROUP)", return false);
}
else {
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = streamAddrM;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false);
}
// Update multicasting flag
isMulticastM = true;
}
return true;
}
bool cSatipSocket::Leave(void)
{
debug1("%s", __PRETTY_FUNCTION__);
// Check if socket exists
if (socketDescM >= 0 && isMulticastM) {
// Leave the existing multicast group
if (useSsmM) {
// Source-specific multicast (SSM) is used
struct group_source_req gsr;
struct sockaddr_in *grp;
struct sockaddr_in *src;
gsr.gsr_interface = 0; // if_nametoindex("any") ?
grp = (struct sockaddr_in*)&gsr.gsr_group;
grp->sin_family = AF_INET;
grp->sin_addr.s_addr = streamAddrM;
grp->sin_port = 0;
src = (struct sockaddr_in*)&gsr.gsr_source;
src->sin_family = AF_INET;
src->sin_addr.s_addr = sourceAddrM;
src->sin_port = 0;
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_LEAVE_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_LEAVE_SOURCE_GROUP)", return false);
}
else {
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = streamAddrM;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false);
}
// Update multicasting flag
isMulticastM = false;
}
return true;
}
int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP) int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
{ {
debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP); debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP);
@ -132,8 +255,22 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
if (socketDescM && bufferAddrP && (bufferLenP > 0)) if (socketDescM && bufferAddrP && (bufferLenP > 0))
len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT); len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT);
if (len > 0) if (len > 0) {
#ifndef __FreeBSD__
if (isMulticastM) {
// Process auxiliary received data and validate source address
for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg);
if ((i->ipi_addr.s_addr == streamAddrM) || (htonl(INADDR_ANY) == streamAddrM))
return len; return len;
}
}
}
else
#endif // __FreeBSD__
return len;
}
} while (len > 0); } while (len > 0);
ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1); ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1);
return 0; return 0;

View File

@ -15,14 +15,23 @@ private:
int socketPortM; int socketPortM;
int socketDescM; int socketDescM;
struct sockaddr_in sockAddrM; struct sockaddr_in sockAddrM;
bool isMulticastM;
bool useSsmM;
in_addr_t streamAddrM;
in_addr_t sourceAddrM;
bool CheckAddress(const char *addrP, in_addr_t *inAddrP);
bool Join(void);
bool Leave(void);
public: public:
cSatipSocket(); cSatipSocket();
virtual ~cSatipSocket(); virtual ~cSatipSocket();
bool Open(const int portP = 0, const bool reuseP = false); bool Open(const int portP = 0, const bool reuseP = false);
bool OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP);
virtual void Close(void); virtual void Close(void);
int Fd(void) { return socketDescM; } int Fd(void) { return socketDescM; }
int Port(void) { return socketPortM; } int Port(void) { return socketPortM; }
bool IsMulticast(void) { return isMulticastM; }
bool IsOpen(void) { return (socketDescM >= 0); } bool IsOpen(void) { return (socketDescM >= 0); }
bool Flush(void); bool Flush(void);
int Read(unsigned char *bufferAddrP, unsigned int bufferLenP); int Read(unsigned char *bufferAddrP, unsigned int bufferLenP);

53
tuner.c
View File

@ -55,12 +55,13 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
int i = SatipConfig.GetPortRangeStart() ? SatipConfig.GetPortRangeStop() - SatipConfig.GetPortRangeStart() - 1 : 100; int i = SatipConfig.GetPortRangeStart() ? SatipConfig.GetPortRangeStop() - SatipConfig.GetPortRangeStart() - 1 : 100;
int port = SatipConfig.GetPortRangeStart(); int port = SatipConfig.GetPortRangeStart();
while (i-- > 0) { while (i-- > 0) {
if (rtpM.Open(port) && rtcpM.Open(rtpM.Port() + 1)) // RTP must use an even port number
if (rtpM.Open(port) && (rtpM.Port() % 2 == 0) && rtcpM.Open(rtpM.Port() + 1))
break; break;
rtpM.Close(); rtpM.Close();
rtcpM.Close(); rtcpM.Close();
if (SatipConfig.GetPortRangeStart()) if (SatipConfig.GetPortRangeStart())
++port; port += 2;
} }
if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) { if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) {
error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM); error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM);
@ -223,7 +224,7 @@ bool cSatipTuner::Connect(void)
} }
else if (rtspM.Options(*connectionUri)) { else if (rtspM.Options(*connectionUri)) {
cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM); cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM);
bool useTcp = SatipConfig.GetUseRtpOverTcp() && nextServerM.IsValid() && nextServerM.IsQuirk(cSatipServer::eSatipQuirkRtpOverTcp); bool useTcp = SatipConfig.IsTransportModeRtpOverTcp() && nextServerM.IsValid() && nextServerM.IsQuirk(cSatipServer::eSatipQuirkRtpOverTcp);
// Flush any old content // Flush any old content
//rtpM.Flush(); //rtpM.Flush();
//rtcpM.Flush(); //rtcpM.Flush();
@ -296,6 +297,11 @@ void cSatipTuner::ProcessVideoData(u_char *bufferP, int lengthP)
reConnectM.Set(eConnectTimeoutMs); reConnectM.Set(eConnectTimeoutMs);
} }
void cSatipTuner::ProcessRtpData(u_char *bufferP, int lengthP)
{
rtpM.Process(bufferP, lengthP);
}
void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
{ {
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM); debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM);
@ -349,6 +355,11 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
reConnectM.Set(eConnectTimeoutMs); reConnectM.Set(eConnectTimeoutMs);
} }
void cSatipTuner::ProcessRtcpData(u_char *bufferP, int lengthP)
{
rtcpM.Process(bufferP, lengthP);
}
void cSatipTuner::SetStreamId(int streamIdP) void cSatipTuner::SetStreamId(int streamIdP)
{ {
cMutexLock MutexLock(&mutexM); cMutexLock MutexLock(&mutexM);
@ -366,6 +377,37 @@ void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs; timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
} }
void cSatipTuner::SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP)
{
cMutexLock MutexLock(&mutexM);
debug1("%s (%d, %d, %s, %s) [device %d]", __PRETTY_FUNCTION__, rtpPortP, rtcpPortP, streamAddrP, sourceAddrP, deviceIdM);
bool multicast = !isempty(streamAddrP);
// Adapt RTP to any transport media change
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) cString cSatipTuner::GetBaseUrl(const char *addressP, const int portP)
{ {
debug16("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, addressP, portP, deviceIdM); debug16("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, addressP, portP, deviceIdM);
@ -393,6 +435,9 @@ bool cSatipTuner::SetSource(cSatipServer *serverP, const int transponderP, const
streamAddrM = rtspM.RtspUnescapeString(*nextServerM.GetAddress()); streamAddrM = rtspM.RtspUnescapeString(*nextServerM.GetAddress());
streamParamM = rtspM.RtspUnescapeString(parameterP); streamParamM = rtspM.RtspUnescapeString(parameterP);
streamPortM = nextServerM.GetPort(); streamPortM = nextServerM.GetPort();
// Modify parameter if required
if (nextServerM.IsQuirk(cSatipServer::eSatipQuirkForcePilot) && strstr(parameterP, "msys=dvbs2") && !strstr(parameterP, "plts="))
streamParamM = rtspM.RtspUnescapeString(*cString::sprintf("%s&plts=on", parameterP));
// Reconnect // Reconnect
RequestState(tsSet, smExternal); RequestState(tsSet, smExternal);
} }
@ -643,5 +688,5 @@ cString cSatipTuner::GetSignalStatus(void)
cString cSatipTuner::GetInformation(void) cString cSatipTuner::GetInformation(void)
{ {
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); 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,8 +157,11 @@ public:
public: public:
virtual void ProcessVideoData(u_char *bufferP, int lengthP); virtual void ProcessVideoData(u_char *bufferP, int lengthP);
virtual void ProcessApplicationData(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 SetStreamId(int streamIdP);
virtual void SetSessionTimeout(const char *sessionP, int timeoutP); virtual void SetSessionTimeout(const char *sessionP, int timeoutP);
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP);
virtual int GetId(void); virtual int GetId(void);
}; };

View File

@ -14,8 +14,11 @@ public:
virtual ~cSatipTunerIf() {} virtual ~cSatipTunerIf() {}
virtual void ProcessVideoData(u_char *bufferP, int lengthP) = 0; virtual void ProcessVideoData(u_char *bufferP, int lengthP) = 0;
virtual void ProcessApplicationData(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 SetStreamId(int streamIdP) = 0;
virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0; virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0;
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP) = 0;
virtual int GetId(void) = 0; virtual int GetId(void) = 0;
private: private: