[vdr-plugin-satip] 02/06: New upstream version 2.2.4
Tobias Grimm
tiber-guest at moszumanska.debian.org
Sat Jan 7 11:37:58 UTC 2017
This is an automated email from the git hooks/post-receive script.
tiber-guest pushed a commit to branch master
in repository vdr-plugin-satip.
commit 8c82d5dc8b01d3b66e68c50ca3dfef32a1da6b00
Author: Tobias Grimm <etobi at debian.org>
Date: Tue Jan 3 19:57:48 2017 +0100
New upstream version 2.2.4
---
HISTORY | 12 ++
README | 20 +++-
common.h | 22 ++--
config.c | 3 +
config.h | 18 +++
device.c | 22 +++-
device.h | 1 +
deviceif.h | 1 +
discover.c | 77 +++++++++++--
discover.h | 19 +++-
msearch.c | 7 +-
msearch.h | 1 +
param.c | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
param.h | 1 +
po/ca_ES.po | 26 ++++-
po/de_DE.po | 39 +++++--
po/es_ES.po | 26 ++++-
po/fi_FI.po | 31 ++++-
poller.c | 2 +-
pollerif.h | 1 +
rtcp.c | 10 ++
rtcp.h | 1 +
rtp.c | 16 +++
rtp.h | 1 +
rtsp.c | 105 +++++++++++++++--
rtsp.h | 12 +-
satip.c | 80 +++++++++++--
sectionfilter.c | 13 +++
sectionfilter.h | 1 +
server.c | 196 ++++++++++++++++++++++++--------
server.h | 30 ++++-
setup.c | 28 ++++-
setup.h | 2 +
socket.c | 155 ++++++++++++++++++++++++-
socket.h | 11 +-
tuner.c | 117 +++++++++++++++----
tuner.h | 7 ++
tunerif.h | 3 +
38 files changed, 1277 insertions(+), 184 deletions(-)
diff --git a/HISTORY b/HISTORY
index c2af5dd..0166834 100644
--- a/HISTORY
+++ b/HISTORY
@@ -144,3 +144,15 @@ VDR Plugin 'satip' Revision History
- Reset the RTSP connection after any failed connect.
- Added tweaks for minisatip and Schwaiger MS41IP.
- Updated for vdr-2.3.1 (Thanks to Klaus Schmidinger).
+
+2016-12-18: Version 2.2.4
+
+- Updated German translation (Thanks to Frank Neumann).
+- Fixed Panasonic CXW804 support (Thanks to Tobias Grimm).
+- Fixed C++11 support (Thanks to Tobias Grimm).
+- Fixed server assigment with source validation (Thanks to Patrick Boettcher).
+- Added configurable RTP/RTCP ports (Thanks to chriszero).
+- Added support for X-SATIP-RTSP-Port header.
+- Added multicast and RTP-over-TCP support.
+- Added support for activating/deactivating server on-the-fly.
+- Extended command-line parameters for setting server quirks.
diff --git a/README b/README
index 49b0b38..0d414ab 100644
--- a/README
+++ b/README
@@ -52,9 +52,15 @@ separated list of "<ipaddress>|<model>|<description>" entries. The model
consists of a DVB system (DVBS2,DVBT2,DVBT,DVBC) and number of available
frontends separated by a hyphen:
-vdr -P 'satip -s <ipaddress>|<model>|<description>;...'
-vdr -P 'satip -s 192.168.0.1|DVBS2-2,DVBT2-2|Octo1'
-vdr -P 'satip -s 192.168.0.1|DVBS2-4|Octo1;192.168.0.2|DVBT2-4|Octo2'
+vdr -P 'satip -s <ipaddress>[:<port>]|<model>[:<filter>]|<description>[:<quirk>];...'
+vdr -P 'satip -s 192.168.0.1|DVBS2-2,DVBT2-2|OctopusNet'
+vdr -P 'satip -s 192.168.0.1|DVBS2-4|OctopusNet;192.168.0.2|DVBT2-4|minisatip:0x18'
+vdr -P 'satip -s 192.168.0.1:554|DVBS2-2:S19.2E|OctopusNet;192.168.0.2:8554|DVBS2-4:S19.2E,S1W|minisatip'
+
+The plugin accepts a "--portrange" (-p) command-line parameter, that can
+be used to manually specify the RTP & RTCP port range and therefore
+enables using the plugin through a NAT (e.g. Docker bridged network).
+A minimum of 2 ports per device is required.
SAT>IP satellite positions (aka. signal sources) shall be defined via
sources.conf. If the source description begins with a number, it's used
@@ -110,6 +116,11 @@ Setup menu:
"Disable filter" options which allow you
to disable the individual section filters.
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.
- [Yellow:Devices] Opens SAT>IP device status menu.
- [Blue:Info] Opens SAT>IP information/statistics menu.
@@ -125,6 +136,9 @@ Information menu:
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
result of invalid channel parameters or lack of free SAT>IP tuners.
diff --git a/common.h b/common.h
index ac9ea20..d5539a8 100644
--- a/common.h
+++ b/common.h
@@ -13,9 +13,11 @@
#include <vdr/config.h>
#include <vdr/i18n.h>
+#define SATIP_DEFAULT_RTSP_PORT 554
+
#define SATIP_MAX_DEVICES MAXDEVICES
-#define SATIP_BUFFER_SIZE KILOBYTE(1024)
+#define SATIP_BUFFER_SIZE KILOBYTE(2048)
#define SATIP_DEVICE_INFO_ALL 0
#define SATIP_DEVICE_INFO_GENERAL 1
@@ -48,15 +50,15 @@
esyslog("curl_easy_perform() [%s,%d] failed: %s (%d)", __FILE__, __LINE__, curl_easy_strerror(res), res); \
}
-#define ERROR_IF_FUNC(exp, errstr, func, ret) \
- do { \
- if (exp) { \
- char tmp[64]; \
- esyslog("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
- strerror_r(errno, tmp, sizeof(tmp))); \
- func; \
- ret; \
- } \
+#define ERROR_IF_FUNC(exp, errstr, func, ret) \
+ do { \
+ if (exp) { \
+ char tmp[64]; \
+ esyslog("[%s,%d]: " errstr ": %s", __FILE__, __LINE__, \
+ strerror_r(errno, tmp, sizeof(tmp))); \
+ func; \
+ ret; \
+ } \
} while (0)
diff --git a/config.c b/config.c
index 050453c..6743e9c 100644
--- a/config.c
+++ b/config.c
@@ -17,6 +17,9 @@ cSatipConfig::cSatipConfig(void)
ciExtensionM(0),
eitScanM(1),
useBytesM(1),
+ portRangeStartM(0),
+ portRangeStopM(0),
+ transportModeM(eTransportModeUnicast),
detachedModeM(false),
disableServerQuirksM(false),
useSingleModelServersM(false)
diff --git a/config.h b/config.h
index b7745cf..45503f6 100644
--- a/config.h
+++ b/config.h
@@ -19,6 +19,9 @@ private:
unsigned int ciExtensionM;
unsigned int eitScanM;
unsigned int useBytesM;
+ unsigned int portRangeStartM;
+ unsigned int portRangeStopM;
+ unsigned int transportModeM;
bool detachedModeM;
bool disableServerQuirksM;
bool useSingleModelServersM;
@@ -34,6 +37,12 @@ public:
eOperatingModeHigh,
eOperatingModeCount
};
+ enum eTransportMode {
+ eTransportModeUnicast = 0,
+ eTransportModeMulticast,
+ eTransportModeRtpOverTcp,
+ eTransportModeCount
+ };
enum eTraceMode {
eTraceModeNormal = 0x0000,
eTraceModeDebug1 = 0x0001,
@@ -67,6 +76,10 @@ public:
int GetCICAM(unsigned int indexP) const;
unsigned int GetEITScan(void) const { return eitScanM; }
unsigned int GetUseBytes(void) const { return useBytesM; }
+ 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 GetDisableServerQuirks(void) const { return disableServerQuirksM; }
bool GetUseSingleModelServers(void) const { return useSingleModelServersM; }
@@ -74,6 +87,8 @@ public:
int GetDisabledSources(unsigned int indexP) const;
unsigned int GetDisabledFiltersCount(void) const;
int GetDisabledFilters(unsigned int indexP) const;
+ unsigned int GetPortRangeStart(void) const { return portRangeStartM; }
+ unsigned int GetPortRangeStop(void) const { return portRangeStopM; }
void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; }
void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); }
@@ -81,11 +96,14 @@ public:
void SetCICAM(unsigned int indexP, int cicamP);
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; }
void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; }
+ void SetTransportMode(unsigned int transportModeP) { transportModeM = transportModeP; }
void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; }
void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; }
void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; }
void SetDisabledSources(unsigned int indexP, int sourceP);
void SetDisabledFilters(unsigned int indexP, int numberP);
+ void SetPortRangeStart(unsigned int rangeStartP) { portRangeStartM = rangeStartP; }
+ void SetPortRangeStop(unsigned int rangeStopP) { portRangeStopM = rangeStopP; }
};
extern cSatipConfig SatipConfig;
diff --git a/device.c b/device.c
index ad96434..ee8c1c5 100644
--- a/device.c
+++ b/device.c
@@ -120,8 +120,12 @@ cString cSatipDevice::GetSatipStatus(void)
info = cString::sprintf("%sCardIndex: %d HasLock: yes Strength: %d Quality: %d%s\n", *info, device->CardIndex(), device->SignalStrength(), device->SignalQuality(), live ? " Live: yes" : "");
else
info = cString::sprintf("%sCardIndex: %d HasLock: no\n", *info, device->CardIndex());
- if (channel && channel->Number() > 0)
- info = cString::sprintf("%sTransponder: %d Channel: %s\n", *info, (channel && channel->Number() > 0) ? channel->Transponder() : 0, (channel && channel->Number() > 0) ? channel->Name() : "---");
+ if (channel) {
+ if (channel->Number() > 0 && device->Receiving())
+ info = cString::sprintf("%sTransponder: %d Channel: %s\n", *info, channel->Transponder(), channel->Name());
+ else
+ info = cString::sprintf("%sTransponder: %d\n", *info, channel->Transponder());
+ }
if (timers)
info = cString::sprintf("%sRecording: %d timer%s\n", *info, timers, (timers > 1) ? "s" : "");
info = cString::sprintf("%s\n", *info);
@@ -136,7 +140,7 @@ cString cSatipDevice::GetGeneralInformation(void)
#if defined(APIVERSNUM) && APIVERSNUM >= 20301
LOCK_CHANNELS_READ;
#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(),
pTunerM ? *pTunerM->GetInformation() : "",
pTunerM ? *pTunerM->GetSignalStatus() : "",
@@ -206,6 +210,8 @@ cString cSatipDevice::DeviceType(void) const
cString cSatipDevice::DeviceName(void) const
{
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
+ if (!Receiving())
+ return cString::sprintf("%s %d", *DeviceType(), deviceIndexM);
return deviceNameM;
}
@@ -355,6 +361,7 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
}
else if (pTunerM) {
pTunerM->SetSource(NULL, 0, NULL, deviceIndexM);
+ deviceNameM = cString::sprintf("%s %d", *DeviceType(), deviceIndexM);
return true;
}
return false;
@@ -366,7 +373,7 @@ bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
if (pTunerM && handleP && handleP->pid >= 0) {
if (onP)
return pTunerM->SetPid(handleP->pid, typeP, true);
- else if (!handleP->used)
+ else if (!handleP->used && pSectionFilterHandlerM && !pSectionFilterHandlerM->Exists(handleP->pid))
return pTunerM->SetPid(handleP->pid, typeP, false);
}
return true;
@@ -472,6 +479,13 @@ int cSatipDevice::GetCISlot(void)
return slot;
}
+cString cSatipDevice::GetTnrParameterString(void)
+{
+ if (channelM.Ca())
+ return GetTnrUrlParameters(&channelM);
+ return NULL;
+}
+
bool cSatipDevice::IsIdle(void)
{
return !Receiving();
diff --git a/device.h b/device.h
index ad18e2f..983e24d 100644
--- a/device.h
+++ b/device.h
@@ -110,6 +110,7 @@ public:
virtual int GetId(void);
virtual int GetPmtPid(void);
virtual int GetCISlot(void);
+ virtual cString GetTnrParameterString(void);
virtual bool IsIdle(void);
};
diff --git a/deviceif.h b/deviceif.h
index b67bfe1..9fe1636 100644
--- a/deviceif.h
+++ b/deviceif.h
@@ -16,6 +16,7 @@ public:
virtual int GetId(void) = 0;
virtual int GetPmtPid(void) = 0;
virtual int GetCISlot(void) = 0;
+ virtual cString GetTnrParameterString(void) = 0;
virtual bool IsIdle(void) = 0;
private:
diff --git a/discover.c b/discover.c
index 990af68..7c128a8 100644
--- a/discover.c
+++ b/discover.c
@@ -32,7 +32,7 @@ bool cSatipDiscover::Initialize(cSatipDiscoverServers *serversP)
if (instanceS) {
if (serversP) {
for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s))
- instanceS->AddServer(s->IpAddress(), s->Model(), s->Description());
+ instanceS->AddServer(s->IpAddress(), s->IpPort(), s->Model(), s->Filters(), s->Description(), s->Quirk());
}
else
instanceS->Activate();
@@ -47,6 +47,18 @@ void cSatipDiscover::Destroy(void)
instanceS->Deactivate();
}
+size_t cSatipDiscover::HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
+{
+ cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
+ size_t len = sizeP * nmembP;
+ debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
+
+ if (obj && (len > 0))
+ obj->headerBufferM.Add(ptrP, len);
+
+ return len;
+}
+
size_t cSatipDiscover::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
{
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
@@ -91,6 +103,7 @@ int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *data
cSatipDiscover::cSatipDiscover()
: cThread("SATIP discover"),
mutexM(),
+ headerBufferM(),
dataBufferM(),
msearchM(*this),
probeUrlListM(),
@@ -176,7 +189,9 @@ void cSatipDiscover::Fetch(const char *urlP)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this);
- // Set callback
+ // Set header and data callbacks
+ SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipDiscover::HeaderCallback);
+ SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
@@ -199,7 +214,8 @@ void cSatipDiscover::Fetch(const char *urlP)
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_PRIMARY_IP, &addr);
if (rc == 200) {
- ParseDeviceInfo(addr);
+ ParseDeviceInfo(addr, ParseRtspPort());
+ headerBufferM.Reset();
dataBufferM.Reset();
}
else
@@ -207,9 +223,32 @@ void cSatipDiscover::Fetch(const char *urlP)
}
}
-void cSatipDiscover::ParseDeviceInfo(const char *addrP)
+int cSatipDiscover::ParseRtspPort(void)
{
- debug1("%s (%s)", __PRETTY_FUNCTION__, addrP);
+ debug1("%s", __PRETTY_FUNCTION__);
+ char *s, *p = headerBufferM.Data();
+ char *r = strtok_r(p, "\r\n", &s);
+ int port = SATIP_DEFAULT_RTSP_PORT;
+
+ while (r) {
+ debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r);
+ r = skipspace(r);
+ if (strstr(r, "X-SATIP-RTSP-Port")) {
+ int tmp = -1;
+ if (sscanf(r, "X-SATIP-RTSP-Port:%11d", &tmp) == 1) {
+ port = tmp;
+ break;
+ }
+ }
+ r = strtok_r(NULL, "\r\n", &s);
+ }
+
+ return port;
+}
+
+void cSatipDiscover::ParseDeviceInfo(const char *addrP, const int portP)
+{
+ debug1("%s (%s, %d)", __PRETTY_FUNCTION__, addrP, portP);
const char *desc = NULL, *model = NULL;
#ifdef USE_TINYXML
TiXmlDocument doc;
@@ -232,12 +271,12 @@ void cSatipDiscover::ParseDeviceInfo(const char *addrP)
model = modelNode.text().as_string("DVBS2-1");
}
#endif
- AddServer(addrP, model, desc);
+ AddServer(addrP, portP, model, NULL, desc, cSatipServer::eSatipQuirkNone);
}
-void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char * descP)
+void cSatipDiscover::AddServer(const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP)
{
- debug1("%s (%s, %s, %s)", __PRETTY_FUNCTION__, addrP, modelP, descP);
+ debug1("%s (%s, %d, %s, %s, %s, %d)", __PRETTY_FUNCTION__, addrP, portP, modelP, filtersP, descP, quirkP);
cMutexLock MutexLock(&mutexM);
if (SatipConfig.GetUseSingleModelServers() && modelP && !isempty(modelP)) {
int n = 0;
@@ -246,9 +285,9 @@ void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char
while (r) {
r = skipspace(r);
cString desc = cString::sprintf("%s #%d", !isempty(descP) ? descP : "MyBrokenHardware", n++);
- cSatipServer *tmp = new cSatipServer(addrP, r, desc);
+ cSatipServer *tmp = new cSatipServer(addrP, portP, r, filtersP, desc, quirkP);
if (!serversM.Update(tmp)) {
- info("Adding server '%s|%s|%s' CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
+ info("Adding server '%s|%s|%s' Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
serversM.Add(tmp);
}
else
@@ -258,9 +297,9 @@ void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char
FREE_POINTER(p);
}
else {
- cSatipServer *tmp = new cSatipServer(addrP, modelP, descP);
+ cSatipServer *tmp = new cSatipServer(addrP, portP, modelP, filtersP, descP, quirkP);
if (!serversM.Update(tmp)) {
- info("Adding server '%s|%s|%s' CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
+ info("Adding server '%s|%s|%s' Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
serversM.Add(tmp);
}
else
@@ -317,6 +356,13 @@ cString cSatipDiscover::GetServerList(void)
return serversM.List();
}
+void cSatipDiscover::ActivateServer(cSatipServer *serverP, bool onOffP)
+{
+ debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP);
+ cMutexLock MutexLock(&mutexM);
+ serversM.Activate(serverP, onOffP);
+}
+
void cSatipDiscover::AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP)
{
debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
@@ -352,6 +398,13 @@ cString cSatipDiscover::GetServerAddress(cSatipServer *serverP)
return serversM.GetAddress(serverP);
}
+int cSatipDiscover::GetServerPort(cSatipServer *serverP)
+{
+ debug16("%s", __PRETTY_FUNCTION__);
+ cMutexLock MutexLock(&mutexM);
+ return serversM.GetPort(serverP);
+}
+
int cSatipDiscover::NumProvidedSystems(void)
{
debug16("%s", __PRETTY_FUNCTION__);
diff --git a/discover.h b/discover.h
index 5942e42..52c3d30 100644
--- a/discover.h
+++ b/discover.h
@@ -21,16 +21,22 @@
class cSatipDiscoverServer : public cListObject {
private:
+ int ipPortM;
+ int quirkM;
cString ipAddressM;
cString descriptionM;
cString modelM;
+ cString filtersM;
public:
- cSatipDiscoverServer(const char *ipAddressP, const char *modelP, const char *descriptionP)
+ cSatipDiscoverServer(const char *ipAddressP, const int ipPortP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP)
{
- ipAddressM = ipAddressP; modelM = modelP; descriptionM = descriptionP;
+ ipAddressM = ipAddressP; ipPortM = ipPortP; modelM = modelP; filtersM = filtersP; descriptionM = descriptionP; quirkM = quirkP;
}
+ int IpPort(void) { return ipPortM; }
+ int Quirk(void) { return quirkM; }
const char *IpAddress(void) { return *ipAddressM; }
const char *Model(void) { return *modelM; }
+ const char *Filters(void) { return *filtersM; }
const char *Description(void) { return *descriptionM; }
};
@@ -47,9 +53,11 @@ private:
eCleanupTimeoutMs = 124000 // in milliseoonds
};
static cSatipDiscover *instanceS;
+ 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 int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
cMutex mutexM;
+ cSatipMemoryBuffer headerBufferM;
cSatipMemoryBuffer dataBufferM;
cSatipMsearch msearchM;
cStringList probeUrlListM;
@@ -59,8 +67,9 @@ private:
cSatipServers serversM;
void Activate(void);
void Deactivate(void);
- void ParseDeviceInfo(const char *addrP);
- void AddServer(const char *addrP, const char *modelP, const char *descP);
+ int ParseRtspPort(void);
+ void ParseDeviceInfo(const char *addrP, const int portP);
+ void AddServer(const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP);
void Fetch(const char *urlP);
// constructor
cSatipDiscover();
@@ -83,11 +92,13 @@ public:
cSatipServer *GetServer(cSatipServer *serverP);
cSatipServers *GetServers(void);
cString GetServerString(cSatipServer *serverP);
+ void ActivateServer(cSatipServer *serverP, bool onOffP);
void AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP);
void DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP);
bool IsServerQuirk(cSatipServer *serverP, int quirkP);
bool HasServerCI(cSatipServer *serverP);
cString GetServerAddress(cSatipServer *serverP);
+ int GetServerPort(cSatipServer *serverP);
cString GetServerList(void);
int NumProvidedSystems(void);
diff --git a/msearch.c b/msearch.c
index f5edafc..b137a05 100644
--- a/msearch.c
+++ b/msearch.c
@@ -29,7 +29,7 @@ cSatipMsearch::cSatipMsearch(cSatipDiscoverIf &discoverP)
memset(bufferM, 0, bufferLenM);
else
error("Cannot create Msearch buffer!");
- if (!Open(eDiscoveryPort))
+ if (!Open(eDiscoveryPort, true))
error("Cannot open Msearch port!");
}
@@ -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";
diff --git a/msearch.h b/msearch.h
index db00c86..73bd375 100644
--- a/msearch.h
+++ b/msearch.h
@@ -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;
};
diff --git a/param.c b/param.c
index c71902d..5104559 100644
--- a/param.c
+++ b/param.c
@@ -163,34 +163,344 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
dtp.SetModulation(QPSK);
dtp.SetRollOff(ROLLOFF_35);
}
+ if ((channelP->Rid() % 100) > 0)
+ q += snprintf(q, STBUFLEFT, "&fe=%d", channelP->Rid() % 100);
+ ST(" S *") q += snprintf(q, STBUFLEFT, "src=%d&", ((src > 0) && (src <= 255)) ? src : 1);
q += snprintf(q, STBUFLEFT, "freq=%s", *dtoa(freq, "%lg"));
- ST(" S *") q += snprintf(q, STBUFLEFT, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1);
- ST(" S *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
- ST("C 1") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization()));
- ST("C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId());
- ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", dtp.T2SystemId());
+ ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues);
ST("C 2") q += snprintf(q, STBUFLEFT, "&c2tft=%d", C2TuningFrequencyType);
- ST("C 2") q += snprintf(q, STBUFLEFT, "&ds=%d", DataSlice);
- ST("C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues);
- ST(" T2") q += PrintUrlString(q, STBUFLEFT, dtp.SisoMiso(), SatipSisoMisoValues);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues);
ST("C 2") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues);
- ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(), SatipGuardValues);
- ST("CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(), SatipCodeRateValues);
- ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Pilot(), SatipPilotValues);
- ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
- ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
- ST("C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
- ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues);
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesSat);
ST("C *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesCable);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesTerrestrial);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues);
- if ((channelP->Rid() % 100) > 0)
- snprintf(q, STBUFLEFT, "&fe=%d", channelP->Rid() % 100);
+ ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
+ ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
+ ST("C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
+ ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Pilot(), SatipPilotValues);
+ ST(" S *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
+ ST("C 1") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
+ ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(), SatipGuardValues);
+ ST("CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(), SatipCodeRateValues);
+ ST("C 2") q += snprintf(q, STBUFLEFT, "&ds=%d", DataSlice);
+ ST("C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId());
+ ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", dtp.T2SystemId());
+ ST(" T2") q += PrintUrlString(q, STBUFLEFT, dtp.SisoMiso(), SatipSisoMisoValues);
+ ST("C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues);
#undef ST
return buffer;
}
return NULL;
}
+
+cString GetTnrUrlParameters(const cChannel *channelP)
+{
+ if (channelP) {
+ cDvbTransponderParameters dtp(channelP->Parameters());
+ eTrackType track = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
+
+ // TunerType: Byte;
+ // 0 = cable, 1 = satellite, 2 = terrestrial, 3 = atsc, 4 = iptv, 5 = stream (URL, DVBViewer GE)
+ int TunerType = 0;
+ if (channelP->IsCable())
+ TunerType = 0;
+ else if (channelP->IsSat())
+ TunerType = 1;
+ else if (channelP->IsTerr())
+ TunerType = 2;
+ else if (channelP->IsAtsc())
+ TunerType = 3;
+
+ // Frequency: DWord;
+ // DVB-S: MHz if < 1000000, kHz if >= 1000000
+ // DVB-T/C, ATSC: kHz
+ // IPTV: IP address Byte3.Byte2.Byte1.Byte0
+ int Frequency = channelP->Frequency() / 1000;
+
+ // Symbolrate: DWord;
+ // DVB S/C: in kSym/s
+ // DVB-T, ATSC: 0
+ // IPTV: Port
+ int Symbolrate = (channelP->IsSat() || channelP->IsCable()) ? channelP->Srate() : 0;
+
+ // LNB_LOF: Word;
+ // DVB-S: Local oscillator frequency of the LNB
+ // DVB-T/C, ATSC: 0
+ // IPTV: Byte0 and Byte1 of Source IP
+ int LNB_LOF = channelP->IsSat() ? Setup.LnbSLOF : 0;
+
+ // Tone: Byte;
+ // 0 = off, 1 = 22 khz
+ int Tone = (channelP->Frequency() < Setup.LnbSLOF) ? 0 : 1;
+
+ // Polarity: Byte;
+ // DVB-S polarity: 0 = horizontal, 1 = vertical, 2 = circular left, 3 = circular right
+ // DVB-C modulation: 0 = Auto, 1 = 16QAM, 2 = 32QAM, 3 = 64QAM, 4 = 128QAM, 5 = 256 QAM
+ // DVB-T bandwidth: 0 = 6 MHz, 1 = 7 MHz, 2 = 8 MHz
+ // IPTV: Byte3 of SourceIP
+ int Polarity = 0;
+ if (channelP->IsSat()) {
+ switch (tolower(dtp.Polarization())) {
+ case 'h':
+ Polarity = 0;
+ break;
+ case 'v':
+ Polarity = 1;
+ break;
+ case 'l':
+ Polarity = 2;
+ break;
+ case 'r':
+ Polarity = 3;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (channelP->IsCable()) {
+ switch (dtp.Modulation()) {
+ case 999:
+ Polarity = 0;
+ break;
+ case 16:
+ Polarity = 1;
+ break;
+ case 32:
+ Polarity = 2;
+ break;
+ case 64:
+ Polarity = 3;
+ break;
+ case 128:
+ Polarity = 4;
+ break;
+ case 256:
+ Polarity = 5;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (channelP->IsTerr()) {
+ switch (dtp.Bandwidth()) {
+ case 6:
+ Polarity = 0;
+ break;
+ case 7:
+ Polarity = 1;
+ break;
+ case 8:
+ Polarity = 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // DiSEqC: Byte;
+ // 0 = None
+ // 1 = Pos A (mostly translated to PosA/OptA)
+ // 2 = Pos B (mostly translated to PosB/OptA)
+ // 3 = PosA/OptA
+ // 4 = PosB/OptA
+ // 5 = PosA/OptB
+ // 6 = PosB/OptB
+ // 7 = Preset Position (DiSEqC 1.2, see DiSEqCExt)
+ // 8 = Angular Position (DiSEqC 1.2, see DiSEqCExt)
+ // 9 = DiSEqC Command Sequence (see DiSEqCExt)
+ int DiSEqC = 0;
+
+ // FEC: Byte;
+ // 0 = Auto
+ // 1 = 1/2
+ // 2 = 2/3
+ // 3 = 3/4
+ // 4 = 5/6
+ // 5 = 7/8
+ // 6 = 8/9
+ // 7 = 3/5
+ // 8 = 4/5
+ // 9 = 9/10
+ // IPTV: Byte2 of SourceIP
+ // DVB C/T, ATSC: 0
+ int FEC = 0;
+ if (channelP->IsSat()) {
+ switch (dtp.CoderateH()) {
+ case 999:
+ FEC = 0;
+ break;
+ case 12:
+ FEC = 1;
+ break;
+ case 23:
+ FEC = 2;
+ break;
+ case 34:
+ FEC = 3;
+ break;
+ case 56:
+ FEC = 4;
+ break;
+ case 78:
+ FEC = 5;
+ break;
+ case 89:
+ FEC = 6;
+ break;
+ case 35:
+ FEC = 7;
+ break;
+ case 45:
+ FEC = 8;
+ break;
+ case 910:
+ FEC = 9;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Audio_PID: Word;
+ int Audio_PID = channelP->Apid(0);
+ if (IS_AUDIO_TRACK(track))
+ Audio_PID = channelP->Apid(int(track - ttAudioFirst));
+ else if (IS_DOLBY_TRACK(track))
+ Audio_PID = channelP->Dpid(int(track - ttDolbyFirst));
+
+ // Video_PID: Word;
+ int Video_PID = channelP->Vpid();
+
+ // PMT_PID: Word;
+ int PMT_PID = channelP->Ppid();
+
+ // Service_ID: Word;
+ int Service_ID = channelP->Sid();
+
+ // SatModulation: Byte;
+ // Bit 0..1: satellite modulation. 0 = Auto, 1 = QPSK, 2 = 8PSK, 3 = 16QAM or APSK for DVB-S2
+ // Bit 2: modulation system. 0 = DVB-S/T/C, 1 = DVB-S2/T2/C2
+ // Bit 3..4: DVB-S2: roll-off. 0 = 0.35, 1 = 0.25, 2 = 0.20, 3 = reserved
+ // Bit 5..6: spectral inversion, 0 = undefined, 1 = auto, 2 = normal, 3 = inverted
+ // Bit 7: DVB-S2: pilot symbols, 0 = off, 1 = on
+ // DVB-T2: DVB-T2 Lite, 0 = off, 1 = on
+ int SatModulation = 0;
+ if (channelP->IsSat() && dtp.System()) {
+ switch (dtp.Modulation()) {
+ case 999:
+ SatModulation |= (0 & 0x3) << 0;
+ break;
+ case 2:
+ SatModulation |= (1 & 0x3) << 0;
+ break;
+ case 5:
+ SatModulation |= (2 & 0x3) << 0;
+ break;
+ case 6:
+ SatModulation |= (3 & 0x3) << 0;
+ break;
+ default:
+ break;
+ }
+ }
+ SatModulation |= (dtp.System() & 0x1) << 2;
+ if (channelP->IsSat() && dtp.System()) {
+ switch (dtp.RollOff()) {
+ case 35:
+ SatModulation |= (0 & 0x3) << 3;
+ break;
+ case 25:
+ SatModulation |= (1 & 0x3) << 3;
+ break;
+ case 20:
+ SatModulation |= (2 & 0x3) << 3;
+ break;
+ default:
+ break;
+ }
+ }
+ switch (dtp.Inversion()) {
+ case 999:
+ SatModulation |= (1 & 0x3) << 5;
+ break;
+ case 0:
+ SatModulation |= (2 & 0x3) << 5;
+ break;
+ case 1:
+ SatModulation |= (3 & 0x3) << 5;
+ break;
+ default:
+ break;
+ }
+ if (channelP->IsSat() && dtp.System()) {
+ switch (dtp.Pilot()) {
+ case 0:
+ SatModulation |= (0 & 0x1) << 7;
+ break;
+ case 1:
+ SatModulation |= (1 & 0x1) << 7;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // DiSEqCExt: Word;
+ // DiSEqC Extension, meaning depends on DiSEqC
+ // DiSEqC = 0..6: 0
+ // DiSEqC = 7: Preset Position (DiSEqC 1.2)
+ // DiSEqC = 8: Orbital Position (DiSEqC 1.2, USALS, for calculating motor angle)
+ // Same format as OrbitalPos above
+ // DiSEQC = 9: Orbital Position referencing DiSEqC sequence defined in DiSEqC.xml/ini
+ // Same format as OrbitalPos above
+ int DiSEqCExt = 0;
+
+ // Flags: Byte;
+ // Bit 0: 1 = encrypted channel
+ // Bit 1: reserved, set to 0
+ // Bit 2: 1 = channel broadcasts RDS data
+ // Bit 3: 1 = channel is a video service (even if the Video PID is temporarily = 0)
+ // Bit 4: 1 = channel is an audio service (even if the Audio PID is temporarily = 0)
+ // Bit 5: 1 = audio has a different samplerate than 48 KHz
+ // Bit 6: 1 = bandstacking, internally polarisation is always set to H
+ // Bit 7: 1 = channel entry is an additional audio track of the preceding
+ // channel with bit 7 = 0
+ int Flags = (channelP->Ca() > 0xFF) ? 1 : 0;
+
+ // ChannelGroup: Byte;
+ // 0 = Group A, 1 = Group B, 2 = Group C etc.
+ int ChannelGroup = 0;
+
+ // TransportStream_ID: Word;
+ int TransportStream_ID = channelP->Tid();
+
+ // OriginalNetwork_ID: Word;
+ int OriginalNetwork_ID = channelP->Nid();
+
+ // Substream: Word;
+ // DVB-S/C/T, ATSC, IPTV: 0
+ // DVB-T2: 0 = PLP_ID not set, 1..256: PLP_ID + 1, 257... reserved
+ int Substream = (channelP->IsTerr() && dtp.System()) ? dtp.StreamId() - 1 : 0;
+
+ // OrbitalPos: Word;
+ // DVB-S: orbital position x 10, 0 = undefined, 1..1800 east, 1801..3599 west (1°W = 3599)
+ // DVB-C: 4000..4999
+ // DVB-T: 5000..5999
+ // ATSC: 6000..6999
+ // IPTV: 7000..7999
+ // Stream: 8000..8999
+ int OrbitalPos = 0;
+ if (channelP->IsSat()) {
+ OrbitalPos = cSource::Position(channelP->Source());
+ if (OrbitalPos != 3600)
+ OrbitalPos += 1800;
+ }
+
+ return cString::sprintf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ TunerType, Frequency, Symbolrate, LNB_LOF, Tone, Polarity, DiSEqC, FEC, Audio_PID, Video_PID, PMT_PID, Service_ID,
+ SatModulation, DiSEqCExt, Flags, ChannelGroup, TransportStream_ID, OriginalNetwork_ID, Substream, OrbitalPos);
+ }
+ return NULL;
+}
diff --git a/param.h b/param.h
index ae68578..82de1b3 100644
--- a/param.h
+++ b/param.h
@@ -11,5 +11,6 @@
#include "common.h"
cString GetTransponderUrlParameters(const cChannel *channelP);
+cString GetTnrUrlParameters(const cChannel *channelP);
#endif // __SATIP_PARAM_H
diff --git a/po/ca_ES.po b/po/ca_ES.po
index 653f8fe..5627c62 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -1,14 +1,14 @@
# 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.
# Gabriel Bonich, 2014-2015
#
msgid ""
msgstr ""
-"Project-Id-Version: vdr-satip 2.2.3\n"
+"Project-Id-Version: vdr-satip 2.2.4\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-04-26 04:26+0300\n"
-"PO-Revision-Date: 2015-04-26 04:26+0300\n"
+"POT-Creation-Date: 2016-12-18 12:18+0200\n"
+"PO-Revision-Date: 2016-12-18 12:18+0200\n"
"Last-Translator: Gabriel Bonich <gbonich at gmail.com>\n"
"Language-Team: Catalan <vdr at linuxtv.org>\n"
"Language: ca\n"
@@ -85,6 +85,15 @@ msgstr "Normal"
msgid "high"
msgstr "Alt"
+msgid "Unicast"
+msgstr ""
+
+msgid "Multicast"
+msgstr ""
+
+msgid "RTP-over-TCP"
+msgstr ""
+
msgid "Button$Devices"
msgstr "Dispositius"
@@ -178,6 +187,15 @@ msgstr "Filtra"
msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Definir un filtre mal comportar a la llista negra."
+msgid "Transport mode"
+msgstr ""
+
+msgid ""
+"Define which transport mode shall be used.\n"
+"\n"
+"Unicast, Multicast, RTP-over-TCP"
+msgstr ""
+
msgid "Active SAT>IP servers:"
msgstr "Activa SAT>IP servers:"
diff --git a/po/de_DE.po b/po/de_DE.po
index b1794cd..e7c66fd 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -1,14 +1,14 @@
# 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.
-# Frank Neumann, 2014-2015
+# Frank Neumann, 2014-2016
#
msgid ""
msgstr ""
-"Project-Id-Version: vdr-satip 2.2.3\n"
+"Project-Id-Version: vdr-satip 2.2.4\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-04-26 04:26+0300\n"
-"PO-Revision-Date: 2015-04-26 04:26+0300\n"
+"POT-Creation-Date: 2016-12-18 12:18+0200\n"
+"PO-Revision-Date: 2016-12-18 12:18+0200\n"
"Last-Translator: Frank Neumann <fnu at yavdr.org>\n"
"Language-Team: German <vdr at linuxtv.org>\n"
"Language: de\n"
@@ -85,11 +85,20 @@ msgstr "normal"
msgid "high"
msgstr "hoch"
+msgid "Unicast"
+msgstr "Unicast"
+
+msgid "Multicast"
+msgstr "Multicast"
+
+msgid "RTP-over-TCP"
+msgstr "RTP-over-TCP"
+
msgid "Button$Devices"
msgstr "Geräte"
msgid "Operating mode"
-msgstr "Betriebsmodus"
+msgstr "Betriebsart"
msgid ""
"Define the used operating mode for all SAT>IP devices:\n"
@@ -99,7 +108,7 @@ msgid ""
"normal - devices are working within normal parameters\n"
"high - devices are working at the highest priority"
msgstr ""
-"Bestimme den Betriebsmodus für alle SAT>IP Geräte:\n"
+"Bestimme die Betriebsart für alle SAT>IP Geräte:\n"
"\n"
"aus - Geräte sind abgeschaltet\n"
"niedrig - Geräte arbeiten mit geringster Priorität\n"
@@ -170,13 +179,25 @@ msgid ""
msgstr ""
"Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\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"
msgstr "Filter"
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 "Transport mode"
+msgstr "Übertragungsart"
+
+msgid ""
+"Define which transport mode shall be used.\n"
+"\n"
+"Unicast, Multicast, RTP-over-TCP"
+msgstr ""
+"Lege die gewünschte Übertragungsart fest.\n"
+"\n"
+"Unicast, Multicast, RTP-over-TCP"
msgid "Active SAT>IP servers:"
msgstr "Aktive SAT>IP Server:"
diff --git a/po/es_ES.po b/po/es_ES.po
index dbc27d3..39353be 100644
--- a/po/es_ES.po
+++ b/po/es_ES.po
@@ -1,14 +1,14 @@
# 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.
# Gabriel Bonich, 2014-2015
#
msgid ""
msgstr ""
-"Project-Id-Version: vdr-satip 2.2.3\n"
+"Project-Id-Version: vdr-satip 2.2.4\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-04-26 04:26+0300\n"
-"PO-Revision-Date: 2015-04-26 04:26+0300\n"
+"POT-Creation-Date: 2016-12-18 12:18+0200\n"
+"PO-Revision-Date: 2016-12-18 12:18+0200\n"
"Last-Translator: Gabriel Bonich <gbonich at gmail.com>\n"
"Language-Team: Spanish <vdr at linuxtv.org>\n"
"Language: es\n"
@@ -85,6 +85,15 @@ msgstr "Normal"
msgid "high"
msgstr "Alto"
+msgid "Unicast"
+msgstr ""
+
+msgid "Multicast"
+msgstr ""
+
+msgid "RTP-over-TCP"
+msgstr ""
+
msgid "Button$Devices"
msgstr "Dispositivos"
@@ -178,6 +187,15 @@ msgstr "Filtra"
msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Define un filtro para poner en la lista negra."
+msgid "Transport mode"
+msgstr ""
+
+msgid ""
+"Define which transport mode shall be used.\n"
+"\n"
+"Unicast, Multicast, RTP-over-TCP"
+msgstr ""
+
msgid "Active SAT>IP servers:"
msgstr "Activa SAT>IP servers:"
diff --git a/po/fi_FI.po b/po/fi_FI.po
index fbad1b1..aa8e173 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -1,14 +1,14 @@
# 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.
-# Rolf Ahrenberg, 2015
+# Rolf Ahrenberg, 2015-2016
#
msgid ""
msgstr ""
-"Project-Id-Version: vdr-satip 2.2.3\n"
+"Project-Id-Version: vdr-satip 2.2.4\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-04-26 04:26+0300\n"
-"PO-Revision-Date: 2015-04-26 04:26+0300\n"
+"POT-Creation-Date: 2016-12-18 12:18+0200\n"
+"PO-Revision-Date: 2016-12-18 12:18+0200\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr at linuxtv.org>\n"
"Language: fi\n"
@@ -85,6 +85,15 @@ msgstr "normaali"
msgid "high"
msgstr "korkea"
+msgid "Unicast"
+msgstr "Unicast"
+
+msgid "Multicast"
+msgstr "Multicast"
+
+msgid "RTP-over-TCP"
+msgstr "RTP-over-TCP"
+
msgid "Button$Devices"
msgstr "Laitteet"
@@ -177,6 +186,18 @@ msgstr "Suodatin"
msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle."
+msgid "Transport mode"
+msgstr "Siirtoyhteystapa"
+
+msgid ""
+"Define which transport mode shall be used.\n"
+"\n"
+"Unicast, Multicast, RTP-over-TCP"
+msgstr ""
+"Määrittele käytettävä siirtoyhteystapa.\n"
+"\n"
+"Unicast, Multicast, RTP-over-TCP"
+
msgid "Active SAT>IP servers:"
msgstr "Aktiiviset SAT>IP-palvelimet:"
diff --git a/poller.c b/poller.c
index 4058321..eeff216 100644
--- a/poller.c
+++ b/poller.c
@@ -79,7 +79,7 @@ void cSatipPoller::Action(void)
// Do the thread loop
while (Running()) {
int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, -1);
- ERROR_IF_FUNC((nfds == -1), "epoll_wait() failed", break, ;);
+ ERROR_IF_FUNC((nfds == -1 && errno != EINTR), "epoll_wait() failed", break, ;);
for (int i = 0; i < nfds; ++i) {
cSatipPollerIf* poll = reinterpret_cast<cSatipPollerIf *>(events[i].data.ptr);
if (poll) {
diff --git a/pollerif.h b/pollerif.h
index 3447871..67d33fb 100644
--- a/pollerif.h
+++ b/pollerif.h
@@ -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:
diff --git a/rtcp.c b/rtcp.c
index c815287..a89640c 100644
--- a/rtcp.c
+++ b/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());
diff --git a/rtcp.h b/rtcp.h
index 59fb176..898b310 100644
--- a/rtcp.h
+++ b/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;
};
diff --git a/rtp.c b/rtp.c
index 0be033a..03ee267 100644
--- a/rtp.c
+++ b/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());
diff --git a/rtp.h b/rtp.h
index 104a49c..56071f9 100644
--- a/rtp.h
+++ b/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;
};
diff --git a/rtsp.c b/rtsp.c
index 562626e..87c194a 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -17,12 +17,14 @@ cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP)
: tunerM(tunerP),
headerBufferM(),
dataBufferM(),
- modeM(cmUnicast),
handleM(NULL),
headerListM(NULL),
errorNoMoreM(""),
errorOutOfRangeM(""),
- errorCheckSyntaxM("")
+ errorCheckSyntaxM(""),
+ modeM(cSatipConfig::eTransportModeUnicast),
+ interleavedRtpIdM(0),
+ interleavedRtcpIdM(1)
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
Create();
@@ -58,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);
@@ -87,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());
@@ -123,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()));
}
@@ -171,9 +215,9 @@ bool cSatipRtsp::Options(const char *uriP)
return result;
}
-bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP)
+bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTcpP)
{
- debug1("%s (%s, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, tunerM.GetId());
+ debug1("%s (%s, %d, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, useTcpP, tunerM.GetId());
bool result = false;
if (handleM && !isempty(uriP)) {
@@ -182,15 +226,18 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP)
cTimeMs processing(0);
CURLcode res = CURLE_OK;
- switch (modeM) {
- case cmMulticast:
- // RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl>
- transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP);
+ switch (SatipConfig.GetTransportMode()) {
+ case cSatipConfig::eTransportModeMulticast:
+ // RTP/AVP;multicast;destination=<multicast group address>;port=<RTP port>-<RTCP port>;ttl=<ttl>[;source=<multicast source address>]
+ transport = cString::sprintf("RTP/AVP;multicast");
break;
default:
- case cmUnicast:
// RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port>
- transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP);
+ // RTP/AVP/TCP;unicast;client_port=<client RTP port>-<client RTCP port>
+ 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;
}
@@ -203,6 +250,9 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP)
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);
@@ -310,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,6 +403,35 @@ void cSatipRtsp::ParseHeader(void)
tunerM.SetSessionTimeout(skipspace(session), -1);
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);
}
}
@@ -418,10 +499,12 @@ bool cSatipRtsp::ValidateLatestResponse(long *rcP)
// SETUP PLAY TEARDOWN
// The message body of the response may contain the "Out-of-Range:" parameter followed
// by a space-separated list of the attribute names that are not understood:
- // "src" "fe" "freq" "pol" "msys" "mtype" "plts" "ro" "sr" "fec" "pids" "addpids" "delpids" "mcast
+ // "src" "fe" "freq" "pol" "msys" "mtype" "plts" "ro" "sr" "fec" "pids" "addpids" "delpids" "mcast"
if (!isempty(*errorOutOfRangeM)) {
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("Out of range: %s (error code %ld: %s) [device %d]", *errorOutOfRangeM, rc, url, tunerM.GetId());
+ // Reseting the connection wouldn't help anything due to invalid channel configuration, so let it be successful
+ result = true;
break;
}
case 503:
diff --git a/rtsp.h b/rtsp.h
index 1897ac6..fb09c27 100644
--- a/rtsp.h
+++ b/rtsp.h
@@ -22,22 +22,25 @@ 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
};
- enum eCommunicationMode { cmUnicast, cmMulticast };
cSatipTunerIf &tunerM;
cSatipMemoryBuffer headerBufferM;
cSatipMemoryBuffer dataBufferM;
- eCommunicationMode modeM;
CURL *handleM;
struct curl_slist *headerListM;
cString errorNoMoreM;
cString errorOutOfRangeM;
cString errorCheckSyntaxM;
+ int modeM;
+ unsigned int interleavedRtpIdM;
+ unsigned int interleavedRtcpIdM;
void Create(void);
void Destroy(void);
@@ -53,10 +56,11 @@ public:
explicit cSatipRtsp(cSatipTunerIf &tunerP);
virtual ~cSatipRtsp();
+ cString GetActiveMode(void);
cString RtspUnescapeString(const char *strP);
void Reset(void);
bool Options(const char *uriP);
- bool Setup(const char *uriP, int rtpPortP, int rtcpPortP);
+ bool Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTcpP);
bool SetSession(const char *sessionP);
bool Describe(const char *uriP);
bool Play(const char *uriP);
diff --git a/satip.c b/satip.c
index 3453c48..089c3e2 100644
--- a/satip.c
+++ b/satip.c
@@ -27,7 +27,7 @@
#define GITVERSION ""
#endif
- const char VERSION[] = "2.2.3" GITVERSION;
+ const char VERSION[] = "2.2.4" GITVERSION;
static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
class cPluginSatip : public cPlugin {
@@ -35,6 +35,7 @@ private:
unsigned int deviceCountM;
cSatipDiscoverServers *serversM;
void ParseServer(const char *paramP);
+ void ParsePortRange(const char *paramP);
int ParseCicams(const char *valueP, int *cicamsP);
int ParseSources(const char *valueP, int *sourcesP);
int ParseFilters(const char *valueP, int *filtersP);
@@ -83,11 +84,13 @@ const char *cPluginSatip::CommandLineHelp(void)
// Return a string that describes all known command line options.
return " -d <num>, --devices=<number> set number of devices to be created\n"
" -t <mode>, --trace=<mode> set the tracing mode\n"
- " -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>|<model2>|<desc2>\n"
+ " -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>:<port>|<model2>:<filter>|<desc2>:<quirk>\n"
" define hard-coded SAT>IP server(s)\n"
" -D, --detach set the detached mode on\n"
" -S, --single set the single model server mode on\n"
- " -n, --noquirks disable all the server quirks\n";
+ " -n, --noquirks disable autodetection of the server quirks\n"
+ " -p, --portrange=<start>-<end> set a range of ports used for the RT[C]P server\n"
+ " a minimum of 2 ports per device is required.\n";
}
bool cPluginSatip::ProcessArgs(int argc, char *argv[])
@@ -98,6 +101,7 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
{ "devices", required_argument, NULL, 'd' },
{ "trace", required_argument, NULL, 't' },
{ "server", required_argument, NULL, 's' },
+ { "portrange",required_argument, NULL, 'p' },
{ "detach", no_argument, NULL, 'D' },
{ "single", no_argument, NULL, 'S' },
{ "noquirks", no_argument, NULL, 'n' },
@@ -105,8 +109,9 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
};
cString server;
+ cString portrange;
int c;
- while ((c = getopt_long(argc, argv, "d:t:s:DSn", long_options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "d:t:s:p:DSn", long_options, NULL)) != -1) {
switch (c) {
case 'd':
deviceCountM = strtol(optarg, NULL, 0);
@@ -126,10 +131,15 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
case 'n':
SatipConfig.SetDisableServerQuirks(true);
break;
+ case 'p':
+ portrange = optarg;
+ break;
default:
return false;
}
}
+ if (!isempty(*portrange))
+ ParsePortRange(portrange);
// this must be done after all parameters are parsed
if (!isempty(*server))
ParseServer(*server);
@@ -222,7 +232,9 @@ void cPluginSatip::ParseServer(const char *paramP)
while (r) {
r = skipspace(r);
debug3("%s server[%d]=%s", __PRETTY_FUNCTION__, n, r);
- cString serverAddr, serverModel, serverDescription;
+ cString serverAddr, serverModel, serverFilters, serverDescription;
+ int serverQuirk = cSatipServer::eSatipQuirkNone;
+ int serverPort = SATIP_DEFAULT_RTSP_PORT;
int n2 = 0;
char *s2, *p2 = r;
char *r2 = strtok_r(p2, "|", &s2);
@@ -230,13 +242,34 @@ void cPluginSatip::ParseServer(const char *paramP)
debug3("%s param[%d]=%s", __PRETTY_FUNCTION__, n2, r2);
switch (n2++) {
case 0:
+ {
serverAddr = r2;
+ char *r3 = strchr(r2, ':');
+ if (r3) {
+ serverPort = strtol(r3 + 1, NULL, 0);
+ serverAddr = serverAddr.Truncate(r3 - r2);
+ }
+ }
break;
case 1:
+ {
serverModel = r2;
+ char *r3 = strchr(r2, ':');
+ if (r3) {
+ serverFilters = r3 + 1;
+ serverModel = serverModel.Truncate(r3 - r2);
+ }
+ }
break;
case 2:
+ {
serverDescription = r2;
+ char *r3 = strchr(r2, ':');
+ if (r3) {
+ serverQuirk = strtol(r3 + 1, NULL, 0);
+ serverDescription = serverDescription.Truncate(r3 - r2);
+ }
+ }
break;
default:
break;
@@ -244,10 +277,10 @@ void cPluginSatip::ParseServer(const char *paramP)
r2 = strtok_r(NULL, "|", &s2);
}
if (*serverAddr && *serverModel && *serverDescription) {
- debug1("%s ipaddr=%s model=%s desc=%s", __PRETTY_FUNCTION__, *serverAddr, *serverModel, *serverDescription);
+ debug1("%s ipaddr=%s port=%d model=%s (%s) desc=%s (%d)", __PRETTY_FUNCTION__, *serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk);
if (!serversM)
serversM = new cSatipDiscoverServers();
- serversM->Add(new cSatipDiscoverServer(*serverAddr, *serverModel, *serverDescription));
+ serversM->Add(new cSatipDiscoverServer(*serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk));
}
++n;
r = strtok_r(NULL, ";", &s);
@@ -255,6 +288,37 @@ void cPluginSatip::ParseServer(const char *paramP)
FREE_POINTER(p);
}
+void cPluginSatip::ParsePortRange(const char *paramP)
+{
+ char *s, *p = skipspace(paramP);
+ char *r = strtok_r(p, "-", &s);
+ unsigned int rangeStart = 0;
+ unsigned int rangeStop = 0;
+ if (r) {
+ rangeStart = strtol(r, NULL, 0);
+ r = strtok_r(NULL, "-", &s);
+ }
+ if (r)
+ rangeStop = strtol(r, NULL, 0);
+ else {
+ error("Port range argument not valid '%s'", paramP);
+ rangeStart = 0;
+ rangeStop = 0;
+ }
+ 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);
+ rangeStart = 0;
+ rangeStop = 0;
+ }
+ SatipConfig.SetPortRangeStart(rangeStart);
+ SatipConfig.SetPortRangeStop(rangeStop);
+}
+
int cPluginSatip::ParseCicams(const char *valueP, int *cicamsP)
{
debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP);
@@ -342,6 +406,8 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
for (unsigned int i = 0; i < DisabledFiltersCount; ++i)
SatipConfig.SetDisabledFilters(i, DisabledFilters[i]);
}
+ else if (!strcasecmp(nameP, "TransportMode"))
+ SatipConfig.SetTransportMode(atoi(valueP));
else
return false;
return true;
diff --git a/sectionfilter.c b/sectionfilter.c
index edf0382..10f655b 100644
--- a/sectionfilter.c
+++ b/sectionfilter.c
@@ -338,6 +338,19 @@ cString cSatipSectionFilterHandler::GetInformation(void)
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)
{
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);
diff --git a/sectionfilter.h b/sectionfilter.h
index e25c897..833511c 100644
--- a/sectionfilter.h
+++ b/sectionfilter.h
@@ -80,6 +80,7 @@ public:
cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP);
virtual ~cSatipSectionFilterHandler();
cString GetInformation(void);
+ bool Exists(u_short pidP);
int Open(u_short pidP, u_char tidP, u_char maskP);
void Close(int handleP);
int GetPid(int handleP);
diff --git a/server.c b/server.c
index b732b3b..01613a4 100644
--- a/server.c
+++ b/server.c
@@ -80,16 +80,38 @@ bool cSatipFrontends::Detach(int deviceIdP, int transponderP)
// --- cSatipServer -----------------------------------------------------------
-cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char *descriptionP)
+cSatipServer::cSatipServer(const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP)
: addressM((addressP && *addressP) ? addressP : "0.0.0.0"),
modelM((modelP && *modelP) ? modelP : "DVBS-1"),
+ filtersM((filtersP && *filtersP) ? filtersP : ""),
descriptionM(!isempty(descriptionP) ? descriptionP : "MyBrokenHardware"),
quirksM(""),
- quirkM(eSatipQuirkNone),
+ portM(portP),
+ quirkM(quirkP),
hasCiM(false),
+ activeM(true),
createdM(time(NULL)),
lastSeenM(0)
{
+ memset(sourceFiltersM, 0, sizeof(sourceFiltersM));
+ if (!isempty(*filtersM)) {
+ char *s, *p = strdup(*filtersM);
+ char *r = strtok_r(p, ",", &s);
+ unsigned int i = 0;
+ while (r) {
+ int t = cSource::FromString(skipspace(r));
+ if (t && i < ELEMENTS(sourceFiltersM))
+ sourceFiltersM[i++] = t;
+ r = strtok_r(NULL, ",", &s);
+ }
+ if (i) {
+ filtersM = "";
+ for (unsigned int j = 0; j < i; ++j)
+ filtersM = cString::sprintf("%s%s%s", *filtersM, isempty(*filtersM) ? "" : ",", *cSource::ToString(sourceFiltersM[j]));
+ debug3("%s filters=%s", __PRETTY_FUNCTION__, *filtersM);
+ }
+ FREE_POINTER(p);
+ }
if (!SatipConfig.GetDisableServerQuirks()) {
// These devices contain a session id bug:
// Inverto Airscreen Server IDL 400 ?
@@ -97,28 +119,61 @@ cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char
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
- ) {
+ )
quirkM |= eSatipQuirkSessionId;
- quirksM = cString::sprintf("%s%sSessionId", *quirksM, isempty(*quirksM) ? "" : ",");
- }
+ // These devices contain support for RTP over TCP:
+ if (strstr(*descriptionM, "minisatip") || // minisatip server
+ strstr(*descriptionM, "DVBViewer") || // DVBViewer Media Server
+ strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
+ strstr(*descriptionM, "DIGIBIT") || // Telestar Digibit R1
+ strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
+ )
+ quirkM |= eSatipQuirkRtpOverTcp;
// These devices contain a play (add/delpids) parameter bug:
if (strstr(*descriptionM, "fritzdvbc") // Fritz!WLAN Repeater DVB-C
- ) {
+ )
quirkM |= eSatipQuirkPlayPids;
- quirksM = cString::sprintf("%s%sPlayPids", *quirksM, isempty(*quirksM) ? "" : ",");
- }
// These devices contain a frontend locking bug:
if (strstr(*descriptionM, "fritzdvbc") || // Fritz!WLAN Repeater DVB-C
strstr(*descriptionM, "Schwaiger Sat>IP Server") // Schwaiger MS41IP
- ) {
+ )
quirkM |= eSatipQuirkForceLock;
- quirksM = cString::sprintf("%s%sForceLock", *quirksM, isempty(*quirksM) ? "" : ",");
- }
- debug3("%s description=%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM, *quirksM);
+ // These devices support the X_PMT protocol extension
+ if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
+ strstr(*descriptionM, "minisatip") // minisatip server
+ )
+ quirkM |= eSatipQuirkCiXpmt;
+ // These devices support the TNR protocol extension
+ if (strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
+ )
+ 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;
}
- // These devices support the X_PMT protocol extension
+ if ((quirkM & eSatipQuirkMask) & eSatipQuirkSessionId)
+ quirksM = cString::sprintf("%s%sSessionId", *quirksM, isempty(*quirksM) ? "" : ",");
+ if ((quirkM & eSatipQuirkMask) & eSatipQuirkPlayPids)
+ quirksM = cString::sprintf("%s%sPlayPids", *quirksM, isempty(*quirksM) ? "" : ",");
+ if ((quirkM & eSatipQuirkMask) & eSatipQuirkForceLock)
+ quirksM = cString::sprintf("%s%sForceLock", *quirksM, isempty(*quirksM) ? "" : ",");
+ if ((quirkM & eSatipQuirkMask) & eSatipQuirkRtpOverTcp)
+ quirksM = cString::sprintf("%s%sRtpOverTcp", *quirksM, isempty(*quirksM) ? "" : ",");
+ if ((quirkM & eSatipQuirkMask) & eSatipQuirkCiXpmt)
+ quirksM = cString::sprintf("%s%sCiXpmt", *quirksM, isempty(*quirksM) ? "" : ",");
+ if ((quirkM & eSatipQuirkMask) & eSatipQuirkCiTnr)
+ 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);
+ // These devices support external CI
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
- strstr(*descriptionM, "minisatip") // minisatip server
+ strstr(*descriptionM, "minisatip") || // minisatip server
+ strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
) {
hasCiM = true;
}
@@ -153,7 +208,7 @@ cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char
}
r = strtok_r(NULL, ",", &s);
}
- free(p);
+ FREE_POINTER(p);
}
cSatipServer::~cSatipServer()
@@ -172,53 +227,72 @@ int cSatipServer::Compare(const cListObject &listObjectP) const
return result;
}
+bool cSatipServer::IsValidSource(int sourceP)
+{
+ if (sourceFiltersM[0]) {
+ for (unsigned int i = 0; i < ELEMENTS(sourceFiltersM); ++i) {
+ if (sourceP == sourceFiltersM[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
bool cSatipServer::Assign(int deviceIdP, int sourceP, int systemP, int transponderP)
{
bool result = false;
- if (cSource::IsType(sourceP, 'S'))
- result = frontendsM[eSatipFrontendDVBS2].Assign(deviceIdP, transponderP);
- else if (cSource::IsType(sourceP, 'T')) {
- if (systemP)
- result = frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
- else
- result = frontendsM[eSatipFrontendDVBT].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
- }
- else if (cSource::IsType(sourceP, 'C')) {
- if (systemP)
- result = frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
- else
- result = frontendsM[eSatipFrontendDVBC].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
+ if (IsValidSource(sourceP)) {
+ if (cSource::IsType(sourceP, 'S'))
+ result = frontendsM[eSatipFrontendDVBS2].Assign(deviceIdP, transponderP);
+ else if (cSource::IsType(sourceP, 'T')) {
+ if (systemP)
+ result = frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
+ else
+ result = frontendsM[eSatipFrontendDVBT].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
+ }
+ else if (cSource::IsType(sourceP, 'C')) {
+ if (systemP)
+ result = frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
+ else
+ result = frontendsM[eSatipFrontendDVBC].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
+ }
}
return result;
}
bool cSatipServer::Matches(int sourceP)
{
- if (cSource::IsType(sourceP, 'S'))
- return GetModulesDVBS2();
- else if (cSource::IsType(sourceP, 'T'))
- return GetModulesDVBT() || GetModulesDVBT2();
- else if (cSource::IsType(sourceP, 'C'))
- return GetModulesDVBC() || GetModulesDVBC2();
+ if (IsValidSource(sourceP)) {
+ if (cSource::IsType(sourceP, 'S'))
+ return GetModulesDVBS2();
+ else if (cSource::IsType(sourceP, 'T'))
+ return GetModulesDVBT() || GetModulesDVBT2();
+ else if (cSource::IsType(sourceP, 'C'))
+ return GetModulesDVBC() || GetModulesDVBC2();
+ }
return false;
}
bool cSatipServer::Matches(int deviceIdP, int sourceP, int systemP, int transponderP)
{
bool result = false;
- if (cSource::IsType(sourceP, 'S'))
- result = frontendsM[eSatipFrontendDVBS2].Matches(deviceIdP, transponderP);
- else if (cSource::IsType(sourceP, 'T')) {
- if (systemP)
- result = frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
- else
- result = frontendsM[eSatipFrontendDVBT].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
- }
- else if (cSource::IsType(sourceP, 'C')) {
- if (systemP)
- result = frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
- else
- result = frontendsM[eSatipFrontendDVBC].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
+ if (IsValidSource(sourceP)) {
+ if (cSource::IsType(sourceP, 'S'))
+ result = frontendsM[eSatipFrontendDVBS2].Matches(deviceIdP, transponderP);
+ else if (cSource::IsType(sourceP, 'T')) {
+ if (systemP)
+ result = frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
+ else
+ result = frontendsM[eSatipFrontendDVBT].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
+ }
+ else if (cSource::IsType(sourceP, 'C')) {
+ if (systemP)
+ result = frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
+ else
+ result = frontendsM[eSatipFrontendDVBC].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
+ }
}
return result;
}
@@ -287,11 +361,11 @@ cSatipServer *cSatipServers::Find(int sourceP)
cSatipServer *cSatipServers::Assign(int deviceIdP, int sourceP, int transponderP, int systemP)
{
for (cSatipServer *s = First(); s; s = Next(s)) {
- if (s->Matches(deviceIdP, sourceP, systemP, transponderP))
+ if (s->IsActive() && s->Matches(deviceIdP, sourceP, systemP, transponderP))
return s;
}
for (cSatipServer *s = First(); s; s = Next(s)) {
- if (s->Assign(deviceIdP, sourceP, systemP, transponderP))
+ if (s->IsActive() && s->Assign(deviceIdP, sourceP, systemP, transponderP))
return s;
}
return NULL;
@@ -308,6 +382,16 @@ cSatipServer *cSatipServers::Update(cSatipServer *serverP)
return NULL;
}
+void cSatipServers::Activate(cSatipServer *serverP, bool onOffP)
+{
+ for (cSatipServer *s = First(); s; s = Next(s)) {
+ if (s == serverP) {
+ s->Activate(onOffP);
+ break;
+ }
+ }
+}
+
void cSatipServers::Attach(cSatipServer *serverP, int deviceIdP, int transponderP)
{
for (cSatipServer *s = First(); s; s = Next(s)) {
@@ -374,6 +458,18 @@ cString cSatipServers::GetAddress(cSatipServer *serverP)
return address;
}
+int cSatipServers::GetPort(cSatipServer *serverP)
+{
+ int port = SATIP_DEFAULT_RTSP_PORT;
+ for (cSatipServer *s = First(); s; s = Next(s)) {
+ if (s == serverP) {
+ port = s->Port();
+ break;
+ }
+ }
+ return port;
+}
+
cString cSatipServers::GetString(cSatipServer *serverP)
{
cString list = "";
@@ -390,7 +486,7 @@ cString cSatipServers::List(void)
{
cString list = "";
for (cSatipServer *s = First(); s; s = Next(s))
- list = cString::sprintf("%s%s|%s|%s\n", *list, s->Address(), s->Model(), s->Description());
+ list = cString::sprintf("%s%c %s|%s|%s\n", *list, s->IsActive() ? '+' : '-', s->Address(), s->Model(), s->Description());
return list;
}
diff --git a/server.h b/server.h
index 45bb1df..ea9ae2d 100644
--- a/server.h
+++ b/server.h
@@ -54,25 +54,37 @@ private:
eSatipFrontendDVBC2,
eSatipFrontendCount
};
+ enum {
+ eSatipMaxSourceFilters = 16
+ };
cString addressM;
cString modelM;
+ cString filtersM;
cString descriptionM;
cString quirksM;
cSatipFrontends frontendsM[eSatipFrontendCount];
+ int sourceFiltersM[eSatipMaxSourceFilters];
+ int portM;
int quirkM;
bool hasCiM;
+ bool activeM;
time_t createdM;
cTimeMs lastSeenM;
+ bool IsValidSource(int sourceP);
public:
enum eSatipQuirk {
- eSatipQuirkNone = 0x00,
- eSatipQuirkSessionId = 0x01,
- eSatipQuirkPlayPids = 0x02,
- eSatipQuirkForceLock = 0x04,
- eSatipQuirkMask = 0x0F
+ eSatipQuirkNone = 0x00,
+ eSatipQuirkSessionId = 0x01,
+ eSatipQuirkPlayPids = 0x02,
+ eSatipQuirkForceLock = 0x04,
+ eSatipQuirkRtpOverTcp = 0x08,
+ eSatipQuirkCiXpmt = 0x10,
+ eSatipQuirkCiTnr = 0x20,
+ eSatipQuirkForcePilot = 0x40,
+ eSatipQuirkMask = 0xFF
};
- cSatipServer(const char *addressP, const char *modelP, const char *descriptionP);
+ cSatipServer(const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP);
virtual ~cSatipServer();
virtual int Compare(const cListObject &listObjectP) const;
bool Assign(int deviceIdP, int sourceP, int systemP, int transponderP);
@@ -85,13 +97,17 @@ public:
int GetModulesDVBT2(void);
int GetModulesDVBC(void);
int GetModulesDVBC2(void);
+ void Activate(bool onOffP) { activeM = onOffP; }
const char *Address(void) { return *addressM; }
const char *Model(void) { return *modelM; }
+ const char *Filters(void) { return *filtersM; }
const char *Description(void) { return *descriptionM; }
const char *Quirks(void) { return *quirksM; }
+ int Port(void) { return portM; }
bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); }
bool HasQuirk(void) { return (quirkM != eSatipQuirkNone); }
bool HasCI(void) { return hasCiM; }
+ bool IsActive(void) { return activeM; }
void Update(void) { lastSeenM.Set(); }
uint64_t LastSeen(void) { return lastSeenM.Elapsed(); }
time_t Created(void) { return createdM; }
@@ -105,6 +121,7 @@ public:
cSatipServer *Find(int sourceP);
cSatipServer *Assign(int deviceIdP, int sourceP, int transponderP, int systemP);
cSatipServer *Update(cSatipServer *serverP);
+ void Activate(cSatipServer *serverP, bool onOffP);
void Attach(cSatipServer *serverP, int deviceIdP, int transponderP);
void Detach(cSatipServer *serverP, int deviceIdP, int transponderP);
bool IsQuirk(cSatipServer *serverP, int quirkP);
@@ -112,6 +129,7 @@ public:
void Cleanup(uint64_t intervalMsP = 0);
cString GetAddress(cSatipServer *serverP);
cString GetString(cSatipServer *serverP);
+ int GetPort(cSatipServer *serverP);
cString List(void);
int NumProvidedSystems(void);
};
diff --git a/setup.c b/setup.c
index 479ea97..c178c61 100644
--- a/setup.c
+++ b/setup.c
@@ -86,6 +86,8 @@ eOSState cSatipEditSrcItem::ProcessKey(eKeys Key)
class cSatipServerInfo : public cOsdMenu
{
private:
+ cSatipServer *serverM;
+ int activeM;
cString addressM;
cString modelM;
cString descriptionM;
@@ -101,6 +103,8 @@ public:
cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP)
: cOsdMenu(tr("SAT>IP Server"), 20),
+ serverM(serverP),
+ activeM(serverP && serverP->IsActive()),
addressM(serverP ? serverP->Address() : "---"),
modelM(serverP ? serverP->Model() : "---"),
descriptionM(serverP ? serverP->Description() : "---"),
@@ -118,6 +122,7 @@ cSatipServerInfo::~cSatipServerInfo()
void cSatipServerInfo::Setup(void)
{
+ Add(new cMenuEditBoolItem(trVDR("Active"), &activeM));
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Address"), *addressM), osUnknown, false));
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Model"), *modelM), osUnknown, false));
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Description"), *descriptionM), osUnknown, false));
@@ -127,6 +132,7 @@ void cSatipServerInfo::Setup(void)
eOSState cSatipServerInfo::ProcessKey(eKeys keyP)
{
+ int oldActive = activeM;
eOSState state = cOsdMenu::ProcessKey(keyP);
if (state == osUnknown) {
@@ -135,6 +141,12 @@ eOSState cSatipServerInfo::ProcessKey(eKeys keyP)
default: state = osContinue; break;
}
}
+
+ if (keyP != kNone && oldActive != activeM) {
+ cSatipDiscover::GetInstance()->ActivateServer(serverM, activeM);
+ Setup();
+ }
+
return state;
}
@@ -155,7 +167,7 @@ cSatipServerItem::cSatipServerItem(cSatipServer *serverP)
{
SetSelectable(true);
// Must begin with a '#' character!
- SetText(*cString::sprintf("# %s (%s)\t%s", serverM->Address(), serverM->Model(), serverM->Description()));
+ SetText(*cString::sprintf("%s %s (%s)\t%s", serverM->IsActive() ? "+" : "-", serverM->Address(), serverM->Model(), serverM->Description()));
}
void cSatipServerItem::SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP)
@@ -333,6 +345,7 @@ cSatipPluginSetup::cSatipPluginSetup()
: detachedModeM(SatipConfig.GetDetachedMode()),
deviceCountM(0),
operatingModeM(SatipConfig.GetOperatingMode()),
+ transportModeM(SatipConfig.GetTransportMode()),
ciExtensionM(SatipConfig.GetCIExtension()),
eitScanM(SatipConfig.GetEITScan()),
numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()),
@@ -343,6 +356,9 @@ cSatipPluginSetup::cSatipPluginSetup()
operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low");
operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal");
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)
cicamsM[i] = SatipConfig.GetCICAM(i);
for (unsigned int i = 0; i < ELEMENTS(ca_systems_table); ++i)
@@ -400,6 +416,8 @@ void cSatipPluginSetup::Setup(void)
helpM.Append(tr("Define an ill-behaving filter to be blacklisted."));
}
}
+ 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("");
@@ -465,10 +483,12 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
int oldNumDisabledFilters = numDisabledFiltersM;
eOSState state = cMenuSetupPage::ProcessKey(keyP);
- // Ugly hack with hardcoded '#' character :(
+ // Ugly hack with hardcoded '+/-' characters :(
const char *p = Get(Current())->Text();
- if (!hadSubMenu && !HasSubMenu() && (*p == '#') && (keyP == kOk))
+ if (!hadSubMenu && !HasSubMenu() && p && (*p == '+' || *p == '-') && (keyP == kOk))
return DeviceInfo();
+ if (hadSubMenu && !HasSubMenu())
+ Setup();
if (state == osUnknown) {
switch (keyP) {
@@ -547,6 +567,7 @@ void cSatipPluginSetup::Store(void)
{
// Store values into setup.conf
SetupStore("OperatingMode", operatingModeM);
+ SetupStore("TransportMode", transportModeM);
SetupStore("EnableCIExtension", ciExtensionM);
SetupStore("EnableEITScan", eitScanM);
StoreCicams("CICAM", cicamsM);
@@ -554,6 +575,7 @@ void cSatipPluginSetup::Store(void)
StoreFilters("DisabledFilters", disabledFilterIndexesM);
// Update global config
SatipConfig.SetOperatingMode(operatingModeM);
+ SatipConfig.SetTransportMode(transportModeM);
SatipConfig.SetCIExtension(ciExtensionM);
SatipConfig.SetEITScan(eitScanM);
for (int i = 0; i < MAX_CICAM_COUNT; ++i)
diff --git a/setup.h b/setup.h
index d8dcd66..e97ce2f 100644
--- a/setup.h
+++ b/setup.h
@@ -18,7 +18,9 @@ private:
bool detachedModeM;
int deviceCountM;
int operatingModeM;
+ int transportModeM;
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];
+ const char *transportModeTextsM[cSatipConfig::eTransportModeCount];
int ciExtensionM;
int cicamsM[MAX_CICAM_COUNT];
const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE];
diff --git a/socket.c b/socket.c
index 29c2602..4cb19f3 100644
--- a/socket.c
+++ b/socket.c
@@ -21,7 +21,11 @@
cSatipSocket::cSatipSocket()
: socketPortM(0),
- socketDescM(-1)
+ socketDescM(-1),
+ isMulticastM(false),
+ useSsmM(false),
+ streamAddrM(htonl(INADDR_ANY)),
+ sourceAddrM(htonl(INADDR_ANY))
{
debug1("%s", __PRETTY_FUNCTION__);
memset(&sockAddrM, 0, sizeof(sockAddrM));
@@ -34,10 +38,17 @@ cSatipSocket::~cSatipSocket()
Close();
}
-bool cSatipSocket::Open(const int portP)
+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
if (socketDescM < 0) {
+ int yes;
socklen_t len = sizeof(sockAddrM);
// Create socket
socketDescM = socket(PF_INET, SOCK_DGRAM, 0);
@@ -46,9 +57,19 @@ bool cSatipSocket::Open(const int portP)
ERROR_IF_FUNC(fcntl(socketDescM, F_SETFL, O_NONBLOCK), "fcntl(O_NONBLOCK)",
Close(), return false);
// Allow multiple sockets to use the same PORT number
- int yes = 1;
+ yes = reuseP;
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0,
"setsockopt(SO_REUSEADDR)", Close(), return false);
+ yes = reuseP;
+#ifdef SO_REUSEPORT
+ ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0 && errno != ENOPROTOOPT,
+ "setsockopt(SO_REUSEPORT)", Close(), return false);
+#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
memset(&sockAddrM, 0, sizeof(sockAddrM));
sockAddrM.sin_family = AF_INET;
@@ -57,23 +78,41 @@ bool cSatipSocket::Open(const int portP)
ERROR_IF_FUNC(bind(socketDescM, (struct sockaddr *)&sockAddrM, sizeof(sockAddrM)) < 0,
"bind()", Close(), return false);
// Update socket port
- ERROR_IF_FUNC(getsockname(socketDescM,(struct sockaddr*)&sockAddrM, &len) < 0,
+ ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0,
"getsockname()", Close(), return false);
socketPortM = ntohs(sockAddrM.sin_port);
+ isMulticastM = false;
}
debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM);
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)
{
debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM);
// Check if socket exists
if (socketDescM >= 0) {
+ Leave();
close(socketDescM);
socketDescM = -1;
socketPortM = 0;
memset(&sockAddrM, 0, sizeof(sockAddrM));
+ streamAddrM = htonl(INADDR_ANY);
+ sourceAddrM = htonl(INADDR_ANY);
+ isMulticastM = false;
+ useSsmM = false;
}
}
@@ -96,6 +135,96 @@ bool cSatipSocket::Flush(void)
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)
{
debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP);
@@ -126,8 +255,22 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
if (socketDescM && bufferAddrP && (bufferLenP > 0))
len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT);
- if (len > 0)
- return len;
+ 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;
+ }
+ }
+ }
+ else
+#endif // __FreeBSD__
+ return len;
+ }
} while (len > 0);
ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1);
return 0;
diff --git a/socket.h b/socket.h
index f9a93d8..12d1ac4 100644
--- a/socket.h
+++ b/socket.h
@@ -15,14 +15,23 @@ private:
int socketPortM;
int socketDescM;
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:
cSatipSocket();
virtual ~cSatipSocket();
- bool Open(const int portP = 0);
+ 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);
int Fd(void) { return socketDescM; }
int Port(void) { return socketPortM; }
+ bool IsMulticast(void) { return isMulticastM; }
bool IsOpen(void) { return (socketDescM >= 0); }
bool Flush(void);
int Read(unsigned char *bufferAddrP, unsigned int bufferLenP);
diff --git a/tuner.c b/tuner.c
index c12a19e..0ff758f 100644
--- a/tuner.c
+++ b/tuner.c
@@ -25,6 +25,8 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
rtcpM(*this),
streamAddrM(""),
streamParamM(""),
+ tnrParamM(""),
+ streamPortM(SATIP_DEFAULT_RTSP_PORT),
currentServerM(NULL, deviceP.GetId(), 0),
nextServerM(NULL, deviceP.GetId(), 0),
mutexM(),
@@ -50,12 +52,16 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
debug1("%s (, %d) [device %d]", __PRETTY_FUNCTION__, packetLenP, deviceIdM);
// Open sockets
- int i = 100;
+ int i = SatipConfig.GetPortRangeStart() ? SatipConfig.GetPortRangeStop() - SatipConfig.GetPortRangeStart() - 1 : 100;
+ int port = SatipConfig.GetPortRangeStart();
while (i-- > 0) {
- if (rtpM.Open(0) && 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;
rtpM.Close();
rtcpM.Close();
+ if (SatipConfig.GetPortRangeStart())
+ port += 2;
}
if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) {
error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM);
@@ -205,7 +211,8 @@ bool cSatipTuner::Connect(void)
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
if (!isempty(*streamAddrM)) {
- cString connectionUri = cString::sprintf("rtsp://%s/", *streamAddrM);
+ cString connectionUri = GetBaseUrl(*streamAddrM, streamPortM);
+ tnrParamM = "";
// Just retune
if (streamIdM >= 0) {
cString uri = cString::sprintf("%sstream=%d?%s", *connectionUri, streamIdM, *streamParamM);
@@ -217,10 +224,11 @@ bool cSatipTuner::Connect(void)
}
else if (rtspM.Options(*connectionUri)) {
cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM);
+ bool useTcp = SatipConfig.IsTransportModeRtpOverTcp() && nextServerM.IsValid() && nextServerM.IsQuirk(cSatipServer::eSatipQuirkRtpOverTcp);
// Flush any old content
//rtpM.Flush();
//rtcpM.Flush();
- if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port())) {
+ if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port(), useTcp)) {
keepAliveM.Set(timeoutM);
if (nextServerM.IsValid()) {
currentServerM = nextServerM;
@@ -244,7 +252,7 @@ bool cSatipTuner::Disconnect(void)
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
if (!isempty(*streamAddrM) && (streamIdM >= 0)) {
- cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
+ cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM);
rtspM.Teardown(*uri);
// some devices requires a teardown for TCP connection also
rtspM.Reset();
@@ -289,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);
@@ -342,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);
@@ -359,6 +377,47 @@ void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
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)
+{
+ debug16("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, addressP, portP, deviceIdM);
+
+ if (portP != SATIP_DEFAULT_RTSP_PORT)
+ return cString::sprintf("rtsp://%s:%d/", addressP, portP);
+
+ return cString::sprintf("rtsp://%s/", addressP);
+}
+
int cSatipTuner::GetId(void)
{
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
@@ -375,6 +434,10 @@ bool cSatipTuner::SetSource(cSatipServer *serverP, const int transponderP, const
// Update stream address and parameter
streamAddrM = rtspM.RtspUnescapeString(*nextServerM.GetAddress());
streamParamM = rtspM.RtspUnescapeString(parameterP);
+ 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
RequestState(tsSet, smExternal);
}
@@ -413,7 +476,7 @@ bool cSatipTuner::UpdatePids(bool forceP)
cMutexLock MutexLock(&mutexM);
if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) &&
!isempty(*streamAddrM) && (streamIdM > 0)) {
- cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
+ cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM);
bool useci = (SatipConfig.GetCIExtension() && currentServerM.HasCI());
bool usedummy = currentServerM.IsQuirk(cSatipServer::eSatipQuirkPlayPids);
if (forceP || usedummy) {
@@ -429,20 +492,30 @@ bool cSatipTuner::UpdatePids(bool forceP)
uri = cString::sprintf("%s%sdelpids=%s", *uri, addPidsM.Size() ? "&" : "?", *delPidsM.ListPids());
}
if (useci) {
- // CI extension parameters:
- // - x_pmt : specifies the PMT of the service you want the CI to decode
- // - x_ci : specfies which CI slot (1..n) to use
- // value 0 releases the CI slot
- // CI slot released automatically if the stream is released,
- // but not when used retuning to another channel
- int pid = deviceM->GetPmtPid();
- if ((pid > 0) && (pid != pmtPidM)) {
- int slot = deviceM->GetCISlot();
- uri = cString::sprintf("%s&x_pmt=%d", *uri, pid);
- if (slot > 0)
- uri = cString::sprintf("%s&x_ci=%d", *uri, slot);
+ if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkCiXpmt)) {
+ // CI extension parameters:
+ // - x_pmt : specifies the PMT of the service you want the CI to decode
+ // - x_ci : specfies which CI slot (1..n) to use
+ // value 0 releases the CI slot
+ // CI slot released automatically if the stream is released,
+ // but not when used retuning to another channel
+ int pid = deviceM->GetPmtPid();
+ if ((pid > 0) && (pid != pmtPidM)) {
+ int slot = deviceM->GetCISlot();
+ uri = cString::sprintf("%s&x_pmt=%d", *uri, pid);
+ if (slot > 0)
+ uri = cString::sprintf("%s&x_ci=%d", *uri, slot);
+ }
+ pmtPidM = pid;
+ }
+ else if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkCiTnr)) {
+ // CI extension parameters:
+ // - tnr : specifies a channel config entry
+ cString param = deviceM->GetTnrParameterString();
+ if (!isempty(*param) && strcmp(*tnrParamM, *param) != 0)
+ uri = cString::sprintf("%s&tnr=%s", *uri, *param);
+ tnrParamM = param;
}
- pmtPidM = pid;
}
pidUpdateCacheM.Set(ePidUpdateIntervalMs);
if (!rtspM.Play(*uri))
@@ -463,7 +536,7 @@ bool cSatipTuner::KeepAlive(bool forceP)
forceP = true;
}
if (forceP && !isempty(*streamAddrM)) {
- cString uri = cString::sprintf("rtsp://%s/", *streamAddrM);
+ cString uri = GetBaseUrl(*streamAddrM, streamPortM);
if (!rtspM.Options(*uri))
return false;
}
@@ -480,7 +553,7 @@ bool cSatipTuner::ReadReceptionStatus(bool forceP)
forceP = true;
}
if (forceP && !isempty(*streamAddrM) && (streamIdM > 0)) {
- cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
+ cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM);
if (rtspM.Describe(*uri))
return true;
}
@@ -615,5 +688,5 @@ cString cSatipTuner::GetSignalStatus(void)
cString cSatipTuner::GetInformation(void)
{
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
- return (currentStateM >= tsTuned) ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed";
+ return (currentStateM >= tsTuned) ? cString::sprintf("%s?%s (%s) [stream=%d]", *GetBaseUrl(*streamAddrM, streamPortM), *streamParamM, *rtspM.GetActiveMode(), streamIdM) : "connection failed";
}
diff --git a/tuner.h b/tuner.h
index 1c7f655..3d35cfd 100644
--- a/tuner.h
+++ b/tuner.h
@@ -69,6 +69,7 @@ public:
void Set(cSatipServer *serverP, const int transponderP) { serverM = serverP; transponderM = transponderP; }
void Reset(void) { serverM = NULL; transponderM = 0; }
cString GetAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerAddress(serverM) : ""; }
+ int GetPort(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerPort(serverM) : SATIP_DEFAULT_RTSP_PORT; }
cString GetInfo(void) { return cString::sprintf("server=%s deviceid=%d transponder=%d", serverM ? "assigned" : "null", deviceIdM, transponderM); }
};
@@ -98,6 +99,8 @@ private:
cSatipRtcp rtcpM;
cString streamAddrM;
cString streamParamM;
+ cString tnrParamM;
+ int streamPortM;
cSatipTunerServer currentServerM;
cSatipTunerServer nextServerM;
cMutex mutexM;
@@ -130,6 +133,7 @@ private:
bool RequestState(eTunerState stateP, eStateMode modeP);
const char *StateModeString(eStateMode modeP);
const char *TunerStateString(eTunerState stateP);
+ cString GetBaseUrl(const char *addressP, const int portP);
protected:
virtual void Action(void);
@@ -153,8 +157,11 @@ 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);
virtual int GetId(void);
};
diff --git a/tunerif.h b/tunerif.h
index f5ea6a6..9eaac0c 100644
--- a/tunerif.h
+++ b/tunerif.h
@@ -14,8 +14,11 @@ 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;
virtual int GetId(void) = 0;
private:
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-satip.git
More information about the pkg-vdr-dvb-changes
mailing list