mirror of
https://github.com/rofafor/vdr-plugin-satip.git
synced 2023-10-10 11:37:42 +00:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5e8b7b7c5e | ||
|
88b2ad9244 | ||
|
7b58d9f28f | ||
|
f493df0e3d | ||
|
9a6ae40954 | ||
|
b5ec84fd91 | ||
|
e7a74f3ad4 | ||
|
40d280af10 | ||
|
9f2d99435d | ||
|
06dd2f7261 | ||
|
dfbb3515ef |
21
HISTORY
21
HISTORY
@@ -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.
|
||||
|
11
Makefile
11
Makefile
@@ -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
15
README
@@ -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
|
||||
|
38
common.c
38
common.c
@@ -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},
|
||||
};
|
||||
|
12
common.h
12
common.h
@@ -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 {
|
||||
|
19
device.c
19
device.c
@@ -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;
|
||||
}
|
||||
|
5
device.h
5
device.h
@@ -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;
|
||||
|
55
discover.c
55
discover.c
@@ -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);
|
||||
|
@@ -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
12
param.c
@@ -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());
|
||||
|
18
po/de_DE.po
18
po/de_DE.po
@@ -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"
|
||||
|
16
po/fi_FI.po
16
po/fi_FI.po
@@ -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)"
|
||||
|
4
satip.c
4
satip.c
@@ -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];
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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);
|
||||
|
4
server.c
4
server.c
@@ -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;
|
||||
}
|
||||
|
||||
|
26
socket.c
26
socket.c
@@ -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
|
||||
|
6
socket.h
6
socket.h
@@ -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
55
tuner.c
@@ -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
12
tuner.h
@@ -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);
|
||||
|
Reference in New Issue
Block a user