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

27 Commits

Author SHA1 Message Date
Rolf Ahrenberg
37a0572a64 Updated HISTORY. 2015-09-18 18:49:44 +03:00
Rolf Ahrenberg
613c0aed7c Added a force lock quirk for Schwaiger MS41IP. 2015-09-18 18:31:53 +03:00
Rolf Ahrenberg
c3ad29eb27 Updated for vdr-2.3.1 (Thanks to Klaus Schmidinger). 2015-08-20 19:12:21 +03:00
Rolf Ahrenberg
e90b8651e6 Silenced some cppcheck warnings. 2015-08-16 01:38:03 +03:00
Rolf Ahrenberg
0f370aa36a Added a tuning timeout for better recovery. 2015-08-16 01:10:52 +03:00
Rolf Ahrenberg
49e2dd1fc1 Reset the RTSP connection after any failed connect. 2015-06-04 18:51:09 +03:00
Rolf Ahrenberg
ba0b808ec4 Enabled the X_PMT extension for minisatip servers. 2015-05-26 21:18:05 +03:00
Rolf Ahrenberg
4e2535a7e2 Added a double check for the idle release. 2015-05-23 15:28:37 +03:00
Rolf Ahrenberg
6384b8694e Added a timeout for releasing idling devices. 2015-05-22 22:43:08 +03:00
Rolf Ahrenberg
6c4c8a10b7 Set the default device count to two. 2015-04-26 12:49:40 +03:00
Rolf Ahrenberg
8b43cdc634 Added initial support for detaching and attaching SAT>IP servers. 2015-04-12 21:25:41 +03:00
Rolf Ahrenberg
fe010ab72c Added a more flexible OPER command in the SVDRP interface. 2015-04-09 21:36:13 +03:00
Rolf Ahrenberg
7bdc152f76 Prepared for a release. 2015-04-03 20:37:29 +03:00
Rolf Ahrenberg
bd6774ba28 Relaxed the server cleanup timeout. 2015-03-26 00:28:17 +02:00
Rolf Ahrenberg
fbf7977853 Added a memory guard for cSatipMemoryBuffer(). 2015-03-26 00:23:55 +02:00
Rolf Ahrenberg
19a6a4a5ee Simplified GetTransponderUrlParameters(). 2015-03-22 23:44:15 +02:00
Rolf Ahrenberg
7b683dba8d Implemented cSatipMemoryBuffer(). 2015-03-22 20:06:47 +02:00
Rolf Ahrenberg
942d3a936e Fixed CURL buffer size for discovery. 2015-03-22 17:33:08 +02:00
Rolf Ahrenberg
748ea15d1d Updated against SAT>IP protocol specification version 1.2.2. 2015-03-22 16:47:02 +02:00
Rolf Ahrenberg
1d75da403a Simplified GetTransponderUrlParameters(). 2015-03-22 16:33:48 +02:00
Rolf Ahrenberg
4d8263e8fd Improved RTSP error checking. 2015-03-18 22:59:38 +02:00
Rolf Ahrenberg
7019b719a5 Fixed a memory leak in TinyXML implementation (Thanks to Oliver Endriss). 2015-03-18 20:55:10 +02:00
Rolf Ahrenberg
39249ca2d5 Fixed generic error macros. 2015-03-08 15:53:54 +02:00
Rolf Ahrenberg
68e0d1474e Got rid of SATIP_DEBUG. 2015-03-07 17:50:48 +02:00
Rolf Ahrenberg
ad5c221e44 Fixed wrong indenting. 2015-03-04 19:43:01 +02:00
Rolf Ahrenberg
826e53e8ea Fixed the discovery tracing level. 2015-03-03 19:09:51 +02:00
Rolf Ahrenberg
f4dd02a9aa Robustify the server discovery. 2015-03-02 20:08:21 +02:00
33 changed files with 466 additions and 186 deletions

24
HISTORY
View File

@@ -120,3 +120,27 @@ VDR Plugin 'satip' Revision History
- Fixed memory deallocation errors.
- Cleaned up all scan-build warnings.
- Refactored the frontend handling.
2015-04-04: Version 2.2.1
- Improved RTSP error checking.
- Got rid of SATIP_DEBUG.
- Robustify the server discovery.
- Fixed a memory leak in TinyXML implementation
(Thanks to Oliver Endriss).
- Updated against SAT>IP protocol specification
version 1.2.2.
2015-04-26: Version 2.2.2
- Added a more flexible OPER command in the SVDRP
interface.
- Added new ATTA and DETA SVDRP commands.
- Set the default device count to two.
2015-09-18: Version 2.2.3
- Added a timeout for releasing idling devices.
- 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).

View File

@@ -2,18 +2,10 @@
# Makefile for SAT>IP plugin
#
# Debugging on/off
#SATIP_DEBUG = 1
# Use TinyXML instead of PugiXML
#SATIP_USE_TINYXML = 1
# Strip debug symbols? Set eg. to /bin/true if not
STRIP = strip
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
# By default the main source file also carries this name.
@@ -40,6 +32,7 @@ TMPDIR ?= /tmp
export CFLAGS = $(call PKGCFG,cflags)
export CXXFLAGS = $(call PKGCFG,cxxflags)
STRIP ?= /bin/true
### The version number of VDR's plugin API:
@@ -75,12 +68,6 @@ else
LIBS += -lpugixml
endif
ifdef SATIP_DEBUG
ifeq ($(SATIP_DEBUG),1)
DEFINES += -DDEBUG
endif
endif
ifneq ($(strip $(GITTAG)),)
DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"'
endif
@@ -142,9 +129,7 @@ install-i18n: $(I18Nmsgs)
$(SOFILE): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
ifndef SATIP_DEBUG
@$(STRIP) $@
endif
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)

2
README
View File

@@ -42,7 +42,7 @@ make -C satip-X.Y.Z install
Configuration:
The plugin accepts a "--devices" (-d) command-line parameter defaulting
to one. This parameter defines how many simultaneous transponders can
to two. This parameter defines how many simultaneous transponders can
be received, if there are available SAT>IP tuners.
The plugin accepts also a "--server" (-s) command-line parameter, that

View File

@@ -35,7 +35,7 @@
#define SATIP_CURL_EASY_GETINFO(X, Y, Z) \
if ((res = curl_easy_getinfo((X), (Y), (Z))) != CURLE_OK) { \
error("curl_easy_getinfo(%s) [%s,%d] failed: %s (%d)", #Y, __FILE__, __LINE__, curl_easy_strerror(res), res); \
esyslog("curl_easy_getinfo(%s) [%s,%d] failed: %s (%d)", #Y, __FILE__, __LINE__, curl_easy_strerror(res), res); \
}
#define SATIP_CURL_EASY_SETOPT(X, Y, Z) \
@@ -48,15 +48,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]; \
#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; \
} \
strerror_r(errno, tmp, sizeof(tmp))); \
func; \
ret; \
} \
} while (0)
@@ -84,6 +84,52 @@
#define ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
class cSatipMemoryBuffer {
private:
enum {
eMaxDataSize = MEGABYTE(2)
};
char *dataM;
size_t sizeM;
void *AllocBuffer(void *ptrP, size_t sizeP)
{
// There might be a realloc() out there that doesn't like reallocing NULL pointers, so we take care of it here
if (ptrP)
return realloc(ptrP, sizeP);
else
return malloc(sizeP);
}
// to prevent copy constructor and assignment
cSatipMemoryBuffer(const cSatipMemoryBuffer&);
cSatipMemoryBuffer& operator=(const cSatipMemoryBuffer&);
public:
cSatipMemoryBuffer() : dataM(NULL), sizeM(0) {}
~cSatipMemoryBuffer() { Reset(); }
size_t Add(char *dataP, size_t sizeP)
{
if (sizeP > 0) {
size_t len = sizeM + sizeP + 1;
if (len < eMaxDataSize) {
dataM = (char *)AllocBuffer(dataM, len);
if (dataM) {
memcpy(&(dataM[sizeM]), dataP, sizeP);
sizeM += sizeP;
dataM[sizeM] = 0;
return sizeP;
}
else
esyslog("[%s,%d]: Failed to allocate memory", __FILE__, __LINE__);
}
else
esyslog("[%s,%d]: Buffer overflow", __FILE__, __LINE__);
}
return 0;
};
char *Data(void) { return dataM; }
size_t Size(void) { return sizeM; }
void Reset(void) { FREE_POINTER(dataM); sizeM = 0; };
};
uint16_t ts_pid(const uint8_t *bufP);
uint8_t payload(const uint8_t *bufP);
const char *id_pid(const u_short pidP);

View File

@@ -17,6 +17,7 @@ cSatipConfig::cSatipConfig(void)
ciExtensionM(0),
eitScanM(1),
useBytesM(1),
detachedModeM(false),
disableServerQuirksM(false),
useSingleModelServersM(false)
{

View File

@@ -19,6 +19,7 @@ private:
unsigned int ciExtensionM;
unsigned int eitScanM;
unsigned int useBytesM;
bool detachedModeM;
bool disableServerQuirksM;
bool useSingleModelServersM;
int cicamsM[MAX_CICAM_COUNT];
@@ -34,24 +35,24 @@ public:
eOperatingModeCount
};
enum eTraceMode {
eTraceModeNormal = 0x0000,
eTraceModeDebug1 = 0x0001,
eTraceModeDebug2 = 0x0002,
eTraceModeDebug3 = 0x0004,
eTraceModeDebug4 = 0x0008,
eTraceModeDebug5 = 0x0010,
eTraceModeDebug6 = 0x0020,
eTraceModeDebug7 = 0x0040,
eTraceModeDebug8 = 0x0080,
eTraceModeDebug9 = 0x0100,
eTraceModeDebug10 = 0x0200,
eTraceModeDebug11 = 0x0400,
eTraceModeDebug12 = 0x0800,
eTraceModeDebug13 = 0x1000,
eTraceModeDebug14 = 0x2000,
eTraceModeDebug15 = 0x4000,
eTraceModeDebug16 = 0x8000,
eTraceModeMask = 0xFFFF
eTraceModeNormal = 0x0000,
eTraceModeDebug1 = 0x0001,
eTraceModeDebug2 = 0x0002,
eTraceModeDebug3 = 0x0004,
eTraceModeDebug4 = 0x0008,
eTraceModeDebug5 = 0x0010,
eTraceModeDebug6 = 0x0020,
eTraceModeDebug7 = 0x0040,
eTraceModeDebug8 = 0x0080,
eTraceModeDebug9 = 0x0100,
eTraceModeDebug10 = 0x0200,
eTraceModeDebug11 = 0x0400,
eTraceModeDebug12 = 0x0800,
eTraceModeDebug13 = 0x1000,
eTraceModeDebug14 = 0x2000,
eTraceModeDebug15 = 0x4000,
eTraceModeDebug16 = 0x8000,
eTraceModeMask = 0xFFFF
};
cSatipConfig();
unsigned int GetOperatingMode(void) const { return operatingModeM; }
@@ -66,6 +67,7 @@ public:
int GetCICAM(unsigned int indexP) const;
unsigned int GetEITScan(void) const { return eitScanM; }
unsigned int GetUseBytes(void) const { return useBytesM; }
bool GetDetachedMode(void) const { return detachedModeM; }
bool GetDisableServerQuirks(void) const { return disableServerQuirksM; }
bool GetUseSingleModelServers(void) const { return useSingleModelServersM; }
unsigned int GetDisabledSourcesCount(void) const;
@@ -79,6 +81,7 @@ public:
void SetCICAM(unsigned int indexP, int cicamP);
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; }
void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; }
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);

View File

@@ -103,7 +103,12 @@ cString cSatipDevice::GetSatipStatus(void)
bool live = (device == cDevice::ActualDevice());
bool lock = device->HasLock();
const cChannel *channel = device->GetCurrentlyTunedTransponder();
#if defined(APIVERSNUM) && APIVERSNUM >= 20301
LOCK_TIMERS_READ;
for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer)) {
#else
for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
#endif
if (timer->Recording()) {
cRecordControl *control = cRecordControls::GetRecordControl(timer);
if (control && control->Device() == device)
@@ -128,13 +133,20 @@ cString cSatipDevice::GetSatipStatus(void)
cString cSatipDevice::GetGeneralInformation(void)
{
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
#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",
deviceIndexM, CardIndex(),
pTunerM ? *pTunerM->GetInformation() : "",
pTunerM ? *pTunerM->GetSignalStatus() : "",
pTunerM ? *pTunerM->GetTunerStatistic() : "",
*GetBufferStatistic(),
#if defined(APIVERSNUM) && APIVERSNUM >= 20301
*Channels->GetByNumber(cDevice::CurrentChannel())->ToText());
#else
*Channels.GetByNumber(cDevice::CurrentChannel())->ToText());
#endif
}
cString cSatipDevice::GetPidsInformation(void)
@@ -219,6 +231,8 @@ bool cSatipDevice::ProvidesSource(int sourceP) const
{
cSource *s = Sources.Get(sourceP);
debug9("%s (%c) desc='%s' [device %u]", __PRETTY_FUNCTION__, cSource::ToChar(sourceP), s ? s->Description() : "", deviceIndexM);
if (SatipConfig.GetDetachedMode())
return false;
// source descriptions starting with '0' are disabled
if (s && s->Description() && (*(s->Description()) == '0'))
return false;
@@ -348,7 +362,7 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
{
debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP->pid, typeP, onP, deviceIndexM);
debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP ? handleP->pid : -1, typeP, onP, deviceIndexM);
if (pTunerM && handleP && handleP->pid >= 0) {
if (onP)
return pTunerM->SetPid(handleP->pid, typeP, true);
@@ -458,6 +472,11 @@ int cSatipDevice::GetCISlot(void)
return slot;
}
bool cSatipDevice::IsIdle(void)
{
return !Receiving();
}
uchar *cSatipDevice::GetData(int *availableP)
{
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
@@ -501,6 +520,8 @@ void cSatipDevice::SkipData(int countP)
bool cSatipDevice::GetTSPacket(uchar *&dataP)
{
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
if (SatipConfig.GetDetachedMode())
return false;
if (tsBufferM) {
if (cCamSlot *cs = CamSlot()) {
if (cs->WantsTsData()) {

View File

@@ -43,7 +43,7 @@ private:
// constructor & destructor
public:
cSatipDevice(unsigned int deviceIndexP);
explicit cSatipDevice(unsigned int deviceIndexP);
virtual ~cSatipDevice();
cString GetInformation(unsigned int pageP = SATIP_DEVICE_INFO_ALL);
@@ -110,6 +110,7 @@ public:
virtual int GetId(void);
virtual int GetPmtPid(void);
virtual int GetCISlot(void);
virtual bool IsIdle(void);
};
#endif // __SATIP_DEVICE_H

View File

@@ -16,9 +16,10 @@ public:
virtual int GetId(void) = 0;
virtual int GetPmtPid(void) = 0;
virtual int GetCISlot(void) = 0;
virtual bool IsIdle(void) = 0;
private:
cSatipDeviceIf(const cSatipDeviceIf&);
explicit cSatipDeviceIf(const cSatipDeviceIf&);
cSatipDeviceIf& operator=(const cSatipDeviceIf&);
};

View File

@@ -47,43 +47,14 @@ void cSatipDiscover::Destroy(void)
instanceS->Deactivate();
}
size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
size_t cSatipDiscover::DataCallback(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) {
CURLcode res = CURLE_OK;
const char *desc = NULL, *model = NULL, *addr = NULL;
#ifdef USE_TINYXML
TiXmlDocument doc;
char *xml = MALLOC(char, len + 1);
memcpy(xml, ptrP, len);
*(xml + len + 1) = 0;
doc.Parse((const char *)xml);
TiXmlHandle docHandle(&doc);
TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement();
if (descElement)
desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware";
TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement();
if (modelElement)
model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1";
#else
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_buffer(ptrP, len);
if (result) {
pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName");
if (descNode)
desc = descNode.text().as_string("MyBrokenHardware");
pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP");
if (modelNode)
model = modelNode.text().as_string("DVBS2-1");
}
#endif
SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr);
obj->AddServer(addr, model, desc);
}
if (obj && (len > 0))
obj->dataBufferM.Add(ptrP, len);
return len;
}
@@ -120,6 +91,7 @@ int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *data
cSatipDiscover::cSatipDiscover()
: cThread("SATIP discover"),
mutexM(),
dataBufferM(),
msearchM(*this),
probeUrlListM(),
handleM(curl_easy_init()),
@@ -170,7 +142,7 @@ void cSatipDiscover::Action(void)
probeIntervalM.Set(eProbeIntervalMs);
msearchM.Probe();
mutexM.Lock();
serversM.Cleanup(eProbeIntervalMs * 2);
serversM.Cleanup(eCleanupTimeoutMs);
mutexM.Unlock();
}
mutexM.Lock();
@@ -195,6 +167,7 @@ void cSatipDiscover::Fetch(const char *urlP)
{
debug1("%s (%s)", __PRETTY_FUNCTION__, urlP);
if (handleM && !isempty(urlP)) {
const char *addr = NULL;
long rc = 0;
CURLcode res = CURLE_OK;
@@ -204,7 +177,7 @@ void cSatipDiscover::Fetch(const char *urlP)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this);
// Set callback
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
// No progress meter and no signaling
@@ -224,11 +197,44 @@ void cSatipDiscover::Fetch(const char *urlP)
// Fetch the data
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
if (rc != 200)
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_PRIMARY_IP, &addr);
if (rc == 200) {
ParseDeviceInfo(addr);
dataBufferM.Reset();
}
else
error("Discovery detected invalid status code: %ld", rc);
}
}
void cSatipDiscover::ParseDeviceInfo(const char *addrP)
{
debug1("%s (%s)", __PRETTY_FUNCTION__, addrP);
const char *desc = NULL, *model = NULL;
#ifdef USE_TINYXML
TiXmlDocument doc;
doc.Parse(dataBufferM.Data());
TiXmlHandle docHandle(&doc);
TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement();
if (descElement)
desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware";
TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement();
if (modelElement)
model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1";
#else
pugi::xml_document doc;
if (doc.load_buffer(dataBufferM.Data(), dataBufferM.Size())) {
pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName");
if (descNode)
desc = descNode.text().as_string("MyBrokenHardware");
pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP");
if (modelNode)
model = modelNode.text().as_string("DVBS2-1");
}
#endif
AddServer(addrP, model, desc);
}
void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char * descP)
{
debug1("%s (%s, %s, %s)", __PRETTY_FUNCTION__, addrP, modelP, descP);

View File

@@ -13,6 +13,7 @@
#include <vdr/thread.h>
#include <vdr/tools.h>
#include "common.h"
#include "discoverif.h"
#include "msearch.h"
#include "server.h"
@@ -39,15 +40,17 @@ class cSatipDiscoverServers : public cList<cSatipDiscoverServer> {
class cSatipDiscover : public cThread, public cSatipDiscoverIf {
private:
enum {
eSleepTimeoutMs = 500, // in milliseconds
eConnectTimeoutMs = 1500, // in milliseconds
eProbeTimeoutMs = 2000, // in milliseconds
eProbeIntervalMs = 60000 // in milliseconds
eSleepTimeoutMs = 500, // in milliseconds
eConnectTimeoutMs = 1500, // in milliseconds
eProbeTimeoutMs = 2000, // in milliseconds
eProbeIntervalMs = 60000, // in milliseconds
eCleanupTimeoutMs = 124000 // in milliseoonds
};
static cSatipDiscover *instanceS;
static size_t WriteCallback(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 dataBufferM;
cSatipMsearch msearchM;
cStringList probeUrlListM;
CURL *handleM;
@@ -56,6 +59,7 @@ 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);
void Fetch(const char *urlP);
// constructor

View File

@@ -15,7 +15,7 @@ public:
virtual void SetUrl(const char *urlP) = 0;
private:
cSatipDiscoverIf(const cSatipDiscoverIf&);
explicit cSatipDiscoverIf(const cSatipDiscoverIf&);
cSatipDiscoverIf& operator=(const cSatipDiscoverIf&);
};

5
log.h
View File

@@ -34,9 +34,9 @@
#define debug10(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug10) ? dsyslog("SATIP10: " x) : void() )
// 0x0400: CI
#define debug11(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug11) ? dsyslog("SATIP11: " x) : void() )
// 0x0800: Discovery
// 0x0800: Pids
#define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() )
// 0x1000: Pids
// 0x1000: Discovery
#define debug13(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug13) ? dsyslog("SATIP13: " x) : void() )
// 0x2000: TBD
#define debug14(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug14) ? dsyslog("SATIP14: " x) : void() )
@@ -46,4 +46,3 @@
#define debug16(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug16) ? dsyslog("SATIP16: " x) : void() )
#endif // __SATIP_LOG_H

View File

@@ -45,6 +45,9 @@ void cSatipMsearch::Probe(void)
cSatipPoller::GetInstance()->Register(*this);
registeredM = true;
}
// Send two queries with one second interval
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
cCondWait::SleepMs(1000);
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
}
@@ -60,12 +63,12 @@ void cSatipMsearch::Process(void)
int length;
while ((length = Read(bufferM, bufferLenM)) > 0) {
bufferM[min(length, int(bufferLenM - 1))] = 0;
debug12("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM);
debug13("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM);
bool status = false, valid = false;
char *s, *p = reinterpret_cast<char *>(bufferM), *location = NULL;
char *r = strtok_r(p, "\r\n", &s);
while (r) {
debug12("%s r=%s", __PRETTY_FUNCTION__, r);
debug13("%s r=%s", __PRETTY_FUNCTION__, r);
// Check the status code
// HTTP/1.1 200 OK
if (!status && startswith(r, "HTTP/1.1 200 OK"))

View File

@@ -26,7 +26,7 @@ private:
bool registeredM;
public:
cSatipMsearch(cSatipDiscoverIf &discoverP);
explicit cSatipMsearch(cSatipDiscoverIf &discoverP);
virtual ~cSatipMsearch();
void Probe(void);

18
param.c
View File

@@ -147,9 +147,6 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
cDvbTransponderParameters dtp(channelP->Parameters());
int DataSlice = 0;
int C2TuningFrequencyType = 0;
int Pilot = dtp.Pilot();
int T2SystemId = dtp.T2SystemId();
int SisoMiso = dtp.SisoMiso();
float freq = channelP->Frequency();
char type = cSource::ToChar(channelP->Source());
cSource *source = Sources.Get(channelP->Source());
@@ -161,26 +158,31 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
freq /= 1000L;
#define ST(s) if (strchr(s, type) && (strchr(s, '0' + dtp.System() + 1) || strchr(s, '*')))
#define STBUFLEFT (sizeof(buffer) - (q - buffer))
ST(" S 1") { // to comply with SAT>IP protocol specification 1.2.2
dtp.SetPilot(PILOT_OFF);
dtp.SetModulation(QPSK);
dtp.SetRollOff(ROLLOFF_35);
}
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", T2SystemId);
ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", dtp.T2SystemId());
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, SisoMiso, SatipSisoMisoValues);
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 2") q += PrintUrlString(q, STBUFLEFT, Pilot, SatipPilotValues);
ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
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 2") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues);
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);

View File

@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 2.2.0\n"
"Project-Id-Version: vdr-satip 2.2.3\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2015-02-19 02:19+0200\n"
"PO-Revision-Date: 2015-02-19 02:19+0200\n"
"POT-Creation-Date: 2015-04-26 04:26+0300\n"
"PO-Revision-Date: 2015-04-26 04:26+0300\n"
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
"Language-Team: Catalan <vdr@linuxtv.org>\n"
"Language: ca\n"

View File

@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 2.2.0\n"
"Project-Id-Version: vdr-satip 2.2.3\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2015-02-19 02:19+0200\n"
"PO-Revision-Date: 2015-02-19 02:19+0200\n"
"POT-Creation-Date: 2015-04-26 04:26+0300\n"
"PO-Revision-Date: 2015-04-26 04:26+0300\n"
"Last-Translator: Frank Neumann <fnu@yavdr.org>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
"Language: de\n"

View File

@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 2.2.0\n"
"Project-Id-Version: vdr-satip 2.2.3\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2015-02-19 02:19+0200\n"
"PO-Revision-Date: 2015-02-19 02:19+0200\n"
"POT-Creation-Date: 2015-04-26 04:26+0300\n"
"PO-Revision-Date: 2015-04-26 04:26+0300\n"
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
"Language-Team: Spanish <vdr@linuxtv.org>\n"
"Language: es\n"

View File

@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 2.2.0\n"
"Project-Id-Version: vdr-satip 2.2.3\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2015-02-19 02:19+0200\n"
"PO-Revision-Date: 2015-02-19 02:19+0200\n"
"POT-Creation-Date: 2015-04-26 04:26+0300\n"
"PO-Revision-Date: 2015-04-26 04:26+0300\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
"Language: fi\n"

View File

@@ -17,7 +17,7 @@ public:
virtual cString ToString(void) const = 0;
private:
cSatipPollerIf(const cSatipPollerIf&);
explicit cSatipPollerIf(const cSatipPollerIf&);
cSatipPollerIf& operator=(const cSatipPollerIf&);
};

2
rtcp.c
View File

@@ -36,7 +36,7 @@ int cSatipRtcp::GetFd(void)
int cSatipRtcp::GetApplicationOffset(int *lengthP)
{
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, *lengthP, tunerM.GetId());
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP ? *lengthP : -1, tunerM.GetId());
if (!lengthP)
return -1;
int offset = 0;

2
rtcp.h
View File

@@ -23,7 +23,7 @@ private:
int GetApplicationOffset(int *lengthP);
public:
cSatipRtcp(cSatipTunerIf &tunerP);
explicit cSatipRtcp(cSatipTunerIf &tunerP);
virtual ~cSatipRtcp();
// for internal poller interface

2
rtp.h
View File

@@ -28,7 +28,7 @@ private:
int GetHeaderLength(unsigned char *bufferP, unsigned int lengthP);
public:
cSatipRtp(cSatipTunerIf &tunerP);
explicit cSatipRtp(cSatipTunerIf &tunerP);
virtual ~cSatipRtp();
virtual void Close(void);

201
rtsp.c
View File

@@ -15,9 +15,14 @@
cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP)
: tunerM(tunerP),
headerBufferM(),
dataBufferM(),
modeM(cmUnicast),
handleM(NULL),
headerListM(NULL)
headerListM(NULL),
errorNoMoreM(""),
errorOutOfRangeM(""),
errorCheckSyntaxM("")
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
Create();
@@ -29,46 +34,26 @@ cSatipRtsp::~cSatipRtsp()
Destroy();
}
size_t cSatipRtsp::HeaderCallback(void *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);
char *s, *p = (char *)ptrP;
char *r = strtok_r(p, "\r\n", &s);
while (obj && r) {
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, len, r);
r = skipspace(r);
if (strstr(r, "com.ses.streamID")) {
int streamid = -1;
if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1)
obj->tunerM.SetStreamId(streamid);
}
else if (strstr(r, "Session:")) {
int timeout = -1;
char *session = NULL;
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
obj->tunerM.SetSessionTimeout(skipspace(session), timeout * 1000);
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
obj->tunerM.SetSessionTimeout(skipspace(session), -1);
FREE_POINTER(session);
}
r = strtok_r(NULL, "\r\n", &s);
}
return len;
}
size_t cSatipRtsp::WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
size_t cSatipRtsp::HeaderCallback(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 && (len > 0))
obj->tunerM.ProcessApplicationData((u_char*)ptrP, len);
obj->headerBufferM.Add(ptrP, len);
return len;
}
size_t cSatipRtsp::DataCallback(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)
obj->dataBufferM.Add(ptrP, len);
return len;
}
@@ -216,10 +201,22 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP)
// Set header callback for catching the session and timeout
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipRtsp::HeaderCallback);
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_PERFORM(handleM);
// Session id is now known - disable header parsing
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
if (headerBufferM.Size() > 0) {
ParseHeader();
headerBufferM.Reset();
}
if (dataBufferM.Size() > 0) {
ParseData();
dataBufferM.Reset();
}
result = ValidateLatestResponse(&rc);
debug5("%s (%s, %d, %d) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, rc, processing.Elapsed(), tunerM.GetId());
@@ -253,11 +250,15 @@ bool cSatipRtsp::Describe(const char *uriP)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::WriteCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
if (dataBufferM.Size() > 0) {
tunerM.ProcessApplicationData((u_char *)dataBufferM.Data(), dataBufferM.Size());
dataBufferM.Reset();
}
result = ValidateLatestResponse(&rc);
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
@@ -278,7 +279,15 @@ bool cSatipRtsp::Play(const char *uriP)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
if (dataBufferM.Size() > 0) {
ParseData();
dataBufferM.Reset();
}
result = ValidateLatestResponse(&rc);
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
@@ -299,7 +308,15 @@ bool cSatipRtsp::Teardown(const char *uriP)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, 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_PERFORM(handleM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
if (dataBufferM.Size() > 0) {
ParseData();
dataBufferM.Reset();
}
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_CLIENT_CSEQ, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL);
@@ -311,24 +328,122 @@ bool cSatipRtsp::Teardown(const char *uriP)
return result;
}
void cSatipRtsp::ParseHeader(void)
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
char *s, *p = headerBufferM.Data();
char *r = strtok_r(p, "\r\n", &s);
while (r) {
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r);
r = skipspace(r);
if (strstr(r, "com.ses.streamID")) {
int streamid = -1;
if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1)
tunerM.SetStreamId(streamid);
}
else if (strstr(r, "Session:")) {
int timeout = -1;
char *session = NULL;
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
tunerM.SetSessionTimeout(skipspace(session), timeout * 1000);
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
tunerM.SetSessionTimeout(skipspace(session), -1);
FREE_POINTER(session);
}
r = strtok_r(NULL, "\r\n", &s);
}
}
void cSatipRtsp::ParseData(void)
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
char *s, *p = dataBufferM.Data();
char *r = strtok_r(p, "\r\n", &s);
while (r) {
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, dataBufferM.Size(), r);
r = skipspace(r);
if (strstr(r, "No-More:")) {
char *tmp = NULL;
if (sscanf(r, "No-More:%m[^;]", &tmp) == 1) {
errorNoMoreM = skipspace(tmp);
debug3("%s No-More: %s [device %d]", __PRETTY_FUNCTION__, *errorNoMoreM, tunerM.GetId());
}
FREE_POINTER(tmp);
}
else if (strstr(r, "Out-of-Range:")) {
char *tmp = NULL;
if (sscanf(r, "Out-of-Range:%m[^;]", &tmp) == 1) {
errorOutOfRangeM = skipspace(tmp);
debug3("%s Out-of-Range: %s [device %d]", __PRETTY_FUNCTION__, *errorOutOfRangeM, tunerM.GetId());
}
FREE_POINTER(tmp);
}
else if (strstr(r, "Check-Syntax:")) {
char *tmp = NULL;
if (sscanf(r, "Check-Syntax:%m[^;]", &tmp) == 1) {
errorCheckSyntaxM = skipspace(tmp);
debug3("%s Check-Syntax: %s [device %d]", __PRETTY_FUNCTION__, *errorCheckSyntaxM, tunerM.GetId());
}
FREE_POINTER(tmp);
}
r = strtok_r(NULL, "\r\n", &s);
}
}
bool cSatipRtsp::ValidateLatestResponse(long *rcP)
{
bool result = false;
if (handleM) {
char *url = NULL;
long rc = 0;
CURLcode res = CURLE_OK;
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
if (rc == 200)
result = true;
else if (rc != 0) {
char *url = NULL;
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("Detected invalid status code %ld: %s [device %d]", rc, url, tunerM.GetId());
}
switch (rc) {
case 200:
result = true;
break;
case 400:
// SETUP PLAY TEARDOWN
// The message body of the response may contain the "Check-Syntax:" parameter followed
// by the malformed syntax
if (!isempty(*errorCheckSyntaxM)) {
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("Check syntax: %s (error code %ld: %s) [device %d]", *errorCheckSyntaxM, rc, url, tunerM.GetId());
break;
}
case 403:
// 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
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());
break;
}
case 503:
// SETUP PLAY
// The message body of the response may contain the "No-More:" parameter followed
// by a space-separated list of the missing ressources: “sessions” "frontends" "pids
if (!isempty(*errorNoMoreM)) {
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("No more: %s (error code %ld: %s) [device %d]", *errorNoMoreM, rc, url, tunerM.GetId());
break;
}
default:
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("Detected invalid status code %ld: %s [device %d]", rc, url, tunerM.GetId());
break;
}
if (rcP)
*rcP = rc;
}
errorNoMoreM = "";
errorOutOfRangeM = "";
errorCheckSyntaxM = "";
debug1("%s result=%s [device %d]", __PRETTY_FUNCTION__, result ? "ok" : "failed", tunerM.GetId());
return result;

14
rtsp.h
View File

@@ -15,12 +15,13 @@
#error "libcurl is missing required RTSP support"
#endif
#include "common.h"
#include "tunerif.h"
class cSatipRtsp {
private:
static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
enum {
@@ -29,12 +30,19 @@ private:
enum eCommunicationMode { cmUnicast, cmMulticast };
cSatipTunerIf &tunerM;
cSatipMemoryBuffer headerBufferM;
cSatipMemoryBuffer dataBufferM;
eCommunicationMode modeM;
CURL *handleM;
struct curl_slist *headerListM;
cString errorNoMoreM;
cString errorOutOfRangeM;
cString errorCheckSyntaxM;
void Create(void);
void Destroy(void);
void ParseHeader(void);
void ParseData(void);
bool ValidateLatestResponse(long *rcP);
// to prevent copy constructor and assignment
@@ -42,7 +50,7 @@ private:
cSatipRtsp& operator=(const cSatipRtsp&);
public:
cSatipRtsp(cSatipTunerIf &tunerP);
explicit cSatipRtsp(cSatipTunerIf &tunerP);
virtual ~cSatipRtsp();
cString RtspUnescapeString(const char *strP);

44
satip.c
View File

@@ -27,7 +27,7 @@
#define GITVERSION ""
#endif
const char VERSION[] = "2.2.0" GITVERSION;
const char VERSION[] = "2.2.3" GITVERSION;
static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
class cPluginSatip : public cPlugin {
@@ -62,7 +62,7 @@ public:
};
cPluginSatip::cPluginSatip(void)
: deviceCountM(1),
: deviceCountM(2),
serversM(NULL)
{
debug16("%s", __PRETTY_FUNCTION__);
@@ -85,6 +85,7 @@ const char *cPluginSatip::CommandLineHelp(void)
" -t <mode>, --trace=<mode> set the tracing mode\n"
" -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>|<model2>|<desc2>\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";
}
@@ -97,6 +98,7 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
{ "devices", required_argument, NULL, 'd' },
{ "trace", required_argument, NULL, 't' },
{ "server", required_argument, NULL, 's' },
{ "detach", no_argument, NULL, 'D' },
{ "single", no_argument, NULL, 'S' },
{ "noquirks", no_argument, NULL, 'n' },
{ NULL, no_argument, NULL, 0 }
@@ -104,7 +106,7 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
cString server;
int c;
while ((c = getopt_long(argc, argv, "d:t:s:Sn", long_options, NULL)) != -1) {
while ((c = getopt_long(argc, argv, "d:t:s:DSn", long_options, NULL)) != -1) {
switch (c) {
case 'd':
deviceCountM = strtol(optarg, NULL, 0);
@@ -115,6 +117,9 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
case 's':
server = optarg;
break;
case 'D':
SatipConfig.SetDetachedMode(true);
break;
case 'S':
SatipConfig.SetUseSingleModelServers(true);
break;
@@ -366,8 +371,12 @@ const char **cPluginSatip::SVDRPHelpPages(void)
" Lists status information of SAT>IP devices.\n",
"CONT\n"
" Shows SAT>IP device count.\n",
"OPER\n"
" Toggles operating mode of SAT>IP devices.\n",
"OPER [ off | low | normal | high ]\n"
" Gets and(or sets operating mode of SAT>IP devices.\n",
"ATTA\n"
" Attach active SAT>IP servers.\n",
"DETA\n"
" Detachs active SAT>IP servers.\n",
"TRAC [ <mode> ]\n"
" Gets and/or sets used tracing mode.\n",
NULL
@@ -434,8 +443,19 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
}
else if (strcasecmp(commandP, "OPER") == 0) {
cString mode;
SatipConfig.ToggleOperatingMode();
switch (SatipConfig.GetOperatingMode()) {
unsigned int oper = SatipConfig.GetOperatingMode();
if (optionP && *optionP) {
if (strcasecmp(optionP, "off") == 0)
oper = cSatipConfig::eOperatingModeOff;
else if (strcasecmp(optionP, "low") == 0)
oper = cSatipConfig::eOperatingModeLow;
else if (strcasecmp(optionP, "normal") == 0)
oper = cSatipConfig::eOperatingModeNormal;
else if (strcasecmp(optionP, "high") == 0)
oper = cSatipConfig::eOperatingModeHigh;
SatipConfig.SetOperatingMode(oper);
}
switch (oper) {
case cSatipConfig::eOperatingModeOff:
mode = "off";
break;
@@ -454,6 +474,16 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
}
return cString::sprintf("SATIP operating mode: %s\n", *mode);
}
else if (strcasecmp(commandP, "ATTA") == 0) {
SatipConfig.SetDetachedMode(false);
info("SATIP servers attached");
return cString("SATIP servers attached");
}
else if (strcasecmp(commandP, "DETA") == 0) {
SatipConfig.SetDetachedMode(true);
info("SATIP servers detached");
return cString("SATIP servers detached");
}
else if (strcasecmp(commandP, "TRAC") == 0) {
if (optionP && *optionP)
SatipConfig.SetTraceMode(strtol(optionP, NULL, 0));

View File

@@ -108,7 +108,8 @@ cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char
quirksM = cString::sprintf("%s%sPlayPids", *quirksM, isempty(*quirksM) ? "" : ",");
}
// These devices contain a frontend locking bug:
if (strstr(*descriptionM, "fritzdvbc") // Fritz!WLAN Repeater DVB-C
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) ? "" : ",");
@@ -116,8 +117,11 @@ cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char
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
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
strstr(*descriptionM, "minisatip") // minisatip server
) {
hasCiM = true;
}
char *s, *p = strdup(*modelM);
char *r = strtok_r(p, ",", &s);
while (r) {

24
setup.c
View File

@@ -94,7 +94,7 @@ private:
void Setup(void);
public:
cSatipServerInfo(cSatipServer *serverP);
explicit cSatipServerInfo(cSatipServer *serverP);
virtual ~cSatipServerInfo();
virtual eOSState ProcessKey(eKeys keyP);
};
@@ -145,7 +145,7 @@ private:
cSatipServer *serverM;
public:
cSatipServerItem(cSatipServer *serverP);
explicit cSatipServerItem(cSatipServer *serverP);
cSatipServer *Server(void) { return serverM; }
virtual void SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP);
};
@@ -330,7 +330,8 @@ eOSState cSatipMenuInfo::ProcessKey(eKeys keyP)
// --- cSatipPluginSetup ------------------------------------------------------
cSatipPluginSetup::cSatipPluginSetup()
: deviceCountM(0),
: detachedModeM(SatipConfig.GetDetachedMode()),
deviceCountM(0),
operatingModeM(SatipConfig.GetOperatingMode()),
ciExtensionM(SatipConfig.GetCIExtension()),
eitScanM(SatipConfig.GetEITScan()),
@@ -402,12 +403,15 @@ void cSatipPluginSetup::Setup(void)
Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false));
helpM.Append("");
cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers();
deviceCountM = servers->Count();
for (cSatipServer *s = servers->First(); s; s = servers->Next(s)) {
Add(new cSatipServerItem(s));
helpM.Append("");
}
detachedModeM = SatipConfig.GetDetachedMode();
if (!detachedModeM) {
cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers();
deviceCountM = servers->Count();
for (cSatipServer *s = servers->First(); s; s = servers->Next(s)) {
Add(new cSatipServerItem(s));
helpM.Append("");
}
}
SetCurrent(Get(current));
Display();
@@ -480,7 +484,7 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
if ((keyP == kNone) && (cSatipDiscover::GetInstance()->GetServers()->Count() != deviceCountM))
Setup();
if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode) || (ciExtensionM != oldCiExtension))) {
if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode) || (ciExtensionM != oldCiExtension) || (detachedModeM != SatipConfig.GetDetachedMode()))) {
while ((numDisabledSourcesM < oldNumDisabledSources) && (oldNumDisabledSources > 0))
disabledSourcesM[--oldNumDisabledSources] = cSource::stNone;
while ((numDisabledFiltersM < oldNumDisabledFilters) && (oldNumDisabledFilters > 0))

View File

@@ -15,6 +15,7 @@
class cSatipPluginSetup : public cMenuSetupPage
{
private:
bool detachedModeM;
int deviceCountM;
int operatingModeM;
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];

24
tuner.c
View File

@@ -91,6 +91,10 @@ cSatipTuner::~cSatipTuner()
void cSatipTuner::Action(void)
{
debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIdM);
bool lastIdleStatus = false;
cTimeMs idleCheck(eIdleCheckTimeoutMs);
cTimeMs tuning(eTuningTimeoutMs);
reConnectM.Set(eConnectTimeoutMs);
// Do the thread loop
while (Running()) {
@@ -107,6 +111,7 @@ void cSatipTuner::Action(void)
case tsSet:
debug4("%s: tsSet [device %d]", __PRETTY_FUNCTION__, deviceIdM);
if (Connect()) {
tuning.Set(eTuningTimeoutMs);
RequestState(tsTuned, smInternal);
UpdatePids(true);
}
@@ -116,6 +121,8 @@ void cSatipTuner::Action(void)
case tsTuned:
debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM);
reConnectM.Set(eConnectTimeoutMs);
idleCheck.Set(eIdleCheckTimeoutMs);
lastIdleStatus = false;
// Read reception statistics via DESCRIBE and RTCP
if (hasLockM || ReadReceptionStatus()) {
// Quirk for devices without valid reception data
@@ -127,6 +134,10 @@ void cSatipTuner::Action(void)
if (hasLockM)
RequestState(tsLocked, smInternal);
}
else if (tuning.TimedOut()) {
error("Tuning timeout - retuning [device %d]", deviceIdM);
RequestState(tsSet, smInternal);
}
break;
case tsLocked:
debug4("%s: tsLocked [device %d]", __PRETTY_FUNCTION__, deviceIdM);
@@ -145,6 +156,16 @@ void cSatipTuner::Action(void)
RequestState(tsSet, smInternal);
break;
}
if (idleCheck.TimedOut()) {
bool currentIdleStatus = deviceM->IsIdle();
if (lastIdleStatus && currentIdleStatus) {
info("Idle timeout - releasing [device %d]", deviceIdM);
RequestState(tsRelease, smInternal);
}
lastIdleStatus = currentIdleStatus;
idleCheck.Set(eIdleCheckTimeoutMs);
break;
}
break;
default:
error("Unknown tuner status %d [device %d]", currentStateM, deviceIdM);
@@ -209,8 +230,7 @@ bool cSatipTuner::Connect(void)
return true;
}
}
else
rtspM.Reset();
rtspM.Reset();
streamIdM = -1;
error("Connect failed [device %d]", deviceIdM);
}

View File

@@ -83,6 +83,8 @@ private:
eStatusUpdateTimeoutMs = 1000, // in milliseconds
ePidUpdateIntervalMs = 250, // in milliseconds
eConnectTimeoutMs = 5000, // in milliseconds
eIdleCheckTimeoutMs = 15000, // in milliseconds
eTuningTimeoutMs = 20000, // in milliseconds
eMinKeepAliveIntervalMs = 30000 // in milliseconds
};
enum eTunerState { tsIdle, tsRelease, tsSet, tsTuned, tsLocked };

View File

@@ -19,7 +19,7 @@ public:
virtual int GetId(void) = 0;
private:
cSatipTunerIf(const cSatipTunerIf&);
explicit cSatipTunerIf(const cSatipTunerIf&);
cSatipTunerIf& operator=(const cSatipTunerIf&);
};