mirror of
https://github.com/rofafor/vdr-plugin-satip.git
synced 2023-10-10 11:37:42 +00:00
Compare commits
116 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
dadd26f980 | ||
|
5c5f21631f | ||
|
29eaf994f8 | ||
|
f884b23f7c | ||
|
1bc2dc01fd | ||
|
eba49c979f | ||
|
3475c179d1 | ||
|
4cb25ce93c | ||
|
c5499ce1da | ||
|
fa226b0d2f | ||
|
4b714196f3 | ||
|
9cace319a3 | ||
|
01d2afcfc2 | ||
|
8ea561a021 | ||
|
d23578cea9 | ||
|
629c4ff378 | ||
|
2d997b3fdd | ||
|
7f9d016b52 | ||
|
778f3bd84a | ||
|
382e1dedef | ||
|
fecbd3cbd4 | ||
|
7c1aa732b4 | ||
|
395390fb32 | ||
|
913cdbef66 | ||
|
60a2b1fecf | ||
|
b9d89b8c1d | ||
|
d0ffc3e1a5 | ||
|
46db1dea11 | ||
|
dd320af7f2 | ||
|
d6ffffd932 | ||
|
7f9060a4cb | ||
|
097a607389 | ||
|
45b3166729 | ||
|
38f815d439 | ||
|
23dce9e205 | ||
|
796a047401 | ||
|
b62a25597b | ||
|
81f6af3bdf | ||
|
9a40a8eeec | ||
|
0668fb7a15 | ||
|
735e7487d3 | ||
|
d48fe3bced | ||
|
98437ce57e | ||
|
f6ab251294 | ||
|
0fe1722dee | ||
|
9b88c0d55f | ||
|
e6e185cbd7 | ||
|
561ca26098 | ||
|
4600a2a070 | ||
|
52f54d2177 | ||
|
8415075de9 | ||
|
eea0aa33bd | ||
|
cdb2e0e3b4 | ||
|
e0727516ce | ||
|
fde3198997 | ||
|
c966d28d13 | ||
|
6d68ef3e49 | ||
|
1642f59980 | ||
|
80abbddae7 | ||
|
8bd4a1a67d | ||
|
3a16e57f87 | ||
|
1244397365 | ||
|
1f528cf7e1 | ||
|
5d697c36dc | ||
|
005fa59dd6 | ||
|
6d64a8b0a7 | ||
|
4e2e6d0b9b | ||
|
ade52d5a22 | ||
|
524b21e042 | ||
|
0896df33e6 | ||
|
111a1ff16d | ||
|
8d198178bb | ||
|
ec596a02b8 | ||
|
8ec972d4ee | ||
|
54f8b4f0a6 | ||
|
f5015bcfba | ||
|
443dd9706a | ||
|
2dcf3bbd6a | ||
|
12d61d37cf | ||
|
a94d25b635 | ||
|
6b2090e9ad | ||
|
5c051d919b | ||
|
02bf42b006 | ||
|
adddf3e4e7 | ||
|
3a742f1f14 | ||
|
82fe5c59c8 | ||
|
304f1d4af6 | ||
|
4a9a36a9c2 | ||
|
daa2f903c8 | ||
|
d36597954a | ||
|
0bf841555b | ||
|
0431806f24 | ||
|
ede0294943 | ||
|
e05801b464 | ||
|
e51650cd0a | ||
|
45d0227d2b | ||
|
7110cee7a9 | ||
|
a9109d750c | ||
|
ac4ab867d9 | ||
|
2f723e0f66 | ||
|
72a5ad34fb | ||
|
123fc5f96b | ||
|
cf930286c2 | ||
|
2308fc4a65 | ||
|
04e7648c01 | ||
|
18ca0beaa7 | ||
|
aeb8f24474 | ||
|
bde88d78b1 | ||
|
30e8040f99 | ||
|
5795bb58af | ||
|
d81f700194 | ||
|
0de0be5ae4 | ||
|
92b2c63f0d | ||
|
c4d82eac36 | ||
|
3630a9f78a | ||
|
c8497e1fce |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,3 +4,6 @@
|
||||
*~
|
||||
po/*.pot
|
||||
po/*.mo
|
||||
.settings
|
||||
.cproject
|
||||
.project
|
||||
|
24
HISTORY
24
HISTORY
@@ -64,3 +64,27 @@ VDR Plugin 'satip' Revision History
|
||||
|
||||
- Added a validity check for the session member.
|
||||
- Added a session id quirk for Triax TSS 400.
|
||||
|
||||
2014-12-24: Version 1.0.0
|
||||
|
||||
- Fixed the cable only device detection.
|
||||
- Added support for blacklisted sources.
|
||||
- Fixed server reuse for active transponders.
|
||||
- Added a preliminary support for Fritz!WLAN
|
||||
Repeater DVB-C (Thanks to Christian Wick).
|
||||
- Added a preliminary support for Telestar
|
||||
Digibit R1 (Thanks to Dirk Wagner).
|
||||
- Added a new device status menu.
|
||||
- Added support for SAT>IP frontend selection via
|
||||
Radio ID.
|
||||
- Added command-line switches for manually defining
|
||||
used SAT>IP servers and setting used tracing mode.
|
||||
- Added new STAT and TRAC commands into the SVDRP
|
||||
interface.
|
||||
- Refactored the tuner implementation.
|
||||
- Updated against SAT>IP protocol specification
|
||||
version 1.2.1.
|
||||
- Refactored input thread to increase performance.
|
||||
- Added plenty of performance tweaks (Thanks to
|
||||
Stefan Schallenberg).
|
||||
- Fixed EIT scan (Thanks to Stefan Schallenberg).
|
||||
|
5
Makefile
5
Makefile
@@ -88,8 +88,9 @@ all-redirect: all
|
||||
|
||||
### The object files (add further files here):
|
||||
|
||||
OBJS = $(PLUGIN).o common.o config.o device.o discover.o param.o \
|
||||
sectionfilter.o server.o setup.o socket.o statistics.o tuner.o
|
||||
OBJS = $(PLUGIN).o common.o config.o device.o discover.o msearch.o param.o \
|
||||
poller.o rtp.o rtcp.o rtsp.o sectionfilter.o server.o setup.o socket.o \
|
||||
statistics.o tuner.o
|
||||
|
||||
### The main target:
|
||||
|
||||
|
21
README
21
README
@@ -44,6 +44,10 @@ The plugin accepts a "--devices" (-d) command-line parameter defaulting
|
||||
to one. 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
|
||||
can be used to manually configure static SAT>IP servers if autodetection
|
||||
via UPnP somehow can't be used.
|
||||
|
||||
SAT>IP satellite positions (aka. signal sources) shall be defined via
|
||||
sources.conf. If the source description begins with a number, it's used
|
||||
as SAT>IP signal source selection parameter. Otherwise, the default
|
||||
@@ -58,6 +62,10 @@ S19.2E 2
|
||||
S19.2E 3 Astra 1KR/1L/1M/2C
|
||||
=> Signal source = 3
|
||||
|
||||
A channel can be assigned into a specific SAT>IP frontend by giving the
|
||||
identifier number in RID field of a channels.conf entry.
|
||||
Valid range: 1 ... 8
|
||||
|
||||
Setup menu:
|
||||
|
||||
- Operating mode = off If you want exclude all SAT>IP devices
|
||||
@@ -71,16 +79,20 @@ Setup menu:
|
||||
- Enable EPG scanning = yes If you want exclude all SAT>IP devices
|
||||
from VDR's EIT background scanning, set
|
||||
this option to "no".
|
||||
- Disabled sources = none If your SAT>IP servers don't have certain
|
||||
satellite positions available you can
|
||||
disable them via this option.
|
||||
- Disabled filters = none Certain section filters might cause some
|
||||
unwanted behaviour to VDR such as time
|
||||
being falsely synchronized etc. This option
|
||||
allows creation of blacklists of ill-behaving
|
||||
allows creation of blacklists of ill-behaving
|
||||
filters. If this option is set to a non-zero
|
||||
value, the menu page will contain that many
|
||||
"Disable filter" options which allow you
|
||||
to disable the individual section filters.
|
||||
Valid range: "none" = 0 ... 7
|
||||
- [Red:Scan] Forces network scanning of SAT>IP hardware.
|
||||
- [Yellow:Devices] Opens SAT>IP device status menu.
|
||||
- [Blue:Info] Opens SAT>IP information/statistics menu.
|
||||
- [Ok] Opens information menu of selected SAT>IP
|
||||
device.
|
||||
@@ -97,10 +109,6 @@ Notes:
|
||||
- The stream id "-1" states about unsuccessful tuning. This might be a
|
||||
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 (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.
|
||||
|
||||
@@ -108,6 +116,9 @@ Notes:
|
||||
direct access to any DVB card devices. The integrated CAM slot in
|
||||
Octopus Net devices isn't supported.
|
||||
|
||||
- Tracing can be set on/off dynamically via command-line switch or
|
||||
SVDRP command.
|
||||
|
||||
Acknowledgements:
|
||||
|
||||
- Big thanks to Digital Devices GmbH for providing the Octopus Net
|
||||
|
22
common.h
22
common.h
@@ -8,23 +8,16 @@
|
||||
#ifndef __SATIP_COMMON_H
|
||||
#define __SATIP_COMMON_H
|
||||
|
||||
#include <vdr/device.h>
|
||||
#include <vdr/tools.h>
|
||||
#include <vdr/config.h>
|
||||
#include <vdr/i18n.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define debug(x...) dsyslog("SATIP: " x);
|
||||
#define info(x...) isyslog("SATIP: " x);
|
||||
#define error(x...) esyslog("ERROR: " x);
|
||||
#else
|
||||
#define debug(x...) ;
|
||||
#define info(x...) isyslog("SATIP: " x);
|
||||
#define error(x...) esyslog("ERROR: " x);
|
||||
#endif
|
||||
|
||||
#define ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
#define SATIP_BUFFER_SIZE MEGABYTE(1)
|
||||
#define SATIP_MAX_DEVICES MAXDEVICES
|
||||
|
||||
#define SATIP_BUFFER_SIZE KILOBYTE(1024)
|
||||
|
||||
#define SATIP_DEVICE_INFO_ALL 0
|
||||
#define SATIP_DEVICE_INFO_GENERAL 1
|
||||
@@ -36,6 +29,7 @@
|
||||
#define SATIP_STATS_ACTIVE_PIDS_COUNT 10
|
||||
#define SATIP_STATS_ACTIVE_FILTERS_COUNT 10
|
||||
|
||||
#define MAX_DISABLED_SOURCES_COUNT 5
|
||||
#define SECTION_FILTER_TABLE_SIZE 5
|
||||
|
||||
#define SATIP_CURL_EASY_GETINFO(X, Y, Z) \
|
||||
@@ -45,19 +39,19 @@
|
||||
|
||||
#define SATIP_CURL_EASY_SETOPT(X, Y, Z) \
|
||||
if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { \
|
||||
error("curl_easy_setopt(%s, %s) [%s,%d] failed: %s (%d)", #Y, #Z, __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
||||
esyslog("curl_easy_setopt(%s, %s) [%s,%d] failed: %s (%d)", #Y, #Z, __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
||||
}
|
||||
|
||||
#define SATIP_CURL_EASY_PERFORM(X) \
|
||||
if ((res = curl_easy_perform((X))) != CURLE_OK) { \
|
||||
error("curl_easy_perform() [%s,%d] failed: %s (%d)", __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
||||
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]; \
|
||||
error("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
|
||||
esyslog("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
|
||||
strerror_r(errno, tmp, sizeof(tmp))); \
|
||||
func; \
|
||||
ret; \
|
||||
|
25
config.c
25
config.c
@@ -6,20 +6,43 @@
|
||||
*/
|
||||
|
||||
#include "discover.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
|
||||
cSatipConfig SatipConfig;
|
||||
|
||||
cSatipConfig::cSatipConfig(void)
|
||||
: operatingModeM(eOperatingModeLow),
|
||||
traceModeM(eTraceModeNormal),
|
||||
eitScanM(1),
|
||||
useBytesM(1)
|
||||
{
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(disabledSourcesM); ++i)
|
||||
disabledSourcesM[i] = cSource::stNone;
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(disabledFiltersM); ++i)
|
||||
disabledFiltersM[i] = -1;
|
||||
memset(configDirectoryM, 0, sizeof(configDirectoryM));
|
||||
}
|
||||
|
||||
unsigned int cSatipConfig::GetDisabledSourcesCount(void) const
|
||||
{
|
||||
unsigned int n = 0;
|
||||
while ((n < ARRAY_SIZE(disabledSourcesM) && (disabledSourcesM[n] != cSource::stNone)))
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
int cSatipConfig::GetDisabledSources(unsigned int indexP) const
|
||||
{
|
||||
return (indexP < ARRAY_SIZE(disabledSourcesM)) ? disabledSourcesM[indexP] : cSource::stNone;
|
||||
}
|
||||
|
||||
void cSatipConfig::SetDisabledSources(unsigned int indexP, int sourceP)
|
||||
{
|
||||
if (indexP < ARRAY_SIZE(disabledSourcesM))
|
||||
disabledSourcesM[indexP] = sourceP;
|
||||
}
|
||||
|
||||
unsigned int cSatipConfig::GetDisabledFiltersCount(void) const
|
||||
{
|
||||
unsigned int n = 0;
|
||||
@@ -41,6 +64,6 @@ void cSatipConfig::SetDisabledFilters(unsigned int indexP, int numberP)
|
||||
|
||||
void cSatipConfig::SetConfigDirectory(const char *directoryP)
|
||||
{
|
||||
debug("cSatipConfig::%s(%s)", __FUNCTION__, directoryP);
|
||||
debug1("%s (%s)", __PRETTY_FUNCTION__, directoryP);
|
||||
ERROR_IF(!realpath(directoryP, configDirectoryM), "Cannot canonicalize configuration directory");
|
||||
}
|
||||
|
30
config.h
30
config.h
@@ -15,19 +15,41 @@ class cSatipConfig
|
||||
{
|
||||
private:
|
||||
unsigned int operatingModeM;
|
||||
unsigned int traceModeM;
|
||||
unsigned int eitScanM;
|
||||
unsigned int useBytesM;
|
||||
int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT];
|
||||
int disabledFiltersM[SECTION_FILTER_TABLE_SIZE];
|
||||
char configDirectoryM[PATH_MAX];
|
||||
|
||||
public:
|
||||
enum {
|
||||
enum eOperatingMode {
|
||||
eOperatingModeOff = 0,
|
||||
eOperatingModeLow,
|
||||
eOperatingModeNormal,
|
||||
eOperatingModeHigh,
|
||||
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
|
||||
};
|
||||
cSatipConfig();
|
||||
unsigned int GetOperatingMode(void) const { return operatingModeM; }
|
||||
bool IsOperatingModeOff(void) const { return (operatingModeM == eOperatingModeOff); }
|
||||
@@ -35,16 +57,22 @@ public:
|
||||
bool IsOperatingModeNormal(void) const { return (operatingModeM == eOperatingModeNormal); }
|
||||
bool IsOperatingModeHigh(void) const { return (operatingModeM == eOperatingModeHigh); }
|
||||
void ToggleOperatingMode(void) { operatingModeM = (operatingModeM + 1) % eOperatingModeCount; }
|
||||
unsigned int GetTraceMode(void) const { return traceModeM; }
|
||||
bool IsTraceMode(eTraceMode modeP) const { return (traceModeM & modeP); }
|
||||
unsigned int GetEITScan(void) const { return eitScanM; }
|
||||
unsigned int GetUseBytes(void) const { return useBytesM; }
|
||||
const char *GetConfigDirectory(void) const { return configDirectoryM; }
|
||||
unsigned int GetDisabledSourcesCount(void) const;
|
||||
int GetDisabledSources(unsigned int indexP) const;
|
||||
unsigned int GetDisabledFiltersCount(void) const;
|
||||
int GetDisabledFilters(unsigned int indexP) const;
|
||||
|
||||
void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; }
|
||||
void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); }
|
||||
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; }
|
||||
void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; }
|
||||
void SetConfigDirectory(const char *directoryP);
|
||||
void SetDisabledSources(unsigned int indexP, int sourceP);
|
||||
void SetDisabledFilters(unsigned int indexP, int numberP);
|
||||
};
|
||||
|
||||
|
143
device.c
143
device.c
@@ -5,13 +5,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vdr/menu.h> // cRecordControl
|
||||
|
||||
#include "config.h"
|
||||
#include "discover.h"
|
||||
#include "log.h"
|
||||
#include "param.h"
|
||||
#include "device.h"
|
||||
|
||||
#define SATIP_MAX_DEVICES MAXDEVICES
|
||||
|
||||
static cSatipDevice * SatipDevicesS[SATIP_MAX_DEVICES] = { NULL };
|
||||
|
||||
cSatipDevice::cSatipDevice(unsigned int indexP)
|
||||
@@ -25,11 +26,11 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
|
||||
{
|
||||
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
|
||||
bufsize -= (bufsize % TS_SIZE);
|
||||
isyslog("creating SAT>IP device %d (CardIndex=%d)", deviceIndexM, CardIndex());
|
||||
info("Creating device CardIndex=%d DeviceNumber=%d [device %u]", CardIndex(), DeviceNumber(), deviceIndexM);
|
||||
tsBufferM = new cRingBufferLinear(bufsize + 1, TS_SIZE, false,
|
||||
*cString::sprintf("SAT>IP TS %d", deviceIndexM));
|
||||
*cString::sprintf("SATIP#%d TS", deviceIndexM));
|
||||
if (tsBufferM) {
|
||||
tsBufferM->SetTimeouts(100, 100);
|
||||
tsBufferM->SetTimeouts(10, 10);
|
||||
tsBufferM->SetIoThrottle();
|
||||
pTunerM = new cSatipTuner(*this, tsBufferM->Free());
|
||||
}
|
||||
@@ -40,7 +41,7 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
|
||||
|
||||
cSatipDevice::~cSatipDevice()
|
||||
{
|
||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug1("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
// Stop section handler
|
||||
StopSectionHandler();
|
||||
DELETE_POINTER(pSectionFilterHandlerM);
|
||||
@@ -50,7 +51,7 @@ cSatipDevice::~cSatipDevice()
|
||||
|
||||
bool cSatipDevice::Initialize(unsigned int deviceCountP)
|
||||
{
|
||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceCountP);
|
||||
debug1("%s (%u)", __PRETTY_FUNCTION__, deviceCountP);
|
||||
if (deviceCountP > SATIP_MAX_DEVICES)
|
||||
deviceCountP = SATIP_MAX_DEVICES;
|
||||
for (unsigned int i = 0; i < deviceCountP; ++i)
|
||||
@@ -62,7 +63,7 @@ bool cSatipDevice::Initialize(unsigned int deviceCountP)
|
||||
|
||||
void cSatipDevice::Shutdown(void)
|
||||
{
|
||||
debug("cSatipDevice::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
for (int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
||||
if (SatipDevicesS[i])
|
||||
SatipDevicesS[i]->CloseDvr();
|
||||
@@ -72,7 +73,7 @@ void cSatipDevice::Shutdown(void)
|
||||
unsigned int cSatipDevice::Count(void)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
debug("cSatipDevice::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
for (unsigned int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
||||
if (SatipDevicesS[i] != NULL)
|
||||
count++;
|
||||
@@ -82,19 +83,51 @@ unsigned int cSatipDevice::Count(void)
|
||||
|
||||
cSatipDevice *cSatipDevice::GetSatipDevice(int cardIndexP)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%d)", __FUNCTION__, cardIndexP);
|
||||
debug16("%s (%d)", __PRETTY_FUNCTION__, cardIndexP);
|
||||
for (unsigned int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
||||
if (SatipDevicesS[i] && (SatipDevicesS[i]->CardIndex() == cardIndexP)) {
|
||||
//debug("cSatipDevice::%s(%d): found!", __FUNCTION__, cardIndexP);
|
||||
debug16("%s (%d): Found!", __PRETTY_FUNCTION__, cardIndexP);
|
||||
return SatipDevicesS[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cString cSatipDevice::GetSatipStatus(void)
|
||||
{
|
||||
cString info = "";
|
||||
for (int i = 0; i < cDevice::NumDevices(); i++) {
|
||||
const cDevice *device = cDevice::GetDevice(i);
|
||||
if (device && strstr(device->DeviceType(), "SAT>IP")) {
|
||||
int timers = 0;
|
||||
bool live = (device == cDevice::ActualDevice());
|
||||
bool lock = device->HasLock();
|
||||
const cChannel *channel = device->GetCurrentlyTunedTransponder();
|
||||
for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
|
||||
if (timer->Recording()) {
|
||||
cRecordControl *control = cRecordControls::GetRecordControl(timer);
|
||||
if (control && control->Device() == device)
|
||||
timers++;
|
||||
}
|
||||
}
|
||||
info = cString::sprintf("%sDevice: %s\n", *info, *device->DeviceName());
|
||||
if (lock)
|
||||
info = cString::sprintf("%sCardIndex: %d HasLock: yes Strength: %d Quality: %d%s\n", *info, device->CardIndex(), device->SignalStrength(), device->SignalQuality(), live ? " Live: yes" : "");
|
||||
else
|
||||
info = cString::sprintf("%sCardIndex: %d HasLock: no\n", *info, device->CardIndex());
|
||||
if (channel && channel->Number() > 0)
|
||||
info = cString::sprintf("%sTransponder: %d Channel: %s\n", *info, (channel && channel->Number() > 0) ? channel->Transponder() : 0, (channel && channel->Number() > 0) ? channel->Name() : "---");
|
||||
if (timers)
|
||||
info = cString::sprintf("%sRecording: %d timer%s\n", *info, timers, (timers > 1) ? "s" : "");
|
||||
info = cString::sprintf("%s\n", *info);
|
||||
}
|
||||
}
|
||||
return isempty(*info) ? cString(tr("SAT>IP information not available!")) : info;
|
||||
}
|
||||
|
||||
cString cSatipDevice::GetGeneralInformation(void)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s",
|
||||
deviceIndexM, CardIndex(),
|
||||
pTunerM ? *pTunerM->GetInformation() : "",
|
||||
@@ -106,13 +139,13 @@ cString cSatipDevice::GetGeneralInformation(void)
|
||||
|
||||
cString cSatipDevice::GetPidsInformation(void)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return GetPidStatistic();
|
||||
}
|
||||
|
||||
cString cSatipDevice::GetFiltersInformation(void)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return cString::sprintf("Active section filters:\n%s", pSectionFilterHandlerM ? *pSectionFilterHandlerM->GetInformation() : "");
|
||||
}
|
||||
|
||||
@@ -148,50 +181,60 @@ cString cSatipDevice::GetInformation(unsigned int pageP)
|
||||
|
||||
bool cSatipDevice::Ready(void)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return ((cSatipDiscover::GetInstance()->GetServerCount() > 0) || (createdM.Elapsed() > eReadyTimeoutMs));
|
||||
}
|
||||
|
||||
cString cSatipDevice::DeviceType(void) const
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return "SAT>IP";
|
||||
}
|
||||
|
||||
cString cSatipDevice::DeviceName(void) const
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return deviceNameM;
|
||||
}
|
||||
|
||||
bool cSatipDevice::AvoidRecording(void) const
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return SatipConfig.IsOperatingModeLow();
|
||||
}
|
||||
|
||||
int cSatipDevice::SignalStrength(void) const
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return (pTunerM ? pTunerM->SignalStrength() : -1);
|
||||
}
|
||||
|
||||
int cSatipDevice::SignalQuality(void) const
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return (pTunerM ? pTunerM->SignalQuality() : -1);
|
||||
}
|
||||
|
||||
bool cSatipDevice::ProvidesSource(int sourceP) const
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
return (!SatipConfig.IsOperatingModeOff() && !!cSatipDiscover::GetInstance()->GetServer(sourceP));
|
||||
debug9("%s (%c) [device %u]", __PRETTY_FUNCTION__, cSource::ToChar(sourceP), deviceIndexM);
|
||||
if (!SatipConfig.IsOperatingModeOff() && !!cSatipDiscover::GetInstance()->GetServer(sourceP)) {
|
||||
int numDisabledSourcesM = SatipConfig.GetDisabledSourcesCount();
|
||||
for (int i = 0; i < numDisabledSourcesM; ++i) {
|
||||
if (sourceP == SatipConfig.GetDisabledSources(i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipDevice::ProvidesTransponder(const cChannel *channelP) const
|
||||
{
|
||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
return (ProvidesSource(channelP->Source()));
|
||||
debug9("%s (%d) transponder=%d source=%c [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, channelP ? channelP->Transponder() : -1, channelP ? cSource::ToChar(channelP->Source()) : '?', deviceIndexM);
|
||||
if (!ProvidesSource(channelP->Source()))
|
||||
return false;
|
||||
return DeviceHooksProvidesTransponder(channelP);
|
||||
}
|
||||
|
||||
bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool *needsDetachReceiversP) const
|
||||
@@ -200,7 +243,7 @@ bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool
|
||||
bool hasPriority = (priorityP == IDLEPRIORITY) || (priorityP > this->Priority());
|
||||
bool needsDetachReceivers = false;
|
||||
|
||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug9("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, priorityP, !!needsDetachReceiversP, deviceIndexM);
|
||||
|
||||
if (channelP && ProvidesTransponder(channelP)) {
|
||||
result = hasPriority;
|
||||
@@ -272,31 +315,37 @@ bool cSatipDevice::MaySwitchTransponder(const cChannel *channelP) const
|
||||
|
||||
bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
|
||||
{
|
||||
debug9("%s (%d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, liveViewP, deviceIndexM);
|
||||
if (channelP) {
|
||||
cDvbTransponderParameters dtp(channelP->Parameters());
|
||||
cString params = GetTransponderUrlParameters(channelP);
|
||||
if (isempty(params)) {
|
||||
error("Unrecognized SAT>IP channel parameters: %s", channelP->Parameters());
|
||||
error("Unrecognized channel parameters: %s [device %u]", channelP->Parameters(), deviceIndexM);
|
||||
return false;
|
||||
}
|
||||
cString address;
|
||||
cSatipServer *server = cSatipDiscover::GetInstance()->GetServer(channelP->Source(), dtp.System());
|
||||
cSatipServer *server = cSatipDiscover::GetInstance()->GetServer(channelP->Source(), channelP->Transponder(), dtp.System());
|
||||
if (!server) {
|
||||
debug("cSatipDevice::%s(%u): no suitable server found", __FUNCTION__, deviceIndexM);
|
||||
debug1("%s No suitable server found [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return false;
|
||||
}
|
||||
cSatipDiscover::GetInstance()->SetTransponder(server, channelP->Transponder());
|
||||
if (pTunerM && pTunerM->SetSource(server, *params, deviceIndexM)) {
|
||||
deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server));
|
||||
channelM = *channelP;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (pTunerM) {
|
||||
pTunerM->SetSource(NULL, NULL, deviceIndexM);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u): pid=%d type=%d on=%d", __FUNCTION__, deviceIndexM, handleP->pid, typeP, onP);
|
||||
debug9("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP->pid, typeP, onP, deviceIndexM);
|
||||
if (pTunerM && handleP && handleP->pid >= 0) {
|
||||
if (onP)
|
||||
return pTunerM->SetPid(handleP->pid, typeP, true);
|
||||
@@ -308,7 +357,7 @@ 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);
|
||||
debug9("%s (%d, %02X, %02X) [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, deviceIndexM);
|
||||
if (pSectionFilterHandlerM) {
|
||||
int handle = pSectionFilterHandlerM->Open(pidP, tidP, maskP);
|
||||
if (pTunerM && (handle >= 0))
|
||||
@@ -320,17 +369,18 @@ int cSatipDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP)
|
||||
|
||||
void cSatipDevice::CloseFilter(int handleP)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u): handle=%d", __FUNCTION__, deviceIndexM, handleP);
|
||||
if (pSectionFilterHandlerM) {
|
||||
int pid = pSectionFilterHandlerM->GetPid(handleP);
|
||||
debug9("%s (%d) [device %u]", __PRETTY_FUNCTION__, pid, deviceIndexM);
|
||||
if (pTunerM)
|
||||
pTunerM->SetPid(pSectionFilterHandlerM->GetPid(handleP), ptOther, false);
|
||||
pTunerM->SetPid(pid, ptOther, false);
|
||||
pSectionFilterHandlerM->Close(handleP);
|
||||
}
|
||||
}
|
||||
|
||||
bool cSatipDevice::OpenDvr(void)
|
||||
{
|
||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug9("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
isPacketDeliveredM = false;
|
||||
tsBufferM->Clear();
|
||||
if (pTunerM)
|
||||
@@ -341,7 +391,7 @@ bool cSatipDevice::OpenDvr(void)
|
||||
|
||||
void cSatipDevice::CloseDvr(void)
|
||||
{
|
||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug9("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
if (pTunerM)
|
||||
pTunerM->Close();
|
||||
isOpenDvrM = false;
|
||||
@@ -349,21 +399,21 @@ void cSatipDevice::CloseDvr(void)
|
||||
|
||||
bool cSatipDevice::HasLock(int timeoutMsP) const
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u): timeoutMs=%d", __FUNCTION__, deviceIndexM, timeoutMsP);
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, timeoutMsP, deviceIndexM);
|
||||
return (pTunerM && pTunerM->HasLock());
|
||||
}
|
||||
|
||||
bool cSatipDevice::HasInternalCam(void)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return false;
|
||||
}
|
||||
|
||||
void cSatipDevice::WriteData(uchar *bufferP, int lengthP)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
// Fill up TS buffer
|
||||
if (tsBufferM) {
|
||||
if (isOpenDvrM && tsBufferM) {
|
||||
int len = tsBufferM->Put(bufferP, lengthP);
|
||||
if (len != lengthP)
|
||||
tsBufferM->ReportOverflow(lengthP - len);
|
||||
@@ -373,23 +423,14 @@ void cSatipDevice::WriteData(uchar *bufferP, int lengthP)
|
||||
pSectionFilterHandlerM->Write(bufferP, lengthP);
|
||||
}
|
||||
|
||||
unsigned int cSatipDevice::CheckData(void)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
if (tsBufferM)
|
||||
return (unsigned int)tsBufferM->Free();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cSatipDevice::GetId(void)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
return deviceIndexM;
|
||||
}
|
||||
|
||||
uchar *cSatipDevice::GetData(int *availableP)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
if (isOpenDvrM && tsBufferM) {
|
||||
int count = 0;
|
||||
if (isPacketDeliveredM)
|
||||
@@ -420,7 +461,7 @@ uchar *cSatipDevice::GetData(int *availableP)
|
||||
|
||||
void cSatipDevice::SkipData(int countP)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
tsBufferM->Del(countP);
|
||||
isPacketDeliveredM = false;
|
||||
// Update buffer statistics
|
||||
@@ -429,7 +470,7 @@ void cSatipDevice::SkipData(int countP)
|
||||
|
||||
bool cSatipDevice::GetTSPacket(uchar *&dataP)
|
||||
{
|
||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
if (tsBufferM) {
|
||||
#if defined(APIVERSNUM) && APIVERSNUM >= 20104
|
||||
if (cCamSlot *cs = CamSlot()) {
|
||||
@@ -447,8 +488,6 @@ bool cSatipDevice::GetTSPacket(uchar *&dataP)
|
||||
dataP = GetData();
|
||||
return true;
|
||||
}
|
||||
// Reduce cpu load by preventing busylooping
|
||||
cCondWait::SleepMs(10);
|
||||
dataP = NULL;
|
||||
return true;
|
||||
}
|
||||
|
2
device.h
2
device.h
@@ -23,6 +23,7 @@ public:
|
||||
static void Shutdown(void);
|
||||
static unsigned int Count(void);
|
||||
static cSatipDevice *GetSatipDevice(int CardIndex);
|
||||
static cString GetSatipStatus(void);
|
||||
|
||||
// private parts
|
||||
private:
|
||||
@@ -106,7 +107,6 @@ public:
|
||||
// for internal device interface
|
||||
public:
|
||||
virtual void WriteData(u_char *bufferP, int lengthP);
|
||||
virtual unsigned int CheckData(void);
|
||||
virtual int GetId(void);
|
||||
};
|
||||
|
||||
|
@@ -13,7 +13,6 @@ public:
|
||||
cSatipDeviceIf() {}
|
||||
virtual ~cSatipDeviceIf() {}
|
||||
virtual void WriteData(u_char *bufferP, int lengthP) = 0;
|
||||
virtual unsigned int CheckData(void) = 0;
|
||||
virtual int GetId(void) = 0;
|
||||
|
||||
private:
|
||||
|
313
discover.c
313
discover.c
@@ -13,18 +13,12 @@
|
||||
#endif
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "socket.h"
|
||||
#include "discover.h"
|
||||
|
||||
cSatipDiscover *cSatipDiscover::instanceS = NULL;
|
||||
|
||||
const char *cSatipDiscover::bcastAddressS = "239.255.255.250";
|
||||
const char *cSatipDiscover::bcastMessageS = "M-SEARCH * HTTP/1.1\r\n" \
|
||||
"HOST: 239.255.255.250:1900\r\n" \
|
||||
"MAN: \"ssdp:discover\"\r\n" \
|
||||
"ST: urn:ses-com:device:SatIPServer:1\r\n" \
|
||||
"MX: 2\r\n\r\n";
|
||||
|
||||
cSatipDiscover *cSatipDiscover::GetInstance(void)
|
||||
{
|
||||
if (!instanceS)
|
||||
@@ -32,17 +26,23 @@ cSatipDiscover *cSatipDiscover::GetInstance(void)
|
||||
return instanceS;
|
||||
}
|
||||
|
||||
bool cSatipDiscover::Initialize(void)
|
||||
bool cSatipDiscover::Initialize(cSatipDiscoverServers *serversP)
|
||||
{
|
||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
if (instanceS)
|
||||
instanceS->Activate();
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (instanceS) {
|
||||
if (serversP) {
|
||||
for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s))
|
||||
instanceS->AddServer(s->IpAddress(), s->Model(), s->Description());
|
||||
}
|
||||
else
|
||||
instanceS->Activate();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cSatipDiscover::Destroy(void)
|
||||
{
|
||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (instanceS)
|
||||
instanceS->Deactivate();
|
||||
}
|
||||
@@ -51,7 +51,7 @@ size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, vo
|
||||
{
|
||||
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
|
||||
size_t len = sizeP * nmembP;
|
||||
//debug("cSatipDiscover::%s(%zu)", __FUNCTION__, len);
|
||||
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
|
||||
|
||||
if (obj) {
|
||||
CURLcode res = CURLE_OK;
|
||||
@@ -82,37 +82,64 @@ size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, vo
|
||||
}
|
||||
#endif
|
||||
SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr);
|
||||
obj->AddServer(addr, desc, model);
|
||||
obj->AddServer(addr, model, desc);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP)
|
||||
{
|
||||
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(userPtrP);
|
||||
|
||||
if (obj) {
|
||||
switch (typeP) {
|
||||
case CURLINFO_TEXT:
|
||||
debug2("%s HTTP INFO %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||
break;
|
||||
case CURLINFO_HEADER_IN:
|
||||
debug2("%s HTTP HEAD <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||
break;
|
||||
case CURLINFO_HEADER_OUT:
|
||||
debug2("%s HTTP HEAD >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||
break;
|
||||
case CURLINFO_DATA_IN:
|
||||
debug2("%s HTTP DATA <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||
break;
|
||||
case CURLINFO_DATA_OUT:
|
||||
debug2("%s HTTP DATA >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cSatipDiscover::cSatipDiscover()
|
||||
: cThread("SAT>IP discover"),
|
||||
: cThread("SATIP discover"),
|
||||
mutexM(),
|
||||
msearchM(*this),
|
||||
probeUrlListM(),
|
||||
handleM(curl_easy_init()),
|
||||
socketM(new cSatipSocket()),
|
||||
sleepM(),
|
||||
probeIntervalM(0),
|
||||
serversM(new cSatipServers())
|
||||
serversM()
|
||||
{
|
||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
// Start the thread
|
||||
Start();
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cSatipDiscover::~cSatipDiscover()
|
||||
{
|
||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
Deactivate();
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
// Free allocated memory
|
||||
DELETENULL(socketM);
|
||||
DELETENULL(serversM);
|
||||
if (handleM)
|
||||
curl_easy_cleanup(handleM);
|
||||
handleM = NULL;
|
||||
probeUrlListM.Clear();
|
||||
}
|
||||
|
||||
void cSatipDiscover::Activate(void)
|
||||
@@ -123,7 +150,7 @@ void cSatipDiscover::Activate(void)
|
||||
|
||||
void cSatipDiscover::Deactivate(void)
|
||||
{
|
||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
sleepM.Signal();
|
||||
if (Running())
|
||||
@@ -132,190 +159,158 @@ void cSatipDiscover::Deactivate(void)
|
||||
|
||||
void cSatipDiscover::Action(void)
|
||||
{
|
||||
debug("cSatipDiscover::%s(): entering", __FUNCTION__);
|
||||
debug1("%s Entering", __PRETTY_FUNCTION__);
|
||||
probeIntervalM.Set(eProbeIntervalMs);
|
||||
msearchM.Probe();
|
||||
// Do the thread loop
|
||||
while (Running()) {
|
||||
cStringList tmp;
|
||||
|
||||
if (probeIntervalM.TimedOut()) {
|
||||
probeIntervalM.Set(eProbeIntervalMs);
|
||||
Probe();
|
||||
Janitor();
|
||||
msearchM.Probe();
|
||||
mutexM.Lock();
|
||||
serversM.Cleanup(eProbeIntervalMs * 2);
|
||||
mutexM.Unlock();
|
||||
}
|
||||
mutexM.Lock();
|
||||
if (probeUrlListM.Size()) {
|
||||
for (int i = 0; i < probeUrlListM.Size(); ++i)
|
||||
tmp.Insert(strdup(probeUrlListM.At(i)));
|
||||
probeUrlListM.Clear();
|
||||
}
|
||||
mutexM.Unlock();
|
||||
if (tmp.Size()) {
|
||||
for (int i = 0; i < tmp.Size(); ++i)
|
||||
Fetch(tmp.At(i));
|
||||
tmp.Clear();
|
||||
}
|
||||
// to avoid busy loop and reduce cpu load
|
||||
sleepM.Wait(10);
|
||||
sleepM.Wait(eSleepTimeoutMs);
|
||||
}
|
||||
debug("cSatipDiscover::%s(): exiting", __FUNCTION__);
|
||||
debug1("%s Exiting", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
void cSatipDiscover::Janitor(void)
|
||||
void cSatipDiscover::Fetch(const char *urlP)
|
||||
{
|
||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
debug1("%s (%s)", __PRETTY_FUNCTION__, urlP);
|
||||
if (handleM && !isempty(urlP)) {
|
||||
long rc = 0;
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
// Verbose output
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback);
|
||||
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_WRITEDATA, this);
|
||||
|
||||
// No progress meter and no signaling
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
// Set timeouts
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||
|
||||
// Set user-agent
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
|
||||
|
||||
// Set URL
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, urlP);
|
||||
|
||||
// Fetch the data
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
||||
if (rc != 200)
|
||||
error("Discovery detected invalid status code: %ld", rc);
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char * descP)
|
||||
{
|
||||
debug1("%s (%s, %s, %s)", __PRETTY_FUNCTION__, addrP, modelP, descP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (serversM)
|
||||
serversM->Cleanup(eProbeIntervalMs * 2);
|
||||
}
|
||||
|
||||
void cSatipDiscover::Probe(void)
|
||||
{
|
||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
if (socketM && socketM->Open(eDiscoveryPort)) {
|
||||
cTimeMs timeout(eProbeTimeoutMs);
|
||||
socketM->Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
|
||||
while (Running() && !timeout.TimedOut()) {
|
||||
Read();
|
||||
// to avoid busy loop and reduce cpu load
|
||||
sleepM.Wait(100);
|
||||
}
|
||||
socketM->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipDiscover::Read(void)
|
||||
{
|
||||
//debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
if (socketM) {
|
||||
unsigned char *buf = MALLOC(unsigned char, eProbeBufferSize + 1);
|
||||
if (buf) {
|
||||
memset(buf, 0, eProbeBufferSize + 1);
|
||||
int len = socketM->Read(buf, eProbeBufferSize);
|
||||
if (len > 0) {
|
||||
//debug("cSatipDiscover::%s(): len=%d", __FUNCTION__, len);
|
||||
bool status = false, valid = false;
|
||||
char *s, *p = reinterpret_cast<char *>(buf), *location = NULL;
|
||||
char *r = strtok_r(p, "\r\n", &s);
|
||||
while (r) {
|
||||
//debug("cSatipDiscover::%s(): %s", __FUNCTION__, r);
|
||||
// Check the status code
|
||||
// HTTP/1.1 200 OK
|
||||
if (!status && startswith(r, "HTTP/1.1 200 OK")) {
|
||||
status = true;
|
||||
}
|
||||
if (status) {
|
||||
// Check the location data
|
||||
// LOCATION: http://192.168.0.115:8888/octonet.xml
|
||||
if (startswith(r, "LOCATION:")) {
|
||||
location = compactspace(r + 9);
|
||||
debug("cSatipDiscover::%s(): location='%s'", __FUNCTION__, location);
|
||||
}
|
||||
// Check the source type
|
||||
// ST: urn:ses-com:device:SatIPServer:1
|
||||
else if (startswith(r, "ST:")) {
|
||||
char *st = compactspace(r + 3);
|
||||
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
|
||||
valid = true;
|
||||
debug("cSatipDiscover::%s(): st='%s'", __FUNCTION__, st);
|
||||
}
|
||||
// Check whether all the required data is found
|
||||
if (valid && !isempty(location))
|
||||
break;
|
||||
}
|
||||
r = strtok_r(NULL, "\r\n", &s);
|
||||
}
|
||||
if (handleM && valid && !isempty(location)) {
|
||||
long rc = 0;
|
||||
CURLcode res = CURLE_OK;
|
||||
#ifdef DEBUG
|
||||
// Verbose output
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
|
||||
#endif
|
||||
// Set callback
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
|
||||
|
||||
// No progress meter and no signaling
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
// Set timeouts
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||
|
||||
// Set user-agent
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
|
||||
|
||||
// Set URL
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, location);
|
||||
|
||||
// Fetch the data
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
||||
if (rc != 200)
|
||||
error("Discovery detected invalid status code: %ld", rc);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipDiscover::AddServer(const char *addrP, const char *descP, const char * modelP)
|
||||
{
|
||||
debug("cSatipDiscover::%s(%s, %s, %s)", __FUNCTION__, addrP, descP, modelP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (serversM) {
|
||||
cSatipServer *tmp = new cSatipServer(addrP, descP, modelP);
|
||||
// Validate against existing servers
|
||||
if (!serversM->Update(tmp)) {
|
||||
info("Adding device %s (%s %s)", tmp->Description(), tmp->Address(), tmp->Model());
|
||||
serversM->Add(tmp);
|
||||
}
|
||||
else
|
||||
DELETENULL(tmp);
|
||||
cSatipServer *tmp = new cSatipServer(addrP, modelP, descP);
|
||||
// Validate against existing servers
|
||||
if (!serversM.Update(tmp)) {
|
||||
info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
|
||||
serversM.Add(tmp);
|
||||
}
|
||||
else
|
||||
DELETENULL(tmp);
|
||||
}
|
||||
|
||||
int cSatipDiscover::GetServerCount(void)
|
||||
{
|
||||
//debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM ? serversM->Count() : -1;
|
||||
return serversM.Count();
|
||||
}
|
||||
|
||||
cSatipServer *cSatipDiscover::GetServer(int sourceP, int systemP)
|
||||
cSatipServer *cSatipDiscover::GetServer(int sourceP, int transponderP, int systemP)
|
||||
{
|
||||
//debug("cSatipDiscover::%s(%d, %d)", __FUNCTION__, sourceP, systemP);
|
||||
debug16("%s (%d, %d, %d)", __PRETTY_FUNCTION__, sourceP, transponderP, systemP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM ? serversM->Find(sourceP, systemP) : NULL;
|
||||
return serversM.Find(sourceP, transponderP, systemP);
|
||||
}
|
||||
|
||||
cSatipServer *cSatipDiscover::GetServer(cSatipServer *serverP)
|
||||
{
|
||||
//debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM ? serversM->Find(serverP) : NULL;
|
||||
return serversM.Find(serverP);
|
||||
}
|
||||
|
||||
cSatipServers *cSatipDiscover::GetServers(void)
|
||||
{
|
||||
//debug("cSatipDiscover::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM;
|
||||
return &serversM;
|
||||
}
|
||||
|
||||
cString cSatipDiscover::GetServerString(cSatipServer *serverP)
|
||||
{
|
||||
//debug("cSatipDiscover::%s(%d)", __FUNCTION__, modelP);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM ? serversM->GetString(serverP) : "";
|
||||
return serversM.GetString(serverP);
|
||||
}
|
||||
|
||||
cString cSatipDiscover::GetServerList(void)
|
||||
{
|
||||
//debug("cSatipDiscover::%s(%d)", __FUNCTION__, modelP);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM ? serversM->List() : "";
|
||||
return serversM.List();
|
||||
}
|
||||
|
||||
void cSatipDiscover::SetTransponder(cSatipServer *serverP, int transponderP)
|
||||
{
|
||||
debug16("%s (, %d)", __PRETTY_FUNCTION__, transponderP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
serversM.SetTransponder(serverP, transponderP);
|
||||
}
|
||||
|
||||
void cSatipDiscover::UseServer(cSatipServer *serverP, bool onOffP)
|
||||
{
|
||||
//debug("cSatipDiscover::%s(%d)", __FUNCTION__, modelP);
|
||||
debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (serversM)
|
||||
serversM->Use(serverP, onOffP);
|
||||
serversM.Use(serverP, onOffP);
|
||||
}
|
||||
|
||||
int cSatipDiscover::NumProvidedSystems(void)
|
||||
{
|
||||
//debug("cSatipDiscover::%s(%d)", __FUNCTION__, modelP);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM ? serversM->NumProvidedSystems() : 0;
|
||||
return serversM.NumProvidedSystems();
|
||||
}
|
||||
|
||||
void cSatipDiscover::SetUrl(const char *urlP)
|
||||
{
|
||||
debug16("%s (%s)", __PRETTY_FUNCTION__, urlP);
|
||||
mutexM.Lock();
|
||||
probeUrlListM.Insert(strdup(urlP));
|
||||
mutexM.Unlock();
|
||||
sleepM.Signal();
|
||||
}
|
||||
|
48
discover.h
48
discover.h
@@ -13,34 +13,51 @@
|
||||
#include <vdr/thread.h>
|
||||
#include <vdr/tools.h>
|
||||
|
||||
#include "discoverif.h"
|
||||
#include "msearch.h"
|
||||
#include "server.h"
|
||||
#include "socket.h"
|
||||
|
||||
class cSatipDiscover : public cThread {
|
||||
class cSatipDiscoverServer : public cListObject {
|
||||
private:
|
||||
cString ipAddressM;
|
||||
cString descriptionM;
|
||||
cString modelM;
|
||||
public:
|
||||
cSatipDiscoverServer(const char *ipAddressP, const char *modelP, const char *descriptionP)
|
||||
{
|
||||
ipAddressM = ipAddressP; modelM = modelP; descriptionM = descriptionP;
|
||||
}
|
||||
const char *IpAddress(void) { return *ipAddressM; }
|
||||
const char *Model(void) { return *modelM; }
|
||||
const char *Description(void) { return *descriptionM; }
|
||||
};
|
||||
|
||||
class cSatipDiscoverServers : public cList<cSatipDiscoverServer> {
|
||||
};
|
||||
|
||||
class cSatipDiscover : public cThread, public cSatipDiscoverIf {
|
||||
private:
|
||||
enum {
|
||||
eSleepTimeoutMs = 500, // in milliseconds
|
||||
eConnectTimeoutMs = 1500, // in milliseconds
|
||||
eDiscoveryPort = 1900,
|
||||
eProbeBufferSize = 1024, // in bytes
|
||||
eProbeTimeoutMs = 2000, // in milliseconds
|
||||
eProbeIntervalMs = 60000 // in milliseconds
|
||||
};
|
||||
static cSatipDiscover *instanceS;
|
||||
static const char *bcastAddressS;
|
||||
static const char *bcastMessageS;
|
||||
static size_t WriteCallback(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;
|
||||
cSatipMsearch msearchM;
|
||||
cStringList probeUrlListM;
|
||||
CURL *handleM;
|
||||
cSatipSocket *socketM;
|
||||
cCondWait sleepM;
|
||||
cTimeMs probeIntervalM;
|
||||
cSatipServers *serversM;
|
||||
cSatipServers serversM;
|
||||
void Activate(void);
|
||||
void Deactivate(void);
|
||||
void Janitor(void);
|
||||
void Probe(void);
|
||||
void Read(void);
|
||||
void AddServer(const char *addrP, const char *descP, const char *modelP);
|
||||
void AddServer(const char *addrP, const char *modelP, const char *descP);
|
||||
void Fetch(const char *urlP);
|
||||
// constructor
|
||||
cSatipDiscover();
|
||||
// to prevent copy constructor and assignment
|
||||
@@ -52,18 +69,23 @@ protected:
|
||||
|
||||
public:
|
||||
static cSatipDiscover *GetInstance(void);
|
||||
static bool Initialize(void);
|
||||
static bool Initialize(cSatipDiscoverServers *serversP);
|
||||
static void Destroy(void);
|
||||
virtual ~cSatipDiscover();
|
||||
void TriggerScan(void) { probeIntervalM.Set(0); }
|
||||
int GetServerCount(void);
|
||||
cSatipServer *GetServer(int sourceP, int systemP = -1);
|
||||
cSatipServer *GetServer(int sourceP, int transponderP = 0, int systemP = -1);
|
||||
cSatipServer *GetServer(cSatipServer *serverP);
|
||||
cSatipServers *GetServers(void);
|
||||
cString GetServerString(cSatipServer *serverP);
|
||||
void SetTransponder(cSatipServer *serverP, int transponderP);
|
||||
void UseServer(cSatipServer *serverP, bool onOffP);
|
||||
cString GetServerList(void);
|
||||
int NumProvidedSystems(void);
|
||||
|
||||
// for internal discover interface
|
||||
public:
|
||||
virtual void SetUrl(const char *urlP);
|
||||
};
|
||||
|
||||
#endif // __SATIP_DISCOVER_H
|
||||
|
22
discoverif.h
Normal file
22
discoverif.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* discoverif.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_DISCOVERIF_H
|
||||
#define __SATIP_DISCOVERIF_H
|
||||
|
||||
class cSatipDiscoverIf {
|
||||
public:
|
||||
cSatipDiscoverIf() {}
|
||||
virtual ~cSatipDiscoverIf() {}
|
||||
virtual void SetUrl(const char *urlP) = 0;
|
||||
|
||||
private:
|
||||
cSatipDiscoverIf(const cSatipDiscoverIf&);
|
||||
cSatipDiscoverIf& operator=(const cSatipDiscoverIf&);
|
||||
};
|
||||
|
||||
#endif // __SATIP_DISCOVERIF_H
|
49
log.h
Normal file
49
log.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* log.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_LOG_H
|
||||
#define __SATIP_LOG_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define error(x...) esyslog("SATIP-ERROR: " x)
|
||||
#define info(x...) isyslog("SATIP: " x)
|
||||
// 0x0001: Generic call stack
|
||||
#define debug1(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug1) ? dsyslog("SATIP1: " x) : void() )
|
||||
// 0x0002: CURL data flow
|
||||
#define debug2(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug2) ? dsyslog("SATIP2: " x) : void() )
|
||||
// 0x0004: Data parsing
|
||||
#define debug3(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug3) ? dsyslog("SATIP3: " x) : void() )
|
||||
// 0x0008: Tuner state machine
|
||||
#define debug4(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug4) ? dsyslog("SATIP4: " x) : void() )
|
||||
// 0x0010: RTSP responses
|
||||
#define debug5(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug5) ? dsyslog("SATIP5: " x) : void() )
|
||||
// 0x0020: RTP throughput performance
|
||||
#define debug6(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug6) ? dsyslog("SATIP6: " x) : void() )
|
||||
// 0x0040: RTP packet internals
|
||||
#define debug7(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug7) ? dsyslog("SATIP7: " x) : void() )
|
||||
// 0x0080: Section filtering
|
||||
#define debug8(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug8) ? dsyslog("SATIP8: " x) : void() )
|
||||
// 0x0100: Channel switching
|
||||
#define debug9(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug9) ? dsyslog("SATIP9: " x) : void() )
|
||||
// 0x0200: RTCP packets
|
||||
#define debug10(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug10) ? dsyslog("SATIP10: " x) : void() )
|
||||
// 0x0400: TBD
|
||||
#define debug11(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug11) ? dsyslog("SATIP11: " x) : void() )
|
||||
// 0x0800: TBD
|
||||
#define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() )
|
||||
// 0x1000: TBD
|
||||
#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() )
|
||||
// 0x4000: TBD
|
||||
#define debug15(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug15) ? dsyslog("SATIP15: " x) : void() )
|
||||
// 0x8000; Extra call stack
|
||||
#define debug16(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug16) ? dsyslog("SATIP16: " x) : void() )
|
||||
|
||||
#endif // __SATIP_LOG_H
|
||||
|
104
msearch.c
Normal file
104
msearch.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* msearch.c: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "discover.h"
|
||||
#include "log.h"
|
||||
#include "poller.h"
|
||||
#include "msearch.h"
|
||||
|
||||
const char *cSatipMsearch::bcastAddressS = "239.255.255.250";
|
||||
const char *cSatipMsearch::bcastMessageS = "M-SEARCH * HTTP/1.1\r\n" \
|
||||
"HOST: 239.255.255.250:1900\r\n" \
|
||||
"MAN: \"ssdp:discover\"\r\n" \
|
||||
"ST: urn:ses-com:device:SatIPServer:1\r\n" \
|
||||
"MX: 2\r\n\r\n";
|
||||
|
||||
cSatipMsearch::cSatipMsearch(cSatipDiscoverIf &discoverP)
|
||||
: discoverM(discoverP),
|
||||
bufferLenM(eProbeBufferSize),
|
||||
bufferM(MALLOC(unsigned char, bufferLenM)),
|
||||
registeredM(false)
|
||||
{
|
||||
if (bufferM)
|
||||
memset(bufferM, 0, bufferLenM);
|
||||
else
|
||||
error("Cannot create Msearch buffer!");
|
||||
if (!Open(eDiscoveryPort))
|
||||
error("Cannot open Msearch port!");
|
||||
}
|
||||
|
||||
cSatipMsearch::~cSatipMsearch()
|
||||
{
|
||||
}
|
||||
|
||||
void cSatipMsearch::Probe(void)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (!registeredM) {
|
||||
cSatipPoller::GetInstance()->Register(*this);
|
||||
registeredM = true;
|
||||
}
|
||||
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
|
||||
}
|
||||
|
||||
int cSatipMsearch::GetFd(void)
|
||||
{
|
||||
return Fd();
|
||||
}
|
||||
|
||||
void cSatipMsearch::Process(void)
|
||||
{
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
if (bufferM) {
|
||||
int length;
|
||||
while ((length = Read(bufferM, bufferLenM)) > 0) {
|
||||
bufferM[min(length, int(bufferLenM - 1))] = 0;
|
||||
debug3("%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) {
|
||||
debug3("%s r=%s", __PRETTY_FUNCTION__, r);
|
||||
// Check the status code
|
||||
// HTTP/1.1 200 OK
|
||||
if (!status && startswith(r, "HTTP/1.1 200 OK"))
|
||||
status = true;
|
||||
if (status) {
|
||||
// Check the location data
|
||||
// LOCATION: http://192.168.0.115:8888/octonet.xml
|
||||
if (startswith(r, "LOCATION:")) {
|
||||
location = compactspace(r + 9);
|
||||
debug1("%s location='%s'", __PRETTY_FUNCTION__, location);
|
||||
}
|
||||
// Check the source type
|
||||
// ST: urn:ses-com:device:SatIPServer:1
|
||||
else if (startswith(r, "ST:")) {
|
||||
char *st = compactspace(r + 3);
|
||||
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
|
||||
valid = true;
|
||||
debug1("%s st='%s'", __PRETTY_FUNCTION__, st);
|
||||
}
|
||||
// Check whether all the required data is found
|
||||
if (valid && !isempty(location)) {
|
||||
discoverM.SetUrl(location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
r = strtok_r(NULL, "\r\n", &s);
|
||||
}
|
||||
}
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
error("Error %d reading in %s", errno, *ToString());
|
||||
}
|
||||
}
|
||||
|
||||
cString cSatipMsearch::ToString(void) const
|
||||
{
|
||||
return "MSearch";
|
||||
}
|
40
msearch.h
Normal file
40
msearch.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* msearch.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_MSEARCH_H_
|
||||
#define __SATIP_MSEARCH_H_
|
||||
|
||||
#include "discoverif.h"
|
||||
#include "socket.h"
|
||||
#include "pollerif.h"
|
||||
|
||||
class cSatipMsearch : public cSatipSocket, public cSatipPollerIf {
|
||||
private:
|
||||
enum {
|
||||
eProbeBufferSize = 1024, // in bytes
|
||||
eDiscoveryPort = 1900,
|
||||
};
|
||||
static const char *bcastAddressS;
|
||||
static const char *bcastMessageS;
|
||||
cSatipDiscoverIf &discoverM;
|
||||
unsigned int bufferLenM;
|
||||
unsigned char *bufferM;
|
||||
bool registeredM;
|
||||
|
||||
public:
|
||||
cSatipMsearch(cSatipDiscoverIf &discoverP);
|
||||
virtual ~cSatipMsearch();
|
||||
void Probe(void);
|
||||
|
||||
// for internal poller interface
|
||||
public:
|
||||
virtual int GetFd(void);
|
||||
virtual void Process(void);
|
||||
virtual cString ToString(void) const;
|
||||
};
|
||||
|
||||
#endif /* __SATIP_MSEARCH_H_ */
|
57
param.c
57
param.c
@@ -24,24 +24,24 @@ static const tSatipParameterMap SatipBandwidthValues[] = {
|
||||
{ 8000000, "&bw=8" },
|
||||
{ 10000000, "&bw=10" },
|
||||
{ 1712000, "&bw=1.712" },
|
||||
{ -1, NULL }
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipPilotValues[] = {
|
||||
{ PILOT_OFF, "&plts=off" },
|
||||
{ PILOT_ON, "&plts=on" },
|
||||
{ PILOT_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
{ PILOT_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipSisoMisoValues[] = {
|
||||
{ 0, "&sm=0" },
|
||||
{ 1, "&sm=1" },
|
||||
{ -1, NULL }
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipCodeRateValues[] = {
|
||||
{ FEC_NONE, "" },
|
||||
{ FEC_NONE, "" },
|
||||
{ FEC_1_2, "&fec=12" },
|
||||
{ FEC_2_3, "&fec=23" },
|
||||
{ FEC_3_4, "&fec=34" },
|
||||
@@ -52,8 +52,8 @@ static const tSatipParameterMap SatipCodeRateValues[] = {
|
||||
{ FEC_7_8, "&fec=78" },
|
||||
{ FEC_8_9, "&fec=89" },
|
||||
{ FEC_9_10, "&fec=910" },
|
||||
{ FEC_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
{ FEC_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipModulationValues[] = {
|
||||
@@ -63,26 +63,26 @@ static const tSatipParameterMap SatipModulationValues[] = {
|
||||
{ QAM_64, "&mtype=64qam" },
|
||||
{ QAM_128, "&mtype=128qam" },
|
||||
{ QAM_256, "&mtype=256qam" },
|
||||
{ QAM_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
{ QAM_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipSystemValuesSat[] = {
|
||||
{ 0, "&msys=dvbs" },
|
||||
{ 1, "&msys=dvbs2" },
|
||||
{ -1, NULL }
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipSystemValuesTerrestrial[] = {
|
||||
{ 0, "&msys=dvbt" },
|
||||
{ 1, "&msys=dvbt2" },
|
||||
{ -1, NULL }
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipSystemValuesCable[] = {
|
||||
{ 0, "&msys=dvbc" },
|
||||
{ 1, "&msys=dvbc2" },
|
||||
{ -1, NULL }
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipTransmissionValues[] = {
|
||||
@@ -92,8 +92,8 @@ static const tSatipParameterMap SatipTransmissionValues[] = {
|
||||
{ TRANSMISSION_MODE_8K, "&tmode=8k" },
|
||||
{ TRANSMISSION_MODE_16K, "&tmode=16k" },
|
||||
{ TRANSMISSION_MODE_32K, "&tmode=32k" },
|
||||
{ TRANSMISSION_MODE_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
{ TRANSMISSION_MODE_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipGuardValues[] = {
|
||||
@@ -104,16 +104,23 @@ static const tSatipParameterMap SatipGuardValues[] = {
|
||||
{ GUARD_INTERVAL_1_128, "&gi=1128" },
|
||||
{ GUARD_INTERVAL_19_128, "&gi=19128" },
|
||||
{ GUARD_INTERVAL_19_256, "&gi=19256" },
|
||||
{ GUARD_INTERVAL_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
{ GUARD_INTERVAL_AUTO, "" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipRollOffValues[] = {
|
||||
{ ROLLOFF_AUTO, "" },
|
||||
{ ROLLOFF_AUTO, "" },
|
||||
{ ROLLOFF_20, "&ro=0.20" },
|
||||
{ ROLLOFF_25, "&ro=0.25" },
|
||||
{ ROLLOFF_35, "&ro=0.35" },
|
||||
{ -1, NULL }
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipInversionValues[] = {
|
||||
{ INVERSION_AUTO, "" },
|
||||
{ INVERSION_OFF, "&specinv=0" },
|
||||
{ INVERSION_ON, "&specinv=1" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static int SatipUserIndex(int valueP, const tSatipParameterMap *mapP)
|
||||
@@ -138,6 +145,8 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
|
||||
if (channelP) {
|
||||
char buffer[255];
|
||||
cDvbTransponderParameters dtp(channelP->Parameters());
|
||||
int DataSlice = 0;
|
||||
int C2TuningFrequencyType = 0;
|
||||
#if defined(APIVERSNUM) && APIVERSNUM < 20106
|
||||
int Pilot = PILOT_AUTO;
|
||||
int T2SystemId = 0;
|
||||
@@ -160,22 +169,30 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
|
||||
#define STBUFLEFT (sizeof(buffer) - (q - buffer))
|
||||
q += snprintf(q, STBUFLEFT, "freq=%s", *dtoa(freq, "%lg"));
|
||||
ST(" S *") q += snprintf(q, STBUFLEFT, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1);
|
||||
ST("CS *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
|
||||
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("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(" 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("C T*") 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.System(), SatipSystemValuesSat);
|
||||
ST("C *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesCable);
|
||||
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesTerrestrial);
|
||||
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues);
|
||||
if (channelP->Rid() > 0)
|
||||
q += snprintf(q, STBUFLEFT, "&fe=%d", channelP->Rid());
|
||||
#undef ST
|
||||
return buffer;
|
||||
}
|
||||
|
44
po/ca_ES.po
44
po/ca_ES.po
@@ -5,10 +5,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 0.3.3\n"
|
||||
"Project-Id-Version: vdr-satip 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
|
||||
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
|
||||
"POT-Creation-Date: 2014-12-24 12:24+0200\n"
|
||||
"PO-Revision-Date: 2014-12-24 12:24+0200\n"
|
||||
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
|
||||
"Language-Team: Catalan <vdr@linuxtv.org>\n"
|
||||
"Language: ca\n"
|
||||
@@ -31,11 +31,14 @@ msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
||||
msgid "TDT (0x70)"
|
||||
msgstr "TDT (0x70)"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "SAT>IP Informació no disponible!"
|
||||
|
||||
msgid "SAT>IP Devices"
|
||||
msgstr "SAT>IP Dispositius"
|
||||
|
||||
msgid "SAT>IP Device"
|
||||
msgstr "SAT>IP Dispositiu"
|
||||
msgid "SAT>IP Server"
|
||||
msgstr ""
|
||||
|
||||
msgid "Address"
|
||||
msgstr "Adressa"
|
||||
@@ -49,6 +52,9 @@ msgstr "Descripció"
|
||||
msgid "Creation date"
|
||||
msgstr "Creació de data"
|
||||
|
||||
msgid "SAT>IP Device Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "SAT>IP Information"
|
||||
msgstr "SAT>IP Informació"
|
||||
|
||||
@@ -64,9 +70,6 @@ msgstr "Filtres"
|
||||
msgid "Bits/bytes"
|
||||
msgstr "Bits/Bytes"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "SAT>IP Informació no disponible!"
|
||||
|
||||
msgid "off"
|
||||
msgstr "Apagat"
|
||||
|
||||
@@ -79,6 +82,9 @@ msgstr "Normal"
|
||||
msgid "high"
|
||||
msgstr "Alt"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr ""
|
||||
|
||||
msgid "Operating mode"
|
||||
msgstr "Mode de operació"
|
||||
|
||||
@@ -109,16 +115,28 @@ msgstr ""
|
||||
"\n"
|
||||
"Aquesta configuració desactiva la funcionalitat d'escaneig EIT automàtica per a tots els dispositius SAT>IP."
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Desactiva filtres"
|
||||
msgid "Disabled sources"
|
||||
msgstr ""
|
||||
|
||||
msgid "none"
|
||||
msgstr "no"
|
||||
|
||||
msgid ""
|
||||
"Define number of sources to be disabled.\n"
|
||||
"\n"
|
||||
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
|
||||
msgstr ""
|
||||
|
||||
msgid "Define a source to be blacklisted."
|
||||
msgstr ""
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Desactiva filtres"
|
||||
|
||||
msgid ""
|
||||
"Define number of section filters to be disabled.\n"
|
||||
"\n"
|
||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||
msgstr ""
|
||||
"Defineix el numero de filtres de secció que seran deshabilitats.\n"
|
||||
"\n"
|
||||
@@ -130,8 +148,8 @@ msgstr "Filtra"
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Definir un filtre mal comportar a la llista negra."
|
||||
|
||||
msgid "Active SAT>IP devices:"
|
||||
msgstr "Dispositius SAT>IP actius:"
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Help"
|
||||
msgstr "Ajuda"
|
||||
|
47
po/de_DE.po
47
po/de_DE.po
@@ -5,10 +5,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 0.3.3\n"
|
||||
"Project-Id-Version: vdr-satip 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
|
||||
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
|
||||
"POT-Creation-Date: 2014-12-24 12:24+0200\n"
|
||||
"PO-Revision-Date: 2014-12-24 12:24+0200\n"
|
||||
"Last-Translator: Frank Neumann <fnu@yavdr.org>\n"
|
||||
"Language-Team: German <vdr@linuxtv.org>\n"
|
||||
"Language: de\n"
|
||||
@@ -31,11 +31,14 @@ msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
||||
msgid "TDT (0x70)"
|
||||
msgstr "TDT (0x70)"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "Keine SAT>IP Informationen verfügbar!"
|
||||
|
||||
msgid "SAT>IP Devices"
|
||||
msgstr "SAT>IP Geräte"
|
||||
|
||||
msgid "SAT>IP Device"
|
||||
msgstr "SAT>IP Gerät"
|
||||
msgid "SAT>IP Server"
|
||||
msgstr "SAT>IP Server"
|
||||
|
||||
msgid "Address"
|
||||
msgstr "Adresse"
|
||||
@@ -49,6 +52,9 @@ msgstr "Beschreibung"
|
||||
msgid "Creation date"
|
||||
msgstr "Zeitpunkt der Erstellung"
|
||||
|
||||
msgid "SAT>IP Device Status"
|
||||
msgstr "SAT>IP Geräte Status"
|
||||
|
||||
msgid "SAT>IP Information"
|
||||
msgstr "SAT>IP Informationen"
|
||||
|
||||
@@ -64,9 +70,6 @@ msgstr "Filter"
|
||||
msgid "Bits/bytes"
|
||||
msgstr "Bits/Bytes"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "Keine SAT>IP Informationen verfügbar!"
|
||||
|
||||
msgid "off"
|
||||
msgstr "aus"
|
||||
|
||||
@@ -79,6 +82,9 @@ msgstr "normal"
|
||||
msgid "high"
|
||||
msgstr "hoch"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr ""
|
||||
|
||||
msgid "Operating mode"
|
||||
msgstr "Betriebsmodus"
|
||||
|
||||
@@ -109,16 +115,31 @@ msgstr ""
|
||||
"\n"
|
||||
"Diese Einstellung schaltet die automatische EIT Aktualisierung für alle SAT>IP Geräte."
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Deaktivierte Filter"
|
||||
msgid "Disabled sources"
|
||||
msgstr "Deaktivierte Quellen"
|
||||
|
||||
msgid "none"
|
||||
msgstr "keine"
|
||||
|
||||
msgid ""
|
||||
"Define number of sources to be disabled.\n"
|
||||
"\n"
|
||||
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
|
||||
msgstr ""
|
||||
"Definiert die Anzahl der deaktivierten Quellen.\n"
|
||||
"\n"
|
||||
"Für einige SAT>IP server sind nicht alle Satellitenpositionen verfügbar, nicht verfügbare Quellen können hier ausgeblendet werden"
|
||||
|
||||
msgid "Define a source to be blacklisted."
|
||||
msgstr "Bestimme eine Quelle, die ausgeblendet wird"
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Deaktivierte Filter"
|
||||
|
||||
msgid ""
|
||||
"Define number of section filters to be disabled.\n"
|
||||
"\n"
|
||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||
msgstr ""
|
||||
"Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\n"
|
||||
"\n"
|
||||
@@ -130,8 +151,8 @@ msgstr "Filter"
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Bestimme einen fehlerhaften Filter der ausgeblendet werden soll."
|
||||
|
||||
msgid "Active SAT>IP devices:"
|
||||
msgstr "Aktive SAT>IP Geräte:"
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr "Aktive SAT>IP Server"
|
||||
|
||||
msgid "Help"
|
||||
msgstr "Hilfe"
|
||||
|
44
po/es_ES.po
44
po/es_ES.po
@@ -5,10 +5,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 0.3.3\n"
|
||||
"Project-Id-Version: vdr-satip 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
|
||||
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
|
||||
"POT-Creation-Date: 2014-12-24 12:24+0200\n"
|
||||
"PO-Revision-Date: 2014-12-24 12:24+0200\n"
|
||||
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
|
||||
"Language-Team: Spanish <vdr@linuxtv.org>\n"
|
||||
"Language: es\n"
|
||||
@@ -31,11 +31,14 @@ msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
||||
msgid "TDT (0x70)"
|
||||
msgstr "TDT (0x70)"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "SAT>IP Información no disponible!"
|
||||
|
||||
msgid "SAT>IP Devices"
|
||||
msgstr "SAT>IP Dispositivos"
|
||||
|
||||
msgid "SAT>IP Device"
|
||||
msgstr "SAT>IP Dispositivo"
|
||||
msgid "SAT>IP Server"
|
||||
msgstr ""
|
||||
|
||||
msgid "Address"
|
||||
msgstr "Dirección"
|
||||
@@ -49,6 +52,9 @@ msgstr "Descripción"
|
||||
msgid "Creation date"
|
||||
msgstr "Fecha creación"
|
||||
|
||||
msgid "SAT>IP Device Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "SAT>IP Information"
|
||||
msgstr "SAT>IP Información"
|
||||
|
||||
@@ -64,9 +70,6 @@ msgstr "Filtros"
|
||||
msgid "Bits/bytes"
|
||||
msgstr "Bits/Bytes"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "SAT>IP Información no disponible!"
|
||||
|
||||
msgid "off"
|
||||
msgstr "Apagado"
|
||||
|
||||
@@ -79,6 +82,9 @@ msgstr "Normal"
|
||||
msgid "high"
|
||||
msgstr "Alto"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr ""
|
||||
|
||||
msgid "Operating mode"
|
||||
msgstr "Modo de operación"
|
||||
|
||||
@@ -109,16 +115,28 @@ msgstr ""
|
||||
"\n"
|
||||
"Esta configuración desactiva la funcionalidad del escaneo EIT automática para todos los Dispositivos SAT>IP."
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Desactiva filtros"
|
||||
msgid "Disabled sources"
|
||||
msgstr ""
|
||||
|
||||
msgid "none"
|
||||
msgstr "no"
|
||||
|
||||
msgid ""
|
||||
"Define number of sources to be disabled.\n"
|
||||
"\n"
|
||||
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
|
||||
msgstr ""
|
||||
|
||||
msgid "Define a source to be blacklisted."
|
||||
msgstr ""
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Desactiva filtros"
|
||||
|
||||
msgid ""
|
||||
"Define number of section filters to be disabled.\n"
|
||||
"\n"
|
||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||
msgstr ""
|
||||
"Define el numero de filtros de sección que seran deshabilitados.\n"
|
||||
"\n"
|
||||
@@ -130,8 +148,8 @@ msgstr "Filtra"
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Define un filtro para poner en la lista negra."
|
||||
|
||||
msgid "Active SAT>IP devices:"
|
||||
msgstr "Dispositivos SAT>IP activos:"
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Help"
|
||||
msgstr "Ayuda"
|
||||
|
47
po/fi_FI.po
47
po/fi_FI.po
@@ -5,10 +5,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 0.3.3\n"
|
||||
"Project-Id-Version: vdr-satip 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
|
||||
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
|
||||
"POT-Creation-Date: 2014-12-24 12:24+0200\n"
|
||||
"PO-Revision-Date: 2014-12-24 12:24+0200\n"
|
||||
"Last-Translator: Rolf Ahrenberg\n"
|
||||
"Language-Team: Finnish <vdr@linuxtv.org>\n"
|
||||
"Language: fi\n"
|
||||
@@ -31,11 +31,14 @@ msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
||||
msgid "TDT (0x70)"
|
||||
msgstr "TDT (0x70)"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "SAT>IP-tietoja ei saatavilla!"
|
||||
|
||||
msgid "SAT>IP Devices"
|
||||
msgstr "SAT>IP-laitteet"
|
||||
|
||||
msgid "SAT>IP Device"
|
||||
msgstr "SAT>IP-laite"
|
||||
msgid "SAT>IP Server"
|
||||
msgstr "SAT>IP-palvelin"
|
||||
|
||||
msgid "Address"
|
||||
msgstr "Osoite"
|
||||
@@ -49,6 +52,9 @@ msgstr "Kuvaus"
|
||||
msgid "Creation date"
|
||||
msgstr "Luontiajankohta"
|
||||
|
||||
msgid "SAT>IP Device Status"
|
||||
msgstr "SAT>IP-laitteiden tiedot"
|
||||
|
||||
msgid "SAT>IP Information"
|
||||
msgstr "SAT>IP-tiedot"
|
||||
|
||||
@@ -64,9 +70,6 @@ msgstr "Suodattimet"
|
||||
msgid "Bits/bytes"
|
||||
msgstr "Bitit/tavut"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "SAT>IP-tietoja ei saatavilla!"
|
||||
|
||||
msgid "off"
|
||||
msgstr "ei käytössä"
|
||||
|
||||
@@ -79,6 +82,9 @@ msgstr "normaali"
|
||||
msgid "high"
|
||||
msgstr "korkea"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr "Laitteet"
|
||||
|
||||
msgid "Operating mode"
|
||||
msgstr "Laitteiden toimintatapa"
|
||||
|
||||
@@ -108,16 +114,31 @@ msgstr ""
|
||||
"\n"
|
||||
"Tällä asetuksella saadaan otettua automaattinen EIT-datan päivitys pois päältä kaikilta SAT>IP-laitteilta."
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Käytöstä poistetut suodattimet"
|
||||
msgid "Disabled sources"
|
||||
msgstr "Käytöstä poistetut lähteet"
|
||||
|
||||
msgid "none"
|
||||
msgstr "tyhjä"
|
||||
|
||||
msgid ""
|
||||
"Define number of sources to be disabled.\n"
|
||||
"\n"
|
||||
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
|
||||
msgstr ""
|
||||
"Määrittele käytöstä poistettavien lähteiden lukumäärä.\n"
|
||||
"\n"
|
||||
"SAT>IP-palvelimilla ei välttämättä ole kaikkia ohjelmalähteitä tarjolla."
|
||||
|
||||
msgid "Define a source to be blacklisted."
|
||||
msgstr "Määrittele käytöstä"
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Käytöstä poistetut suodattimet"
|
||||
|
||||
msgid ""
|
||||
"Define number of section filters to be disabled.\n"
|
||||
"\n"
|
||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||
msgstr ""
|
||||
"Määrittele käytöstä poistettavien suodattimien lukumäärä sektioille.\n"
|
||||
"\n"
|
||||
@@ -129,8 +150,8 @@ msgstr "Suodatin"
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle."
|
||||
|
||||
msgid "Active SAT>IP devices:"
|
||||
msgstr "Aktiiviset SAT>IP-laitteet:"
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr "Aktiiviset SAT>IP-palvelimet:"
|
||||
|
||||
msgid "Help"
|
||||
msgstr "Opaste"
|
||||
|
122
poller.c
Normal file
122
poller.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* poller.c: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
||||
#include <inttypes.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "poller.h"
|
||||
|
||||
cSatipPoller *cSatipPoller::instanceS = NULL;
|
||||
|
||||
cSatipPoller *cSatipPoller::GetInstance(void)
|
||||
{
|
||||
if (!instanceS)
|
||||
instanceS = new cSatipPoller();
|
||||
return instanceS;
|
||||
}
|
||||
|
||||
bool cSatipPoller::Initialize(void)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (instanceS)
|
||||
instanceS->Activate();
|
||||
return true;
|
||||
}
|
||||
|
||||
void cSatipPoller::Destroy(void)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (instanceS)
|
||||
instanceS->Deactivate();
|
||||
}
|
||||
|
||||
cSatipPoller::cSatipPoller()
|
||||
: cThread("SATIP poller"),
|
||||
mutexM(),
|
||||
fdM(epoll_create(eMaxFileDescriptors))
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cSatipPoller::~cSatipPoller()
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
Deactivate();
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
close(fdM);
|
||||
// Free allocated memory
|
||||
}
|
||||
|
||||
void cSatipPoller::Activate(void)
|
||||
{
|
||||
// Start the thread
|
||||
Start();
|
||||
}
|
||||
|
||||
void cSatipPoller::Deactivate(void)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (Running())
|
||||
Cancel(3);
|
||||
}
|
||||
|
||||
void cSatipPoller::Action(void)
|
||||
{
|
||||
debug1("%s Entering", __PRETTY_FUNCTION__);
|
||||
struct epoll_event events[eMaxFileDescriptors];
|
||||
uint64_t maxElapsed = 0;
|
||||
// Increase priority
|
||||
SetPriority(-1);
|
||||
// Do the thread loop
|
||||
while (Running()) {
|
||||
int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, -1);
|
||||
ERROR_IF_FUNC((nfds == -1), "epoll_wait() failed", break, ;);
|
||||
for (int i = 0; i < nfds; ++i) {
|
||||
cSatipPollerIf* poll = reinterpret_cast<cSatipPollerIf *>(events[i].data.ptr);
|
||||
if (poll) {
|
||||
uint64_t elapsed;
|
||||
cTimeMs processing(0);
|
||||
poll->Process();
|
||||
elapsed = processing.Elapsed();
|
||||
if (elapsed > maxElapsed) {
|
||||
maxElapsed = elapsed;
|
||||
debug1("%s Processing %s took %" PRIu64 " ms", __PRETTY_FUNCTION__, *(poll->ToString()), maxElapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
debug1("%s Exiting", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
bool cSatipPoller::Register(cSatipPollerIf &pollerP)
|
||||
{
|
||||
debug1("%s fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd());
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLIN | EPOLLET;
|
||||
ev.data.ptr = &pollerP;
|
||||
ERROR_IF_RET(epoll_ctl(fdM, EPOLL_CTL_ADD, pollerP.GetFd(), &ev) == -1, "epoll_ctl(EPOLL_CTL_ADD) failed", return false);
|
||||
debug1("%s Added interface fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipPoller::Unregister(cSatipPollerIf &pollerP)
|
||||
{
|
||||
debug1("%s fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd());
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
ERROR_IF_RET((epoll_ctl(fdM, EPOLL_CTL_DEL, pollerP.GetFd(), NULL) == -1), "epoll_ctl(EPOLL_CTL_DEL) failed", return false);
|
||||
debug1("%s Removed interface fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd());
|
||||
|
||||
return true;
|
||||
}
|
44
poller.h
Normal file
44
poller.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* poller.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_POLLER_H
|
||||
#define __SATIP_POLLER_H
|
||||
|
||||
#include <vdr/thread.h>
|
||||
#include <vdr/tools.h>
|
||||
|
||||
#include "pollerif.h"
|
||||
|
||||
class cSatipPoller : public cThread {
|
||||
private:
|
||||
enum {
|
||||
eMaxFileDescriptors = SATIP_MAX_DEVICES * 2, // Data + Application
|
||||
};
|
||||
static cSatipPoller *instanceS;
|
||||
cMutex mutexM;
|
||||
int fdM;
|
||||
void Activate(void);
|
||||
void Deactivate(void);
|
||||
// constructor
|
||||
cSatipPoller();
|
||||
// to prevent copy constructor and assignment
|
||||
cSatipPoller(const cSatipPoller&);
|
||||
cSatipPoller& operator=(const cSatipPoller&);
|
||||
|
||||
protected:
|
||||
virtual void Action(void);
|
||||
|
||||
public:
|
||||
static cSatipPoller *GetInstance(void);
|
||||
static bool Initialize(void);
|
||||
static void Destroy(void);
|
||||
virtual ~cSatipPoller();
|
||||
bool Register(cSatipPollerIf &pollerP);
|
||||
bool Unregister(cSatipPollerIf &pollerP);
|
||||
};
|
||||
|
||||
#endif // __SATIP_POLLER_H
|
24
pollerif.h
Normal file
24
pollerif.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* pollerif.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_POLLERIF_H
|
||||
#define __SATIP_POLLERIF_H
|
||||
|
||||
class cSatipPollerIf {
|
||||
public:
|
||||
cSatipPollerIf() {}
|
||||
virtual ~cSatipPollerIf() {}
|
||||
virtual int GetFd(void) = 0;
|
||||
virtual void Process(void) = 0;
|
||||
virtual cString ToString(void) const = 0;
|
||||
|
||||
private:
|
||||
cSatipPollerIf(const cSatipPollerIf&);
|
||||
cSatipPollerIf& operator=(const cSatipPollerIf&);
|
||||
};
|
||||
|
||||
#endif // __SATIP_POLLERIF_H
|
100
rtcp.c
Normal file
100
rtcp.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* rtcp.c: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "rtcp.h"
|
||||
|
||||
cSatipRtcp::cSatipRtcp(cSatipTunerIf &tunerP)
|
||||
: tunerM(tunerP),
|
||||
bufferLenM(eApplicationMaxSizeB),
|
||||
bufferM(MALLOC(unsigned char, bufferLenM))
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
if (bufferM)
|
||||
memset(bufferM, 0, bufferLenM);
|
||||
else
|
||||
error("Cannot create RTCP buffer! [device %d]", tunerM.GetId());
|
||||
}
|
||||
|
||||
cSatipRtcp::~cSatipRtcp()
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
DELETE_POINTER(bufferM);
|
||||
}
|
||||
|
||||
int cSatipRtcp::GetFd(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
return Fd();
|
||||
}
|
||||
|
||||
int cSatipRtcp::GetApplicationOffset(int *lengthP)
|
||||
{
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, *lengthP, tunerM.GetId());
|
||||
if (!lengthP)
|
||||
return -1;
|
||||
int offset = 0;
|
||||
int total = *lengthP;
|
||||
while (total > 0) {
|
||||
// Version
|
||||
unsigned int v = (bufferM[offset] >> 6) & 0x03;
|
||||
// Padding
|
||||
//unsigned int p = (bufferM[offset] >> 5) & 0x01;
|
||||
// Subtype
|
||||
//unsigned int st = bufferM[offset] & 0x1F;
|
||||
// Payload type
|
||||
unsigned int pt = bufferM[offset + 1] & 0xFF;
|
||||
// Lenght
|
||||
unsigned int length = ((bufferM[offset + 2] & 0xFF) << 8) | (bufferM[offset + 3] & 0xFF);
|
||||
// Convert it to bytes
|
||||
length = (length + 1) * 4;
|
||||
// V=2, APP = 204
|
||||
if ((v == 2) && (pt == 204)) {
|
||||
// SSCR/CSCR
|
||||
//unsigned int ssrc = ((bufferM[offset + 4] & 0xFF) << 24) | ((bufferM[offset + 5] & 0xFF) << 16) |
|
||||
// ((bufferM[offset + 6] & 0xFF) << 8) | (bufferM[offset + 7] & 0xFF);
|
||||
// Name
|
||||
if ((bufferM[offset + 8] == 'S') && (bufferM[offset + 9] == 'E') &&
|
||||
(bufferM[offset + 10] == 'S') && (bufferM[offset + 11] == '1')) {
|
||||
// Identifier
|
||||
//unsigned int id = ((bufferM[offset + 12] & 0xFF) << 8) | (bufferM[offset + 13] & 0xFF);
|
||||
// String length
|
||||
int string_length = ((bufferM[offset + 14] & 0xFF) << 8) | (bufferM[offset + 15] & 0xFF);
|
||||
if (string_length > 0) {
|
||||
*lengthP = string_length;
|
||||
return (offset + 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += length;
|
||||
total -= length;
|
||||
}
|
||||
*lengthP = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void cSatipRtcp::Process(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
if (bufferM) {
|
||||
int length;
|
||||
while ((length = Read(bufferM, bufferLenM)) > 0) {
|
||||
int offset = GetApplicationOffset(&length);
|
||||
if (offset >= 0)
|
||||
tunerM.ProcessApplicationData(bufferM + offset, length);
|
||||
}
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
error("Error %d reading in %s", errno, *ToString());
|
||||
}
|
||||
}
|
||||
|
||||
cString cSatipRtcp::ToString(void) const
|
||||
{
|
||||
return cString::sprintf("RTCP [device %d]", tunerM.GetId());
|
||||
}
|
36
rtcp.h
Normal file
36
rtcp.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* rtcp.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_RTCP_H_
|
||||
#define __SATIP_RTCP_H_
|
||||
|
||||
#include "socket.h"
|
||||
#include "tunerif.h"
|
||||
#include "pollerif.h"
|
||||
|
||||
class cSatipRtcp : public cSatipSocket, public cSatipPollerIf {
|
||||
private:
|
||||
enum {
|
||||
eApplicationMaxSizeB = 1500,
|
||||
};
|
||||
cSatipTunerIf &tunerM;
|
||||
unsigned int bufferLenM;
|
||||
unsigned char *bufferM;
|
||||
int GetApplicationOffset(int *lenghtP);
|
||||
|
||||
public:
|
||||
cSatipRtcp(cSatipTunerIf &tunerP);
|
||||
virtual ~cSatipRtcp();
|
||||
|
||||
// for internal poller interface
|
||||
public:
|
||||
virtual int GetFd(void);
|
||||
virtual void Process(void);
|
||||
virtual cString ToString(void) const;
|
||||
};
|
||||
|
||||
#endif /* __SATIP_RTCP_H_ */
|
151
rtp.c
Normal file
151
rtp.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* rtp.c: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "rtp.h"
|
||||
|
||||
cSatipRtp::cSatipRtp(cSatipTunerIf &tunerP)
|
||||
: tunerM(tunerP),
|
||||
bufferLenM(eRtpPacketReadCount * eMaxUdpPacketSizeB),
|
||||
bufferM(MALLOC(unsigned char, bufferLenM)),
|
||||
lastErrorReportM(0),
|
||||
packetErrorsM(0),
|
||||
sequenceNumberM(-1)
|
||||
{
|
||||
debug1("%s () [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
if (!bufferM)
|
||||
error("Cannot create RTP buffer! [device %d]", tunerM.GetId());
|
||||
}
|
||||
|
||||
cSatipRtp::~cSatipRtp()
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
DELETE_POINTER(bufferM);
|
||||
}
|
||||
|
||||
int cSatipRtp::GetFd(void)
|
||||
{
|
||||
return Fd();
|
||||
}
|
||||
|
||||
void cSatipRtp::Close(void)
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
|
||||
cSatipSocket::Close();
|
||||
|
||||
sequenceNumberM = -1;
|
||||
if (packetErrorsM) {
|
||||
info("Detected %d RTP packet errors [device %d]", packetErrorsM, tunerM.GetId());
|
||||
packetErrorsM = 0;
|
||||
lastErrorReportM = time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int cSatipRtp::GetHeaderLenght(unsigned char *bufferP, unsigned int lengthP)
|
||||
{
|
||||
debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, tunerM.GetId());
|
||||
unsigned int headerlen = 0;
|
||||
|
||||
if (lengthP > 0) {
|
||||
if (bufferP[0] == TS_SYNC_BYTE)
|
||||
return headerlen;
|
||||
else if (lengthP > 3) {
|
||||
// http://tools.ietf.org/html/rfc3550
|
||||
// http://tools.ietf.org/html/rfc2250
|
||||
// Version
|
||||
unsigned int v = (bufferP[0] >> 6) & 0x03;
|
||||
// Extension bit
|
||||
unsigned int x = (bufferP[0] >> 4) & 0x01;
|
||||
// CSCR count
|
||||
unsigned int cc = bufferP[0] & 0x0F;
|
||||
// Payload type: MPEG2 TS = 33
|
||||
unsigned int pt = bufferP[1] & 0x7F;
|
||||
if (pt != 33)
|
||||
debug7("%s (%d) Received invalid RTP payload type %d - v=%d [device %d]",
|
||||
__PRETTY_FUNCTION__, lengthP, pt, v, tunerM.GetId());
|
||||
// Sequence number
|
||||
int seq = ((bufferP[2] & 0xFF) << 8) | (bufferP[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 [device %d]", packetErrorsM, tunerM.GetId());
|
||||
packetErrorsM = 0;
|
||||
lastErrorReportM = time(NULL);
|
||||
}
|
||||
sequenceNumberM = seq;
|
||||
}
|
||||
else
|
||||
sequenceNumberM = seq;
|
||||
// Header lenght
|
||||
headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
|
||||
// Check if extension
|
||||
if (x) {
|
||||
// Extension header length
|
||||
unsigned int ehl = (((bufferP[headerlen + 2] & 0xFF) << 8) | (bufferP[headerlen + 3] & 0xFF));
|
||||
// Update header length
|
||||
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
||||
}
|
||||
// Check for empty payload
|
||||
if (lengthP == headerlen) {
|
||||
debug7("%s (%d) Received empty RTP packet #%d [device %d]", __PRETTY_FUNCTION__, lengthP, seq, tunerM.GetId());
|
||||
headerlen = -1;
|
||||
}
|
||||
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
||||
else if ((v != 2) || (((lengthP - headerlen) % TS_SIZE) != 0) || (bufferP[headerlen] != TS_SYNC_BYTE)) {
|
||||
debug7("%s (%d) Received incorrect RTP packet #%d v=%d len=%d sync=0x%02X [device %d]", __PRETTY_FUNCTION__,
|
||||
lengthP, seq, v, headerlen, bufferP[headerlen], tunerM.GetId());
|
||||
headerlen = -1;
|
||||
}
|
||||
else
|
||||
debug7("%s (%d) Received RTP packet #%d v=%d len=%d sync=0x%02X [device %d]", __PRETTY_FUNCTION__,
|
||||
lengthP, seq, v, headerlen, bufferP[headerlen], tunerM.GetId());
|
||||
}
|
||||
}
|
||||
|
||||
return headerlen;
|
||||
}
|
||||
|
||||
void cSatipRtp::Process(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
if (bufferM) {
|
||||
unsigned int lenMsg[eRtpPacketReadCount];
|
||||
uint64_t elapsed;
|
||||
int count = 0;
|
||||
cTimeMs processing(0);
|
||||
|
||||
do {
|
||||
count = ReadMulti(bufferM, lenMsg, eRtpPacketReadCount, eMaxUdpPacketSizeB);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
unsigned char *p = &bufferM[i * eMaxUdpPacketSizeB];
|
||||
int headerlen = GetHeaderLenght(p, lenMsg[i]);
|
||||
if ((headerlen >= 0) && (headerlen < (int)lenMsg[i]))
|
||||
tunerM.ProcessVideoData(p + headerlen, lenMsg[i] - headerlen);
|
||||
}
|
||||
} while (count >= eRtpPacketReadCount);
|
||||
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
error("Error %d reading in %s [device %d]", errno, *ToString(), tunerM.GetId());
|
||||
|
||||
elapsed = processing.Elapsed();
|
||||
if (elapsed > 1)
|
||||
debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, count, elapsed, tunerM.GetId());
|
||||
}
|
||||
}
|
||||
|
||||
cString cSatipRtp::ToString(void) const
|
||||
{
|
||||
return cString::sprintf("RTP [device %d]", tunerM.GetId());
|
||||
}
|
42
rtp.h
Normal file
42
rtp.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* rtp.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_RTP_H_
|
||||
#define __SATIP_RTP_H_
|
||||
|
||||
#include "socket.h"
|
||||
#include "tunerif.h"
|
||||
#include "pollerif.h"
|
||||
|
||||
class cSatipRtp : public cSatipSocket, public cSatipPollerIf {
|
||||
private:
|
||||
enum {
|
||||
eRtpPacketReadCount = 50,
|
||||
eMaxUdpPacketSizeB = TS_SIZE * 7 + 12,
|
||||
eReportIntervalS = 300 // in seconds
|
||||
};
|
||||
cSatipTunerIf &tunerM;
|
||||
unsigned int bufferLenM;
|
||||
unsigned char *bufferM;
|
||||
time_t lastErrorReportM;
|
||||
int packetErrorsM;
|
||||
int sequenceNumberM;
|
||||
int GetHeaderLenght(unsigned char *bufferP, unsigned int lengthP);
|
||||
|
||||
public:
|
||||
cSatipRtp(cSatipTunerIf &tunerP);
|
||||
virtual ~cSatipRtp();
|
||||
virtual void Close(void);
|
||||
|
||||
// for internal poller interface
|
||||
public:
|
||||
virtual int GetFd(void);
|
||||
virtual void Process(void);
|
||||
virtual cString ToString(void) const;
|
||||
};
|
||||
|
||||
#endif /* __SATIP_RTP_H_ */
|
335
rtsp.c
Normal file
335
rtsp.c
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* rtsp.c: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP)
|
||||
: tunerM(tunerP),
|
||||
modeM(cmUnicast),
|
||||
handleM(NULL),
|
||||
headerListM(NULL)
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
Create();
|
||||
}
|
||||
|
||||
cSatipRtsp::~cSatipRtsp()
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP)
|
||||
{
|
||||
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(userPtrP);
|
||||
|
||||
if (obj) {
|
||||
switch (typeP) {
|
||||
case CURLINFO_TEXT:
|
||||
debug2("%s [device %d] RTSP INFO %.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||
break;
|
||||
case CURLINFO_HEADER_IN:
|
||||
debug2("%s [device %d] RTSP HEAD <<< %.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||
break;
|
||||
case CURLINFO_HEADER_OUT:
|
||||
debug2("%s [device %d] RTSP HEAD >>>\n%.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||
break;
|
||||
case CURLINFO_DATA_IN:
|
||||
debug2("%s [device %d] RTSP DATA <<< %.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||
break;
|
||||
case CURLINFO_DATA_OUT:
|
||||
debug2("%s [device %d] RTSP DATA >>>\n%.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cString cSatipRtsp::RtspUnescapeString(const char *strP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId());
|
||||
if (handleM) {
|
||||
char *p = curl_easy_unescape(handleM, strP, 0, NULL);
|
||||
cString s = p;
|
||||
curl_free(p);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
return cString(strP);
|
||||
}
|
||||
|
||||
void cSatipRtsp::Create(void)
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
if (!handleM)
|
||||
handleM = curl_easy_init();
|
||||
|
||||
if (handleM) {
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
// Verbose output
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipRtsp::DebugCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this);
|
||||
|
||||
// No progress meter and no signaling
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
// Set timeouts
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||
|
||||
// Set user-agent
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, tunerM.GetId()));
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipRtsp::Destroy(void)
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
if (handleM) {
|
||||
// Cleanup curl stuff
|
||||
if (headerListM) {
|
||||
curl_slist_free_all(headerListM);
|
||||
headerListM = NULL;
|
||||
}
|
||||
curl_easy_cleanup(handleM);
|
||||
handleM = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipRtsp::Reset(void)
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
Destroy();
|
||||
Create();
|
||||
}
|
||||
|
||||
bool cSatipRtsp::Options(const char *uriP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||
bool result = false;
|
||||
|
||||
if (handleM && !isempty(uriP)) {
|
||||
long rc = 0;
|
||||
cTimeMs processing(0);
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, uriP);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
|
||||
result = ValidateLatestResponse(&rc);
|
||||
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP)
|
||||
{
|
||||
debug1("%s (%s, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, tunerM.GetId());
|
||||
bool result = false;
|
||||
|
||||
if (handleM && !isempty(uriP)) {
|
||||
cString transport;
|
||||
long rc = 0;
|
||||
cTimeMs processing(0);
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
switch (modeM) {
|
||||
case cmMulticast:
|
||||
// RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl>
|
||||
transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP);
|
||||
break;
|
||||
default:
|
||||
case cmUnicast:
|
||||
// RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port>
|
||||
transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP);
|
||||
break;
|
||||
}
|
||||
|
||||
// Setup media stream
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_TRANSPORT, *transport);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
|
||||
// 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_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);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipRtsp::SetSession(const char *sessionP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, sessionP, tunerM.GetId());
|
||||
if (handleM) {
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
debug1("%s: session id quirk enabled [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, sessionP);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipRtsp::Describe(const char *uriP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||
bool result = false;
|
||||
|
||||
if (handleM && !isempty(uriP)) {
|
||||
long rc = 0;
|
||||
cTimeMs processing(0);
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
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_WRITEDATA, this);
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
|
||||
|
||||
result = ValidateLatestResponse(&rc);
|
||||
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipRtsp::Play(const char *uriP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||
bool result = false;
|
||||
|
||||
if (handleM && !isempty(uriP)) {
|
||||
long rc = 0;
|
||||
cTimeMs processing(0);
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
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_PERFORM(handleM);
|
||||
|
||||
result = ValidateLatestResponse(&rc);
|
||||
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipRtsp::Teardown(const char *uriP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||
bool result = false;
|
||||
|
||||
if (handleM && !isempty(uriP)) {
|
||||
long rc = 0;
|
||||
cTimeMs processing(0);
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
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_PERFORM(handleM);
|
||||
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_CLIENT_CSEQ, 1L);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL);
|
||||
|
||||
result = ValidateLatestResponse(&rc);
|
||||
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipRtsp::ValidateLatestResponse(long *rcP)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (handleM) {
|
||||
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());
|
||||
}
|
||||
if (rcP)
|
||||
*rcP = rc;
|
||||
}
|
||||
debug1("%s result=%s [device %d]", __PRETTY_FUNCTION__, result ? "ok" : "failed", tunerM.GetId());
|
||||
|
||||
return result;
|
||||
}
|
58
rtsp.h
Normal file
58
rtsp.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* rtsp.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_RTSP_H
|
||||
#define __SATIP_RTSP_H
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <curl/easy.h>
|
||||
|
||||
#ifndef CURLOPT_RTSPHEADER
|
||||
#error "libcurl is missing required RTSP support"
|
||||
#endif
|
||||
|
||||
#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 int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
|
||||
|
||||
enum {
|
||||
eConnectTimeoutMs = 1500, // in milliseconds
|
||||
};
|
||||
enum eCommunicationMode { cmUnicast, cmMulticast };
|
||||
|
||||
cSatipTunerIf &tunerM;
|
||||
eCommunicationMode modeM;
|
||||
CURL *handleM;
|
||||
struct curl_slist *headerListM;
|
||||
|
||||
void Create(void);
|
||||
void Destroy(void);
|
||||
bool ValidateLatestResponse(long *rcP);
|
||||
|
||||
// to prevent copy constructor and assignment
|
||||
cSatipRtsp(const cSatipRtsp&);
|
||||
cSatipRtsp& operator=(const cSatipRtsp&);
|
||||
|
||||
public:
|
||||
cSatipRtsp(cSatipTunerIf &tunerP);
|
||||
virtual ~cSatipRtsp();
|
||||
|
||||
cString RtspUnescapeString(const char *strP);
|
||||
void Reset(void);
|
||||
bool Options(const char *uriP);
|
||||
bool Setup(const char *uriP, int rtpPortP, int rtcpPortP);
|
||||
bool SetSession(const char *sessionP);
|
||||
bool Describe(const char *uriP);
|
||||
bool Play(const char *uriP);
|
||||
bool Teardown(const char *uriP);
|
||||
};
|
||||
|
||||
#endif // __SATIP_RTSP_H
|
162
satip.c
162
satip.c
@@ -11,6 +11,8 @@
|
||||
#include "config.h"
|
||||
#include "device.h"
|
||||
#include "discover.h"
|
||||
#include "log.h"
|
||||
#include "poller.h"
|
||||
#include "setup.h"
|
||||
|
||||
#if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM < 0x072400
|
||||
@@ -25,13 +27,15 @@
|
||||
#define GITVERSION ""
|
||||
#endif
|
||||
|
||||
const char VERSION[] = "0.3.3" GITVERSION;
|
||||
const char VERSION[] = "1.0.0" GITVERSION;
|
||||
static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
|
||||
|
||||
class cPluginSatip : public cPlugin {
|
||||
private:
|
||||
unsigned int deviceCountM;
|
||||
cSatipDiscover *discoverM;
|
||||
cSatipDiscoverServers *serversM;
|
||||
void ParseServer(const char *paramP);
|
||||
int ParseSources(const char *valueP, int *sourcesP);
|
||||
int ParseFilters(const char *valueP, int *filtersP);
|
||||
public:
|
||||
cPluginSatip(void);
|
||||
@@ -58,9 +62,9 @@ public:
|
||||
|
||||
cPluginSatip::cPluginSatip(void)
|
||||
: deviceCountM(1),
|
||||
discoverM(NULL)
|
||||
serversM(NULL)
|
||||
{
|
||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
// Initialize any member variables here.
|
||||
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
|
||||
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
|
||||
@@ -68,31 +72,41 @@ cPluginSatip::cPluginSatip(void)
|
||||
|
||||
cPluginSatip::~cPluginSatip()
|
||||
{
|
||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
// Clean up after yourself!
|
||||
}
|
||||
|
||||
const char *cPluginSatip::CommandLineHelp(void)
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Return a string that describes all known command line options.
|
||||
return " -d <num>, --devices=<number> number of devices to be created\n";
|
||||
return " -d <num>, --devices=<number> set number of devices to be created\n"
|
||||
" -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>|<model2>|<desc2>\n"
|
||||
" define hard-coded SAT>IP server(s)\n";
|
||||
}
|
||||
|
||||
bool cPluginSatip::ProcessArgs(int argc, char *argv[])
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Implement command line argument processing here if applicable.
|
||||
static const struct option long_options[] = {
|
||||
{ "devices", required_argument, NULL, 'd' },
|
||||
{ "trace", required_argument, NULL, 't' },
|
||||
{ "server", required_argument, NULL, 's' },
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) {
|
||||
while ((c = getopt_long(argc, argv, "d:t:s:", long_options, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
deviceCountM = atoi(optarg);
|
||||
deviceCountM = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 't':
|
||||
SatipConfig.SetTraceMode(strtol(optarg, NULL, 0));
|
||||
break;
|
||||
case 's':
|
||||
ParseServer(optarg);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@@ -103,18 +117,19 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
|
||||
|
||||
bool cPluginSatip::Initialize(void)
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Initialize any background activities the plugin shall perform.
|
||||
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
|
||||
error("Unable to initialize CURL");
|
||||
SatipConfig.SetConfigDirectory(cPlugin::ResourceDirectory(PLUGIN_NAME_I18N));
|
||||
cSatipDiscover::GetInstance()->Initialize();
|
||||
cSatipPoller::GetInstance()->Initialize();
|
||||
cSatipDiscover::GetInstance()->Initialize(serversM);
|
||||
return cSatipDevice::Initialize(deviceCountM);
|
||||
}
|
||||
|
||||
bool cPluginSatip::Start(void)
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Start any background activities the plugin shall perform.
|
||||
curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
|
||||
cString info = cString::sprintf("Using CURL %s", data->version);
|
||||
@@ -129,63 +144,122 @@ bool cPluginSatip::Start(void)
|
||||
|
||||
void cPluginSatip::Stop(void)
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Stop any background activities the plugin is performing.
|
||||
cSatipDevice::Shutdown();
|
||||
cSatipDiscover::GetInstance()->Destroy();
|
||||
cSatipPoller::GetInstance()->Destroy();
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
void cPluginSatip::Housekeeping(void)
|
||||
{
|
||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
// Perform any cleanup or other regular tasks.
|
||||
}
|
||||
|
||||
void cPluginSatip::MainThreadHook(void)
|
||||
{
|
||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
// Perform actions in the context of the main program thread.
|
||||
// WARNING: Use with great care - see PLUGINS.html!
|
||||
}
|
||||
|
||||
cString cPluginSatip::Active(void)
|
||||
{
|
||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
// Return a message string if shutdown should be postponed
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_t cPluginSatip::WakeupTime(void)
|
||||
{
|
||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
// Return custom wakeup time for shutdown script
|
||||
return 0;
|
||||
}
|
||||
|
||||
cOsdObject *cPluginSatip::MainMenuAction(void)
|
||||
{
|
||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
// Perform the action when selected from the main VDR menu.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cMenuSetupPage *cPluginSatip::SetupMenu(void)
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Return a setup menu in case the plugin supports one.
|
||||
return new cSatipPluginSetup();
|
||||
}
|
||||
|
||||
void cPluginSatip::ParseServer(const char *paramP)
|
||||
{
|
||||
debug1("%s (%s)", __PRETTY_FUNCTION__, paramP);
|
||||
int n = 0;
|
||||
char *s, *p = (char *)paramP;
|
||||
char *r = strtok_r(p, ";", &s);
|
||||
while (r) {
|
||||
r = skipspace(r);
|
||||
debug3("%s server[%d]=%s", __PRETTY_FUNCTION__, n, r);
|
||||
cString serverAddr, serverModel, serverDescription;
|
||||
int n2 = 0;
|
||||
char *s2, *p2 = r;
|
||||
char *r2 = strtok_r(p2, "|", &s2);
|
||||
while (r2) {
|
||||
debug3("%s param[%d]=%s", __PRETTY_FUNCTION__, n2, r2);
|
||||
switch (n2++) {
|
||||
case 0:
|
||||
serverAddr = r2;
|
||||
break;
|
||||
case 1:
|
||||
serverModel = r2;
|
||||
break;
|
||||
case 2:
|
||||
serverDescription = r2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
r2 = strtok_r(NULL, "|", &s2);
|
||||
}
|
||||
if (*serverAddr && *serverModel && *serverDescription) {
|
||||
debug1("%s ipaddr=%s model=%s desc=%s", __PRETTY_FUNCTION__, *serverAddr, *serverModel, *serverDescription);
|
||||
if (!serversM)
|
||||
serversM = new cSatipDiscoverServers();
|
||||
serversM->Add(new cSatipDiscoverServer(*serverAddr, *serverModel, *serverDescription));
|
||||
}
|
||||
++n;
|
||||
r = strtok_r(NULL, ";", &s);
|
||||
}
|
||||
}
|
||||
|
||||
int cPluginSatip::ParseSources(const char *valueP, int *sourcesP)
|
||||
{
|
||||
debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP);
|
||||
int n = 0;
|
||||
char *s, *p = (char *)valueP;
|
||||
char *r = strtok_r(p, " ", &s);
|
||||
while (r) {
|
||||
r = skipspace(r);
|
||||
debug3("%s sources[%d]=%s", __PRETTY_FUNCTION__, n, r);
|
||||
if (n < MAX_DISABLED_SOURCES_COUNT) {
|
||||
sourcesP[n++] = cSource::FromString(r);
|
||||
}
|
||||
r = strtok_r(NULL, " \n", &s);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int cPluginSatip::ParseFilters(const char *valueP, int *filtersP)
|
||||
{
|
||||
debug("cPluginSatip::%s(%s)", __FUNCTION__, valueP);
|
||||
debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP);
|
||||
char buffer[256];
|
||||
int n = 0;
|
||||
while (valueP && *valueP && (n < SECTION_FILTER_TABLE_SIZE)) {
|
||||
strn0cpy(buffer, valueP, sizeof(buffer));
|
||||
int i = atoi(buffer);
|
||||
//debug("cPluginSatip::%s(): filters[%d]=%d", __FUNCTION__, n, i);
|
||||
debug3(":%s filters[%d]=%d", __PRETTY_FUNCTION__, n, i);
|
||||
if (i >= 0)
|
||||
filtersP[n++] = i;
|
||||
if ((valueP = strchr(valueP, ' ')) != NULL)
|
||||
@@ -196,12 +270,20 @@ int cPluginSatip::ParseFilters(const char *valueP, int *filtersP)
|
||||
|
||||
bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Parse your own setup parameters and store their values.
|
||||
if (!strcasecmp(nameP, "OperatingMode"))
|
||||
SatipConfig.SetOperatingMode(atoi(valueP));
|
||||
else if (!strcasecmp(nameP, "EnableEITScan"))
|
||||
SatipConfig.SetEITScan(atoi(valueP));
|
||||
else if (!strcasecmp(nameP, "DisabledSources")) {
|
||||
int DisabledSources[MAX_DISABLED_SOURCES_COUNT];
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(DisabledSources); ++i)
|
||||
DisabledSources[i] = cSource::stNone;
|
||||
unsigned int DisabledSourcesCount = ParseSources(valueP, DisabledSources);
|
||||
for (unsigned int i = 0; i < DisabledSourcesCount; ++i)
|
||||
SatipConfig.SetDisabledSources(i, DisabledSources[i]);
|
||||
}
|
||||
else if (!strcasecmp(nameP, "DisabledFilters")) {
|
||||
int DisabledFilters[SECTION_FILTER_TABLE_SIZE];
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(DisabledFilters); ++i)
|
||||
@@ -217,13 +299,13 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
|
||||
|
||||
bool cPluginSatip::Service(const char *idP, void *dataP)
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char **cPluginSatip::SVDRPHelpPages(void)
|
||||
{
|
||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
static const char *HelpPages[] = {
|
||||
"INFO [ <page> ] [ <card index> ]\n"
|
||||
" Prints SAT>IP device information and statistics.\n"
|
||||
@@ -233,10 +315,16 @@ const char **cPluginSatip::SVDRPHelpPages(void)
|
||||
" Toggles between bit or byte information mode.\n",
|
||||
"LIST\n"
|
||||
" Lists active SAT>IP servers.\n",
|
||||
"SCAN\n"
|
||||
" Scans active SAT>IP servers.\n",
|
||||
"STAT\n"
|
||||
" 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",
|
||||
"TRAC [ <mode> ]\n"
|
||||
" Gets and/or sets used tracing mode.\n",
|
||||
NULL
|
||||
};
|
||||
return HelpPages;
|
||||
@@ -244,7 +332,7 @@ const char **cPluginSatip::SVDRPHelpPages(void)
|
||||
|
||||
cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, int &replyCodeP)
|
||||
{
|
||||
debug("cPluginSatip::%s(%s, %s)", __FUNCTION__, commandP, optionP);
|
||||
debug1("%s (%s, %s,)", __PRETTY_FUNCTION__, commandP, optionP);
|
||||
if (strcasecmp(commandP, "INFO") == 0) {
|
||||
int index = cDevice::ActualDevice()->CardIndex();
|
||||
int page = SATIP_DEVICE_INFO_ALL;
|
||||
@@ -271,13 +359,13 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
|
||||
}
|
||||
else {
|
||||
replyCodeP = 550; // Requested action not taken
|
||||
return cString("SAT>IP information not available!");
|
||||
return cString("SATIP information not available!");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(commandP, "MODE") == 0) {
|
||||
unsigned int mode = !SatipConfig.GetUseBytes();
|
||||
SatipConfig.SetUseBytes(mode);
|
||||
return cString::sprintf("SAT>IP information mode: %s\n", mode ? "bytes" : "bits");
|
||||
return cString::sprintf("SATIP information mode: %s\n", mode ? "bytes" : "bits");
|
||||
}
|
||||
else if (strcasecmp(commandP, "LIST") == 0) {
|
||||
cString list = cSatipDiscover::GetInstance()->GetServerList();
|
||||
@@ -286,11 +374,18 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
|
||||
}
|
||||
else {
|
||||
replyCodeP = 550; // Requested action not taken
|
||||
return cString("No SAT>IP devices detected!");
|
||||
return cString("No SATIP servers detected!");
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(commandP, "SCAN") == 0) {
|
||||
cSatipDiscover::GetInstance()->TriggerScan();
|
||||
return cString("SATIP server scan requested");
|
||||
}
|
||||
else if (strcasecmp(commandP, "STAT") == 0) {
|
||||
return cSatipDevice::GetSatipStatus();
|
||||
}
|
||||
else if (strcasecmp(commandP, "CONT") == 0) {
|
||||
return cString::sprintf("SAT>IP device count: %u", cSatipDevice::Count());
|
||||
return cString::sprintf("SATIP device count: %u", cSatipDevice::Count());
|
||||
}
|
||||
else if (strcasecmp(commandP, "OPER") == 0) {
|
||||
cString mode;
|
||||
@@ -312,7 +407,12 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
|
||||
mode = "unknown";
|
||||
break;
|
||||
}
|
||||
return cString::sprintf("SAT>IP operating mode: %s\n", *mode);
|
||||
return cString::sprintf("SATIP operating mode: %s\n", *mode);
|
||||
}
|
||||
else if (strcasecmp(commandP, "TRAC") == 0) {
|
||||
if (optionP && *optionP)
|
||||
SatipConfig.SetTraceMode(strtol(optionP, NULL, 0));
|
||||
return cString::sprintf("SATIP tracing mode: 0x%04X\n", SatipConfig.GetTraceMode());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "sectionfilter.h"
|
||||
|
||||
cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP)
|
||||
@@ -20,7 +21,7 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
|
||||
ringBufferM(new cRingBufferFrame(eDmxMaxSectionCount * eDmxMaxSectionSize)),
|
||||
deviceIndexM(deviceIndexP)
|
||||
{
|
||||
//debug("cSatipSectionFilter::%s(%d, %d)", __FUNCTION__, deviceIndexM, pidM);
|
||||
debug16("%s (%d, %d, %d, %d) [device %d]", __PRETTY_FUNCTION__, deviceIndexM, pidM, tidP, maskP, deviceIndexM);
|
||||
int i;
|
||||
|
||||
memset(secBufBaseM, 0, sizeof(secBufBaseM));
|
||||
@@ -37,10 +38,10 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
|
||||
for (i = 0; i < eDmxMaxFilterSize; ++i)
|
||||
filterValueM[i] ^= 0xFF;
|
||||
|
||||
uint8_t mask, mode, doneq = 0;
|
||||
uint8_t doneq = 0;
|
||||
for (i = 0; i < eDmxMaxFilterSize; ++i) {
|
||||
mode = filterModeM[i];
|
||||
mask = filterMaskM[i];
|
||||
uint8_t mode = filterModeM[i];
|
||||
uint8_t mask = filterMaskM[i];
|
||||
maskAndModeM[i] = (uint8_t)(mask & mode);
|
||||
maskAndNotModeM[i] = (uint8_t)(mask & ~mode);
|
||||
doneq |= maskAndNotModeM[i];
|
||||
@@ -61,7 +62,7 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
|
||||
|
||||
cSatipSectionFilter::~cSatipSectionFilter()
|
||||
{
|
||||
//debug("cSatipSectionFilter::%s(%d, %d)", __FUNCTION__, deviceIndexM, pidM);
|
||||
debug16("%s pid=%d [device %d]", __PRETTY_FUNCTION__, pidM, deviceIndexM);
|
||||
int tmp = socketM[1];
|
||||
socketM[1] = -1;
|
||||
if (tmp >= 0)
|
||||
@@ -117,7 +118,7 @@ inline int cSatipSectionFilter::Feed(void)
|
||||
|
||||
int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
|
||||
{
|
||||
uint16_t limit, seclen, n;
|
||||
uint16_t limit, n;
|
||||
|
||||
if (tsFeedpM >= eDmxMaxSectionFeedSize)
|
||||
return 0;
|
||||
@@ -139,7 +140,7 @@ int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
|
||||
secBufM = secBufBaseM + secBufpM;
|
||||
|
||||
for (n = 0; secBufpM + 2 < limit; ++n) {
|
||||
seclen = GetLength(secBufM);
|
||||
uint16_t seclen = GetLength(secBufM);
|
||||
if ((seclen <= 0) || (seclen > eDmxMaxSectionSize) || ((seclen + secBufpM) > limit))
|
||||
return 0;
|
||||
secLenM = seclen;
|
||||
@@ -231,12 +232,12 @@ bool cSatipSectionFilter::Send(void)
|
||||
|
||||
|
||||
cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP)
|
||||
: cThread("SAT>IP section handler"),
|
||||
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SAT>IP SECTION HANDLER %d", deviceIndexP))),
|
||||
: cThread(cString::sprintf("SATIP#%d section handler", deviceIndexP)),
|
||||
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SATIP %d section handler", deviceIndexP))),
|
||||
mutexM(),
|
||||
deviceIndexM(deviceIndexP)
|
||||
{
|
||||
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
|
||||
debug1("%s (%d, %d) [device %d]", __PRETTY_FUNCTION__, deviceIndexM, bufferLenP, deviceIndexM);
|
||||
|
||||
// Initialize filter pointers
|
||||
memset(filtersM, 0, sizeof(filtersM));
|
||||
@@ -247,14 +248,14 @@ cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigne
|
||||
ringBufferM->SetIoThrottle();
|
||||
}
|
||||
else
|
||||
error("Failed to allocate buffer for section filter handler (device=%d): ", deviceIndexM);
|
||||
error("Failed to allocate buffer for section filter handler [device=%d]", deviceIndexM);
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
|
||||
{
|
||||
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
// Stop thread
|
||||
if (Running())
|
||||
Cancel(3);
|
||||
@@ -268,7 +269,7 @@ cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
|
||||
|
||||
void cSatipSectionFilterHandler::Action(void)
|
||||
{
|
||||
debug("cSatipSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM);
|
||||
debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
bool processed = false;
|
||||
// Do the thread loop
|
||||
while (Running()) {
|
||||
@@ -299,7 +300,7 @@ void cSatipSectionFilterHandler::Action(void)
|
||||
}
|
||||
}
|
||||
ringBufferM->Del(len);
|
||||
debug("cSatipSectionFilterHandler::%s(%d): Skipped %d bytes to sync on TS packet", __FUNCTION__, deviceIndexM, len);
|
||||
debug1("%s Skipped %d bytes to sync on TS packet [device %d]", __PRETTY_FUNCTION__, len, deviceIndexM);
|
||||
continue;
|
||||
}
|
||||
// Process TS packet through all filters
|
||||
@@ -315,12 +316,12 @@ void cSatipSectionFilterHandler::Action(void)
|
||||
}
|
||||
cCondWait::SleepMs(10); // to avoid busy loop and reduce cpu load
|
||||
}
|
||||
debug("cSatipSectionFilterHandler::%s(%d): exiting", __FUNCTION__, deviceIndexM);
|
||||
debug1("%s Exiting [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
}
|
||||
|
||||
cString cSatipSectionFilterHandler::GetInformation(void)
|
||||
{
|
||||
//debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
// loop through active section filters
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
cString s = "";
|
||||
@@ -339,9 +340,9 @@ cString cSatipSectionFilterHandler::GetInformation(void)
|
||||
|
||||
bool cSatipSectionFilterHandler::Delete(unsigned int indexP)
|
||||
{
|
||||
//debug("cSatipSectionFilterHandler::%s(%d): index=%d", __FUNCTION__, deviceIndexM, indexP);
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);
|
||||
if ((indexP < eMaxSecFilterCount) && filtersM[indexP]) {
|
||||
//debug("cSatipSectionFilterHandler::%s(%d): found %d", __FUNCTION__, deviceIndexM, indexP);
|
||||
debug8("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);
|
||||
cSatipSectionFilter *tmp = filtersM[indexP];
|
||||
filtersM[indexP] = NULL;
|
||||
delete tmp;
|
||||
@@ -352,7 +353,7 @@ bool cSatipSectionFilterHandler::Delete(unsigned int indexP)
|
||||
|
||||
bool cSatipSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const
|
||||
{
|
||||
//debug("cSatipSectionFilterHandler::%s(%d): pid=%d tid=%02X mask=%02X", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
|
||||
debug16("%s (%d, %02X, %02X) [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, deviceIndexM);
|
||||
// loop through section filter table
|
||||
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
||||
int index = SatipConfig.GetDisabledFilters(i);
|
||||
@@ -360,7 +361,7 @@ bool cSatipSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char
|
||||
if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) &&
|
||||
(section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) &&
|
||||
(section_filter_table[index].mask == maskP)) {
|
||||
//debug("cSatipSectionFilterHandler::%s(%d): found %s", __FUNCTION__, deviceIndexM, section_filter_table[index].description);
|
||||
debug8("%s Found %s [device %d]", __PRETTY_FUNCTION__, section_filter_table[index].description, deviceIndexM);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -369,7 +370,6 @@ bool cSatipSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char
|
||||
|
||||
int cSatipSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
|
||||
{
|
||||
// Lock
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
// Blacklist check, refuse certain filters
|
||||
if (IsBlackListed(pidP, tidP, maskP))
|
||||
@@ -378,7 +378,7 @@ int cSatipSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
|
||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||
if (!filtersM[i]) {
|
||||
filtersM[i] = new cSatipSectionFilter(deviceIndexM, pidP, tidP, maskP);
|
||||
//debug("cSatipSectionFilterHandler::%s(%d): pid=%d tid=%02X mask=%02X handle=%d index=%u", __FUNCTION__, deviceIndexM, pidP, tidP, maskP, filtersM[i]->GetFd(), i);
|
||||
debug16("%s (%d, %02X, %02X) handle=%d index=%u [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, filtersM[i]->GetFd(), i, deviceIndexM);
|
||||
return filtersM[i]->GetFd();
|
||||
}
|
||||
}
|
||||
@@ -388,12 +388,11 @@ int cSatipSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
|
||||
|
||||
void cSatipSectionFilterHandler::Close(int handleP)
|
||||
{
|
||||
// Lock
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
// Search the filter for deletion
|
||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||
if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
|
||||
//debug("cSatipSectionFilterHandler::%s(%d): pid=%d handle=%d index=%u", __FUNCTION__, deviceIndexM, filtersM[i]->GetPid(), filtersM[i]->GetFd(), i);
|
||||
debug8("%s (%d) pid=%d index=%u [device %d]", __PRETTY_FUNCTION__, handleP, filtersM[i]->GetPid(), i, deviceIndexM);
|
||||
Delete(i);
|
||||
break;
|
||||
}
|
||||
@@ -402,12 +401,11 @@ void cSatipSectionFilterHandler::Close(int handleP)
|
||||
|
||||
int cSatipSectionFilterHandler::GetPid(int handleP)
|
||||
{
|
||||
// Lock
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
// Search the filter for data
|
||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||
if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
|
||||
//debug("cSatipSectionFilterHandler::%s(%d): pid=%d handle=%d index=%u", __FUNCTION__, deviceIndexM, filtersM[i]->GetPid(), filtersM[i]->GetFd(), i);
|
||||
debug8("%s (%d) pid=%d index=%u [device %d]", __PRETTY_FUNCTION__, handleP, filtersM[i]->GetPid(), i, deviceIndexM);
|
||||
return filtersM[i]->GetPid();
|
||||
}
|
||||
}
|
||||
@@ -416,7 +414,7 @@ int cSatipSectionFilterHandler::GetPid(int handleP)
|
||||
|
||||
void cSatipSectionFilterHandler::Write(uchar *bufferP, int lengthP)
|
||||
{
|
||||
//debug("cSatipSectionFilterHandler::%s(%d): length=%d", __FUNCTION__, deviceIndexM, lengthP);
|
||||
debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIndexM);
|
||||
// Fill up the buffer
|
||||
if (ringBufferM) {
|
||||
int len = ringBufferM->Put(bufferP, lengthP);
|
||||
|
84
server.c
84
server.c
@@ -7,33 +7,45 @@
|
||||
|
||||
#include <vdr/sources.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
|
||||
// --- cSatipServer -----------------------------------------------------------
|
||||
|
||||
cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const char *modelP)
|
||||
cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char *descriptionP)
|
||||
: addressM(addressP),
|
||||
descriptionM(descriptionP),
|
||||
modelM(modelP),
|
||||
descriptionM(descriptionP),
|
||||
modelTypeM(eSatipModelTypeNone),
|
||||
quirkM(eSatipQuirkNone),
|
||||
useCountM(0),
|
||||
transponderM(0),
|
||||
createdM(time(NULL)),
|
||||
lastSeenM(0)
|
||||
{
|
||||
memset(modelCountM, 0, sizeof(modelCountM));
|
||||
if (isempty(*modelM))
|
||||
modelM = "DVBS-1";
|
||||
// These devices contain a session id bug:
|
||||
// Inverto Airscreen Server IDL 400 ?
|
||||
// Telestar Digibit R1 ?
|
||||
// Elgato EyeTV Netstream 4Sat ?
|
||||
if (!isempty(*descriptionM) &&
|
||||
(strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
|
||||
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
|
||||
))
|
||||
quirkM |= eSatipQuirkSessionId;
|
||||
if (!isempty(*descriptionM)) {
|
||||
// These devices contain a session id bug:
|
||||
// Inverto Airscreen Server IDL 400 ?
|
||||
// Elgato EyeTV Netstream 4Sat ?
|
||||
if (strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
|
||||
strstr(*descriptionM, "DIGIBIT") || // Telestar Digibit R1
|
||||
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
|
||||
)
|
||||
quirkM |= eSatipQuirkSessionId;
|
||||
// These devices contain a play (add/delpids) parameter bug:
|
||||
if (strstr(*descriptionM, "fritzdvbc")) // Fritz!WLAN Repeater DVB-C
|
||||
quirkM |= eSatipQuirkPlayPids;
|
||||
// These devices contain a frontend locking bug:
|
||||
if (strstr(*descriptionM, "fritzdvbc")) // Fritz!WLAN Repeater DVB-C
|
||||
quirkM |= eSatipQuirkForceLock;
|
||||
if (quirkM != eSatipQuirkNone)
|
||||
info("Malfunctioning '%s' server detected! Please, fix the firmware.", *descriptionM);
|
||||
}
|
||||
char *s, *p = strdup(*modelM);
|
||||
char *r = strtok_r(p, ",", &s);
|
||||
while (r) {
|
||||
@@ -45,14 +57,11 @@ cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const
|
||||
modelCountM[eSatipModuleDVBS2] = 1;
|
||||
}
|
||||
if (strstr(r, "DVBT2")) {
|
||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBT | cSatipServer::eSatipModelTypeDVBT2;
|
||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBT2;
|
||||
if (char *c = strstr(r, "-"))
|
||||
modelCountM[eSatipModuleDVBT2] = atoi(++c);
|
||||
else
|
||||
modelCountM[eSatipModuleDVBT2] = 1;
|
||||
// Add model quirks here
|
||||
if (!isempty(*descriptionM) && strstr(*descriptionM, "OctopusNet"))
|
||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBC;
|
||||
}
|
||||
if (strstr(r, "DVBT")) {
|
||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBT;
|
||||
@@ -60,9 +69,20 @@ cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const
|
||||
modelCountM[eSatipModuleDVBT] = atoi(++c);
|
||||
else
|
||||
modelCountM[eSatipModuleDVBT] = 1;
|
||||
// Add model quirks here
|
||||
if (!isempty(*descriptionM) && strstr(*descriptionM, "OctopusNet"))
|
||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBC;
|
||||
}
|
||||
if (strstr(r, "DVBC2")) {
|
||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBC2;
|
||||
if (char *c = strstr(r, "-"))
|
||||
modelCountM[eSatipModuleDVBC2] = atoi(++c);
|
||||
else
|
||||
modelCountM[eSatipModuleDVBC2] = 1;
|
||||
}
|
||||
if (strstr(r, "DVBC")) {
|
||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBC;
|
||||
if (char *c = strstr(r, "-"))
|
||||
modelCountM[eSatipModuleDVBC] = atoi(++c);
|
||||
else
|
||||
modelCountM[eSatipModuleDVBC] = 1;
|
||||
}
|
||||
r = strtok_r(NULL, ",", &s);
|
||||
}
|
||||
@@ -98,7 +118,7 @@ cSatipServer *cSatipServers::Find(cSatipServer *serverP)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cSatipServer *cSatipServers::Find(int sourceP, int systemP)
|
||||
cSatipServer *cSatipServers::Find(int sourceP, int transponderP, int systemP)
|
||||
{
|
||||
cSatipServer *result = NULL;
|
||||
int model = 0;
|
||||
@@ -112,6 +132,10 @@ cSatipServer *cSatipServers::Find(int sourceP, int systemP)
|
||||
}
|
||||
else if (cSource::IsType(sourceP, 'C'))
|
||||
model |= cSatipServer::eSatipModelTypeDVBC;
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s->Match(model) && s->Used() && (s->Transponder() == transponderP))
|
||||
return s;
|
||||
}
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s->Match(model)) {
|
||||
result = s;
|
||||
@@ -123,6 +147,16 @@ cSatipServer *cSatipServers::Find(int sourceP, int systemP)
|
||||
return result;
|
||||
}
|
||||
|
||||
void cSatipServers::SetTransponder(cSatipServer *serverP, bool transponderP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
s->SetTransponder(transponderP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cSatipServer *cSatipServers::Update(cSatipServer *serverP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
@@ -148,7 +182,7 @@ void cSatipServers::Cleanup(uint64_t intervalMsP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (!intervalMsP || (s->LastSeen() > intervalMsP)) {
|
||||
info("Removing device %s (%s %s)", s->Description(), s->Address(), s->Model());
|
||||
info("Removing server %s (%s %s)", s->Description(), s->Address(), s->Model());
|
||||
Del(s);
|
||||
}
|
||||
}
|
||||
@@ -178,10 +212,14 @@ int cSatipServers::NumProvidedSystems(void)
|
||||
{
|
||||
int count = 0;
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
// DVB-S*: qpsk, 8psk
|
||||
// DVB-S2: qpsk, 8psk, 16apsk, 32apsk
|
||||
count += s->Satellite() * 4;
|
||||
// DVB-T*: qpsk, qam16, qam64, qam256
|
||||
count += (s->Terrestrial2() ? s->Terrestrial2() : s->Terrestrial()) * 4;
|
||||
// DVB-T2: qpsk, qam16, qam64, qam256
|
||||
// DVB-T: qpsk, qam16, qam64
|
||||
count += s->Terrestrial2() ? s->Terrestrial2() * 4 : s->Terrestrial() * 3;
|
||||
// DVB-C2: qam16, qam32, qam64, qam128, qam256
|
||||
// DVB-C: qam64, qam128, qam256
|
||||
count += s->Cable2() ? s->Cable2() * 5 : s->Cable() * 3;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
24
server.h
24
server.h
@@ -16,15 +16,18 @@ private:
|
||||
eSatipModuleDVBS2 = 0,
|
||||
eSatipModuleDVBT,
|
||||
eSatipModuleDVBT2,
|
||||
eSatipModuleDVBC,
|
||||
eSatipModuleDVBC2,
|
||||
eSatipModuleCount
|
||||
};
|
||||
cString addressM;
|
||||
cString descriptionM;
|
||||
cString modelM;
|
||||
cString descriptionM;
|
||||
int modelCountM[eSatipModuleCount];
|
||||
int modelTypeM;
|
||||
int quirkM;
|
||||
int useCountM;
|
||||
int transponderM;
|
||||
time_t createdM;
|
||||
cTimeMs lastSeenM;
|
||||
|
||||
@@ -32,6 +35,8 @@ public:
|
||||
enum eSatipQuirk {
|
||||
eSatipQuirkNone = 0x00,
|
||||
eSatipQuirkSessionId = 0x01,
|
||||
eSatipQuirkPlayPids = 0x02,
|
||||
eSatipQuirkForceLock = 0x04,
|
||||
eSatipQuirkMask = 0x0F
|
||||
};
|
||||
enum eSatipModelType {
|
||||
@@ -40,20 +45,24 @@ public:
|
||||
eSatipModelTypeDVBT = 0x02,
|
||||
eSatipModelTypeDVBT2 = 0x04,
|
||||
eSatipModelTypeDVBC = 0x08,
|
||||
eSatipModelTypeMask = 0x0F
|
||||
eSatipModelTypeDVBC2 = 0x10,
|
||||
eSatipModelTypeMask = 0xFF
|
||||
};
|
||||
cSatipServer(const char *addressP, const char *descriptionP, const char *modelP);
|
||||
cSatipServer(const char *addressP, const char *modelP, const char *descriptionP);
|
||||
virtual ~cSatipServer();
|
||||
virtual int Compare(const cListObject &listObjectP) const;
|
||||
void Use(bool onOffP);
|
||||
void SetTransponder(const int transponderP) { transponderM = transponderP; }
|
||||
int Transponder(void) { return transponderM; }
|
||||
bool Used(void) { return !!useCountM; }
|
||||
const char *Description() { return *descriptionM; }
|
||||
const char *Address() { return *addressM; }
|
||||
const char *Model(void) { return modelM; }
|
||||
const char *Model(void) { return *modelM; }
|
||||
const char *Description() { return *descriptionM; }
|
||||
bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); }
|
||||
int ModelType(void) { return modelTypeM; }
|
||||
bool Match(int modelP) { return ((modelP & eSatipModelTypeMask) & modelTypeM); }
|
||||
int Cable() { return Match(eSatipModelTypeDVBC) ? (Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : modelCountM[eSatipModuleDVBT]) : 0; } // an ugly hack
|
||||
int Cable() { return Match(eSatipModelTypeDVBC) ? modelCountM[eSatipModuleDVBC] : 0; }
|
||||
int Cable2() { return Match(eSatipModelTypeDVBC2) ? modelCountM[eSatipModuleDVBC2] : 0; }
|
||||
int Satellite() { return Match(eSatipModelTypeDVBS2) ? modelCountM[eSatipModuleDVBS2] : 0; }
|
||||
int Terrestrial() { return Match(eSatipModelTypeDVBT) ? modelCountM[eSatipModuleDVBT] : 0; }
|
||||
int Terrestrial2() { return Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : 0; }
|
||||
@@ -67,7 +76,8 @@ public:
|
||||
class cSatipServers : public cList<cSatipServer> {
|
||||
public:
|
||||
cSatipServer *Find(cSatipServer *serverP);
|
||||
cSatipServer *Find(int sourceP, int systemP);
|
||||
cSatipServer *Find(int sourceP, int transponderP, int systemP);
|
||||
void SetTransponder(cSatipServer *serverP, bool transponderP);
|
||||
cSatipServer *Update(cSatipServer *serverP);
|
||||
void Use(cSatipServer *serverP, bool onOffP);
|
||||
void Cleanup(uint64_t intervalMsP = 0);
|
||||
|
224
setup.c
224
setup.c
@@ -12,8 +12,75 @@
|
||||
#include "config.h"
|
||||
#include "device.h"
|
||||
#include "discover.h"
|
||||
#include "log.h"
|
||||
#include "setup.h"
|
||||
|
||||
// --- cSatipEditSrcItem ------------------------------------------------------
|
||||
// This class is a 99% copy of cMenuEditSrcItem() taken from VDR's menu.c
|
||||
|
||||
class cSatipEditSrcItem : public cMenuEditIntItem {
|
||||
private:
|
||||
const cSource *source;
|
||||
protected:
|
||||
virtual void Set(void);
|
||||
public:
|
||||
cSatipEditSrcItem(const char *Name, int *Value);
|
||||
eOSState ProcessKey(eKeys Key);
|
||||
};
|
||||
|
||||
cSatipEditSrcItem::cSatipEditSrcItem(const char *Name, int *Value)
|
||||
:cMenuEditIntItem(Name, Value, 0)
|
||||
{
|
||||
source = Sources.Get(*Value);
|
||||
if (!source)
|
||||
source = Sources.First();
|
||||
Set();
|
||||
}
|
||||
|
||||
void cSatipEditSrcItem::Set(void)
|
||||
{
|
||||
if (source)
|
||||
SetValue(cString::sprintf("%s - %s", *cSource::ToString(source->Code()), source->Description()));
|
||||
else
|
||||
cMenuEditIntItem::Set();
|
||||
}
|
||||
|
||||
eOSState cSatipEditSrcItem::ProcessKey(eKeys Key)
|
||||
{
|
||||
eOSState state = cMenuEditItem::ProcessKey(Key);
|
||||
|
||||
if (state == osUnknown) {
|
||||
bool IsRepeat = Key & k_Repeat;
|
||||
Key = NORMALKEY(Key);
|
||||
if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly?
|
||||
if (source) {
|
||||
if (source->Prev())
|
||||
source = (cSource *)source->Prev();
|
||||
else if (!IsRepeat)
|
||||
source = Sources.Last();
|
||||
*value = source->Code();
|
||||
}
|
||||
}
|
||||
else if (Key == kRight) {
|
||||
if (source) {
|
||||
if (source->Next())
|
||||
source = (cSource *)source->Next();
|
||||
else if (!IsRepeat)
|
||||
source = Sources.First();
|
||||
}
|
||||
else
|
||||
source = Sources.First();
|
||||
if (source)
|
||||
*value = source->Code();
|
||||
}
|
||||
else
|
||||
return state; // we don't call cMenuEditIntItem::ProcessKey(Key) here since we don't accept numerical input
|
||||
Set();
|
||||
state = osContinue;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cSatipServerInfo -------------------------------------------------------
|
||||
|
||||
class cSatipServerInfo : public cOsdMenu
|
||||
@@ -32,7 +99,7 @@ public:
|
||||
};
|
||||
|
||||
cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP)
|
||||
: cOsdMenu(tr("SAT>IP Device"), 20),
|
||||
: cOsdMenu(tr("SAT>IP Server"), 20),
|
||||
addressM(serverP ? serverP->Address() : "---"),
|
||||
modelM(serverP ? serverP->Model() : "---"),
|
||||
descriptionM(serverP ? serverP->Description() : "---"),
|
||||
@@ -94,6 +161,71 @@ void cSatipServerItem::SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, b
|
||||
displayMenuP->SetItem(Text(), indexP, currentP, selectableP);
|
||||
}
|
||||
|
||||
// --- cSatipMenuDeviceStatus -------------------------------------------------
|
||||
|
||||
class cSatipMenuDeviceStatus : public cOsdMenu
|
||||
{
|
||||
private:
|
||||
enum {
|
||||
eInfoTimeoutMs = 15000
|
||||
};
|
||||
cString textM;
|
||||
cTimeMs timeoutM;
|
||||
void UpdateInfo();
|
||||
|
||||
public:
|
||||
cSatipMenuDeviceStatus();
|
||||
virtual ~cSatipMenuDeviceStatus();
|
||||
virtual void Display(void);
|
||||
virtual eOSState ProcessKey(eKeys keyP);
|
||||
};
|
||||
|
||||
cSatipMenuDeviceStatus::cSatipMenuDeviceStatus()
|
||||
: cOsdMenu(tr("SAT>IP Device Status")),
|
||||
textM(""),
|
||||
timeoutM()
|
||||
{
|
||||
SetMenuCategory(mcText);
|
||||
timeoutM.Set(eInfoTimeoutMs);
|
||||
UpdateInfo();
|
||||
SetHelp(NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
cSatipMenuDeviceStatus::~cSatipMenuDeviceStatus()
|
||||
{
|
||||
}
|
||||
|
||||
void cSatipMenuDeviceStatus::UpdateInfo()
|
||||
{
|
||||
textM = cSatipDevice::GetSatipStatus();
|
||||
Display();
|
||||
timeoutM.Set(eInfoTimeoutMs);
|
||||
}
|
||||
|
||||
void cSatipMenuDeviceStatus::Display(void)
|
||||
{
|
||||
cOsdMenu::Display();
|
||||
DisplayMenu()->SetText(textM, true);
|
||||
if (*textM)
|
||||
cStatus::MsgOsdTextItem(textM);
|
||||
}
|
||||
|
||||
eOSState cSatipMenuDeviceStatus::ProcessKey(eKeys keyP)
|
||||
{
|
||||
eOSState state = cOsdMenu::ProcessKey(keyP);
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (keyP) {
|
||||
case kOk: state = osBack; break;
|
||||
default: if (timeoutM.TimedOut())
|
||||
UpdateInfo();
|
||||
state = osContinue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// --- cSatipMenuInfo ---------------------------------------------------------
|
||||
|
||||
class cSatipMenuInfo : public cOsdMenu
|
||||
@@ -198,13 +330,18 @@ cSatipPluginSetup::cSatipPluginSetup()
|
||||
: deviceCountM(0),
|
||||
operatingModeM(SatipConfig.GetOperatingMode()),
|
||||
eitScanM(SatipConfig.GetEITScan()),
|
||||
numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()),
|
||||
numDisabledFiltersM(SatipConfig.GetDisabledFiltersCount())
|
||||
{
|
||||
debug("cSatipPluginSetup::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
operatingModeTextsM[cSatipConfig::eOperatingModeOff] = tr("off");
|
||||
operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low");
|
||||
operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal");
|
||||
operatingModeTextsM[cSatipConfig::eOperatingModeHigh] = tr("high");
|
||||
if (numDisabledSourcesM > MAX_DISABLED_SOURCES_COUNT)
|
||||
numDisabledSourcesM = MAX_DISABLED_SOURCES_COUNT;
|
||||
for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i)
|
||||
disabledSourcesM[i] = SatipConfig.GetDisabledSources(i);
|
||||
if (numDisabledFiltersM > SECTION_FILTER_TABLE_SIZE)
|
||||
numDisabledFiltersM = SECTION_FILTER_TABLE_SIZE;
|
||||
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
||||
@@ -213,7 +350,7 @@ cSatipPluginSetup::cSatipPluginSetup()
|
||||
}
|
||||
SetMenuCategory(mcSetupPlugins);
|
||||
Setup();
|
||||
SetHelp(trVDR("Button$Scan"), NULL, NULL, trVDR("Button$Info"));
|
||||
SetHelp(trVDR("Button$Scan"), NULL, tr("Button$Devices"), trVDR("Button$Info"));
|
||||
}
|
||||
|
||||
void cSatipPluginSetup::Setup(void)
|
||||
@@ -230,15 +367,23 @@ void cSatipPluginSetup::Setup(void)
|
||||
Add(new cMenuEditBoolItem(tr("Enable EPG scanning"), &eitScanM));
|
||||
helpM.Append(tr("Define whether the EPG background scanning shall be used.\n\nThis setting disables the automatic EIT scanning functionality for all SAT>IP devices."));
|
||||
|
||||
Add(new cMenuEditIntItem(tr("Disabled sources"), &numDisabledSourcesM, 0, MAX_DISABLED_SOURCES_COUNT, tr("none")));
|
||||
helpM.Append(tr("Define number of sources to be disabled.\n\nSAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."));
|
||||
|
||||
for (int i = 0; i < numDisabledSourcesM; ++i) {
|
||||
Add(new cSatipEditSrcItem(*cString::sprintf(" %s %d", trVDR("Source"), i + 1), &disabledSourcesM[i]));
|
||||
helpM.Append(tr("Define a source to be blacklisted."));
|
||||
}
|
||||
|
||||
Add(new cMenuEditIntItem(tr("Disabled filters"), &numDisabledFiltersM, 0, SECTION_FILTER_TABLE_SIZE, tr("none")));
|
||||
helpM.Append(tr("Define number of section filters to be disabled.\n\nCertain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."));
|
||||
helpM.Append(tr("Define number of section filters to be disabled.\n\nCertain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."));
|
||||
|
||||
for (int i = 0; i < numDisabledFiltersM; ++i) {
|
||||
Add(new cMenuEditStraItem(*cString::sprintf(" %s %d", tr("Filter"), i + 1), &disabledFilterIndexesM[i], SECTION_FILTER_TABLE_SIZE, disabledFilterNamesM));
|
||||
helpM.Append(tr("Define an ill-behaving filter to be blacklisted."));
|
||||
}
|
||||
}
|
||||
Add(new cOsdItem(tr("Active SAT>IP devices:"), osUnknown, false));
|
||||
Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false));
|
||||
helpM.Append("");
|
||||
|
||||
cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers();
|
||||
@@ -254,7 +399,7 @@ void cSatipPluginSetup::Setup(void)
|
||||
|
||||
eOSState cSatipPluginSetup::DeviceScan(void)
|
||||
{
|
||||
debug("cSatipPluginSetup::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
cSatipDiscover::GetInstance()->TriggerScan();
|
||||
|
||||
return osContinue;
|
||||
@@ -262,7 +407,7 @@ eOSState cSatipPluginSetup::DeviceScan(void)
|
||||
|
||||
eOSState cSatipPluginSetup::DeviceInfo(void)
|
||||
{
|
||||
debug("cSatipPluginSetup::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (HasSubMenu() || Count() == 0)
|
||||
return osContinue;
|
||||
|
||||
@@ -273,9 +418,18 @@ eOSState cSatipPluginSetup::DeviceInfo(void)
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
eOSState cSatipPluginSetup::ShowDeviceStatus(void)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (HasSubMenu() || Count() == 0)
|
||||
return osContinue;
|
||||
|
||||
return AddSubMenu(new cSatipMenuDeviceStatus());
|
||||
}
|
||||
|
||||
eOSState cSatipPluginSetup::ShowInfo(void)
|
||||
{
|
||||
debug("cSatipPluginSetup::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (HasSubMenu() || Count() == 0)
|
||||
return osContinue;
|
||||
|
||||
@@ -286,6 +440,7 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
|
||||
{
|
||||
bool hadSubMenu = HasSubMenu();
|
||||
int oldOperatingMode = operatingModeM;
|
||||
int oldNumDisabledSources = numDisabledSourcesM;
|
||||
int oldNumDisabledFilters = numDisabledFiltersM;
|
||||
eOSState state = cMenuSetupPage::ProcessKey(keyP);
|
||||
|
||||
@@ -296,18 +451,21 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (keyP) {
|
||||
case kRed: return DeviceScan();
|
||||
case kBlue: return ShowInfo();
|
||||
case kInfo: if (Current() < helpM.Size())
|
||||
return AddSubMenu(new cMenuText(cString::sprintf("%s - %s '%s'", tr("Help"), trVDR("Plugin"), PLUGIN_NAME_I18N), helpM[Current()]));
|
||||
default: state = osContinue; break;
|
||||
case kRed: return DeviceScan();
|
||||
case kYellow: return ShowDeviceStatus();
|
||||
case kBlue: return ShowInfo();
|
||||
case kInfo: if (Current() < helpM.Size())
|
||||
return AddSubMenu(new cMenuText(cString::sprintf("%s - %s '%s'", tr("Help"), trVDR("Plugin"), PLUGIN_NAME_I18N), helpM[Current()]));
|
||||
default: state = osContinue; break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((keyP == kNone) && (cSatipDiscover::GetInstance()->GetServers()->Count() != deviceCountM))
|
||||
Setup();
|
||||
|
||||
if ((keyP != kNone) && ((numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode))) {
|
||||
if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode))) {
|
||||
while ((numDisabledSourcesM < oldNumDisabledSources) && (oldNumDisabledSources > 0))
|
||||
disabledSourcesM[--oldNumDisabledSources] = cSource::stNone;
|
||||
while ((numDisabledFiltersM < oldNumDisabledFilters) && (oldNumDisabledFilters > 0))
|
||||
disabledFilterIndexesM[--oldNumDisabledFilters] = -1;
|
||||
Setup();
|
||||
@@ -316,23 +474,36 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
|
||||
return state;
|
||||
}
|
||||
|
||||
void cSatipPluginSetup::StoreSources(const char *nameP, int *sourcesP)
|
||||
{
|
||||
cString buffer = "";
|
||||
int n = 0;
|
||||
for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i) {
|
||||
if (sourcesP[i] == cSource::stNone)
|
||||
break;
|
||||
if (n++ > 0)
|
||||
buffer = cString::sprintf("%s %s", *buffer, *cSource::ToString(sourcesP[i]));
|
||||
else
|
||||
buffer = cString::sprintf("%s", *cSource::ToString(sourcesP[i]));
|
||||
}
|
||||
debug1("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer);
|
||||
SetupStore(nameP, *buffer);
|
||||
}
|
||||
|
||||
void cSatipPluginSetup::StoreFilters(const char *nameP, int *valuesP)
|
||||
{
|
||||
char buffer[SECTION_FILTER_TABLE_SIZE * 4];
|
||||
char *q = buffer;
|
||||
cString buffer = "";
|
||||
int n = 0;
|
||||
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
||||
char s[3];
|
||||
if (valuesP[i] < 0)
|
||||
break;
|
||||
if (q > buffer)
|
||||
*q++ = ' ';
|
||||
snprintf(s, sizeof(s), "%d", valuesP[i]);
|
||||
strncpy(q, s, strlen(s));
|
||||
q += strlen(s);
|
||||
if (n++ > 0)
|
||||
buffer = cString::sprintf("%s %d", *buffer, valuesP[i]);
|
||||
else
|
||||
buffer = cString::sprintf("%d", valuesP[i]);
|
||||
}
|
||||
*q = 0;
|
||||
debug("cSatipPluginSetup::%s(%s, %s)", __FUNCTION__, nameP, buffer);
|
||||
SetupStore(nameP, buffer);
|
||||
debug1("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer);
|
||||
SetupStore(nameP, *buffer);
|
||||
}
|
||||
|
||||
void cSatipPluginSetup::Store(void)
|
||||
@@ -340,10 +511,13 @@ void cSatipPluginSetup::Store(void)
|
||||
// Store values into setup.conf
|
||||
SetupStore("OperatingMode", operatingModeM);
|
||||
SetupStore("EnableEITScan", eitScanM);
|
||||
StoreSources("DisabledSources", disabledSourcesM);
|
||||
StoreFilters("DisabledFilters", disabledFilterIndexesM);
|
||||
// Update global config
|
||||
SatipConfig.SetOperatingMode(operatingModeM);
|
||||
SatipConfig.SetEITScan(eitScanM);
|
||||
for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i)
|
||||
SatipConfig.SetDisabledSources(i, disabledSourcesM[i]);
|
||||
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i)
|
||||
SatipConfig.SetDisabledFilters(i, disabledFilterIndexesM[i]);
|
||||
}
|
||||
|
4
setup.h
4
setup.h
@@ -19,6 +19,8 @@ private:
|
||||
int operatingModeM;
|
||||
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];
|
||||
int eitScanM;
|
||||
int numDisabledSourcesM;
|
||||
int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT];
|
||||
int numDisabledFiltersM;
|
||||
int disabledFilterIndexesM[SECTION_FILTER_TABLE_SIZE];
|
||||
const char *disabledFilterNamesM[SECTION_FILTER_TABLE_SIZE];
|
||||
@@ -26,8 +28,10 @@ private:
|
||||
|
||||
eOSState DeviceScan(void);
|
||||
eOSState DeviceInfo(void);
|
||||
eOSState ShowDeviceStatus(void);
|
||||
eOSState ShowInfo(void);
|
||||
void Setup(void);
|
||||
void StoreSources(const char *nameP, int *sourcesP);
|
||||
void StoreFilters(const char *nameP, int *valuesP);
|
||||
|
||||
protected:
|
||||
|
152
socket.c
152
socket.c
@@ -16,29 +16,26 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "socket.h"
|
||||
|
||||
cSatipSocket::cSatipSocket()
|
||||
: socketPortM(0),
|
||||
socketDescM(-1),
|
||||
lastErrorReportM(0),
|
||||
packetErrorsM(0),
|
||||
sequenceNumberM(-1)
|
||||
socketDescM(-1)
|
||||
{
|
||||
debug("cSatipSocket::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
||||
}
|
||||
|
||||
cSatipSocket::~cSatipSocket()
|
||||
{
|
||||
debug("cSatipSocket::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Close the socket
|
||||
Close();
|
||||
}
|
||||
|
||||
bool cSatipSocket::Open(const int portP)
|
||||
{
|
||||
debug("cSatipSocket::%s(%d)", __FUNCTION__, portP);
|
||||
// Bind to the socket if it is not active already
|
||||
if (socketDescM < 0) {
|
||||
socklen_t len = sizeof(sockAddrM);
|
||||
@@ -64,30 +61,25 @@ bool cSatipSocket::Open(const int portP)
|
||||
"getsockname()", Close(), return false);
|
||||
socketPortM = ntohs(sockAddrM.sin_port);
|
||||
}
|
||||
debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cSatipSocket::Close(void)
|
||||
{
|
||||
debug("cSatipSocket::%s()", __FUNCTION__);
|
||||
debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM);
|
||||
// Check if socket exists
|
||||
if (socketDescM >= 0) {
|
||||
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)
|
||||
{
|
||||
debug("cSatipSocket::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
if (socketDescM < 0) {
|
||||
const unsigned int len = 65535;
|
||||
unsigned char *buf = MALLOC(unsigned char, len);
|
||||
@@ -106,10 +98,10 @@ bool cSatipSocket::Flush(void)
|
||||
|
||||
int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||
{
|
||||
//debug("cSatipSocket::%s()", __FUNCTION__);
|
||||
debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP);
|
||||
// Error out if socket not initialized
|
||||
if (socketDescM <= 0) {
|
||||
error("Invalid socket in cSatipUdpSocket::%s()", __FUNCTION__);
|
||||
error("%s Invalid socket", __PRETTY_FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
int len = 0;
|
||||
@@ -128,7 +120,7 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||
msgh.msg_controllen = sizeof(cbuf);
|
||||
msgh.msg_name = &sockAddrM;
|
||||
msgh.msg_namelen = addrlen;
|
||||
msgh.msg_iov = &iov;
|
||||
msgh.msg_iov = &iov;
|
||||
msgh.msg_iovlen = 1;
|
||||
msgh.msg_flags = 0;
|
||||
|
||||
@@ -141,110 +133,44 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cSatipSocket::ReadVideo(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||
int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP)
|
||||
{
|
||||
//debug("cSatipSocket::%s()", __FUNCTION__);
|
||||
int len = Read(bufferAddrP, bufferLenP);
|
||||
if (len > 0) {
|
||||
if (bufferAddrP[0] == TS_SYNC_BYTE)
|
||||
return len;
|
||||
else if (len > 3) {
|
||||
// http://tools.ietf.org/html/rfc3550
|
||||
// http://tools.ietf.org/html/rfc2250
|
||||
// Version
|
||||
unsigned int v = (bufferAddrP[0] >> 6) & 0x03;
|
||||
// Extension bit
|
||||
unsigned int x = (bufferAddrP[0] >> 4) & 0x01;
|
||||
// CSCR count
|
||||
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
|
||||
if (x) {
|
||||
// Extension header length
|
||||
unsigned int ehl = (((bufferAddrP[headerlen + 2] & 0xFF) << 8) |
|
||||
(bufferAddrP[headerlen + 3] & 0xFF));
|
||||
// Update header length
|
||||
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
||||
}
|
||||
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
||||
if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) &&
|
||||
(bufferAddrP[headerlen] == TS_SYNC_BYTE)) {
|
||||
// Set argument point to payload in read buffer
|
||||
memmove(bufferAddrP, &bufferAddrP[headerlen], (len - headerlen));
|
||||
return (len - headerlen);
|
||||
}
|
||||
}
|
||||
debug16("%s (, , %d, %d)", __PRETTY_FUNCTION__, elementCountP, elementBufferSizeP);
|
||||
// Error out if socket not initialized
|
||||
if (socketDescM <= 0) {
|
||||
error("%s Invalid socket", __PRETTY_FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
// Initialize iov and msgh structures
|
||||
struct mmsghdr mmsgh[elementCountP];
|
||||
struct iovec iov[elementCountP];
|
||||
memset(mmsgh, 0, sizeof(mmsgh[0]) * elementCountP);
|
||||
for (unsigned int i = 0; i < elementCountP; ++i) {
|
||||
iov[i].iov_base = bufferAddrP + i * elementBufferSizeP;
|
||||
iov[i].iov_len = elementBufferSizeP;
|
||||
mmsgh[i].msg_hdr.msg_iov = &iov[i];
|
||||
mmsgh[i].msg_hdr.msg_iovlen = 1;
|
||||
}
|
||||
|
||||
// Read data from socket as a set
|
||||
int count = -1;
|
||||
if (socketDescM && bufferAddrP && elementRecvSizeP && (elementCountP > 0) && (elementBufferSizeP > 0))
|
||||
count = (int)recvmmsg(socketDescM, mmsgh, elementCountP, MSG_DONTWAIT, NULL);
|
||||
ERROR_IF_RET(count < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmmsg()", return -1);
|
||||
for (int i = 0; i < count; ++i)
|
||||
elementRecvSizeP[i] = mmsgh[i].msg_len;
|
||||
debug16("%s Received %d packets size[0]=%d", __PRETTY_FUNCTION__, count, elementRecvSizeP[0]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int cSatipSocket::ReadApplication(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||
{
|
||||
//debug("cSatipSocket::%s()", __FUNCTION__);
|
||||
int len = Read(bufferAddrP, bufferLenP);
|
||||
int offset = 0;
|
||||
while (len > 0) {
|
||||
// Version
|
||||
unsigned int v = (bufferAddrP[offset] >> 6) & 0x03;
|
||||
// Padding
|
||||
//unsigned int p = (bufferAddrP[offset] >> 5) & 0x01;
|
||||
// Subtype
|
||||
//unsigned int st = bufferAddrP[offset] & 0x1F;
|
||||
// Payload type
|
||||
unsigned int pt = bufferAddrP[offset + 1] & 0xFF;
|
||||
// Lenght
|
||||
unsigned int length = ((bufferAddrP[offset + 2] & 0xFF) << 8) | (bufferAddrP[offset + 3] & 0xFF);
|
||||
// Convert it to bytes
|
||||
length = (length + 1) * 4;
|
||||
// V=2, APP = 204
|
||||
if ((v == 2) && (pt == 204)) {
|
||||
// SSCR/CSCR
|
||||
//unsigned int ssrc = ((bufferAddrP[offset + 4] & 0xFF) << 24) | ((bufferAddrP[offset + 5] & 0xFF) << 16) |
|
||||
// ((bufferAddrP[offset + 6] & 0xFF) << 8) | (bufferAddrP[offset + 7] & 0xFF);
|
||||
// Name
|
||||
if ((bufferAddrP[offset + 8] == 'S') && (bufferAddrP[offset + 9] == 'E') &&
|
||||
(bufferAddrP[offset + 10] == 'S') && (bufferAddrP[offset + 11] == '1')) {
|
||||
// Identifier
|
||||
//unsigned int id = ((bufferAddrP[offset + 12] & 0xFF) << 8) | (bufferAddrP[offset + 13] & 0xFF);
|
||||
// String length
|
||||
int string_length = ((bufferAddrP[offset + 14] & 0xFF) << 8) | (bufferAddrP[offset + 15] & 0xFF);
|
||||
if (string_length > 0) {
|
||||
// Set argument point to payload in read buffer
|
||||
memmove(bufferAddrP, &bufferAddrP[offset + 16], string_length);
|
||||
return string_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += length;
|
||||
len -= length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool cSatipSocket::Write(const char *addrP, const unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||
{
|
||||
debug("cSatipSocket::%s(%s)", __FUNCTION__, addrP);
|
||||
debug1("%s (%s, , %d)", __PRETTY_FUNCTION__, addrP, bufferLenP);
|
||||
// Error out if socket not initialized
|
||||
if (socketDescM <= 0) {
|
||||
error("cSatipSocket::%s(): Invalid socket", __FUNCTION__);
|
||||
error("%s Invalid socket", __PRETTY_FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
struct sockaddr_in sockAddr;
|
||||
|
14
socket.h
14
socket.h
@@ -12,27 +12,21 @@
|
||||
|
||||
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();
|
||||
~cSatipSocket();
|
||||
virtual ~cSatipSocket();
|
||||
bool Open(const int portP = 0);
|
||||
void Close(void);
|
||||
virtual void Close(void);
|
||||
int Fd(void) { return socketDescM; }
|
||||
int Port(void) { return socketPortM; }
|
||||
bool IsOpen(void) { return (socketDescM >= 0); }
|
||||
bool Flush(void);
|
||||
int Read(unsigned char *bufferAddrP, unsigned int bufferLenP);
|
||||
int ReadVideo(unsigned char *bufferAddrP, unsigned int bufferLenP);
|
||||
int ReadApplication(unsigned char *bufferAddrP, unsigned int bufferLenP);
|
||||
int ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP);
|
||||
bool Write(const char *addrP, const unsigned char *bufferAddrP, unsigned int bufferLenP);
|
||||
};
|
||||
|
||||
|
41
statistics.c
41
statistics.c
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "statistics.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
|
||||
// Section statistics class
|
||||
@@ -18,17 +19,17 @@ cSatipSectionStatistics::cSatipSectionStatistics()
|
||||
timerM(),
|
||||
mutexM()
|
||||
{
|
||||
//debug("cSatipSectionStatistics::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cSatipSectionStatistics::~cSatipSectionStatistics()
|
||||
{
|
||||
//debug("cSatipSectionStatistics::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cString cSatipSectionStatistics::GetSectionStatistic()
|
||||
{
|
||||
//debug("cSatipSectionStatistics::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
||||
timerM.Set();
|
||||
@@ -44,7 +45,7 @@ cString cSatipSectionStatistics::GetSectionStatistic()
|
||||
|
||||
void cSatipSectionStatistics::AddSectionStatistic(long bytesP, long callsP)
|
||||
{
|
||||
//debug("cSatipSectionStatistics::%s(%ld, %ld)", __FUNCTION__, bytesP, callsP);
|
||||
debug16("%s (%ld, %ld)", __PRETTY_FUNCTION__, bytesP, callsP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
filteredDataM += bytesP;
|
||||
numberOfCallsM += callsP;
|
||||
@@ -57,7 +58,7 @@ cSatipPidStatistics::cSatipPidStatistics()
|
||||
: timerM(),
|
||||
mutexM()
|
||||
{
|
||||
debug("cSatipPidStatistics::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
||||
for (int i = 0; i < numberOfElements; ++i) {
|
||||
mostActivePidsM[i].pid = -1;
|
||||
@@ -67,12 +68,12 @@ cSatipPidStatistics::cSatipPidStatistics()
|
||||
|
||||
cSatipPidStatistics::~cSatipPidStatistics()
|
||||
{
|
||||
debug("cSatipPidStatistics::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cString cSatipPidStatistics::GetPidStatistic()
|
||||
{
|
||||
//debug("cSatipPidStatistics::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
||||
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
||||
@@ -97,7 +98,7 @@ cString cSatipPidStatistics::GetPidStatistic()
|
||||
|
||||
int cSatipPidStatistics::SortPids(const void* data1P, const void* data2P)
|
||||
{
|
||||
//debug("cSatipPidStatistics::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
const pidStruct *comp1 = reinterpret_cast<const pidStruct*>(data1P);
|
||||
const pidStruct *comp2 = reinterpret_cast<const pidStruct*>(data2P);
|
||||
if (comp1->dataAmount > comp2->dataAmount)
|
||||
@@ -109,7 +110,7 @@ int cSatipPidStatistics::SortPids(const void* data1P, const void* data2P)
|
||||
|
||||
void cSatipPidStatistics::AddPidStatistic(int pidP, long payloadP)
|
||||
{
|
||||
//debug("cSatipPidStatistics::%s(%ld, %ld)", __FUNCTION__, pidP, payloadP);
|
||||
debug16("%s (%d, %ld)", __PRETTY_FUNCTION__, pidP, payloadP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
||||
// If our statistic already is in the array, update it and quit
|
||||
@@ -139,31 +140,33 @@ cSatipTunerStatistics::cSatipTunerStatistics()
|
||||
timerM(),
|
||||
mutexM()
|
||||
{
|
||||
debug("cSatipTunerStatistics::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cSatipTunerStatistics::~cSatipTunerStatistics()
|
||||
{
|
||||
debug("cSatipTunerStatistics::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cString cSatipTunerStatistics::GetTunerStatistic()
|
||||
{
|
||||
//debug("cSatipTunerStatistics::%s()", __FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
mutexM.Lock();
|
||||
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
||||
timerM.Set();
|
||||
long bitrate = elapsed ? (long)(1000.0L * dataBytesM / KILOBYTE(1) / elapsed) : 0L;
|
||||
dataBytesM = 0;
|
||||
mutexM.Unlock();
|
||||
|
||||
if (!SatipConfig.GetUseBytes())
|
||||
bitrate *= 8;
|
||||
cString s = cString::sprintf("%ld k%s/s", bitrate, SatipConfig.GetUseBytes() ? "B" : "bit");
|
||||
dataBytesM = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
void cSatipTunerStatistics::AddTunerStatistic(long bytesP)
|
||||
{
|
||||
//debug("cSatipTunerStatistics::%s(%ld)", __FUNCTION__, bytesP);
|
||||
debug16("%s (%ld)", __PRETTY_FUNCTION__, bytesP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
dataBytesM += bytesP;
|
||||
}
|
||||
@@ -177,17 +180,17 @@ cSatipBufferStatistics::cSatipBufferStatistics()
|
||||
timerM(),
|
||||
mutexM()
|
||||
{
|
||||
debug("cSatipBufferStatistics::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cSatipBufferStatistics::~cSatipBufferStatistics()
|
||||
{
|
||||
debug("cSatipBufferStatistics::%s()", __FUNCTION__);
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cString cSatipBufferStatistics::GetBufferStatistic()
|
||||
{
|
||||
//debug("cSatipBufferStatistics::%s()", __FUNCTION__);
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
||||
timerM.Set();
|
||||
@@ -211,7 +214,7 @@ cString cSatipBufferStatistics::GetBufferStatistic()
|
||||
|
||||
void cSatipBufferStatistics::AddBufferStatistic(long bytesP, long usedP)
|
||||
{
|
||||
//debug("cSatipBufferStatistics::%s(%ld, %ld)", __FUNCTION__, bytesP, usedP);
|
||||
debug16("%s (%ld, %ld)", __PRETTY_FUNCTION__, bytesP, usedP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
dataBytesM += bytesP;
|
||||
if (usedP > usedSpaceM)
|
||||
|
694
tuner.c
694
tuner.c
@@ -5,31 +5,38 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "discover.h"
|
||||
#include "log.h"
|
||||
#include "poller.h"
|
||||
#include "tuner.h"
|
||||
|
||||
cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
|
||||
: cThread("SAT>IP tuner"),
|
||||
: cThread(cString::sprintf("SATIP#%d tuner", deviceP.GetId())),
|
||||
sleepM(),
|
||||
deviceM(&deviceP),
|
||||
packetBufferLenM(packetLenP),
|
||||
rtpSocketM(new cSatipSocket()),
|
||||
rtcpSocketM(new cSatipSocket()),
|
||||
deviceIdM(deviceP.GetId()),
|
||||
rtspM(*this),
|
||||
rtpM(*this),
|
||||
rtcpM(*this),
|
||||
streamAddrM(""),
|
||||
streamParamM(""),
|
||||
currentServerM(NULL),
|
||||
nextServerM(NULL),
|
||||
mutexM(),
|
||||
handleM(NULL),
|
||||
headerListM(NULL),
|
||||
reConnectM(),
|
||||
keepAliveM(),
|
||||
statusUpdateM(),
|
||||
pidUpdateCacheM(),
|
||||
sessionM(""),
|
||||
currentStateM(tsIdle),
|
||||
internalStateM(),
|
||||
externalStateM(),
|
||||
timeoutM(eMinKeepAliveIntervalMs),
|
||||
openedM(false),
|
||||
tunedM(false),
|
||||
hasLockM(false),
|
||||
signalStrengthM(-1),
|
||||
signalQualityM(-1),
|
||||
@@ -38,224 +45,174 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
|
||||
delPidsM(),
|
||||
pidsM()
|
||||
{
|
||||
debug("cSatipTuner::%s(%d) [device %d]", __FUNCTION__, packetBufferLenM, deviceM->GetId());
|
||||
// Allocate packet buffer
|
||||
packetBufferM = MALLOC(unsigned char, packetBufferLenM);
|
||||
if (packetBufferM)
|
||||
memset(packetBufferM, 0, packetBufferLenM);
|
||||
else
|
||||
error("MALLOC() failed for packet buffer [device %d]", deviceM->GetId());
|
||||
debug1("%s (, %d) [device %d]", __PRETTY_FUNCTION__, packetLenP, deviceIdM);
|
||||
|
||||
// Open sockets
|
||||
int i = 100;
|
||||
while (i-- > 0) {
|
||||
if (rtpM.Open(0) && rtcpM.Open(rtpM.Port() + 1))
|
||||
break;
|
||||
rtpM.Close();
|
||||
rtcpM.Close();
|
||||
}
|
||||
if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) {
|
||||
error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM);
|
||||
}
|
||||
// Must be done after socket initialization!
|
||||
cSatipPoller::GetInstance()->Register(rtpM);
|
||||
cSatipPoller::GetInstance()->Register(rtcpM);
|
||||
|
||||
// Start thread
|
||||
Start();
|
||||
}
|
||||
|
||||
cSatipTuner::~cSatipTuner()
|
||||
{
|
||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
// Stop thread
|
||||
sleepM.Signal();
|
||||
if (Running())
|
||||
Cancel(3);
|
||||
Close();
|
||||
// Free allocated memory
|
||||
free(packetBufferM);
|
||||
DELETENULL(rtcpSocketM);
|
||||
DELETENULL(rtpSocketM);
|
||||
}
|
||||
currentStateM = tsIdle;
|
||||
internalStateM.Clear();
|
||||
externalStateM.Clear();
|
||||
|
||||
size_t cSatipTuner::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||
{
|
||||
cSatipTuner *obj = reinterpret_cast<cSatipTuner *>(dataP);
|
||||
size_t len = sizeP * nmembP;
|
||||
//debug("cSatipTuner::%s(%zu)", __FUNCTION__, len);
|
||||
|
||||
char *s, *p = (char *)ptrP;
|
||||
char *r = strtok_r(p, "\r\n", &s);
|
||||
|
||||
while (obj && r) {
|
||||
//debug("cSatipTuner::%s(%zu): %s", __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->SetStreamId(streamid);
|
||||
}
|
||||
else if (strstr(r, "Session:")) {
|
||||
int timeout = -1;
|
||||
char *session = NULL;
|
||||
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
|
||||
obj->SetSessionTimeout(skipspace(session), timeout * 1000);
|
||||
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
|
||||
obj->SetSessionTimeout(skipspace(session));
|
||||
FREE_POINTER(session);
|
||||
}
|
||||
r = strtok_r(NULL, "\r\n", &s);
|
||||
}
|
||||
|
||||
return len;
|
||||
// Close the listening sockets
|
||||
cSatipPoller::GetInstance()->Unregister(rtcpM);
|
||||
cSatipPoller::GetInstance()->Unregister(rtpM);
|
||||
rtcpM.Close();
|
||||
rtpM.Close();
|
||||
}
|
||||
|
||||
void cSatipTuner::Action(void)
|
||||
{
|
||||
debug("cSatipTuner::%s(): entering [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
cTimeMs timeout(eReConnectTimeoutMs);
|
||||
// Increase priority
|
||||
SetPriority(-1);
|
||||
debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
reConnectM.Set(eConnectTimeoutMs);
|
||||
// Do the thread loop
|
||||
while (packetBufferM && Running()) {
|
||||
int length = -1;
|
||||
unsigned int size = min(deviceM->CheckData(), packetBufferLenM);
|
||||
if (tunedM && (size > 0)) {
|
||||
// Update pids
|
||||
UpdatePids();
|
||||
// Remember the heart beat
|
||||
KeepAlive();
|
||||
// Read reception statistics
|
||||
if (rtcpSocketM && rtcpSocketM->IsOpen()) {
|
||||
unsigned char buf[1450];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (rtcpSocketM->ReadApplication(buf, sizeof(buf)) > 0) {
|
||||
ParseReceptionParameters((const char *)buf);
|
||||
timeout.Set(eReConnectTimeoutMs);
|
||||
}
|
||||
}
|
||||
// Read data
|
||||
if (rtpSocketM && rtpSocketM->IsOpen())
|
||||
length = rtpSocketM->ReadVideo(packetBufferM, size);
|
||||
}
|
||||
if (length > 0) {
|
||||
AddTunerStatistic(length);
|
||||
deviceM->WriteData(packetBufferM, length);
|
||||
timeout.Set(eReConnectTimeoutMs);
|
||||
}
|
||||
else {
|
||||
// Reconnect if necessary
|
||||
if (openedM && timeout.TimedOut()) {
|
||||
Disconnect();
|
||||
Connect();
|
||||
timeout.Set(eReConnectTimeoutMs);
|
||||
}
|
||||
sleepM.Wait(10); // to avoid busy loop and reduce cpu load
|
||||
}
|
||||
while (Running()) {
|
||||
UpdateCurrentState();
|
||||
switch (currentStateM) {
|
||||
case tsIdle:
|
||||
debug4("%s: tsIdle [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
break;
|
||||
case tsRelease:
|
||||
debug4("%s: tsRelease [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
Disconnect();
|
||||
RequestState(tsIdle, smInternal);
|
||||
break;
|
||||
case tsSet:
|
||||
debug4("%s: tsSet [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
if (Connect()) {
|
||||
RequestState(tsTuned, smInternal);
|
||||
UpdatePids(true);
|
||||
}
|
||||
else
|
||||
Disconnect();
|
||||
break;
|
||||
case tsTuned:
|
||||
debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
reConnectM.Set(eConnectTimeoutMs);
|
||||
// Read reception statistics via DESCRIBE and RTCP
|
||||
if (hasLockM || ReadReceptionStatus()) {
|
||||
// Quirk for devices without valid reception data
|
||||
if (currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkForceLock)) {
|
||||
hasLockM = true;
|
||||
signalStrengthM = eDefaultSignalStrength;
|
||||
signalQualityM = eDefaultSignalQuality;
|
||||
}
|
||||
if (hasLockM)
|
||||
RequestState(tsLocked, smInternal);
|
||||
}
|
||||
break;
|
||||
case tsLocked:
|
||||
debug4("%s: tsLocked [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
if (!UpdatePids()) {
|
||||
error("Pid update failed - retuning [device %d]", deviceIdM);
|
||||
RequestState(tsSet, smInternal);
|
||||
break;
|
||||
}
|
||||
if (!KeepAlive()) {
|
||||
error("Keep-alive failed - retuning [device %d]", deviceIdM);
|
||||
RequestState(tsSet, smInternal);
|
||||
break;
|
||||
}
|
||||
if (reConnectM.TimedOut()) {
|
||||
error("Connection timeout - retuning [device %d]", deviceIdM);
|
||||
RequestState(tsSet, smInternal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("Unknown tuner status %d [device %d]", currentStateM, deviceIdM);
|
||||
break;
|
||||
}
|
||||
if (!StateRequested())
|
||||
sleepM.Wait(eSleepTimeoutMs); // to avoid busy loop and reduce cpu load
|
||||
}
|
||||
debug("cSatipTuner::%s(): exiting [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
debug1("%s Exiting [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
}
|
||||
|
||||
bool cSatipTuner::Open(void)
|
||||
{
|
||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
if (Connect()) {
|
||||
openedM = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
RequestState(tsSet, smExternal);
|
||||
|
||||
// return always true
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::Close(void)
|
||||
{
|
||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
openedM = false;
|
||||
Disconnect();
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
RequestState(tsRelease, smExternal);
|
||||
|
||||
// return always true
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::Connect(void)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
|
||||
// Initialize the curl session
|
||||
if (!handleM)
|
||||
handleM = curl_easy_init();
|
||||
|
||||
if (handleM && !isempty(*streamAddrM)) {
|
||||
cString uri, control, transport, range;
|
||||
CURLcode res = CURLE_OK;
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
if (!isempty(*streamAddrM)) {
|
||||
cString connectionUri = cString::sprintf("rtsp://%s/", *streamAddrM);
|
||||
// Just retune
|
||||
if (tunedM && (streamIdM >= 0)) {
|
||||
debug("cSatipTuner::%s(): retune [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
keepAliveM.Set(0);
|
||||
KeepAlive();
|
||||
// Flush any old content
|
||||
if (rtpSocketM)
|
||||
rtpSocketM->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Verbose output
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
|
||||
#endif
|
||||
|
||||
// No progress meter and no signaling
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
|
||||
|
||||
// Set timeouts
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||
|
||||
// Set user-agent
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, deviceM->GetId()));
|
||||
|
||||
// Set URL
|
||||
char *p = curl_easy_unescape(handleM, *streamAddrM, 0, NULL);
|
||||
streamAddrM = p;
|
||||
curl_free(p);
|
||||
uri = cString::sprintf("rtsp://%s/", *streamAddrM);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, *uri);
|
||||
|
||||
// Open sockets
|
||||
int i = 100;
|
||||
while (i-- > 0) {
|
||||
if (rtpSocketM->Open() && rtcpSocketM->Open(rtpSocketM->Port() + 1))
|
||||
break;
|
||||
rtpSocketM->Close();
|
||||
rtcpSocketM->Close();
|
||||
if (streamIdM >= 0) {
|
||||
cString uri = cString::sprintf("%sstream=%d?%s", *connectionUri, streamIdM, *streamParamM);
|
||||
//if (pidsM.Size())
|
||||
// uri = cString::sprintf("%s&pids=%s", *uri, *pidsM.ListPids());
|
||||
debug1("%s Retuning [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
if (rtspM.Play(*uri)) {
|
||||
keepAliveM.Set(timeoutM);
|
||||
return true;
|
||||
}
|
||||
if ((rtpSocketM->Port() <= 0) || (rtcpSocketM->Port() <= 0)) {
|
||||
error("Cannot open required RTP/RTCP ports [device %d]", deviceM->GetId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Request server options
|
||||
keepAliveM.Set(timeoutM);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
if (!ValidateLatestResponse())
|
||||
return false;
|
||||
|
||||
// Setup media stream: "&pids=all" for the whole mux
|
||||
uri = cString::sprintf("rtsp://%s/?%s", *streamAddrM, *streamParamM);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
|
||||
transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpSocketM->Port(), rtcpSocketM->Port());
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_TRANSPORT, *transport);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
|
||||
// Set header callback for catching the session and timeout
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipTuner::HeaderCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, 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);
|
||||
if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0")) {
|
||||
debug("cSatipTuner::%s(): session id quirk [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, SkipZeroes(*sessionM));
|
||||
else if (rtspM.Options(*connectionUri)) {
|
||||
cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM);
|
||||
// Flush any old content
|
||||
rtpM.Flush();
|
||||
rtcpM.Flush();
|
||||
if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port())) {
|
||||
keepAliveM.Set(timeoutM);
|
||||
if (nextServerM) {
|
||||
cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
|
||||
currentServerM = nextServerM;
|
||||
nextServerM = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!ValidateLatestResponse())
|
||||
return false;
|
||||
|
||||
// Start playing
|
||||
tunedM = true;
|
||||
UpdatePids(true);
|
||||
if (nextServerM) {
|
||||
cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
|
||||
currentServerM = nextServerM;
|
||||
nextServerM = NULL;
|
||||
}
|
||||
return true;
|
||||
else
|
||||
rtspM.Reset();
|
||||
streamIdM = -1;
|
||||
error("Connect failed [device %d]", deviceIdM);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -264,34 +221,14 @@ bool cSatipTuner::Connect(void)
|
||||
bool cSatipTuner::Disconnect(void)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
// Terminate curl session
|
||||
if (handleM) {
|
||||
// Teardown rtsp session
|
||||
if (!isempty(*streamAddrM) && streamIdM >= 0) {
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
cString 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_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
ValidateLatestResponse();
|
||||
}
|
||||
|
||||
// Cleanup curl stuff
|
||||
if (headerListM) {
|
||||
curl_slist_free_all(headerListM);
|
||||
headerListM = NULL;
|
||||
}
|
||||
curl_easy_cleanup(handleM);
|
||||
handleM = NULL;
|
||||
if (!isempty(*streamAddrM) && (streamIdM >= 0)) {
|
||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||
rtspM.Teardown(*uri);
|
||||
streamIdM = -1;
|
||||
}
|
||||
|
||||
// Close the listening sockets
|
||||
rtpSocketM->Close();
|
||||
rtcpSocketM->Close();
|
||||
|
||||
// Reset signal parameters
|
||||
hasLockM = false;
|
||||
signalStrengthM = -1;
|
||||
@@ -299,39 +236,49 @@ bool cSatipTuner::Disconnect(void)
|
||||
|
||||
if (currentServerM)
|
||||
cSatipDiscover::GetInstance()->UseServer(currentServerM, false);
|
||||
tunedM = false;
|
||||
statusUpdateM.Set(0);
|
||||
timeoutM = eMinKeepAliveIntervalMs;
|
||||
addPidsM.Clear();
|
||||
delPidsM.Clear();
|
||||
|
||||
// return always true
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::ValidateLatestResponse(void)
|
||||
void cSatipTuner::ProcessVideoData(u_char *bufferP, int lengthP)
|
||||
{
|
||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
if (handleM) {
|
||||
long rc = 0;
|
||||
CURLcode res = CURLE_OK;
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
||||
if (rc == 200)
|
||||
return true;
|
||||
else if (rc != 0)
|
||||
error("Tuner detected invalid status code %ld [device %d]", rc, deviceM->GetId());
|
||||
}
|
||||
debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM);
|
||||
if (lengthP > 0) {
|
||||
uint64_t elapsed;
|
||||
cTimeMs processing(0);
|
||||
|
||||
return false;
|
||||
AddTunerStatistic(lengthP);
|
||||
elapsed = processing.Elapsed();
|
||||
if (elapsed > 1)
|
||||
debug6("%s AddTunerStatistic() took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, elapsed, deviceIdM);
|
||||
|
||||
processing.Set(0);
|
||||
deviceM->WriteData(bufferP, lengthP);
|
||||
elapsed = processing.Elapsed();
|
||||
if (elapsed > 1)
|
||||
debug6("%s WriteData() took %" PRIu64 " ms [device %d]", __FUNCTION__, elapsed, deviceIdM);
|
||||
}
|
||||
reConnectM.Set(eConnectTimeoutMs);
|
||||
}
|
||||
|
||||
void cSatipTuner::ParseReceptionParameters(const char *paramP)
|
||||
void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
|
||||
{
|
||||
//debug("cSatipTuner::%s(%s) [device %d]", __FUNCTION__, paramP, deviceM->GetId());
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM);
|
||||
// DVB-S2:
|
||||
// ver=<major>.<minor>;src=<srcID>;tuner=<feID>,<level>,<lock>,<quality>,<frequency>,<polarisation>,<system>,<type>,<pilots>,<roll_off>,<symbol_rate>,<fec_inner>;pids=<pid0>,...,<pidn>
|
||||
// DVB-T2:
|
||||
// ver=1.1;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<tmode>,<mtype>,<gi>,<fec>,<plp>,<t2id>,<sm>;pids=<pid0>,...,<pidn>
|
||||
if (!isempty(paramP)) {
|
||||
char *s = strdup(paramP);
|
||||
// DVB-C2:
|
||||
// ver=1.2;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<mtype>,<sr>,<c2tft>,<ds>,<plp>,<specinv>;pids=<pid0>,...,<pidn>
|
||||
if (lengthP > 0) {
|
||||
char s[lengthP];
|
||||
memcpy(s, (char *)bufferP, lengthP);
|
||||
debug10("%s (%s) [device %d]", __PRETTY_FUNCTION__, s, deviceIdM);
|
||||
char *c = strstr(s, ";tuner=");
|
||||
if (c) {
|
||||
int value;
|
||||
@@ -352,7 +299,7 @@ void cSatipTuner::ParseReceptionParameters(const char *paramP)
|
||||
// "0" the frontend is not locked
|
||||
// "1" the frontend is locked
|
||||
c = strstr(c, ",");
|
||||
hasLockM = atoi(++c);
|
||||
hasLockM = !!atoi(++c);
|
||||
|
||||
// quality:
|
||||
// Numerical value between 0 and 15
|
||||
@@ -365,184 +312,259 @@ void cSatipTuner::ParseReceptionParameters(const char *paramP)
|
||||
// Scale value to 0-100
|
||||
signalQualityM = (hasLockM && (value >= 0)) ? (value * 100 / 15) : 0;
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
reConnectM.Set(eConnectTimeoutMs);
|
||||
}
|
||||
|
||||
void cSatipTuner::SetStreamId(int streamIdP)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug("cSatipTuner::%s(%d) [device %d]", __FUNCTION__, streamIdP, deviceM->GetId());
|
||||
debug1("%s (%d) [device %d]", __PRETTY_FUNCTION__, streamIdP, deviceIdM);
|
||||
streamIdM = streamIdP;
|
||||
}
|
||||
|
||||
void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug("cSatipTuner::%s(%s, %d) [device %d]", __FUNCTION__, sessionP, timeoutP, deviceM->GetId());
|
||||
debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, sessionP, timeoutP, deviceIdM);
|
||||
sessionM = sessionP;
|
||||
if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0"))
|
||||
rtspM.SetSession(SkipZeroes(*sessionM));
|
||||
timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
|
||||
}
|
||||
|
||||
int cSatipTuner::GetId(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return deviceIdM;
|
||||
}
|
||||
|
||||
bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const int indexP)
|
||||
{
|
||||
debug("cSatipTuner::%s(%s, %d) [device %d]", __FUNCTION__, parameterP, indexP, deviceM->GetId());
|
||||
debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, parameterP, indexP, deviceIdM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
nextServerM = cSatipDiscover::GetInstance()->GetServer(serverP);
|
||||
if (nextServerM && !isempty(nextServerM->Address()) && !isempty(parameterP)) {
|
||||
// Update stream address and parameter
|
||||
streamAddrM = nextServerM->Address();
|
||||
streamParamM = parameterP;
|
||||
// Reconnect
|
||||
Connect();
|
||||
if (serverP) {
|
||||
nextServerM = cSatipDiscover::GetInstance()->GetServer(serverP);
|
||||
if (nextServerM && !isempty(nextServerM->Address()) && !isempty(parameterP)) {
|
||||
// Update stream address and parameter
|
||||
streamAddrM = rtspM.RtspUnescapeString(nextServerM->Address());
|
||||
streamParamM = rtspM.RtspUnescapeString(parameterP);
|
||||
// Reconnect
|
||||
RequestState(tsSet, smExternal);
|
||||
}
|
||||
}
|
||||
else {
|
||||
streamAddrM = "";
|
||||
streamParamM = "";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::SetPid(int pidP, int typeP, bool onP)
|
||||
{
|
||||
//debug("cSatipTuner::%s(%d, %d, %d) [device %d]", __FUNCTION__, pidP, typeP, onP, deviceM->GetId());
|
||||
debug16("%s (%d, %d, %d) [device %d]", __PRETTY_FUNCTION__, pidP, typeP, onP, deviceIdM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
bool found = false;
|
||||
for (int i = 0; i < pidsM.Size(); ++i) {
|
||||
if (pidsM[i] == pidP) {
|
||||
found = true;
|
||||
if (!onP)
|
||||
pidsM.Remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (onP && !found)
|
||||
pidsM.Append(pidP);
|
||||
// Generate deltas
|
||||
found = false;
|
||||
if (onP) {
|
||||
for (int i = 0; i < addPidsM.Size(); ++i) {
|
||||
if (addPidsM[i] == pidP) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
addPidsM.Append(pidP);
|
||||
for (int i = 0; i < delPidsM.Size(); ++i) {
|
||||
if (delPidsM[i] == pidP) {
|
||||
delPidsM.Remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pidsM.AddPid(pidP);
|
||||
addPidsM.AddPid(pidP);
|
||||
delPidsM.RemovePid(pidP);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < delPidsM.Size(); ++i) {
|
||||
if (delPidsM[i] == pidP) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
delPidsM.Append(pidP);
|
||||
for (int i = 0; i < addPidsM.Size(); ++i) {
|
||||
if (addPidsM[i] == pidP) {
|
||||
addPidsM.Remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pidsM.RemovePid(pidP);
|
||||
delPidsM.AddPid(pidP);
|
||||
addPidsM.RemovePid(pidP);
|
||||
}
|
||||
debug9("%s (%d, %d, %d) pids=%s [device %d]", __PRETTY_FUNCTION__, pidP, typeP, onP, *pidsM.ListPids(), deviceIdM);
|
||||
pidUpdateCacheM.Set(ePidUpdateIntervalMs);
|
||||
sleepM.Signal();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::UpdatePids(bool forceP)
|
||||
{
|
||||
debug16("%s (%d) tunerState=%s [device %d]", __PRETTY_FUNCTION__, forceP, TunerStateString(currentStateM), deviceIdM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) &&
|
||||
tunedM && handleM && !isempty(*streamAddrM) && (streamIdM > 0)) {
|
||||
CURLcode res = CURLE_OK;
|
||||
!isempty(*streamAddrM) && (streamIdM > 0)) {
|
||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||
if (forceP) {
|
||||
if (pidsM.Size()) {
|
||||
uri = cString::sprintf("%s?pids=", *uri);
|
||||
for (int i = 0; i < pidsM.Size(); ++i)
|
||||
uri = cString::sprintf("%s%d%s", *uri, pidsM[i], (i == (pidsM.Size() - 1)) ? "" : ",");
|
||||
}
|
||||
bool usedummy = !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkPlayPids));
|
||||
if (forceP || usedummy) {
|
||||
if (pidsM.Size())
|
||||
uri = cString::sprintf("%s?pids=%s", *uri, *pidsM.ListPids());
|
||||
if (usedummy && (pidsM.Size() == 1) && (pidsM[0] < 0x20))
|
||||
uri = cString::sprintf("%s,%d", *uri, eDummyPid);
|
||||
}
|
||||
else {
|
||||
if (addPidsM.Size()) {
|
||||
uri = cString::sprintf("%s?addpids=", *uri);
|
||||
for (int i = 0; i < addPidsM.Size(); ++i)
|
||||
uri = cString::sprintf("%s%d%s", *uri, addPidsM[i], (i == (addPidsM.Size() - 1)) ? "" : ",");
|
||||
}
|
||||
if (delPidsM.Size()) {
|
||||
uri = cString::sprintf("%s%sdelpids=", *uri, addPidsM.Size() ? "&" : "?");
|
||||
for (int i = 0; i < delPidsM.Size(); ++i)
|
||||
uri = cString::sprintf("%s%d%s", *uri, delPidsM[i], (i == (delPidsM.Size() - 1)) ? "" : ",");
|
||||
}
|
||||
if (addPidsM.Size())
|
||||
uri = cString::sprintf("%s?addpids=%s", *uri, *addPidsM.ListPids());
|
||||
if (delPidsM.Size())
|
||||
uri = cString::sprintf("%s%sdelpids=%s", *uri, addPidsM.Size() ? "&" : "?", *delPidsM.ListPids());
|
||||
}
|
||||
//debug("cSatipTuner::%s(): %s [device %d]", __FUNCTION__, *uri, deviceM->GetId());
|
||||
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()) {
|
||||
addPidsM.Clear();
|
||||
delPidsM.Clear();
|
||||
}
|
||||
else
|
||||
Disconnect();
|
||||
if (!rtspM.Play(*uri))
|
||||
return false;
|
||||
addPidsM.Clear();
|
||||
delPidsM.Clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::KeepAlive(bool forceP)
|
||||
{
|
||||
debug16("%s (%d) tunerState=%s [device %d]", __PRETTY_FUNCTION__, forceP, TunerStateString(currentStateM), deviceIdM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (keepAliveM.TimedOut()) {
|
||||
keepAliveM.Set(timeoutM);
|
||||
forceP = true;
|
||||
}
|
||||
if (forceP && !isempty(*streamAddrM)) {
|
||||
cString uri = cString::sprintf("rtsp://%s/", *streamAddrM);
|
||||
if (!rtspM.Options(*uri))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::ReadReceptionStatus(bool forceP)
|
||||
{
|
||||
debug16("%s (%d) tunerState=%s [device %d]", __PRETTY_FUNCTION__, forceP, TunerStateString(currentStateM), deviceIdM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (statusUpdateM.TimedOut()) {
|
||||
statusUpdateM.Set(eStatusUpdateTimeoutMs);
|
||||
forceP = true;
|
||||
}
|
||||
if (forceP && !isempty(*streamAddrM) && (streamIdM > 0)) {
|
||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||
if (rtspM.Describe(*uri))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipTuner::KeepAlive(void)
|
||||
void cSatipTuner::UpdateCurrentState(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (tunedM && handleM && keepAliveM.TimedOut()) {
|
||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
CURLcode res = CURLE_OK;
|
||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||
eTunerState state = currentStateM;
|
||||
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
if (ValidateLatestResponse())
|
||||
keepAliveM.Set(timeoutM);
|
||||
else
|
||||
Disconnect();
|
||||
|
||||
return true;
|
||||
if (internalStateM.Size()) {
|
||||
state = internalStateM.At(0);
|
||||
internalStateM.Remove(0);
|
||||
}
|
||||
else if (externalStateM.Size()) {
|
||||
state = externalStateM.At(0);
|
||||
externalStateM.Remove(0);
|
||||
}
|
||||
|
||||
return false;
|
||||
if (currentStateM != state) {
|
||||
debug1("%s: Switching from %s to %s [device %d]", __PRETTY_FUNCTION__, TunerStateString(currentStateM), TunerStateString(state), deviceIdM);
|
||||
currentStateM = state;
|
||||
}
|
||||
}
|
||||
|
||||
bool cSatipTuner::StateRequested(void)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug16("%s current=%s internal=%d external=%d [device %d]", __PRETTY_FUNCTION__, TunerStateString(currentStateM), internalStateM.Size(), externalStateM.Size(), deviceIdM);
|
||||
|
||||
return (internalStateM.Size() || externalStateM.Size());
|
||||
}
|
||||
|
||||
bool cSatipTuner::RequestState(eTunerState stateP, eStateMode modeP)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug1("%s (%s, %s) current=%s internal=%d external=%d [device %d]", __PRETTY_FUNCTION__, TunerStateString(stateP), StateModeString(modeP), TunerStateString(currentStateM), internalStateM.Size(), externalStateM.Size(), deviceIdM);
|
||||
|
||||
if (modeP == smExternal)
|
||||
externalStateM.Append(stateP);
|
||||
else if (modeP == smInternal) {
|
||||
eTunerState state = internalStateM.Size() ? internalStateM.At(internalStateM.Size() - 1) : currentStateM;
|
||||
|
||||
// validate legal state changes
|
||||
switch (state) {
|
||||
case tsIdle:
|
||||
if (stateP == tsRelease)
|
||||
return false;
|
||||
case tsRelease:
|
||||
case tsSet:
|
||||
case tsLocked:
|
||||
case tsTuned:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
internalStateM.Append(stateP);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *cSatipTuner::StateModeString(eStateMode modeP)
|
||||
{
|
||||
switch (modeP) {
|
||||
case smInternal:
|
||||
return "smInternal";
|
||||
case smExternal:
|
||||
return "smExternal";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "---";
|
||||
}
|
||||
|
||||
const char *cSatipTuner::TunerStateString(eTunerState stateP)
|
||||
{
|
||||
switch (stateP) {
|
||||
case tsIdle:
|
||||
return "tsIdle";
|
||||
case tsRelease:
|
||||
return "tsRelease";
|
||||
case tsSet:
|
||||
return "tsSet";
|
||||
case tsLocked:
|
||||
return "tsLocked";
|
||||
case tsTuned:
|
||||
return "tsTuned";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "---";
|
||||
}
|
||||
|
||||
int cSatipTuner::SignalStrength(void)
|
||||
{
|
||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return signalStrengthM;
|
||||
}
|
||||
|
||||
int cSatipTuner::SignalQuality(void)
|
||||
{
|
||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return signalQualityM;
|
||||
}
|
||||
|
||||
bool cSatipTuner::HasLock(void)
|
||||
{
|
||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
return tunedM && hasLockM;
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return (currentStateM >= tsTuned) && hasLockM;
|
||||
}
|
||||
|
||||
cString cSatipTuner::GetSignalStatus(void)
|
||||
{
|
||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return cString::sprintf("lock=%d strength=%d quality=%d", HasLock(), SignalStrength(), SignalQuality());
|
||||
}
|
||||
|
||||
cString cSatipTuner::GetInformation(void)
|
||||
{
|
||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
||||
return tunedM ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed";
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return (currentStateM >= tsTuned) ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed";
|
||||
}
|
||||
|
116
tuner.h
116
tuner.h
@@ -8,69 +8,113 @@
|
||||
#ifndef __SATIP_TUNER_H
|
||||
#define __SATIP_TUNER_H
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <curl/easy.h>
|
||||
|
||||
#ifndef CURLOPT_RTSPHEADER
|
||||
#error "libcurl is missing required RTSP support"
|
||||
#endif
|
||||
|
||||
#include <vdr/thread.h>
|
||||
#include <vdr/tools.h>
|
||||
|
||||
#include "deviceif.h"
|
||||
#include "rtp.h"
|
||||
#include "rtcp.h"
|
||||
#include "rtsp.h"
|
||||
#include "server.h"
|
||||
#include "statistics.h"
|
||||
#include "socket.h"
|
||||
|
||||
class cSatipTuner : public cThread, public cSatipTunerStatistics {
|
||||
class cSatipPid : public cVector<int> {
|
||||
private:
|
||||
int PidIndex(const int &pidP)
|
||||
{
|
||||
for (int i = 0; i < Size(); ++i) {
|
||||
if (pidP == At(i))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static int PidCompare(const void *aPidP, const void *bPidP)
|
||||
{
|
||||
return (*(int*)aPidP - *(int*)bPidP);
|
||||
}
|
||||
|
||||
public:
|
||||
void RemovePid(const int &pidP)
|
||||
{
|
||||
int i = PidIndex(pidP);
|
||||
if (i >= 0) {
|
||||
Remove(i);
|
||||
Sort(PidCompare);
|
||||
}
|
||||
}
|
||||
void AddPid(int pidP)
|
||||
{
|
||||
if (PidIndex(pidP) < 0) {
|
||||
Append(pidP);
|
||||
Sort(PidCompare);
|
||||
}
|
||||
}
|
||||
cString ListPids(void)
|
||||
{
|
||||
cString list = "";
|
||||
if (Size()) {
|
||||
for (int i = 0; i < Size(); ++i)
|
||||
list = cString::sprintf("%s%d,", *list, At(i));
|
||||
list = list.Truncate(-1);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
class cSatipTuner : public cThread, public cSatipTunerStatistics, public cSatipTunerIf
|
||||
{
|
||||
private:
|
||||
enum {
|
||||
eConnectTimeoutMs = 1500, // in milliseconds
|
||||
eDummyPid = 100,
|
||||
eDefaultSignalStrength = 15,
|
||||
eDefaultSignalQuality = 224,
|
||||
eSleepTimeoutMs = 1000, // in milliseconds
|
||||
eStatusUpdateTimeoutMs = 1000, // in milliseconds
|
||||
ePidUpdateIntervalMs = 250, // in milliseconds
|
||||
eReConnectTimeoutMs = 5000, // in milliseconds
|
||||
eConnectTimeoutMs = 5000, // in milliseconds
|
||||
eMinKeepAliveIntervalMs = 30000 // in milliseconds
|
||||
};
|
||||
|
||||
static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
||||
enum eTunerState { tsIdle, tsRelease, tsSet, tsTuned, tsLocked };
|
||||
enum eStateMode { smInternal, smExternal };
|
||||
|
||||
cCondWait sleepM;
|
||||
cSatipDeviceIf* deviceM;
|
||||
unsigned char* packetBufferM;
|
||||
unsigned int packetBufferLenM;
|
||||
cSatipSocket *rtpSocketM;
|
||||
cSatipSocket *rtcpSocketM;
|
||||
int deviceIdM;
|
||||
cSatipRtsp rtspM;
|
||||
cSatipRtp rtpM;
|
||||
cSatipRtcp rtcpM;
|
||||
cString streamAddrM;
|
||||
cString streamParamM;
|
||||
cSatipServer *currentServerM;
|
||||
cSatipServer *nextServerM;
|
||||
cMutex mutexM;
|
||||
CURL *handleM;
|
||||
struct curl_slist *headerListM;
|
||||
cTimeMs reConnectM;
|
||||
cTimeMs keepAliveM;
|
||||
cTimeMs signalInfoCacheM;
|
||||
cTimeMs statusUpdateM;
|
||||
cTimeMs pidUpdateCacheM;
|
||||
cString sessionM;
|
||||
eTunerState currentStateM;
|
||||
cVector<eTunerState> internalStateM;
|
||||
cVector<eTunerState> externalStateM;
|
||||
int timeoutM;
|
||||
bool openedM;
|
||||
bool tunedM;
|
||||
bool hasLockM;
|
||||
int signalStrengthM;
|
||||
int signalQualityM;
|
||||
int streamIdM;
|
||||
cVector<int> addPidsM;
|
||||
cVector<int> delPidsM;
|
||||
cVector<int> pidsM;
|
||||
cSatipPid addPidsM;
|
||||
cSatipPid delPidsM;
|
||||
cSatipPid pidsM;
|
||||
|
||||
bool Connect(void);
|
||||
bool Disconnect(void);
|
||||
bool ValidateLatestResponse(void);
|
||||
void ParseReceptionParameters(const char *paramP);
|
||||
void SetStreamId(int streamIdP);
|
||||
void SetSessionTimeout(const char *sessionP, int timeoutP = 0);
|
||||
bool KeepAlive(void);
|
||||
bool UpdateSignalInfoCache(void);
|
||||
bool KeepAlive(bool forceP = false);
|
||||
bool ReadReceptionStatus(bool forceP = false);
|
||||
bool UpdatePids(bool forceP = false);
|
||||
void UpdateCurrentState(void);
|
||||
bool StateRequested(void);
|
||||
bool RequestState(eTunerState stateP, eStateMode modeP);
|
||||
const char *StateModeString(eStateMode modeP);
|
||||
const char *TunerStateString(eTunerState stateP);
|
||||
|
||||
protected:
|
||||
virtual void Action(void);
|
||||
@@ -78,7 +122,7 @@ protected:
|
||||
public:
|
||||
cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP);
|
||||
virtual ~cSatipTuner();
|
||||
bool IsTuned(void) const { return tunedM; }
|
||||
bool IsTuned(void) const { return (currentStateM >= tsTuned); }
|
||||
bool SetSource(cSatipServer *serverP, const char *parameterP, const int indexP);
|
||||
bool SetPid(int pidP, int typeP, bool onP);
|
||||
bool Open(void);
|
||||
@@ -88,6 +132,14 @@ public:
|
||||
bool HasLock(void);
|
||||
cString GetSignalStatus(void);
|
||||
cString GetInformation(void);
|
||||
|
||||
// for internal tuner interface
|
||||
public:
|
||||
virtual void ProcessVideoData(u_char *bufferP, int lengthP);
|
||||
virtual void ProcessApplicationData(u_char *bufferP, int lengthP);
|
||||
virtual void SetStreamId(int streamIdP);
|
||||
virtual void SetSessionTimeout(const char *sessionP, int timeoutP);
|
||||
virtual int GetId(void);
|
||||
};
|
||||
|
||||
#endif // __SATIP_TUNER_H
|
||||
|
26
tunerif.h
Normal file
26
tunerif.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* tunerif.h: SAT>IP plugin for the Video Disk Recorder
|
||||
*
|
||||
* See the README file for copyright information and how to reach the author.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SATIP_TUNERIF_H
|
||||
#define __SATIP_TUNERIF_H
|
||||
|
||||
class cSatipTunerIf {
|
||||
public:
|
||||
cSatipTunerIf() {}
|
||||
virtual ~cSatipTunerIf() {}
|
||||
virtual void ProcessVideoData(u_char *bufferP, int lenghtP) = 0;
|
||||
virtual void ProcessApplicationData(u_char *bufferP, int lenghtP) = 0;
|
||||
virtual void SetStreamId(int streamIdP) = 0;
|
||||
virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0;
|
||||
virtual int GetId(void) = 0;
|
||||
|
||||
private:
|
||||
cSatipTunerIf(const cSatipTunerIf&);
|
||||
cSatipTunerIf& operator=(const cSatipTunerIf&);
|
||||
};
|
||||
|
||||
#endif // __SATIP_TUNERIF_H
|
Reference in New Issue
Block a user