Discussion:
[vdr-plugin-satip] branch master updated (33e0ed2 -> d31c9f6)
Tobias Grimm
2017-01-07 11:37:58 UTC
Permalink
This is an automated email from the git hooks/post-receive script.

tiber-guest pushed a change to branch master
in repository vdr-plugin-satip.

from 33e0ed2 Fixed "FTBFS with GCC 6 (Closes: #811948)
new e2c6f18 Fixed last commit
new 8c82d5d New upstream version 2.2.4
new 0c1a563 Merge tag 'upstream/2.2.4'
new a1d596d Dropped gcc6-fixes.patch
new e8971de Standards-Version: 3.9.8
new d31c9f6 Update changelog for 2.2.4-1 release

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "adds" were already present in the repository and have only
been added to this reference.


Summary of changes:
HISTORY | 12 ++
README | 20 ++-
common.h | 20 +--
config.c | 3 +
config.h | 18 +++
debian/changelog | 8 +
debian/control | 2 +-
debian/patches/gcc6-fixes.patch | 16 --
debian/patches/series | 1 -
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 +
42 files changed, 1285 insertions(+), 201 deletions(-)
delete mode 100644 debian/patches/gcc6-fixes.patch
delete mode 100644 debian/patches/series
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-satip.git
Tobias Grimm
2017-01-07 11:37:58 UTC
Permalink
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 e2c6f1833ec970c3fb2154aa0d5d794ffcee8d07
Author: Tobias Grimm <***@debian.org>
Date: Sun Apr 17 15:06:16 2016 +0200

Fixed last commit
---
common.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common.h b/common.h
index a17a1fd..ac9ea20 100644
--- a/common.h
+++ b/common.h
@@ -52,7 +52,7 @@
do { \
if (exp) { \
char tmp[64]; \
- esyslog("[%s,%d]: " errstr ": %s", __FILE__, __LINE__, \
+ esyslog("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
strerror_r(errno, tmp, sizeof(tmp))); \
func; \
ret; \
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-satip.git
Tobias Grimm
2017-01-07 11:37:58 UTC
Permalink
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 <***@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 <***@gmail.com>\n"
"Language-Team: Catalan <***@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 <***@yavdr.org>\n"
"Language-Team: German <***@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 <***@gmail.com>\n"
"Language-Team: Spanish <***@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 <***@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
Tobias Grimm
2017-01-07 11:37:58 UTC
Permalink
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 0c1a56344fb36cc0ff5fd711f96547109321592f
Merge: e2c6f18 8c82d5d
Author: Tobias Grimm <***@debian.org>
Date: Tue Jan 3 19:57:48 2017 +0100

Merge tag 'upstream/2.2.4'

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(-)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-satip.git
Tobias Grimm
2017-01-07 11:37:58 UTC
Permalink
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 a1d596d663bc800a0da3508e6894cc0052acc31d
Author: Tobias Grimm <***@debian.org>
Date: Tue Jan 3 19:58:47 2017 +0100

Dropped gcc6-fixes.patch
---
debian/changelog | 6 ++++++
debian/patches/gcc6-fixes.patch | 16 ----------------
debian/patches/series | 1 -
3 files changed, 6 insertions(+), 17 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index e941911..04d5821 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+vdr-plugin-satip (2.2.4-1) UNRELEASED; urgency=medium
+
+ * New upstream release
+
+ -- Tobias Grimm <***@debian.org> Tue, 03 Jan 2017 19:58:29 +0100
+
vdr-plugin-satip (2.2.3-2) unstable; urgency=medium

* Fixed "FTBFS with GCC 6 (Closes: #811948)
diff --git a/debian/patches/gcc6-fixes.patch b/debian/patches/gcc6-fixes.patch
deleted file mode 100644
index 11be3cd..0000000
--- a/debian/patches/gcc6-fixes.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-Description: GCC 6 related fixes
-Author: Tobias Grimm <***@debian.org>
-Bug: https://github.com/rofafor/vdr-plugin-satip/pull/18
----
-This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
---- a/common.h
-+++ b/common.h
-@@ -52,7 +52,7 @@
- do { \
- if (exp) { \
- char tmp[64]; \
-- esyslog("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
-+ esyslog("[%s,%d]: " errstr ": %s", __FILE__, __LINE__, \
- strerror_r(errno, tmp, sizeof(tmp))); \
- func; \
- ret; \
diff --git a/debian/patches/series b/debian/patches/series
deleted file mode 100644
index 9d3fbcb..0000000
--- a/debian/patches/series
+++ /dev/null
@@ -1 +0,0 @@
-gcc6-fixes.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-satip.git
Tobias Grimm
2017-01-07 11:37:58 UTC
Permalink
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 e8971def0b5e878846cd7f3b137c872841f03d41
Author: Tobias Grimm <***@debian.org>
Date: Tue Jan 3 19:59:34 2017 +0100

Standards-Version: 3.9.8
---
debian/control | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/debian/control b/debian/control
index 5e5b52c..27af99b 100644
--- a/debian/control
+++ b/debian/control
@@ -4,7 +4,7 @@ Priority: extra
Maintainer: Debian VDR Team <pkg-vdr-dvb-***@lists.alioth.debian.org>
Uploaders: Frank Neumann <***@yavdr.org>, Tobias Grimm <***@debian.org>
Build-Depends: debhelper (>= 9), vdr-dev (>= 2.2.0), gettext, pkg-config, libcurl4-openssl-dev (>= 7.36.0), libpugixml-dev
-Standards-Version: 3.9.6
+Standards-Version: 3.9.8
Vcs-Git: git://anonscm.debian.org/pkg-vdr-dvb/vdr-plugin-satip.git
Vcs-Browser: http://git.debian.org/?p=pkg-vdr-dvb/vdr-plugin-satip.git
Homepage: http://www.saunalahti.fi/~rahrenbe/vdr/satip/
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-satip.git
Tobias Grimm
2017-01-07 11:37:58 UTC
Permalink
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 d31c9f69ceb868834f017073f9b4708cfaf3b4a9
Author: Tobias Grimm <***@debian.org>
Date: Tue Jan 3 20:00:43 2017 +0100

Update changelog for 2.2.4-1 release
---
debian/changelog | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 04d5821..175a734 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,10 @@
-vdr-plugin-satip (2.2.4-1) UNRELEASED; urgency=medium
+vdr-plugin-satip (2.2.4-1) unstable; urgency=medium

* New upstream release
+ * Dropped GCC 6 fix - fixed upstream
+ * Standards-Version: 3.9.8

- -- Tobias Grimm <***@debian.org> Tue, 03 Jan 2017 19:58:29 +0100
+ -- Tobias Grimm <***@debian.org> Tue, 03 Jan 2017 19:59:56 +0100

vdr-plugin-satip (2.2.3-2) unstable; urgency=medium
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-satip.git
Loading...