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

11 Commits

Author SHA1 Message Date
Rolf Ahrenberg
5e8b7b7c5e Fixed keepalive heartbeat again. 2014-04-01 09:05:13 +03:00
Rolf Ahrenberg
88b2ad9244 Added missing RTP packet error message. 2014-03-30 22:58:43 +03:00
Rolf Ahrenberg
7b58d9f28f Added a check to write new sections only if there is no data in the read socket. 2014-03-30 22:20:56 +03:00
Rolf Ahrenberg
f493df0e3d Changed implementation to report about RTP packet errors on 5 minutes interval only. 2014-03-30 18:20:20 +03:00
Rolf Ahrenberg
9a6ae40954 Optimized the startup delay. 2014-03-28 19:53:22 +02:00
Rolf Ahrenberg
b5ec84fd91 Fixed keepalive heartbeat. 2014-03-28 19:52:17 +02:00
Rolf Ahrenberg
e7a74f3ad4 Fixed reconnection. 2014-03-25 23:50:30 +02:00
Rolf Ahrenberg
40d280af10 Fixed pid leaking while disabling section filters, EIT filter defition and RTP sequence overflow detection. 2014-03-25 23:25:36 +02:00
Rolf Ahrenberg
9f2d99435d Added support for cDevice::Ready() and preliminary RTP packet sequence check. 2014-03-23 17:59:08 +02:00
Rolf Ahrenberg
06dd2f7261 Fixed dates. 2014-03-16 22:30:48 +02:00
Rolf Ahrenberg
dfbb3515ef Changed code to utilize a proper XML library, refactored the session code, fxed EIT scan functionality, and updated for vdr-2.1.6. 2014-03-16 19:58:09 +02:00
20 changed files with 310 additions and 126 deletions

21
HISTORY
View File

@@ -12,3 +12,24 @@ VDR Plugin 'satip' Revision History
- Switched to the standard S/T/C source identifiers.
- Added a new operation mode setup parameter.
- Added new SVDRP commands.
2014-03-16: Version 0.1.1
- Changed code to utilize a proper XML library.
- Refactored the session code.
- Fixed EIT scan functionality.
- Updated for vdr-2.1.6.
2014-03-28: Version 0.2.0
- Added support for cDevice::Ready().
- Fixed pid leaking while disabling section filters.
- Fixed keepalive heartbeat.
2014-04-01: Version 0.2.1
- Changed implementation to report about RTP packet
errors on 5 minutes interval only.
- Added a check to write new sections only if there
is no data in the read socket.
- Fixed keepalive heartbeat again.

View File

@@ -6,6 +6,10 @@
#SATIP_DEBUG = 1
# Use TinyXML instead of PugiXML
#SATIP_USE_TINYXML = 1
# Strip debug symbols? Set eg. to /bin/true if not
STRIP = strip
@@ -64,6 +68,13 @@ INCLUDES +=
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
ifdef SATIP_USE_TINYXML
DEFINES += -DUSE_TINYXML
LIBS += -ltinyxml
else
LIBS += -lpugixml
endif
ifdef SATIP_DEBUG
DEFINES += -DDEBUG
endif

15
README
View File

@@ -17,6 +17,12 @@ Requirements:
- Libcurl - the multiprotocol file transfer library with RTSP support
http://curl.haxx.se/libcurl/
- PugiXML - Light-weight, simple and fast XML parser for C++
http://pugixml.org/
or
TinyXML - a simple, small, C++ XML parser
http://www.grinninglizard.com/tinyxml/
- VDR-2.1.4+ for scrambled channels
Description:
@@ -92,18 +98,23 @@ Notes:
result of invalid channel parameters or lack of free SAT>IP tuners.
- SAT>IP specification 1.2 doesn't support DVB-C/DVB-C2 receivers yet,
but DVB-C is supported for Digital Devices Octopus Net devices.
but DVB-C (KABEL>IP) is supported for Digital Devices Octopus Net
devices.
- If the plugin doesn't detect your SAT>IP network device, make sure
your setup doesn't have firewalled the UDP port 1900.
- Stream decryption requires a separate CAM plugin that works without
direct access to any DVB card devices.
direct access to any DVB card devices. The integrated CAM slot in
Octopus Net devices isn't supported.
- The 100% compliance against SAT>IP specification 1.2 requires a
patched VDR providing channel configuration for pilot, T2 system id,
and SISO/MISO values.
- If you're using Triax TSS400, you'll need the libcurl from 2013-03-20
or newer.
Acknowledgements:
- Big thanks to Digital Devices GmbH for providing the Octopus Net

View File

@@ -57,6 +57,30 @@ char *StripTags(char *strP)
return NULL;
}
int select_single_desc(int descriptorP, const int msP, const bool selectWriteP)
{
// Wait for data
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = msP * 1000L;
// Use select
fd_set infd;
fd_set outfd;
fd_set errfd;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(descriptorP, &errfd);
if (selectWriteP)
FD_SET(descriptorP, &outfd);
else
FD_SET(descriptorP, &infd);
int retval = select(descriptorP + 1, &infd, &outfd, &errfd, &tv);
// Check if error
ERROR_IF_RET(retval < 0, "select()", return retval);
return retval;
}
cString ChangeCase(const cString &strP, bool upperP)
{
cString res(strP);
@@ -70,12 +94,10 @@ cString ChangeCase(const cString &strP, bool upperP)
const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE] =
{
/* description tag pid tid mask */
{trNOOP("PAT (0x00)"), "PAT", 0x00, 0x00, 0xFF},
{trNOOP("NIT (0x40)"), "NIT", 0x10, 0x40, 0xFF},
{trNOOP("SDT (0x42)"), "SDT", 0x11, 0x42, 0xFF},
{trNOOP("EIT (0x4E/0x4F)"), "EIT", 0x12, 0x4E, 0xFE},
{trNOOP("EIT (0x5X)"), "EIT", 0x12, 0x50, 0xF0},
{trNOOP("EIT (0x6X)"), "EIT", 0x12, 0x60, 0xF0},
{trNOOP("TDT (0x70)"), "TDT", 0x14, 0x70, 0xFF},
/* description tag pid tid mask */
{trNOOP("PAT (0x00)"), "PAT", 0x00, 0x00, 0xFF},
{trNOOP("NIT (0x40)"), "NIT", 0x10, 0x40, 0xFF},
{trNOOP("SDT (0x42)"), "SDT", 0x11, 0x42, 0xFF},
{trNOOP("EIT (0x4E/0x4F/0x5X/0x6X)"), "EIT", 0x12, 0x40, 0xC0},
{trNOOP("TDT (0x70)"), "TDT", 0x14, 0x70, 0xFF},
};

View File

@@ -36,7 +36,7 @@
#define SATIP_STATS_ACTIVE_PIDS_COUNT 10
#define SATIP_STATS_ACTIVE_FILTERS_COUNT 10
#define SECTION_FILTER_TABLE_SIZE 7
#define SECTION_FILTER_TABLE_SIZE 5
#define SATIP_CURL_EASY_GETINFO(X, Y, Z) \
if ((res = curl_easy_getinfo((X), (Y), (Z))) != CURLE_OK) { \
@@ -78,12 +78,22 @@
} \
} while (0)
#define FREE_POINTER(ptr) \
do { \
if (ptr) { \
typeof(*ptr) *tmp = ptr; \
ptr = NULL; \
free(tmp); \
} \
} while (0)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
uint16_t ts_pid(const uint8_t *bufP);
uint8_t payload(const uint8_t *bufP);
const char *id_pid(const u_short pidP);
char *StripTags(char *strP);
int select_single_desc(int descriptorP, const int msP, const bool selectWriteP);
cString ChangeCase(const cString &strP, bool upperP);
struct section_filter_table_type {

View File

@@ -19,7 +19,9 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
isPacketDeliveredM(false),
isOpenDvrM(false),
deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)),
channelM()
channelM(),
createdM(0),
mutexM()
{
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
bufsize -= (bufsize % TS_SIZE);
@@ -144,6 +146,12 @@ cString cSatipDevice::GetInformation(unsigned int pageP)
return s;
}
bool cSatipDevice::Ready(void)
{
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
return ((cSatipDiscover::GetInstance()->GetServerCount() > 0) || (createdM.Elapsed() > eReadyTimeoutMs));
}
cString cSatipDevice::DeviceType(void) const
{
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
@@ -224,7 +232,7 @@ bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool
bool cSatipDevice::ProvidesEIT(void) const
{
return (SatipConfig.GetEITScan() && pTunerM && pTunerM->IsTuned());
return (SatipConfig.GetEITScan());
}
int cSatipDevice::NumProvidedSystems(void) const
@@ -300,11 +308,12 @@ bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
int cSatipDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP)
{
//debug("cSatipDevice::%s(%u): pid=%d tid=%d mask=%d", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
//debug("cSatipDevice::%s(%u): pid=%d tid=%d mask=%d", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
if (pSectionFilterHandlerM) {
if (pTunerM)
int handle = pSectionFilterHandlerM->Open(pidP, tidP, maskP);
if (pTunerM && (handle >= 0))
pTunerM->SetPid(pidP, ptOther, true);
return pSectionFilterHandlerM->Open(pidP, tidP, maskP);
return handle;
}
return -1;
}

View File

@@ -26,6 +26,9 @@ public:
// private parts
private:
enum {
eReadyTimeoutMs = 2000 // in milliseconds
};
unsigned int deviceIndexM;
bool isPacketDeliveredM;
bool isOpenDvrM;
@@ -34,6 +37,7 @@ private:
cRingBufferLinear *tsBufferM;
cSatipTuner *pTunerM;
cSatipSectionFilterHandler *pSectionFilterHandlerM;
cTimeMs createdM;
cMutex mutexM;
// constructor & destructor
@@ -54,6 +58,7 @@ private:
// for channel info
public:
virtual bool Ready(void);
virtual cString DeviceType(void) const;
virtual cString DeviceName(void) const;
virtual bool AvoidRecording(void) const;

View File

@@ -6,7 +6,11 @@
*/
#include <string.h>
#ifdef USE_TINYXML
#include <tinyxml.h>
#else
#include <pugixml.hpp>
#endif
#include "common.h"
#include "config.h"
#include "socket.h"
@@ -43,28 +47,40 @@ void cSatipDiscover::Destroy(void)
instanceS->Deactivate();
}
size_t cSatipDiscover::WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
{
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
size_t len = sizeP * nmembP;
//debug("cSatipDiscover::%s(%zu)", __FUNCTION__, len);
char *s, *p = (char *)ptrP;
char *r = strtok_r(p, "\r\n", &s);
char *desc = NULL, *model = NULL, *addr = NULL;
while (r) {
//debug("cSatipDiscover::%s(%zu): %s", __FUNCTION__, len, r);
r = skipspace(r);
// <friendlyName>OctopusNet</friendlyName>
if (startswith(r, "<friendlyName"))
desc = StripTags(r);
// <satip:X_SATIPCAP xmlns:satip="urn:ses-com:satip">DVBT-2</satip:X_SATIPCAP>
if (startswith(r, "<satip:X_SATIPCAP"))
model = StripTags(r);
r = strtok_r(NULL, "\r\n", &s);
}
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, desc, model);
}
@@ -235,6 +251,13 @@ void cSatipDiscover::AddServer(const char *addrP, const char *descP, const char
}
}
int cSatipDiscover::GetServerCount(void)
{
//debug("cSatipDiscover::%s()", __FUNCTION__);
cMutexLock MutexLock(&mutexM);
return serversM ? serversM->Count() : -1;
}
cSatipServer *cSatipDiscover::GetServer(int sourceP, int systemP)
{
//debug("cSatipDiscover::%s(%d, %d)", __FUNCTION__, sourceP, systemP);

View File

@@ -28,7 +28,7 @@ private:
static cSatipDiscover *instanceS;
static const char *bcastAddressS;
static const char *bcastMessageS;
static size_t WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
cMutex mutexM;
CURL *handleM;
cSatipSocket *socketM;
@@ -56,6 +56,7 @@ public:
static void Destroy(void);
virtual ~cSatipDiscover();
void TriggerScan(void) { probeIntervalM.Set(0); }
int GetServerCount(void);
cSatipServer *GetServer(int sourceP, int systemP = -1);
cSatipServer *GetServer(cSatipServer *serverP);
cSatipServers *GetServers(void);

12
param.c
View File

@@ -138,9 +138,15 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
if (channelP) {
char buffer[255];
cDvbTransponderParameters dtp(channelP->Parameters());
int Pilot = PILOT_AUTO; // should be added into cDvbTransponderParameters
int T2SystemId = 0; // should be added into cDvbTransponderParameters
int SisoMiso = 0; // should be added into cDvbTransponderParameters
#if defined(APIVERSNUM) && APIVERSNUM < 20106
int Pilot = PILOT_AUTO;
int T2SystemId = 0;
int SisoMiso = 0;
#else
int Pilot = dtp.Pilot();
int T2SystemId = dtp.T2SystemId();
int SisoMiso = dtp.SisoMiso();
#endif
float freq = channelP->Frequency();
char type = cSource::ToChar(channelP->Source());
cSource *source = Sources.Get(channelP->Source());

View File

@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 0.1.0\n"
"Project-Id-Version: vdr-satip 0.2.1\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-03-15 03:15+0200\n"
"PO-Revision-Date: 2014-03-15 03:15+0200\n"
"POT-Creation-Date: 2014-04-01 04:01+0200\n"
"PO-Revision-Date: 2014-04-01 04:01+0200\n"
"Last-Translator: Frank Neumann <fnu@yavdr.org>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
"Language: de\n"
@@ -25,14 +25,8 @@ msgstr "NIT (0x40)"
msgid "SDT (0x42)"
msgstr "SDT (0x42)"
msgid "EIT (0x4E/0x4F)"
msgstr "EIT (0x4E/0x4F)"
msgid "EIT (0x5X)"
msgstr "EIT (0x5X)"
msgid "EIT (0x6X)"
msgstr "EIT (0x6X)"
msgid "EIT (0x4E/0x4F/0x5X/0x6X)"
msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
msgid "TDT (0x70)"
msgstr "TDT (0x70)"
@@ -53,7 +47,7 @@ msgid "Description"
msgstr "Beschreibung"
msgid "Creation date"
msgstr "Erstellungsdatum"
msgstr "Zeitpunkt der Erstellung"
msgid "SAT>IP Information"
msgstr "SAT>IP Informationen"

View File

@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 0.1.0\n"
"Project-Id-Version: vdr-satip 0.2.1\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-03-15 03:15+0200\n"
"PO-Revision-Date: 2014-03-15 03:15+0200\n"
"POT-Creation-Date: 2014-04-01 04:01+0200\n"
"PO-Revision-Date: 2014-04-01 04:01+0200\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
"Language: fi\n"
@@ -25,14 +25,8 @@ msgstr "NIT (0x40)"
msgid "SDT (0x42)"
msgstr "SDT (0x42)"
msgid "EIT (0x4E/0x4F)"
msgstr "EIT (0x4E/0x4F)"
msgid "EIT (0x5X)"
msgstr "EIT (0x5X)"
msgid "EIT (0x6X)"
msgstr "EIT (0x6X)"
msgid "EIT (0x4E/0x4F/0x5X/0x6X)"
msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
msgid "TDT (0x70)"
msgstr "TDT (0x70)"

View File

@@ -21,7 +21,7 @@
#define GITVERSION ""
#endif
const char VERSION[] = "0.1.0" GITVERSION;
const char VERSION[] = "0.2.1" GITVERSION;
static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
class cPluginSatip : public cPlugin {
@@ -196,7 +196,7 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
// Parse your own setup parameters and store their values.
if (!strcasecmp(nameP, "OperatingMode"))
SatipConfig.SetOperatingMode(atoi(valueP));
if (!strcasecmp(nameP, "EnableEITScan"))
else if (!strcasecmp(nameP, "EnableEITScan"))
SatipConfig.SetEITScan(atoi(valueP));
else if (!strcasecmp(nameP, "DisabledFilters")) {
int DisabledFilters[SECTION_FILTER_TABLE_SIZE];

View File

@@ -100,11 +100,19 @@ int cSatipSectionFilter::Filter(void)
return 0;
// There is no data in the read socket, more can be written
if ((socketM[0] >= 0) && (socketM[1] >= 0) /*&& !select_single_desc(socketM[0], 0, false)*/) {
ssize_t len = write(socketM[1], secBufM, secLenM);
ERROR_IF(len < 0, "write()");
// Update statistics
AddSectionStatistic(len, 1);
if ((secLenM > 0) && (socketM[1] >= 0) && (socketM[0] >= 0)) {
for (i = 0; i < eWriteMaxRetries; ++i) {
if (select_single_desc(socketM[0], 10, false))
continue;
ssize_t len = write(socketM[1], secBufM, secLenM);
ERROR_IF(len < 0, "write()");
// Update statistics
if (len >= 0)
AddSectionStatistic(len, 1);
break;
}
if (i >= eWriteMaxRetries)
debug("Skipped section write (%d bytes)", secLenM);
}
}
return 0;
@@ -213,17 +221,20 @@ void cSatipSectionFilter::Process(const uint8_t* dataP)
cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP)
: cThread("SAT>IP section handler", true),
:
#ifdef USE_THREADED_SECTIONFILTER
cThread("SAT>IP section handler", true),
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SAT>IP SECTION HANDLER %d", deviceIndexP))),
#endif
mutexM(),
deviceIndexM(deviceIndexP),
processedM(false),
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SAT>IP SECTION HANDLER %d", deviceIndexP)))
deviceIndexM(deviceIndexP)
{
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
// Initialize filter pointers
memset(filtersM, 0, sizeof(filtersM));
#ifdef USE_THREADED_SECTIONFILTER
// Create input buffer
if (ringBufferM) {
ringBufferM->SetTimeouts(100, 100);
@@ -231,16 +242,19 @@ cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigne
}
else
error("Failed to allocate buffer for section filter handler (device=%d): ", deviceIndexM);
Start();
#endif
}
cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
{
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
Stop();
#ifdef USE_THREADED_SECTIONFILTER
// Stop thread
if (Running())
Cancel(3);
DELETE_POINTER(ringBufferM);
#endif
// Destroy all filters
cMutexLock MutexLock(&mutexM);
@@ -248,26 +262,19 @@ cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
Delete(i);
}
bool cSatipSectionFilterHandler::Stop(void)
{
debug("cSatipSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM);
// Stop thread
if (Running())
Cancel(3);
return true;
}
#ifdef USE_THREADED_SECTIONFILTER
void cSatipSectionFilterHandler::Action(void)
{
debug("cSatipSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM);
bool processed = false;
// Do the thread loop
while (Running()) {
// Read one TS packet
if (ringBufferM) {
int len = 0;
if (processedM) {
if (processed) {
ringBufferM->Del(TS_SIZE);
processedM = false;
processed = false;
}
uchar *p = ringBufferM->Get(len);
if (p && (len >= TS_SIZE)) {
@@ -289,7 +296,7 @@ void cSatipSectionFilterHandler::Action(void)
filtersM[i]->Process(p);
}
mutexM.Unlock();
processedM = true;
processed = true;
continue;
}
}
@@ -297,6 +304,7 @@ void cSatipSectionFilterHandler::Action(void)
}
debug("cSatipSectionFilterHandler::%s(%d): exiting", __FUNCTION__, deviceIndexM);
}
#endif
cString cSatipSectionFilterHandler::GetInformation(void)
{
@@ -397,10 +405,35 @@ int cSatipSectionFilterHandler::GetPid(int handleP)
void cSatipSectionFilterHandler::Write(uchar *bufferP, int lengthP)
{
//debug("cSatipSectionFilterHandler::%s(%d): length=%d", __FUNCTION__, deviceIndexM, lengthP);
#ifdef USE_THREADED_SECTIONFILTER
// Fill up the buffer
if (ringBufferM) {
int len = ringBufferM->Put(bufferP, lengthP);
if (len != lengthP)
ringBufferM->ReportOverflow(lengthP - len);
}
#else
// Lock
cMutexLock MutexLock(&mutexM);
uchar *p = bufferP;
int len = lengthP;
// Process TS packets through all filters
while (p && (len >= TS_SIZE)) {
if (*p != TS_SYNC_BYTE) {
for (int i = 1; i < len; ++i) {
if (p[i] == TS_SYNC_BYTE) {
p += i;
len -= i;
break;
}
}
}
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i])
filtersM[i]->Process(p);
}
p += TS_SIZE;
len -= TS_SIZE;
}
#endif
}

View File

@@ -16,11 +16,14 @@
#include "common.h"
#include "statistics.h"
#define USE_THREADED_SECTIONFILTER
class cSatipSectionFilter : public cSatipSectionStatistics {
private:
enum dmx_limits {
eDmxMaxFilterSize = 18,
eDmxMaxSectionSize = 4096,
enum {
eWriteMaxRetries = 20,
eDmxMaxFilterSize = 18,
eDmxMaxSectionSize = 4096,
eDmxMaxSectionFeedSize = (eDmxMaxSectionSize + TS_SIZE)
};
@@ -60,27 +63,29 @@ public:
uint16_t GetPid(void) const { return pidM; }
};
#ifdef USE_THREADED_SECTIONFILTER
class cSatipSectionFilterHandler : public cThread {
protected:
virtual void Action(void);
private:
cRingBufferLinear *ringBufferM;
#else
class cSatipSectionFilterHandler {
#endif
private:
enum {
eMaxSecFilterCount = 32
};
cMutex mutexM;
int deviceIndexM;
bool processedM;
cRingBufferLinear *ringBufferM;
cSatipSectionFilter *filtersM[eMaxSecFilterCount];
bool Delete(unsigned int indexP);
bool IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const;
protected:
virtual void Action(void);
public:
cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP);
virtual ~cSatipSectionFilterHandler();
bool Stop(void);
cString GetInformation(void);
int Open(u_short pidP, u_char tidP, u_char maskP);
void Close(int handleP);

View File

@@ -149,7 +149,7 @@ cString cSatipServers::GetString(cSatipServer *serverP)
cString list = "";
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
list = cString::sprintf("%s:%s:%s", s->Address(), s->Model(), s->Description());
list = cString::sprintf("%s|%s|%s", s->Address(), s->Model(), s->Description());
break;
}
}
@@ -160,7 +160,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%s|%s|%s\n", *list, s->Address(), s->Model(), s->Description());
return list;
}

View File

@@ -20,7 +20,10 @@
cSatipSocket::cSatipSocket()
: socketPortM(0),
socketDescM(-1)
socketDescM(-1),
lastErrorReportM(0),
packetErrorsM(0),
sequenceNumberM(-1)
{
debug("cSatipSocket::%s()", __FUNCTION__);
memset(&sockAddrM, 0, sizeof(sockAddrM));
@@ -72,8 +75,14 @@ void cSatipSocket::Close(void)
close(socketDescM);
socketDescM = -1;
socketPortM = 0;
sequenceNumberM = -1;
memset(&sockAddrM, 0, sizeof(sockAddrM));
}
if (packetErrorsM) {
info("detected %d RTP packet errors", packetErrorsM);
packetErrorsM = 0;
lastErrorReportM = time(NULL);
}
}
bool cSatipSocket::Flush(void)
@@ -150,6 +159,21 @@ int cSatipSocket::ReadVideo(unsigned char *bufferAddrP, unsigned int bufferLenP)
unsigned int cc = bufferAddrP[0] & 0x0F;
// Payload type: MPEG2 TS = 33
//unsigned int pt = bufferAddrP[1] & 0x7F;
// Sequence number
int seq = ((bufferAddrP[2] & 0xFF) << 8) | (bufferAddrP[3] & 0xFF);
if ((((sequenceNumberM + 1) % 0xFFFF) == 0) && (seq == 0xFFFF))
sequenceNumberM = -1;
else if ((sequenceNumberM >= 0) && (((sequenceNumberM + 1) % 0xFFFF) != seq)) {
packetErrorsM++;
if (time(NULL) - lastErrorReportM > eReportIntervalS) {
info("detected %d RTP packet errors", packetErrorsM);
packetErrorsM = 0;
lastErrorReportM = time(NULL);
}
sequenceNumberM = seq;
}
else
sequenceNumberM = seq;
// Header lenght
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
// Check if extension

View File

@@ -12,9 +12,15 @@
class cSatipSocket {
private:
enum {
eReportIntervalS = 300 // in seconds
};
int socketPortM;
int socketDescM;
struct sockaddr_in sockAddrM;
time_t lastErrorReportM;
int packetErrorsM;
int sequenceNumberM;
public:
cSatipSocket();

55
tuner.c
View File

@@ -26,7 +26,8 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
headerListM(NULL),
keepAliveM(),
pidUpdateCacheM(),
timeoutM(eKeepAliveIntervalMs),
sessionM(),
timeoutM(eMinKeepAliveIntervalMs),
openedM(false),
tunedM(false),
hasLockM(false),
@@ -67,35 +68,36 @@ size_t cSatipTuner::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void
size_t len = sizeP * nmembP;
//debug("cSatipTuner::%s(%zu)", __FUNCTION__, len);
int id = -1, timeout = -1;
char *s, *p = (char *)ptrP;
char *r = strtok_r(p, "\r\n", &s);
while (r) {
while (obj && r) {
//debug("cSatipTuner::%s(%zu): %s", __FUNCTION__, len, r);
r = skipspace(r);
if (strstr(r, "com.ses.streamID")) {
if (sscanf(r, "com.ses.streamID:%11d", &id) != 1)
id = -1;
int streamid = -1;
if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1)
obj->SetStreamId(streamid);
}
else if (strstr(r, "Session:")) {
int session = -1;
if (sscanf(r, "Session:%11d;timeout=%11d", &session, &timeout) != 2)
timeout = -1;
int timeout = -1;
char *session = NULL;
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
obj->SetSessionTimeout(skipspace(session), (timeout - 1) * 1000);
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
obj->SetSessionTimeout(skipspace(session));
FREE_POINTER(session);
}
r = strtok_r(NULL, "\r\n", &s);
}
if (id >= 0 && obj)
obj->SetStreamInfo(id, timeout);
return len;
}
void cSatipTuner::Action(void)
{
debug("cSatipTuner::%s(): entering", __FUNCTION__);
cTimeMs timeout(0);
cTimeMs timeout(eReConnectTimeoutMs);
// Increase priority
SetPriority(-1);
// Do the thread loop
@@ -127,7 +129,7 @@ void cSatipTuner::Action(void)
}
else {
// Reconnect if necessary
if (openedM && !tunedM && timeout.TimedOut()) {
if (openedM && timeout.TimedOut()) {
Disconnect();
Connect();
timeout.Set(eReConnectTimeoutMs);
@@ -181,7 +183,6 @@ bool cSatipTuner::Connect(void)
// Flush any old content
if (rtpSocketM)
rtpSocketM->Flush();
keepAliveM.Set(eKeepAliveIntervalMs);
return true;
}
@@ -227,6 +228,7 @@ bool cSatipTuner::Connect(void)
}
// Request server options: "&pids=all" for the whole mux
keepAliveM.Set(timeoutM);
uri = cString::sprintf("rtsp://%s/?%s&pids=0", *streamAddrM, *streamParamM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
@@ -245,13 +247,12 @@ bool cSatipTuner::Connect(void)
// Start playing
uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL);
//SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, *sessionM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
SATIP_CURL_EASY_PERFORM(handleM);
if (!ValidateLatestResponse())
return false;
keepAliveM.Set(eKeepAliveIntervalMs);
tunedM = true;
if (nextServerM) {
cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
@@ -303,6 +304,7 @@ bool cSatipTuner::Disconnect(void)
if (currentServerM)
cSatipDiscover::GetInstance()->UseServer(currentServerM, false);
tunedM = false;
timeoutM = eMinKeepAliveIntervalMs;
return true;
}
@@ -369,12 +371,19 @@ void cSatipTuner::ParseReceptionParameters(const char *paramP)
}
}
void cSatipTuner::SetStreamInfo(int idP, int timeoutP)
void cSatipTuner::SetStreamId(int streamIdP)
{
cMutexLock MutexLock(&mutexM);
debug("cSatipTuner::%s(%d, %d)", __FUNCTION__, idP, timeoutP);
streamIdM = idP;
timeoutM = timeoutP > 0 ? timeoutP * 1000L : eKeepAliveIntervalMs;
debug("cSatipTuner::%s(%d)", __FUNCTION__, streamIdP);
streamIdM = streamIdP;
}
void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
{
cMutexLock MutexLock(&mutexM);
debug("cSatipTuner::%s(%s, %d)", __FUNCTION__, sessionP, timeoutP);
sessionM = sessionP;
timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
}
bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const int indexP)
@@ -430,10 +439,8 @@ bool cSatipTuner::UpdatePids(void)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
SATIP_CURL_EASY_PERFORM(handleM);
if (ValidateLatestResponse()) {
keepAliveM.Set(eKeepAliveIntervalMs);
if (ValidateLatestResponse())
pidUpdatedM = false;
}
else
Disconnect();
@@ -455,7 +462,7 @@ bool cSatipTuner::KeepAlive(void)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
SATIP_CURL_EASY_PERFORM(handleM);
if (ValidateLatestResponse())
keepAliveM.Set(eKeepAliveIntervalMs);
keepAliveM.Set(timeoutM);
else
Disconnect();

12
tuner.h
View File

@@ -26,10 +26,10 @@
class cSatipTuner : public cThread, public cSatipTunerStatistics {
private:
enum {
eConnectTimeoutMs = 1500, // in milliseconds
ePidUpdateIntervalMs = 100, // in milliseconds
eReConnectTimeoutMs = 5000, // in milliseconds
eKeepAliveIntervalMs = 600000 // in milliseconds
eConnectTimeoutMs = 1500, // in milliseconds
ePidUpdateIntervalMs = 100, // in milliseconds
eReConnectTimeoutMs = 5000, // in milliseconds
eMinKeepAliveIntervalMs = 300000 // in milliseconds
};
static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
@@ -50,6 +50,7 @@ private:
cTimeMs keepAliveM;
cTimeMs signalInfoCacheM;
cTimeMs pidUpdateCacheM;
cString sessionM;
int timeoutM;
bool openedM;
bool tunedM;
@@ -64,7 +65,8 @@ private:
bool Disconnect(void);
bool ValidateLatestResponse(void);
void ParseReceptionParameters(const char *paramP);
void SetStreamInfo(int idP, int timeoutP);
void SetStreamId(int streamIdP);
void SetSessionTimeout(const char *sessionP, int timeoutP = 0);
bool KeepAlive(void);
bool UpdateSignalInfoCache(void);
bool UpdatePids(void);