mirror of
https://github.com/rofafor/vdr-plugin-satip.git
synced 2023-10-10 11:37:42 +00:00
Compare commits
No commits in common. "master" and "v1.0.2" have entirely different histories.
119
HISTORY
119
HISTORY
@ -108,122 +108,3 @@ VDR Plugin 'satip' Revision History
|
||||
- Updated Spanish and Catalan translations (Thanks to
|
||||
Gabriel Bonich).
|
||||
- Updated German translations (Thanks to Frank Neumann).
|
||||
|
||||
|
||||
===================================
|
||||
VDR Plugin 'satip' Revision History
|
||||
===================================
|
||||
|
||||
2015-02-19: Version 2.2.0
|
||||
|
||||
- Updated for vdr-2.2.0.
|
||||
- Fixed memory deallocation errors.
|
||||
- Cleaned up all scan-build warnings.
|
||||
- Refactored the frontend handling.
|
||||
|
||||
2015-04-04: Version 2.2.1
|
||||
|
||||
- Improved RTSP error checking.
|
||||
- Got rid of SATIP_DEBUG.
|
||||
- Robustify the server discovery.
|
||||
- Fixed a memory leak in TinyXML implementation
|
||||
(Thanks to Oliver Endriss).
|
||||
- Updated against SAT>IP protocol specification
|
||||
version 1.2.2.
|
||||
|
||||
2015-04-26: Version 2.2.2
|
||||
|
||||
- Added a more flexible OPER command in the SVDRP
|
||||
interface.
|
||||
- Added new ATTA and DETA SVDRP commands.
|
||||
- Set the default device count to two.
|
||||
|
||||
2015-09-18: Version 2.2.3
|
||||
|
||||
- Added a timeout for releasing idling devices.
|
||||
- Reset the RTSP connection after any failed connect.
|
||||
- Added tweaks for minisatip and Schwaiger MS41IP.
|
||||
- Updated for vdr-2.3.1 (Thanks to Klaus Schmidinger).
|
||||
|
||||
2016-12-18: Version 2.2.4
|
||||
|
||||
- Updated German translation (Thanks to Frank Neumann).
|
||||
- Fixed Panasonic CXW804 support (Thanks to Tobias Grimm).
|
||||
- Fixed C++11 support (Thanks to Tobias Grimm).
|
||||
- Fixed server assigment with source validation (Thanks to Patrick Boettcher).
|
||||
- Added configurable RTP/RTCP ports (Thanks to chriszero).
|
||||
- Added support for X-SATIP-RTSP-Port header.
|
||||
- Added multicast and RTP-over-TCP support.
|
||||
- Added support for activating/deactivating server on-the-fly.
|
||||
- Extended command-line parameters for setting server quirks.
|
||||
|
||||
2017-08-15: Version 2.2.5
|
||||
|
||||
- Added Polish translation (Thanks to Tomasz Nowak).
|
||||
- Updated Catalan and Spanish translations (Thanks to Gabriel Bonich).
|
||||
- Added support for KATHREIN SatIP Server (Thanks to kavanu).
|
||||
- Added support for FRITZ!Box 6490 Cable (Thanks to 9000h).
|
||||
- Updated FRITZ!WLAN Repeater DVB-C detection for the latest firmware (Thanks to 9000h).
|
||||
- Added GCC7 compatibility (Thanks to Sascha Kuehndel).
|
||||
|
||||
|
||||
===================================
|
||||
VDR Plugin 'satip' Revision History
|
||||
===================================
|
||||
|
||||
2016-12-18: Version 2.3.0
|
||||
|
||||
- Updated for vdr-2.3.1.
|
||||
- Updated German translation (Thanks to Frank Neumann).
|
||||
- Fixed Panasonic CXW804 support (Thanks to Tobias Grimm).
|
||||
- Fixed C++11 support (Thanks to Tobias Grimm).
|
||||
- Fixed server assigment with source validation (Thanks to Patrick Boettcher).
|
||||
- Added configurable RTP/RTCP ports (Thanks to chriszero).
|
||||
- Added support for X-SATIP-RTSP-Port header.
|
||||
- Added multicast and RTP-over-TCP support.
|
||||
- Added support for activating/deactivating server on-the-fly.
|
||||
- Extended command-line parameters for setting server quirks.
|
||||
|
||||
2017-08-15: Version 2.3.1
|
||||
|
||||
- Updated for vdr-2.3.7 (Thanks to Klaus Schmidinger).
|
||||
- Added Polish translation (Thanks to Tomasz Nowak).
|
||||
- Updated Catalan and Spanish translations (Thanks to Gabriel Bonich).
|
||||
- Added support for KATHREIN SatIP Server (Thanks to kavanu).
|
||||
- Added support for FRITZ!Box 6490 Cable (Thanks to 9000h).
|
||||
- Updated FRITZ!WLAN Repeater DVB-C detection for the latest firmware (Thanks to 9000h).
|
||||
- Added GCC7 compatibility (Thanks to Sascha Kuehndel).
|
||||
|
||||
|
||||
===================================
|
||||
VDR Plugin 'satip' Revision History
|
||||
===================================
|
||||
|
||||
2018-04-15: Version 2.4.0
|
||||
|
||||
- Updated for vdr-2.4.0.
|
||||
- Removed speed limit.
|
||||
- Fixed transport media changes.
|
||||
- Fixed memory leak in cSatipSectionFilter (Thanks to Alexander Pipelka).
|
||||
- Added more robust section filter handling (Thanks to Alexander Pipelka).
|
||||
- Added a command line parameter for the RTP receive buffer size (Thanks to Stefan Rehm).
|
||||
|
||||
2021-06-01: Version 2.4.1
|
||||
|
||||
- Added an option to enable/disable frontend reuse.
|
||||
- Added a preliminary ATSC support.
|
||||
- Fixed a channel switching logic bug (Thanks to REELcoder).
|
||||
- Added a workaround for detecting Panasonic devices.
|
||||
- Removed quirks from FRITZ!Box 6490 Cable due to new firmware.
|
||||
- Fixed RTP over TCP.
|
||||
- Fixed URL parameter creation (Thanks to Martin Janser).
|
||||
- Added an option to enable/disable frontend reuse.
|
||||
- Added a preliminary ATSC support.
|
||||
- Fixed a channel switching logic bug (Thanks to REELcoder).
|
||||
- Added quirks for Inverto IDL-400s.
|
||||
- Updated German translation (Thanks to Martin Dummer).
|
||||
- Added a quirk for always teardown before play (Thanks to maazl).
|
||||
- Updated for vdr-2.4.3 (Thanks to <Winfried Koehler).
|
||||
- Added timeout for HasLock (Thanks to Winfried Koehler).
|
||||
- Updated detectsatip script for Python 3.
|
||||
- Fixed keepalive interval.
|
||||
|
44
Makefile
44
Makefile
@ -2,10 +2,18 @@
|
||||
# Makefile for SAT>IP plugin
|
||||
#
|
||||
|
||||
# Debugging on/off
|
||||
|
||||
#SATIP_DEBUG = 1
|
||||
|
||||
# Use TinyXML instead of PugiXML
|
||||
|
||||
#SATIP_USE_TINYXML = 1
|
||||
|
||||
# Strip debug symbols? Set eg. to /bin/true if not
|
||||
|
||||
STRIP = strip
|
||||
|
||||
# The official name of this plugin.
|
||||
# This name will be used in the '-P...' option of VDR to load the plugin.
|
||||
# By default the main source file also carries this name.
|
||||
@ -32,7 +40,6 @@ TMPDIR ?= /tmp
|
||||
|
||||
export CFLAGS = $(call PKGCFG,cflags)
|
||||
export CXXFLAGS = $(call PKGCFG,cxxflags)
|
||||
STRIP ?= /bin/true
|
||||
|
||||
### The version number of VDR's plugin API:
|
||||
|
||||
@ -68,6 +75,12 @@ else
|
||||
LIBS += -lpugixml
|
||||
endif
|
||||
|
||||
ifdef SATIP_DEBUG
|
||||
ifeq ($(SATIP_DEBUG),1)
|
||||
DEFINES += -DDEBUG
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(strip $(GITTAG)),)
|
||||
DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"'
|
||||
endif
|
||||
@ -88,15 +101,14 @@ all: $(SOFILE) i18n
|
||||
### Implicit rules:
|
||||
|
||||
%.o: %.c
|
||||
@echo CC $@
|
||||
$(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
|
||||
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
|
||||
|
||||
### Dependencies:
|
||||
|
||||
MAKEDEP = $(CXX) -MM -MG
|
||||
DEPFILE = .dependencies
|
||||
$(DEPFILE): Makefile
|
||||
$(Q)$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
|
||||
@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
|
||||
|
||||
-include $(DEPFILE)
|
||||
|
||||
@ -109,21 +121,17 @@ I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLU
|
||||
I18Npot = $(PODIR)/$(PLUGIN).pot
|
||||
|
||||
%.mo: %.po
|
||||
@echo MO $@
|
||||
$(Q)msgfmt -c -o $@ $<
|
||||
msgfmt -c -o $@ $<
|
||||
|
||||
$(I18Npot): $(wildcard *.c)
|
||||
@echo GT $@
|
||||
$(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
|
||||
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
|
||||
|
||||
%.po: $(I18Npot)
|
||||
@echo PO $@
|
||||
$(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
|
||||
msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
|
||||
@touch $@
|
||||
|
||||
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
|
||||
@echo IN $@
|
||||
$(Q)install -D -m644 $< $@
|
||||
install -D -m644 $< $@
|
||||
|
||||
.PHONY: i18n
|
||||
i18n: $(I18Nmo) $(I18Npot)
|
||||
@ -133,13 +141,13 @@ install-i18n: $(I18Nmsgs)
|
||||
### Targets:
|
||||
|
||||
$(SOFILE): $(OBJS)
|
||||
@echo LD $@
|
||||
$(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
|
||||
$(Q)$(STRIP) $@
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
|
||||
ifndef SATIP_DEBUG
|
||||
@$(STRIP) $@
|
||||
endif
|
||||
|
||||
install-lib: $(SOFILE)
|
||||
@echo IN $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
|
||||
$(Q)install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
|
||||
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
|
||||
|
||||
install-conf:
|
||||
@mkdir -p $(DESTDIR)$(CFGDIR)/plugins/$(PLUGIN)
|
||||
@ -160,4 +168,4 @@ clean:
|
||||
|
||||
.PHONY: cppcheck
|
||||
cppcheck:
|
||||
$(Q)cppcheck --language=c++ --enable=all -v -f $(OBJS:%.o=%.c)
|
||||
@cppcheck --language=c++ --enable=all -v -f $(OBJS:%.o=%.c)
|
||||
|
88
README
88
README
@ -3,9 +3,9 @@ This is an SAT>IP plugin for the Video Disk Recorder (VDR).
|
||||
Written by: Rolf Ahrenberg
|
||||
< R o l f . A h r e n b e r g @ s c i . f i >
|
||||
|
||||
Project's homepage: https://github.com/rofafor/vdr-plugin-satip
|
||||
Project's homepage: http://www.saunalahti.fi/~rahrenbe/vdr/satip/
|
||||
|
||||
Latest version available at: https://github.com/rofafor/vdr-plugin-satip/releases
|
||||
Latest version available at: http://www.saunalahti.fi/~rahrenbe/vdr/satip/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
@ -26,6 +26,10 @@ Requirements:
|
||||
- Glibc >= 2.12 - the GNU C library (recvmmsg)
|
||||
http://www.gnu.org/software/libc/
|
||||
|
||||
- VDR >= 2.1.4 for scrambled channels
|
||||
|
||||
- VDR >= 2.1.7 for external CI
|
||||
|
||||
Description:
|
||||
|
||||
This plugin integrates SAT>IP network devices seamlessly into VDR.
|
||||
@ -42,51 +46,19 @@ make -C satip-X.Y.Z install
|
||||
Configuration:
|
||||
|
||||
The plugin accepts a "--devices" (-d) command-line parameter defaulting
|
||||
to two. This parameter defines how many simultaneous transponders can
|
||||
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. Multiple service entries can be given
|
||||
separated by a semicolon:
|
||||
via UPnP somehow can't be used. The parameter string is a semicolon
|
||||
separated list of "<ipaddress>|<model>|<description>" entries. The model
|
||||
consists of a DVB system (DVBS2,DVBT2,DVBT,DVBC) and number of available
|
||||
frontends separated by a hyphen:
|
||||
|
||||
[<srcaddress>@]<ipaddress>[:<port>]|<model>[:<filter>]|<description>[:<quirk>];...
|
||||
|
||||
- srcaddress (Optional) Source address can be used to define used
|
||||
networking interface on a host, e.g. 127.0.0.1.
|
||||
- ipaddress IP address of SAT>IP server, e.g. 127.0.0.1.
|
||||
- port (Optional) IP port number of SAT>IP server, e.g 443.
|
||||
- model Model defines DVB modulation system (DVBS2,
|
||||
DVBT2, DVBT, DVBC) and number of available
|
||||
frontends separated by a hyphen, e.g. DVBT2-4.
|
||||
- filter (Optional) Filter can be used to limit satellite frontends
|
||||
to certain satellite position, e.g. S19.2E.
|
||||
- description Friendly name of SAT>IP server. This is used
|
||||
for autodetection of quirks.
|
||||
- quirk (Optional) Quirks are non-standard compliant features and
|
||||
bug fixes of SAT>IP server defined by a
|
||||
hexadecimal number. Multiple quirks can be
|
||||
defined by combining values by addition:
|
||||
|
||||
0x01: Fix session id bug
|
||||
0x02: Fix play parameter (addpids/delpids) bug
|
||||
0x04: Fix frontend locking bug
|
||||
0x08: Support for RTP over TCP
|
||||
0x10: Support the X_PMT protocol extension
|
||||
0x20: Support the CI TNR protocol extension
|
||||
0x40: Fix auto-detection of pilot tones bug
|
||||
0x80: Fix re-tuning bug by teardowning a session
|
||||
|
||||
Examples:
|
||||
|
||||
vdr -P 'satip -s 192.168.0.1|DVBS2-2,DVBT2-2|OctopusNet'
|
||||
vdr -P 'satip -s 192.168.0.1|DVBS2-4|OctopusNet;192.168.0.2|DVBT2-4|minisatip:0x18'
|
||||
vdr -P 'satip -s 192.168.0.1:554|DVBS2-2:S19.2E|OctopusNet;192.168.0.2:8554|DVBS2-4:S19.2E,S1W|minisatip'
|
||||
|
||||
The plugin accepts a "--portrange" (-p) command-line parameter, that can
|
||||
be used to manually specify the RTP & RTCP port range and therefore
|
||||
enables using the plugin through a NAT (e.g. Docker bridged network).
|
||||
A minimum of 2 ports per device is required.
|
||||
vdr -P 'satip -s <ipaddress>|<model>|<description>;...'
|
||||
vdr -P 'satip -s 192.168.0.1|DVBS2-2,DVBT2-2|Octo1'
|
||||
vdr -P 'satip -s 192.168.0.1|DVBS2-4|Octo1;192.168.0.2|DVBT2-4|Octo2'
|
||||
|
||||
SAT>IP satellite positions (aka. signal sources) shall be defined via
|
||||
sources.conf. If the source description begins with a number, it's used
|
||||
@ -142,15 +114,6 @@ Setup menu:
|
||||
"Disable filter" options which allow you
|
||||
to disable the individual section filters.
|
||||
Valid range: "none" = 0 ... 7
|
||||
- Transport mode = unicast If you want to use the non-standard
|
||||
multicast RTP-over-TCP transport mode, set this option
|
||||
rtp-o-tcp accordingly. Otherwise, the transport
|
||||
mode will be RTP-over-UDP via unicast or
|
||||
multicast.
|
||||
- Enable frontend reuse = yes Certain devices might have artifacts if
|
||||
multiple channels are assigned to the same
|
||||
frontend. If you want to avoid such a
|
||||
frontend assignment, set this option to "no".
|
||||
- [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.
|
||||
@ -166,9 +129,6 @@ Information menu:
|
||||
|
||||
Notes:
|
||||
|
||||
- If you are having problems receiving DVB-S2 channels, make sure your
|
||||
channels.conf entry contains correct pilot tone setting.
|
||||
|
||||
- The stream id "-1" states about unsuccessful tuning. This might be a
|
||||
result of invalid channel parameters or lack of free SAT>IP tuners.
|
||||
|
||||
@ -176,8 +136,8 @@ Notes:
|
||||
your setup doesn't have firewalled the UDP port 1900.
|
||||
|
||||
- Stream decryption requires a separate CAM plugin that works without
|
||||
direct access to any DVB card devices. Also the integrated CAM slots
|
||||
in Octopus Net devices are supported.
|
||||
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.
|
||||
@ -189,22 +149,6 @@ Notes:
|
||||
from their webpage: http://www.inverto.tv/support/
|
||||
An update to a newer firmware should be offered afterwards.
|
||||
|
||||
- FRITZ!OS 7.00 or greater recommended for FRITZ!Box Cable devices.
|
||||
Older firmware versions require both PlayPids and ForceLock quirks.
|
||||
|
||||
- If you are experiencing glitches in the video stream, one possible
|
||||
reason can be buffer overflows in RTP receive sockets. You can verify
|
||||
this by checking "receive buffer errors" counter by running "netstat -s"
|
||||
command. If the counter increases every time a video glitch happens,
|
||||
you should try to tweak the RTP receive buffer size with the "--rcvbuf"
|
||||
(-r) plugin parameter.
|
||||
A good starting point for the buffer size is to double the operating
|
||||
system default value until errors disappear or the maximum value is
|
||||
reached. You can check these values in Linux by checking the kernel
|
||||
parameters:
|
||||
$ cat /proc/sys/net/core/rmem_default
|
||||
$ cat /proc/sys/net/core/rmem_max
|
||||
|
||||
Acknowledgements:
|
||||
|
||||
- Big thanks to Digital Devices GmbH for providing the Octopus Net
|
||||
|
54
common.h
54
common.h
@ -13,11 +13,9 @@
|
||||
#include <vdr/config.h>
|
||||
#include <vdr/i18n.h>
|
||||
|
||||
#define SATIP_DEFAULT_RTSP_PORT 554
|
||||
|
||||
#define SATIP_MAX_DEVICES MAXDEVICES
|
||||
|
||||
#define SATIP_BUFFER_SIZE KILOBYTE(2048)
|
||||
#define SATIP_BUFFER_SIZE KILOBYTE(1024)
|
||||
|
||||
#define SATIP_DEVICE_INFO_ALL 0
|
||||
#define SATIP_DEVICE_INFO_GENERAL 1
|
||||
@ -37,7 +35,7 @@
|
||||
|
||||
#define SATIP_CURL_EASY_GETINFO(X, Y, Z) \
|
||||
if ((res = curl_easy_getinfo((X), (Y), (Z))) != CURLE_OK) { \
|
||||
esyslog("curl_easy_getinfo(%s) [%s,%d] failed: %s (%d)", #Y, __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
||||
error("curl_easy_getinfo(%s) [%s,%d] failed: %s (%d)", #Y, __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
||||
}
|
||||
|
||||
#define SATIP_CURL_EASY_SETOPT(X, Y, Z) \
|
||||
@ -54,7 +52,7 @@
|
||||
do { \
|
||||
if (exp) { \
|
||||
char tmp[64]; \
|
||||
esyslog("[%s,%d]: " errstr ": %s", __FILE__, __LINE__, \
|
||||
esyslog("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
|
||||
strerror_r(errno, tmp, sizeof(tmp))); \
|
||||
func; \
|
||||
ret; \
|
||||
@ -86,52 +84,6 @@
|
||||
|
||||
#define ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
class cSatipMemoryBuffer {
|
||||
private:
|
||||
enum {
|
||||
eMaxDataSize = MEGABYTE(2)
|
||||
};
|
||||
char *dataM;
|
||||
size_t sizeM;
|
||||
void *AllocBuffer(void *ptrP, size_t sizeP)
|
||||
{
|
||||
// There might be a realloc() out there that doesn't like reallocing NULL pointers, so we take care of it here
|
||||
if (ptrP)
|
||||
return realloc(ptrP, sizeP);
|
||||
else
|
||||
return malloc(sizeP);
|
||||
}
|
||||
// to prevent copy constructor and assignment
|
||||
cSatipMemoryBuffer(const cSatipMemoryBuffer&);
|
||||
cSatipMemoryBuffer& operator=(const cSatipMemoryBuffer&);
|
||||
public:
|
||||
cSatipMemoryBuffer() : dataM(NULL), sizeM(0) {}
|
||||
~cSatipMemoryBuffer() { Reset(); }
|
||||
size_t Add(char *dataP, size_t sizeP)
|
||||
{
|
||||
if (sizeP > 0) {
|
||||
size_t len = sizeM + sizeP + 1;
|
||||
if (len < eMaxDataSize) {
|
||||
dataM = (char *)AllocBuffer(dataM, len);
|
||||
if (dataM) {
|
||||
memcpy(&(dataM[sizeM]), dataP, sizeP);
|
||||
sizeM += sizeP;
|
||||
dataM[sizeM] = 0;
|
||||
return sizeP;
|
||||
}
|
||||
else
|
||||
esyslog("[%s,%d]: Failed to allocate memory", __FILE__, __LINE__);
|
||||
}
|
||||
else
|
||||
esyslog("[%s,%d]: Buffer overflow", __FILE__, __LINE__);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
char *Data(void) { return dataM; }
|
||||
size_t Size(void) { return sizeM; }
|
||||
void Reset(void) { FREE_POINTER(dataM); sizeM = 0; };
|
||||
};
|
||||
|
||||
uint16_t ts_pid(const uint8_t *bufP);
|
||||
uint8_t payload(const uint8_t *bufP);
|
||||
const char *id_pid(const u_short pidP);
|
||||
|
8
config.c
8
config.c
@ -15,16 +15,10 @@ cSatipConfig::cSatipConfig(void)
|
||||
: operatingModeM(eOperatingModeLow),
|
||||
traceModeM(eTraceModeNormal),
|
||||
ciExtensionM(0),
|
||||
frontendReuseM(1),
|
||||
eitScanM(1),
|
||||
useBytesM(1),
|
||||
portRangeStartM(0),
|
||||
portRangeStopM(0),
|
||||
transportModeM(eTransportModeUnicast),
|
||||
detachedModeM(false),
|
||||
disableServerQuirksM(false),
|
||||
useSingleModelServersM(false),
|
||||
rtpRcvBufSizeM(0)
|
||||
useSingleModelServersM(false)
|
||||
{
|
||||
for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i)
|
||||
cicamsM[i] = 0;
|
||||
|
27
config.h
27
config.h
@ -17,19 +17,13 @@ private:
|
||||
unsigned int operatingModeM;
|
||||
unsigned int traceModeM;
|
||||
unsigned int ciExtensionM;
|
||||
unsigned int frontendReuseM;
|
||||
unsigned int eitScanM;
|
||||
unsigned int useBytesM;
|
||||
unsigned int portRangeStartM;
|
||||
unsigned int portRangeStopM;
|
||||
unsigned int transportModeM;
|
||||
bool detachedModeM;
|
||||
bool disableServerQuirksM;
|
||||
bool useSingleModelServersM;
|
||||
int cicamsM[MAX_CICAM_COUNT];
|
||||
int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT];
|
||||
int disabledFiltersM[SECTION_FILTER_TABLE_SIZE];
|
||||
size_t rtpRcvBufSizeM;
|
||||
|
||||
public:
|
||||
enum eOperatingMode {
|
||||
@ -39,12 +33,6 @@ public:
|
||||
eOperatingModeHigh,
|
||||
eOperatingModeCount
|
||||
};
|
||||
enum eTransportMode {
|
||||
eTransportModeUnicast = 0,
|
||||
eTransportModeMulticast,
|
||||
eTransportModeRtpOverTcp,
|
||||
eTransportModeCount
|
||||
};
|
||||
enum eTraceMode {
|
||||
eTraceModeNormal = 0x0000,
|
||||
eTraceModeDebug1 = 0x0001,
|
||||
@ -75,41 +63,26 @@ public:
|
||||
unsigned int GetTraceMode(void) const { return traceModeM; }
|
||||
bool IsTraceMode(eTraceMode modeP) const { return (traceModeM & modeP); }
|
||||
unsigned int GetCIExtension(void) const { return ciExtensionM; }
|
||||
unsigned int GetFrontendReuse(void) const { return frontendReuseM; }
|
||||
int GetCICAM(unsigned int indexP) const;
|
||||
unsigned int GetEITScan(void) const { return eitScanM; }
|
||||
unsigned int GetUseBytes(void) const { return useBytesM; }
|
||||
unsigned int GetTransportMode(void) const { return transportModeM; }
|
||||
bool IsTransportModeUnicast(void) const { return (transportModeM == eTransportModeUnicast); }
|
||||
bool IsTransportModeRtpOverTcp(void) const { return (transportModeM == eTransportModeRtpOverTcp); }
|
||||
bool IsTransportModeMulticast(void) const { return (transportModeM == eTransportModeMulticast); }
|
||||
bool GetDetachedMode(void) const { return detachedModeM; }
|
||||
bool GetDisableServerQuirks(void) const { return disableServerQuirksM; }
|
||||
bool GetUseSingleModelServers(void) const { return useSingleModelServersM; }
|
||||
unsigned int GetDisabledSourcesCount(void) const;
|
||||
int GetDisabledSources(unsigned int indexP) const;
|
||||
unsigned int GetDisabledFiltersCount(void) const;
|
||||
int GetDisabledFilters(unsigned int indexP) const;
|
||||
unsigned int GetPortRangeStart(void) const { return portRangeStartM; }
|
||||
unsigned int GetPortRangeStop(void) const { return portRangeStopM; }
|
||||
size_t GetRtpRcvBufSize(void) const { return rtpRcvBufSizeM; }
|
||||
|
||||
void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; }
|
||||
void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); }
|
||||
void SetCIExtension(unsigned int onOffP) { ciExtensionM = onOffP; }
|
||||
void SetFrontendReuse(unsigned int onOffP) { frontendReuseM = onOffP; }
|
||||
void SetCICAM(unsigned int indexP, int cicamP);
|
||||
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; }
|
||||
void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; }
|
||||
void SetTransportMode(unsigned int transportModeP) { transportModeM = transportModeP; }
|
||||
void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; }
|
||||
void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; }
|
||||
void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; }
|
||||
void SetDisabledSources(unsigned int indexP, int sourceP);
|
||||
void SetDisabledFilters(unsigned int indexP, int numberP);
|
||||
void SetPortRangeStart(unsigned int rangeStartP) { portRangeStartM = rangeStartP; }
|
||||
void SetPortRangeStop(unsigned int rangeStopP) { portRangeStopM = rangeStopP; }
|
||||
void SetRtpRcvBufSize(size_t sizeP) { rtpRcvBufSizeM = sizeP; }
|
||||
};
|
||||
|
||||
extern cSatipConfig SatipConfig;
|
||||
|
@ -1,98 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
""" Simple tool to detect SAT>IP devices as JSON.
|
||||
"""
|
||||
import json
|
||||
import socket
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
import requests
|
||||
|
||||
SSDP_BIND = "0.0.0.0"
|
||||
SSDP_ADDR = "239.255.255.250"
|
||||
SSDP_PORT = 1900
|
||||
SSDP_MX = 1
|
||||
SSDP_ST = "urn:ses-com:device:SatIPServer:1"
|
||||
SSDP_REQUEST = "\r\n".join(
|
||||
[
|
||||
"M-SEARCH * HTTP/1.1",
|
||||
f"HOST: {SSDP_ADDR}:{SSDP_PORT}",
|
||||
'MAN: "ssdp:discover"',
|
||||
f"MX: {SSDP_MX}",
|
||||
f"ST: {SSDP_ST}",
|
||||
"USER-AGENT: vdr-detectsatip",
|
||||
"\r\n",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def parse_satip_xml(data):
|
||||
"""Parse SAT>IP XML data.
|
||||
|
||||
Args:
|
||||
data (str): XML input data..
|
||||
|
||||
Returns:
|
||||
dict: Parsed SAT>IP device name and frontend information.
|
||||
"""
|
||||
result = {"name": "", "frontends": {}}
|
||||
if data:
|
||||
root = ET.fromstring(data)
|
||||
name = root.find(".//*/{urn:schemas-upnp-org:device-1-0}friendlyName")
|
||||
result["name"] = name.text
|
||||
satipcap = root.find(".//*/{urn:ses-com:satip}X_SATIPCAP")
|
||||
if satipcap is None:
|
||||
# fallback for non-standard Panasonic
|
||||
satipcap = root.find(".//*/{urn-ses-com:satip}X_SATIPCAP")
|
||||
caps = {}
|
||||
for system in satipcap.text.split(","):
|
||||
cap = system.split("-")
|
||||
if cap:
|
||||
count = int(cap[1])
|
||||
if cap[0] in caps:
|
||||
count = count + caps[cap[0]]
|
||||
caps[cap[0]] = count
|
||||
result["frontends"] = caps
|
||||
return result
|
||||
|
||||
|
||||
def detect_satip_devices():
|
||||
"""Detect available SAT>IP devices by sending a broadcast message.
|
||||
|
||||
Returns:
|
||||
list: Found SAT>IP devices.
|
||||
"""
|
||||
urls = []
|
||||
devices = []
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
sock.setblocking(0)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
try:
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
||||
except BaseException:
|
||||
pass
|
||||
sock.settimeout(1)
|
||||
sock.bind((SSDP_BIND, SSDP_PORT))
|
||||
sock.sendto(SSDP_REQUEST.encode("utf-8"), (SSDP_ADDR, SSDP_PORT))
|
||||
try:
|
||||
while 1:
|
||||
data = sock.recv(1024).decode("utf-8")
|
||||
if data:
|
||||
for row in data.split("\r\n"):
|
||||
if "LOCATION:" in row:
|
||||
url = row.replace("LOCATION:", "").strip()
|
||||
if url in urls:
|
||||
continue
|
||||
urls.append(url)
|
||||
info = requests.get(url, timeout=2)
|
||||
devices.append(parse_satip_xml(info.text))
|
||||
else:
|
||||
break
|
||||
except BaseException:
|
||||
pass
|
||||
sock.close()
|
||||
return devices
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
json.dump(detect_satip_devices(), fp=sys.stdout, sort_keys=True, indent=2)
|
129
device.c
129
device.c
@ -15,17 +15,14 @@
|
||||
|
||||
static cSatipDevice * SatipDevicesS[SATIP_MAX_DEVICES] = { NULL };
|
||||
|
||||
cMutex cSatipDevice::mutexS = cMutex();
|
||||
|
||||
cSatipDevice::cSatipDevice(unsigned int indexP)
|
||||
: deviceIndexM(indexP),
|
||||
bytesDeliveredM(0),
|
||||
isPacketDeliveredM(false),
|
||||
isOpenDvrM(false),
|
||||
checkTsBufferM(false),
|
||||
deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)),
|
||||
channelM(),
|
||||
createdM(0),
|
||||
tunedM()
|
||||
mutexM()
|
||||
{
|
||||
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
|
||||
bufsize -= (bufsize % TS_SIZE);
|
||||
@ -45,8 +42,6 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
|
||||
cSatipDevice::~cSatipDevice()
|
||||
{
|
||||
debug1("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
// Release immediately any pending conditional wait
|
||||
tunedM.Broadcast();
|
||||
// Stop section handler
|
||||
StopSectionHandler();
|
||||
DELETE_POINTER(pSectionFilterHandlerM);
|
||||
@ -108,8 +103,7 @@ cString cSatipDevice::GetSatipStatus(void)
|
||||
bool live = (device == cDevice::ActualDevice());
|
||||
bool lock = device->HasLock();
|
||||
const cChannel *channel = device->GetCurrentlyTunedTransponder();
|
||||
LOCK_TIMERS_READ;
|
||||
for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer)) {
|
||||
for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
|
||||
if (timer->Recording()) {
|
||||
cRecordControl *control = cRecordControls::GetRecordControl(timer);
|
||||
if (control && control->Device() == device)
|
||||
@ -121,12 +115,8 @@ cString cSatipDevice::GetSatipStatus(void)
|
||||
info = cString::sprintf("%sCardIndex: %d HasLock: yes Strength: %d Quality: %d%s\n", *info, device->CardIndex(), device->SignalStrength(), device->SignalQuality(), live ? " Live: yes" : "");
|
||||
else
|
||||
info = cString::sprintf("%sCardIndex: %d HasLock: no\n", *info, device->CardIndex());
|
||||
if (channel) {
|
||||
if (channel->Number() > 0 && device->Receiving())
|
||||
info = cString::sprintf("%sTransponder: %d Channel: %s\n", *info, channel->Transponder(), channel->Name());
|
||||
else
|
||||
info = cString::sprintf("%sTransponder: %d\n", *info, channel->Transponder());
|
||||
}
|
||||
if (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);
|
||||
@ -138,14 +128,13 @@ cString cSatipDevice::GetSatipStatus(void)
|
||||
cString cSatipDevice::GetGeneralInformation(void)
|
||||
{
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
LOCK_CHANNELS_READ;
|
||||
return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s\n",
|
||||
return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s",
|
||||
deviceIndexM, CardIndex(),
|
||||
pTunerM ? *pTunerM->GetInformation() : "",
|
||||
pTunerM ? *pTunerM->GetSignalStatus() : "",
|
||||
pTunerM ? *pTunerM->GetTunerStatistic() : "",
|
||||
*GetBufferStatistic(),
|
||||
*Channels->GetByNumber(cDevice::CurrentChannel())->ToText());
|
||||
*Channels.GetByNumber(cDevice::CurrentChannel())->ToText());
|
||||
}
|
||||
|
||||
cString cSatipDevice::GetPidsInformation(void)
|
||||
@ -205,8 +194,6 @@ cString cSatipDevice::DeviceType(void) const
|
||||
cString cSatipDevice::DeviceName(void) const
|
||||
{
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
if (!Receiving())
|
||||
return cString::sprintf("%s %d", *DeviceType(), deviceIndexM);
|
||||
return deviceNameM;
|
||||
}
|
||||
|
||||
@ -216,21 +203,6 @@ bool cSatipDevice::AvoidRecording(void) const
|
||||
return SatipConfig.IsOperatingModeLow();
|
||||
}
|
||||
|
||||
bool cSatipDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
|
||||
{
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
Valid = DTV_STAT_VALID_NONE;
|
||||
if (Strength && pTunerM) {
|
||||
*Strength = pTunerM->SignalStrengthDBm();
|
||||
Valid |= DTV_STAT_VALID_STRENGTH;
|
||||
}
|
||||
if (Status) {
|
||||
*Status = HasLock() ? (DTV_STAT_HAS_SIGNAL | DTV_STAT_HAS_CARRIER | DTV_STAT_HAS_VITERBI | DTV_STAT_HAS_SYNC | DTV_STAT_HAS_LOCK) : DTV_STAT_HAS_NONE;
|
||||
Valid |= DTV_STAT_VALID_STATUS;
|
||||
}
|
||||
return Valid != DTV_STAT_VALID_NONE;
|
||||
}
|
||||
|
||||
int cSatipDevice::SignalStrength(void) const
|
||||
{
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
@ -247,8 +219,6 @@ bool cSatipDevice::ProvidesSource(int sourceP) const
|
||||
{
|
||||
cSource *s = Sources.Get(sourceP);
|
||||
debug9("%s (%c) desc='%s' [device %u]", __PRETTY_FUNCTION__, cSource::ToChar(sourceP), s ? s->Description() : "", deviceIndexM);
|
||||
if (SatipConfig.GetDetachedMode())
|
||||
return false;
|
||||
// source descriptions starting with '0' are disabled
|
||||
if (s && s->Description() && (*(s->Description()) == '0'))
|
||||
return false;
|
||||
@ -295,10 +265,10 @@ bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
result = !!SatipConfig.GetFrontendReuse();
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
needsDetachReceivers = true;
|
||||
needsDetachReceivers = Receiving();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -309,11 +279,7 @@ bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool
|
||||
|
||||
bool cSatipDevice::ProvidesEIT(void) const
|
||||
{
|
||||
#if defined(APIVERSNUM) && APIVERSNUM < 20403
|
||||
return (SatipConfig.GetEITScan());
|
||||
#else
|
||||
return (SatipConfig.GetEITScan()) && DeviceHooksProvidesEIT();
|
||||
#endif
|
||||
}
|
||||
|
||||
int cSatipDevice::NumProvidedSystems(void) const
|
||||
@ -353,7 +319,6 @@ bool cSatipDevice::MaySwitchTransponder(const cChannel *channelP) const
|
||||
|
||||
bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexS); // Global lock to prevent any simultaneous zapping
|
||||
debug9("%s (%d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, liveViewP, deviceIndexM);
|
||||
if (channelP) {
|
||||
cDvbTransponderParameters dtp(channelP->Parameters());
|
||||
@ -363,41 +328,32 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
|
||||
return false;
|
||||
}
|
||||
cString address;
|
||||
cSatipServer *server = cSatipDiscover::GetInstance()->AssignServer(deviceIndexM, channelP->Source(), channelP->Transponder(), dtp.System());
|
||||
cSatipServer *server = cSatipDiscover::GetInstance()->GetServer(channelP->Source(), channelP->Transponder(), dtp.System());
|
||||
if (!server) {
|
||||
debug9("%s No suitable server found [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
return false;
|
||||
}
|
||||
if (pTunerM && pTunerM->SetSource(server, channelP->Transponder(), *params, deviceIndexM)) {
|
||||
cSatipDiscover::GetInstance()->SetTransponder(server, channelP->Transponder());
|
||||
if (pTunerM && pTunerM->SetSource(server, *params, deviceIndexM)) {
|
||||
channelM = *channelP;
|
||||
deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server));
|
||||
// Wait for actual channel tuning to prevent simultaneous frontend allocation failures
|
||||
tunedM.TimedWait(mutexS, eTuningTimeoutMs);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (pTunerM) {
|
||||
pTunerM->SetSource(NULL, 0, NULL, deviceIndexM);
|
||||
deviceNameM = cString::sprintf("%s %d", *DeviceType(), deviceIndexM);
|
||||
pTunerM->SetSource(NULL, NULL, deviceIndexM);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cSatipDevice::SetChannelTuned(void)
|
||||
{
|
||||
debug9("%s () [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
// Release immediately any pending conditional wait
|
||||
tunedM.Broadcast();
|
||||
}
|
||||
|
||||
bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
|
||||
{
|
||||
debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP ? handleP->pid : -1, typeP, onP, deviceIndexM);
|
||||
if (pTunerM && handleP && handleP->pid >= 0 && handleP->pid <= 8191) {
|
||||
debug12("%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);
|
||||
else if (!handleP->used && pSectionFilterHandlerM && !pSectionFilterHandlerM->Exists(handleP->pid))
|
||||
else if (!handleP->used)
|
||||
return pTunerM->SetPid(handleP->pid, typeP, false);
|
||||
}
|
||||
return true;
|
||||
@ -429,7 +385,7 @@ void cSatipDevice::CloseFilter(int handleP)
|
||||
bool cSatipDevice::OpenDvr(void)
|
||||
{
|
||||
debug9("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
bytesDeliveredM = 0;
|
||||
isPacketDeliveredM = false;
|
||||
tsBufferM->Clear();
|
||||
if (pTunerM)
|
||||
pTunerM->Open();
|
||||
@ -448,14 +404,6 @@ void cSatipDevice::CloseDvr(void)
|
||||
bool cSatipDevice::HasLock(int timeoutMsP) const
|
||||
{
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, timeoutMsP, deviceIndexM);
|
||||
if (timeoutMsP > 0) {
|
||||
cTimeMs timer(timeoutMsP);
|
||||
while (!timer.TimedOut()) {
|
||||
if (pTunerM && pTunerM->HasLock())
|
||||
return true;
|
||||
cCondWait::SleepMs(100);
|
||||
}
|
||||
}
|
||||
return (pTunerM && pTunerM->HasLock());
|
||||
}
|
||||
|
||||
@ -486,7 +434,10 @@ int cSatipDevice::GetId(void)
|
||||
|
||||
int cSatipDevice::GetPmtPid(void)
|
||||
{
|
||||
int pid = channelM.Ca() ? ::GetPmtPid(channelM.Source(), channelM.Transponder(), channelM.Sid()) : 0;
|
||||
int pid = 0;
|
||||
#if defined(APIVERSNUM) && APIVERSNUM >= 20107
|
||||
pid = channelM.Ca() ? ::GetPmtPid(channelM.Source(), channelM.Transponder(), channelM.Sid()) : 0;
|
||||
#endif
|
||||
debug11("%s pmtpid=%d source=%c transponder=%d sid=%d name=%s [device %u]", __PRETTY_FUNCTION__, pid, cSource::ToChar(channelM.Source()), channelM.Transponder(), channelM.Sid(), channelM.Name(), deviceIndexM);
|
||||
return pid;
|
||||
}
|
||||
@ -511,29 +462,13 @@ int cSatipDevice::GetCISlot(void)
|
||||
return slot;
|
||||
}
|
||||
|
||||
cString cSatipDevice::GetTnrParameterString(void)
|
||||
{
|
||||
if (channelM.Ca())
|
||||
return GetTnrUrlParameters(&channelM);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cSatipDevice::IsIdle(void)
|
||||
{
|
||||
return !Receiving();
|
||||
}
|
||||
|
||||
uchar *cSatipDevice::GetData(int *availableP, bool checkTsBuffer)
|
||||
uchar *cSatipDevice::GetData(int *availableP)
|
||||
{
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
if (isOpenDvrM && tsBufferM) {
|
||||
int count = 0;
|
||||
if (bytesDeliveredM) {
|
||||
tsBufferM->Del(bytesDeliveredM);
|
||||
bytesDeliveredM = 0;
|
||||
}
|
||||
if (checkTsBuffer && tsBufferM->Available() < TS_SIZE)
|
||||
return NULL;
|
||||
if (isPacketDeliveredM)
|
||||
SkipData(TS_SIZE);
|
||||
uchar *p = tsBufferM->Get(count);
|
||||
if (p && count >= TS_SIZE) {
|
||||
if (*p != TS_SYNC_BYTE) {
|
||||
@ -547,7 +482,7 @@ uchar *cSatipDevice::GetData(int *availableP, bool checkTsBuffer)
|
||||
info("Skipped %d bytes to sync on TS packet", count);
|
||||
return NULL;
|
||||
}
|
||||
bytesDeliveredM = TS_SIZE;
|
||||
isPacketDeliveredM = true;
|
||||
if (availableP)
|
||||
*availableP = count;
|
||||
// Update pid statistics
|
||||
@ -561,7 +496,8 @@ uchar *cSatipDevice::GetData(int *availableP, bool checkTsBuffer)
|
||||
void cSatipDevice::SkipData(int countP)
|
||||
{
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
bytesDeliveredM = countP;
|
||||
tsBufferM->Del(countP);
|
||||
isPacketDeliveredM = false;
|
||||
// Update buffer statistics
|
||||
AddBufferStatistic(countP, tsBufferM->Available());
|
||||
}
|
||||
@ -569,21 +505,20 @@ void cSatipDevice::SkipData(int countP)
|
||||
bool cSatipDevice::GetTSPacket(uchar *&dataP)
|
||||
{
|
||||
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
if (SatipConfig.GetDetachedMode())
|
||||
return false;
|
||||
if (tsBufferM) {
|
||||
#if defined(APIVERSNUM) && APIVERSNUM >= 20104
|
||||
if (cCamSlot *cs = CamSlot()) {
|
||||
if (cs->WantsTsData()) {
|
||||
int available;
|
||||
dataP = GetData(&available, checkTsBufferM);
|
||||
if (!dataP)
|
||||
available = 0;
|
||||
dataP = GetData(&available);
|
||||
if (dataP) {
|
||||
dataP = cs->Decrypt(dataP, available);
|
||||
SkipData(available);
|
||||
checkTsBufferM = dataP != NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
dataP = GetData();
|
||||
return true;
|
||||
}
|
||||
|
20
device.h
20
device.h
@ -18,7 +18,7 @@
|
||||
class cSatipDevice : public cDevice, public cSatipPidStatistics, public cSatipBufferStatistics, public cSatipDeviceIf {
|
||||
// static ones
|
||||
public:
|
||||
static cMutex mutexS;
|
||||
static unsigned int deviceCount;
|
||||
static bool Initialize(unsigned int DeviceCount);
|
||||
static void Shutdown(void);
|
||||
static unsigned int Count(void);
|
||||
@ -28,24 +28,22 @@ public:
|
||||
// private parts
|
||||
private:
|
||||
enum {
|
||||
eReadyTimeoutMs = 2000, // in milliseconds
|
||||
eTuningTimeoutMs = 1000 // in milliseconds
|
||||
eReadyTimeoutMs = 2000 // in milliseconds
|
||||
};
|
||||
unsigned int deviceIndexM;
|
||||
int bytesDeliveredM;
|
||||
bool isPacketDeliveredM;
|
||||
bool isOpenDvrM;
|
||||
bool checkTsBufferM;
|
||||
cString deviceNameM;
|
||||
cChannel channelM;
|
||||
cRingBufferLinear *tsBufferM;
|
||||
cSatipTuner *pTunerM;
|
||||
cSatipSectionFilterHandler *pSectionFilterHandlerM;
|
||||
cTimeMs createdM;
|
||||
cCondVar tunedM;
|
||||
cMutex mutexM;
|
||||
|
||||
// constructor & destructor
|
||||
public:
|
||||
explicit cSatipDevice(unsigned int deviceIndexP);
|
||||
cSatipDevice(unsigned int deviceIndexP);
|
||||
virtual ~cSatipDevice();
|
||||
cString GetInformation(unsigned int pageP = SATIP_DEVICE_INFO_ALL);
|
||||
|
||||
@ -65,7 +63,6 @@ public:
|
||||
virtual cString DeviceType(void) const;
|
||||
virtual cString DeviceName(void) const;
|
||||
virtual bool AvoidRecording(void) const;
|
||||
virtual bool SignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL, int *Status = NULL) const;
|
||||
virtual int SignalStrength(void) const;
|
||||
virtual int SignalQuality(void) const;
|
||||
|
||||
@ -85,7 +82,7 @@ protected:
|
||||
|
||||
// for recording
|
||||
private:
|
||||
uchar *GetData(int *availableP = NULL, bool checkTsBuffer = false);
|
||||
uchar *GetData(int *availableP = NULL);
|
||||
void SkipData(int countP);
|
||||
|
||||
protected:
|
||||
@ -101,7 +98,7 @@ public:
|
||||
|
||||
// for transponder lock
|
||||
public:
|
||||
virtual bool HasLock(int timeoutMsP = 0) const;
|
||||
virtual bool HasLock(int timeoutMsP) const;
|
||||
|
||||
// for common interface
|
||||
public:
|
||||
@ -110,12 +107,9 @@ public:
|
||||
// for internal device interface
|
||||
public:
|
||||
virtual void WriteData(u_char *bufferP, int lengthP);
|
||||
virtual void SetChannelTuned(void);
|
||||
virtual int GetId(void);
|
||||
virtual int GetPmtPid(void);
|
||||
virtual int GetCISlot(void);
|
||||
virtual cString GetTnrParameterString(void);
|
||||
virtual bool IsIdle(void);
|
||||
};
|
||||
|
||||
#endif // __SATIP_DEVICE_H
|
||||
|
@ -13,15 +13,12 @@ public:
|
||||
cSatipDeviceIf() {}
|
||||
virtual ~cSatipDeviceIf() {}
|
||||
virtual void WriteData(u_char *bufferP, int lengthP) = 0;
|
||||
virtual void SetChannelTuned(void) = 0;
|
||||
virtual int GetId(void) = 0;
|
||||
virtual int GetPmtPid(void) = 0;
|
||||
virtual int GetCISlot(void) = 0;
|
||||
virtual cString GetTnrParameterString(void) = 0;
|
||||
virtual bool IsIdle(void) = 0;
|
||||
|
||||
private:
|
||||
explicit cSatipDeviceIf(const cSatipDeviceIf&);
|
||||
cSatipDeviceIf(const cSatipDeviceIf&);
|
||||
cSatipDeviceIf& operator=(const cSatipDeviceIf&);
|
||||
};
|
||||
|
||||
|
206
discover.c
206
discover.c
@ -32,7 +32,7 @@ bool cSatipDiscover::Initialize(cSatipDiscoverServers *serversP)
|
||||
if (instanceS) {
|
||||
if (serversP) {
|
||||
for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s))
|
||||
instanceS->AddServer(s->SrcAddress(), s->IpAddress(), s->IpPort(), s->Model(), s->Filters(), s->Description(), s->Quirk());
|
||||
instanceS->AddServer(s->IpAddress(), s->Model(), s->Description());
|
||||
}
|
||||
else
|
||||
instanceS->Activate();
|
||||
@ -47,26 +47,43 @@ void cSatipDiscover::Destroy(void)
|
||||
instanceS->Deactivate();
|
||||
}
|
||||
|
||||
size_t cSatipDiscover::HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||
size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||
{
|
||||
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
|
||||
size_t len = sizeP * nmembP;
|
||||
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
|
||||
|
||||
if (obj && (len > 0))
|
||||
obj->headerBufferM.Add(ptrP, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t cSatipDiscover::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||
{
|
||||
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
|
||||
size_t len = sizeP * nmembP;
|
||||
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
|
||||
|
||||
if (obj && (len > 0))
|
||||
obj->dataBufferM.Add(ptrP, len);
|
||||
if (obj) {
|
||||
CURLcode res = CURLE_OK;
|
||||
const char *desc = NULL, *model = NULL, *addr = NULL;
|
||||
#ifdef USE_TINYXML
|
||||
TiXmlDocument doc;
|
||||
char *xml = MALLOC(char, len + 1);
|
||||
memcpy(xml, ptrP, len);
|
||||
*(xml + len + 1) = 0;
|
||||
doc.Parse((const char *)xml);
|
||||
TiXmlHandle docHandle(&doc);
|
||||
TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement();
|
||||
if (descElement)
|
||||
desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware";
|
||||
TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement();
|
||||
if (modelElement)
|
||||
model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1";
|
||||
#else
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_buffer(ptrP, len);
|
||||
if (result) {
|
||||
pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName");
|
||||
if (descNode)
|
||||
desc = descNode.text().as_string("MyBrokenHardware");
|
||||
pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP");
|
||||
if (modelNode)
|
||||
model = modelNode.text().as_string("DVBS2-1");
|
||||
}
|
||||
#endif
|
||||
SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr);
|
||||
obj->AddServer(addr, model, desc);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -103,8 +120,6 @@ int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *data
|
||||
cSatipDiscover::cSatipDiscover()
|
||||
: cThread("SATIP discover"),
|
||||
mutexM(),
|
||||
headerBufferM(),
|
||||
dataBufferM(),
|
||||
msearchM(*this),
|
||||
probeUrlListM(),
|
||||
handleM(curl_easy_init()),
|
||||
@ -155,7 +170,7 @@ void cSatipDiscover::Action(void)
|
||||
probeIntervalM.Set(eProbeIntervalMs);
|
||||
msearchM.Probe();
|
||||
mutexM.Lock();
|
||||
serversM.Cleanup(eCleanupTimeoutMs);
|
||||
serversM.Cleanup(eProbeIntervalMs * 2);
|
||||
mutexM.Unlock();
|
||||
}
|
||||
mutexM.Lock();
|
||||
@ -180,7 +195,6 @@ void cSatipDiscover::Fetch(const char *urlP)
|
||||
{
|
||||
debug1("%s (%s)", __PRETTY_FUNCTION__, urlP);
|
||||
if (handleM && !isempty(urlP)) {
|
||||
const char *addr = NULL;
|
||||
long rc = 0;
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
@ -189,10 +203,8 @@ void cSatipDiscover::Fetch(const char *urlP)
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this);
|
||||
|
||||
// Set header and data callbacks
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipDiscover::HeaderCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::DataCallback);
|
||||
// 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
|
||||
@ -212,82 +224,25 @@ void cSatipDiscover::Fetch(const char *urlP)
|
||||
// Fetch the data
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_PRIMARY_IP, &addr);
|
||||
if (rc == 200) {
|
||||
ParseDeviceInfo(addr, ParseRtspPort());
|
||||
headerBufferM.Reset();
|
||||
dataBufferM.Reset();
|
||||
}
|
||||
else
|
||||
if (rc != 200)
|
||||
error("Discovery detected invalid status code: %ld", rc);
|
||||
}
|
||||
}
|
||||
|
||||
int cSatipDiscover::ParseRtspPort(void)
|
||||
void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char * descP)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
char *s, *p = headerBufferM.Data();
|
||||
char *r = strtok_r(p, "\r\n", &s);
|
||||
int port = SATIP_DEFAULT_RTSP_PORT;
|
||||
|
||||
while (r) {
|
||||
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r);
|
||||
r = skipspace(r);
|
||||
if (strstr(r, "X-SATIP-RTSP-Port")) {
|
||||
int tmp = -1;
|
||||
if (sscanf(r, "X-SATIP-RTSP-Port:%11d", &tmp) == 1) {
|
||||
port = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
r = strtok_r(NULL, "\r\n", &s);
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
void cSatipDiscover::ParseDeviceInfo(const char *addrP, const int portP)
|
||||
{
|
||||
debug1("%s (%s, %d)", __PRETTY_FUNCTION__, addrP, portP);
|
||||
const char *desc = NULL, *model = NULL;
|
||||
#ifdef USE_TINYXML
|
||||
TiXmlDocument doc;
|
||||
doc.Parse(dataBufferM.Data());
|
||||
TiXmlHandle docHandle(&doc);
|
||||
TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement();
|
||||
if (descElement)
|
||||
desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware";
|
||||
TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement();
|
||||
if (modelElement)
|
||||
model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1";
|
||||
#else
|
||||
pugi::xml_document doc;
|
||||
if (doc.load_buffer(dataBufferM.Data(), dataBufferM.Size())) {
|
||||
pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName");
|
||||
if (descNode)
|
||||
desc = descNode.text().as_string("MyBrokenHardware");
|
||||
pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP");
|
||||
if (modelNode)
|
||||
model = modelNode.text().as_string("DVBS2-1");
|
||||
}
|
||||
#endif
|
||||
AddServer(NULL, addrP, portP, model, NULL, desc, cSatipServer::eSatipQuirkNone);
|
||||
}
|
||||
|
||||
void cSatipDiscover::AddServer(const char *srcAddrP, const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP)
|
||||
{
|
||||
debug1("%s (%s, %s, %d, %s, %s, %s, %d)", __PRETTY_FUNCTION__, srcAddrP, addrP, portP, modelP, filtersP, descP, quirkP);
|
||||
debug1("%s (%s, %s, %s)", __PRETTY_FUNCTION__, addrP, modelP, descP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (SatipConfig.GetUseSingleModelServers() && modelP && !isempty(modelP)) {
|
||||
if (SatipConfig.GetUseSingleModelServers()) {
|
||||
int n = 0;
|
||||
char *s, *p = strdup(modelP);
|
||||
char *r = strtok_r(p, ",", &s);
|
||||
while (r) {
|
||||
r = skipspace(r);
|
||||
cString desc = cString::sprintf("%s #%d", !isempty(descP) ? descP : "MyBrokenHardware", n++);
|
||||
cSatipServer *tmp = new cSatipServer(srcAddrP, addrP, portP, r, filtersP, desc, quirkP);
|
||||
cSatipServer *tmp = new cSatipServer(addrP, r, desc);
|
||||
if (!serversM.Update(tmp)) {
|
||||
info("Adding server '%s|%s|%s' Bind: %s Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->SrcAddress()) ? tmp->SrcAddress() : "default", !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
|
||||
info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
|
||||
serversM.Add(tmp);
|
||||
}
|
||||
else
|
||||
@ -297,9 +252,9 @@ void cSatipDiscover::AddServer(const char *srcAddrP, const char *addrP, const in
|
||||
FREE_POINTER(p);
|
||||
}
|
||||
else {
|
||||
cSatipServer *tmp = new cSatipServer(srcAddrP, addrP, portP, modelP, filtersP, descP, quirkP);
|
||||
cSatipServer *tmp = new cSatipServer(addrP, modelP, descP);
|
||||
if (!serversM.Update(tmp)) {
|
||||
info("Adding server '%s|%s|%s' Bind: %s Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->SrcAddress()) ? tmp->SrcAddress() : "default", !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
|
||||
info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
|
||||
serversM.Add(tmp);
|
||||
}
|
||||
else
|
||||
@ -314,18 +269,11 @@ int cSatipDiscover::GetServerCount(void)
|
||||
return serversM.Count();
|
||||
}
|
||||
|
||||
cSatipServer *cSatipDiscover::AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP)
|
||||
cSatipServer *cSatipDiscover::GetServer(int sourceP, int transponderP, int systemP)
|
||||
{
|
||||
debug16("%s (%d, %d, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, sourceP, transponderP, systemP);
|
||||
debug16("%s (%d, %d, %d)", __PRETTY_FUNCTION__, sourceP, transponderP, systemP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM.Assign(deviceIdP, sourceP, transponderP, systemP);
|
||||
}
|
||||
|
||||
cSatipServer *cSatipDiscover::GetServer(int sourceP)
|
||||
{
|
||||
debug16("%s (%d)", __PRETTY_FUNCTION__, sourceP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM.Find(sourceP);
|
||||
return serversM.Find(sourceP, transponderP, systemP);
|
||||
}
|
||||
|
||||
cSatipServer *cSatipDiscover::GetServer(cSatipServer *serverP)
|
||||
@ -356,60 +304,18 @@ cString cSatipDiscover::GetServerList(void)
|
||||
return serversM.List();
|
||||
}
|
||||
|
||||
void cSatipDiscover::ActivateServer(cSatipServer *serverP, bool onOffP)
|
||||
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)
|
||||
{
|
||||
debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
serversM.Activate(serverP, onOffP);
|
||||
}
|
||||
|
||||
void cSatipDiscover::AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP)
|
||||
{
|
||||
debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
serversM.Attach(serverP, deviceIdP, transponderP);
|
||||
}
|
||||
|
||||
void cSatipDiscover::DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP)
|
||||
{
|
||||
debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
serversM.Detach(serverP, deviceIdP, transponderP);
|
||||
}
|
||||
|
||||
bool cSatipDiscover::IsServerQuirk(cSatipServer *serverP, int quirkP)
|
||||
{
|
||||
debug16("%s (, %d)", __PRETTY_FUNCTION__, quirkP);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM.IsQuirk(serverP, quirkP);
|
||||
}
|
||||
|
||||
bool cSatipDiscover::HasServerCI(cSatipServer *serverP)
|
||||
{
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM.HasCI(serverP);
|
||||
}
|
||||
|
||||
cString cSatipDiscover::GetSourceAddress(cSatipServer *serverP)
|
||||
{
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM.GetSrcAddress(serverP);
|
||||
}
|
||||
|
||||
cString cSatipDiscover::GetServerAddress(cSatipServer *serverP)
|
||||
{
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM.GetAddress(serverP);
|
||||
}
|
||||
|
||||
int cSatipDiscover::GetServerPort(cSatipServer *serverP)
|
||||
{
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
return serversM.GetPort(serverP);
|
||||
serversM.Use(serverP, onOffP);
|
||||
}
|
||||
|
||||
int cSatipDiscover::NumProvidedSystems(void)
|
||||
|
38
discover.h
38
discover.h
@ -13,7 +13,6 @@
|
||||
#include <vdr/thread.h>
|
||||
#include <vdr/tools.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "discoverif.h"
|
||||
#include "msearch.h"
|
||||
#include "server.h"
|
||||
@ -21,24 +20,16 @@
|
||||
|
||||
class cSatipDiscoverServer : public cListObject {
|
||||
private:
|
||||
int ipPortM;
|
||||
int quirkM;
|
||||
cString srcAddressM;
|
||||
cString ipAddressM;
|
||||
cString descriptionM;
|
||||
cString modelM;
|
||||
cString filtersM;
|
||||
public:
|
||||
cSatipDiscoverServer(const char *srcAddressP, const char *ipAddressP, const int ipPortP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP)
|
||||
cSatipDiscoverServer(const char *ipAddressP, const char *modelP, const char *descriptionP)
|
||||
{
|
||||
srcAddressM = srcAddressP; ipAddressM = ipAddressP; ipPortM = ipPortP; modelM = modelP; filtersM = filtersP; descriptionM = descriptionP; quirkM = quirkP;
|
||||
ipAddressM = ipAddressP; modelM = modelP; descriptionM = descriptionP;
|
||||
}
|
||||
int IpPort(void) { return ipPortM; }
|
||||
int Quirk(void) { return quirkM; }
|
||||
const char *SrcAddress(void) { return *srcAddressM; }
|
||||
const char *IpAddress(void) { return *ipAddressM; }
|
||||
const char *Model(void) { return *modelM; }
|
||||
const char *Filters(void) { return *filtersM; }
|
||||
const char *Description(void) { return *descriptionM; }
|
||||
};
|
||||
|
||||
@ -51,16 +42,12 @@ private:
|
||||
eSleepTimeoutMs = 500, // in milliseconds
|
||||
eConnectTimeoutMs = 1500, // in milliseconds
|
||||
eProbeTimeoutMs = 2000, // in milliseconds
|
||||
eProbeIntervalMs = 60000, // in milliseconds
|
||||
eCleanupTimeoutMs = 124000 // in milliseoonds
|
||||
eProbeIntervalMs = 60000 // in milliseconds
|
||||
};
|
||||
static cSatipDiscover *instanceS;
|
||||
static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
||||
static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
||||
static 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;
|
||||
cSatipMemoryBuffer headerBufferM;
|
||||
cSatipMemoryBuffer dataBufferM;
|
||||
cSatipMsearch msearchM;
|
||||
cStringList probeUrlListM;
|
||||
CURL *handleM;
|
||||
@ -69,9 +56,7 @@ private:
|
||||
cSatipServers serversM;
|
||||
void Activate(void);
|
||||
void Deactivate(void);
|
||||
int ParseRtspPort(void);
|
||||
void ParseDeviceInfo(const char *addrP, const int portP);
|
||||
void AddServer(const char *srcAddrP, const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP);
|
||||
void AddServer(const char *addrP, const char *modelP, const char *descP);
|
||||
void Fetch(const char *urlP);
|
||||
// constructor
|
||||
cSatipDiscover();
|
||||
@ -89,19 +74,12 @@ public:
|
||||
virtual ~cSatipDiscover();
|
||||
void TriggerScan(void) { probeIntervalM.Set(0); }
|
||||
int GetServerCount(void);
|
||||
cSatipServer *AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP);
|
||||
cSatipServer *GetServer(int sourceP);
|
||||
cSatipServer *GetServer(int sourceP, int transponderP = 0, int systemP = -1);
|
||||
cSatipServer *GetServer(cSatipServer *serverP);
|
||||
cSatipServers *GetServers(void);
|
||||
cString GetServerString(cSatipServer *serverP);
|
||||
void ActivateServer(cSatipServer *serverP, bool onOffP);
|
||||
void AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP);
|
||||
void DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP);
|
||||
bool IsServerQuirk(cSatipServer *serverP, int quirkP);
|
||||
bool HasServerCI(cSatipServer *serverP);
|
||||
cString GetServerAddress(cSatipServer *serverP);
|
||||
cString GetSourceAddress(cSatipServer *serverP);
|
||||
int GetServerPort(cSatipServer *serverP);
|
||||
void SetTransponder(cSatipServer *serverP, int transponderP);
|
||||
void UseServer(cSatipServer *serverP, bool onOffP);
|
||||
cString GetServerList(void);
|
||||
int NumProvidedSystems(void);
|
||||
|
||||
|
@ -15,7 +15,7 @@ public:
|
||||
virtual void SetUrl(const char *urlP) = 0;
|
||||
|
||||
private:
|
||||
explicit cSatipDiscoverIf(const cSatipDiscoverIf&);
|
||||
cSatipDiscoverIf(const cSatipDiscoverIf&);
|
||||
cSatipDiscoverIf& operator=(const cSatipDiscoverIf&);
|
||||
};
|
||||
|
||||
|
5
log.h
5
log.h
@ -34,9 +34,9 @@
|
||||
#define debug10(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug10) ? dsyslog("SATIP10: " x) : void() )
|
||||
// 0x0400: CI
|
||||
#define debug11(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug11) ? dsyslog("SATIP11: " x) : void() )
|
||||
// 0x0800: Pids
|
||||
// 0x0800: Discovery
|
||||
#define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() )
|
||||
// 0x1000: Discovery
|
||||
// 0x1000: Pids
|
||||
#define debug13(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug13) ? dsyslog("SATIP13: " x) : void() )
|
||||
// 0x2000: TBD
|
||||
#define debug14(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug14) ? dsyslog("SATIP14: " x) : void() )
|
||||
@ -46,3 +46,4 @@
|
||||
#define debug16(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug16) ? dsyslog("SATIP16: " x) : void() )
|
||||
|
||||
#endif // __SATIP_LOG_H
|
||||
|
||||
|
21
msearch.c
21
msearch.c
@ -29,13 +29,12 @@ cSatipMsearch::cSatipMsearch(cSatipDiscoverIf &discoverP)
|
||||
memset(bufferM, 0, bufferLenM);
|
||||
else
|
||||
error("Cannot create Msearch buffer!");
|
||||
if (!Open(eDiscoveryPort, true))
|
||||
if (!Open(eDiscoveryPort))
|
||||
error("Cannot open Msearch port!");
|
||||
}
|
||||
|
||||
cSatipMsearch::~cSatipMsearch()
|
||||
{
|
||||
FREE_POINTER(bufferM);
|
||||
}
|
||||
|
||||
void cSatipMsearch::Probe(void)
|
||||
@ -45,9 +44,6 @@ void cSatipMsearch::Probe(void)
|
||||
cSatipPoller::GetInstance()->Register(*this);
|
||||
registeredM = true;
|
||||
}
|
||||
// Send two queries with one second interval
|
||||
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
|
||||
cCondWait::SleepMs(1000);
|
||||
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
|
||||
}
|
||||
|
||||
@ -63,12 +59,12 @@ void cSatipMsearch::Process(void)
|
||||
int length;
|
||||
while ((length = Read(bufferM, bufferLenM)) > 0) {
|
||||
bufferM[min(length, int(bufferLenM - 1))] = 0;
|
||||
debug13("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM);
|
||||
debug12("%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) {
|
||||
debug13("%s r=%s", __PRETTY_FUNCTION__, r);
|
||||
debug12("%s r=%s", __PRETTY_FUNCTION__, r);
|
||||
// Check the status code
|
||||
// HTTP/1.1 200 OK
|
||||
if (!status && startswith(r, "HTTP/1.1 200 OK"))
|
||||
@ -76,13 +72,13 @@ void cSatipMsearch::Process(void)
|
||||
if (status) {
|
||||
// Check the location data
|
||||
// LOCATION: http://192.168.0.115:8888/octonet.xml
|
||||
if (strcasestr(r, "LOCATION:") == r) {
|
||||
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 (strcasestr(r, "ST:") == r) {
|
||||
else if (startswith(r, "ST:")) {
|
||||
char *st = compactspace(r + 3);
|
||||
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
|
||||
valid = true;
|
||||
@ -97,14 +93,11 @@ void cSatipMsearch::Process(void)
|
||||
r = strtok_r(NULL, "\r\n", &s);
|
||||
}
|
||||
}
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
error("Error %d reading in %s", errno, *ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipMsearch::Process(unsigned char *dataP, int lengthP)
|
||||
{
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
}
|
||||
|
||||
cString cSatipMsearch::ToString(void) const
|
||||
{
|
||||
return "MSearch";
|
||||
|
@ -26,7 +26,7 @@ private:
|
||||
bool registeredM;
|
||||
|
||||
public:
|
||||
explicit cSatipMsearch(cSatipDiscoverIf &discoverP);
|
||||
cSatipMsearch(cSatipDiscoverIf &discoverP);
|
||||
virtual ~cSatipMsearch();
|
||||
void Probe(void);
|
||||
|
||||
@ -34,7 +34,6 @@ public:
|
||||
public:
|
||||
virtual int GetFd(void);
|
||||
virtual void Process(void);
|
||||
virtual void Process(unsigned char *dataP, int lengthP);
|
||||
virtual cString ToString(void) const;
|
||||
};
|
||||
|
||||
|
387
param.c
387
param.c
@ -59,10 +59,6 @@ static const tSatipParameterMap SatipCodeRateValues[] = {
|
||||
static const tSatipParameterMap SatipModulationValues[] = {
|
||||
{ QPSK, "&mtype=qpsk" },
|
||||
{ PSK_8, "&mtype=8psk" },
|
||||
{ APSK_16, "&mtype=16apsk" },
|
||||
{ APSK_32, "&mtype=32apsk" },
|
||||
{ VSB_8, "&mtype=8vsb" },
|
||||
{ VSB_16, "&mtype=16vsb" },
|
||||
{ QAM_16, "&mtype=16qam" },
|
||||
{ QAM_64, "&mtype=64qam" },
|
||||
{ QAM_128, "&mtype=128qam" },
|
||||
@ -89,11 +85,6 @@ static const tSatipParameterMap SatipSystemValuesCable[] = {
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipSystemValuesAtsc[] = {
|
||||
{ 0, "&msys=atsc" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
static const tSatipParameterMap SatipTransmissionValues[] = {
|
||||
{ TRANSMISSION_MODE_1K, "&tmode=1k" },
|
||||
{ TRANSMISSION_MODE_2K, "&tmode=2k" },
|
||||
@ -156,6 +147,15 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
|
||||
cDvbTransponderParameters dtp(channelP->Parameters());
|
||||
int DataSlice = 0;
|
||||
int C2TuningFrequencyType = 0;
|
||||
#if defined(APIVERSNUM) && APIVERSNUM < 20106
|
||||
int Pilot = PILOT_AUTO;
|
||||
int T2SystemId = 0;
|
||||
int SisoMiso = 0;
|
||||
#else
|
||||
int Pilot = dtp.Pilot();
|
||||
int T2SystemId = dtp.T2SystemId();
|
||||
int SisoMiso = dtp.SisoMiso();
|
||||
#endif
|
||||
float freq = channelP->Frequency();
|
||||
char type = cSource::ToChar(channelP->Source());
|
||||
cSource *source = Sources.Get(channelP->Source());
|
||||
@ -167,353 +167,34 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
|
||||
freq /= 1000L;
|
||||
#define ST(s) if (strchr(s, type) && (strchr(s, '0' + dtp.System() + 1) || strchr(s, '*')))
|
||||
#define STBUFLEFT (sizeof(buffer) - (q - buffer))
|
||||
ST(" S 1") { // to comply with SAT>IP protocol specification 1.2.2
|
||||
dtp.SetPilot(PILOT_OFF);
|
||||
dtp.SetModulation(QPSK);
|
||||
dtp.SetRollOff(ROLLOFF_35);
|
||||
}
|
||||
q += snprintf(q, STBUFLEFT, "freq=%s", *dtoa(freq, "%lg"));
|
||||
ST(" S *") q += snprintf(q, STBUFLEFT, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1);
|
||||
ST(" S *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
|
||||
ST("C 1") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
|
||||
ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization()));
|
||||
ST("C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId());
|
||||
ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", T2SystemId);
|
||||
ST("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(" 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() % 100) > 0)
|
||||
q += snprintf(q, STBUFLEFT, "&fe=%d", channelP->Rid() % 100);
|
||||
ST(" S *") q += snprintf(q, STBUFLEFT, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1);
|
||||
if (freq >= 0L)
|
||||
q += snprintf(q, STBUFLEFT, "&freq=%s", *dtoa(freq, "%lg"));
|
||||
ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization()));
|
||||
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues);
|
||||
ST(" C 2") q += snprintf(q, STBUFLEFT, "&c2tft=%d", C2TuningFrequencyType);
|
||||
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues);
|
||||
ST(" C 2") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues);
|
||||
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("A *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesAtsc);
|
||||
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues);
|
||||
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
||||
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
||||
ST(" C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
||||
ST("A *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
||||
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Pilot(), SatipPilotValues);
|
||||
ST(" S *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
|
||||
ST(" C 1") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
|
||||
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(), SatipGuardValues);
|
||||
ST(" CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(), SatipCodeRateValues);
|
||||
ST(" C 2") q += snprintf(q, STBUFLEFT, "&ds=%d", DataSlice);
|
||||
ST(" C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId());
|
||||
ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", dtp.T2SystemId());
|
||||
ST(" T2") q += PrintUrlString(q, STBUFLEFT, dtp.SisoMiso(), SatipSisoMisoValues);
|
||||
ST(" C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues);
|
||||
ST("A *") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues);
|
||||
#undef ST
|
||||
return &buffer[1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cString GetTnrUrlParameters(const cChannel *channelP)
|
||||
{
|
||||
if (channelP) {
|
||||
cDvbTransponderParameters dtp(channelP->Parameters());
|
||||
eTrackType track = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
|
||||
|
||||
// TunerType: Byte;
|
||||
// 0 = cable, 1 = satellite, 2 = terrestrial, 3 = atsc, 4 = iptv, 5 = stream (URL, DVBViewer GE)
|
||||
int TunerType = 0;
|
||||
if (channelP->IsCable())
|
||||
TunerType = 0;
|
||||
else if (channelP->IsSat())
|
||||
TunerType = 1;
|
||||
else if (channelP->IsTerr())
|
||||
TunerType = 2;
|
||||
else if (channelP->IsAtsc())
|
||||
TunerType = 3;
|
||||
|
||||
// Frequency: DWord;
|
||||
// DVB-S: MHz if < 1000000, kHz if >= 1000000
|
||||
// DVB-T/C, ATSC: kHz
|
||||
// IPTV: IP address Byte3.Byte2.Byte1.Byte0
|
||||
int Frequency = channelP->Frequency() / 1000;
|
||||
|
||||
// Symbolrate: DWord;
|
||||
// DVB S/C: in kSym/s
|
||||
// DVB-T, ATSC: 0
|
||||
// IPTV: Port
|
||||
int Symbolrate = (channelP->IsSat() || channelP->IsCable()) ? channelP->Srate() : 0;
|
||||
|
||||
// LNB_LOF: Word;
|
||||
// DVB-S: Local oscillator frequency of the LNB
|
||||
// DVB-T/C, ATSC: 0
|
||||
// IPTV: Byte0 and Byte1 of Source IP
|
||||
int LNB_LOF = channelP->IsSat() ? Setup.LnbSLOF : 0;
|
||||
|
||||
// Tone: Byte;
|
||||
// 0 = off, 1 = 22 khz
|
||||
int Tone = (channelP->Frequency() < Setup.LnbSLOF) ? 0 : 1;
|
||||
|
||||
// Polarity: Byte;
|
||||
// DVB-S polarity: 0 = horizontal, 1 = vertical, 2 = circular left, 3 = circular right
|
||||
// DVB-C modulation: 0 = Auto, 1 = 16QAM, 2 = 32QAM, 3 = 64QAM, 4 = 128QAM, 5 = 256 QAM
|
||||
// DVB-T bandwidth: 0 = 6 MHz, 1 = 7 MHz, 2 = 8 MHz
|
||||
// IPTV: Byte3 of SourceIP
|
||||
int Polarity = 0;
|
||||
if (channelP->IsSat()) {
|
||||
switch (tolower(dtp.Polarization())) {
|
||||
case 'h':
|
||||
Polarity = 0;
|
||||
break;
|
||||
case 'v':
|
||||
Polarity = 1;
|
||||
break;
|
||||
case 'l':
|
||||
Polarity = 2;
|
||||
break;
|
||||
case 'r':
|
||||
Polarity = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (channelP->IsCable()) {
|
||||
switch (dtp.Modulation()) {
|
||||
case 999:
|
||||
Polarity = 0;
|
||||
break;
|
||||
case 16:
|
||||
Polarity = 1;
|
||||
break;
|
||||
case 32:
|
||||
Polarity = 2;
|
||||
break;
|
||||
case 64:
|
||||
Polarity = 3;
|
||||
break;
|
||||
case 128:
|
||||
Polarity = 4;
|
||||
break;
|
||||
case 256:
|
||||
Polarity = 5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (channelP->IsTerr()) {
|
||||
switch (dtp.Bandwidth()) {
|
||||
case 6:
|
||||
Polarity = 0;
|
||||
break;
|
||||
case 7:
|
||||
Polarity = 1;
|
||||
break;
|
||||
case 8:
|
||||
Polarity = 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// DiSEqC: Byte;
|
||||
// 0 = None
|
||||
// 1 = Pos A (mostly translated to PosA/OptA)
|
||||
// 2 = Pos B (mostly translated to PosB/OptA)
|
||||
// 3 = PosA/OptA
|
||||
// 4 = PosB/OptA
|
||||
// 5 = PosA/OptB
|
||||
// 6 = PosB/OptB
|
||||
// 7 = Preset Position (DiSEqC 1.2, see DiSEqCExt)
|
||||
// 8 = Angular Position (DiSEqC 1.2, see DiSEqCExt)
|
||||
// 9 = DiSEqC Command Sequence (see DiSEqCExt)
|
||||
int DiSEqC = 0;
|
||||
|
||||
// FEC: Byte;
|
||||
// 0 = Auto
|
||||
// 1 = 1/2
|
||||
// 2 = 2/3
|
||||
// 3 = 3/4
|
||||
// 4 = 5/6
|
||||
// 5 = 7/8
|
||||
// 6 = 8/9
|
||||
// 7 = 3/5
|
||||
// 8 = 4/5
|
||||
// 9 = 9/10
|
||||
// IPTV: Byte2 of SourceIP
|
||||
// DVB C/T, ATSC: 0
|
||||
int FEC = 0;
|
||||
if (channelP->IsSat()) {
|
||||
switch (dtp.CoderateH()) {
|
||||
case 999:
|
||||
FEC = 0;
|
||||
break;
|
||||
case 12:
|
||||
FEC = 1;
|
||||
break;
|
||||
case 23:
|
||||
FEC = 2;
|
||||
break;
|
||||
case 34:
|
||||
FEC = 3;
|
||||
break;
|
||||
case 56:
|
||||
FEC = 4;
|
||||
break;
|
||||
case 78:
|
||||
FEC = 5;
|
||||
break;
|
||||
case 89:
|
||||
FEC = 6;
|
||||
break;
|
||||
case 35:
|
||||
FEC = 7;
|
||||
break;
|
||||
case 45:
|
||||
FEC = 8;
|
||||
break;
|
||||
case 910:
|
||||
FEC = 9;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Audio_PID: Word;
|
||||
int Audio_PID = channelP->Apid(0);
|
||||
if (IS_AUDIO_TRACK(track))
|
||||
Audio_PID = channelP->Apid(int(track - ttAudioFirst));
|
||||
else if (IS_DOLBY_TRACK(track))
|
||||
Audio_PID = channelP->Dpid(int(track - ttDolbyFirst));
|
||||
|
||||
// Video_PID: Word;
|
||||
int Video_PID = channelP->Vpid();
|
||||
|
||||
// PMT_PID: Word;
|
||||
int PMT_PID = channelP->Ppid();
|
||||
|
||||
// Service_ID: Word;
|
||||
int Service_ID = channelP->Sid();
|
||||
|
||||
// SatModulation: Byte;
|
||||
// Bit 0..1: satellite modulation. 0 = Auto, 1 = QPSK, 2 = 8PSK, 3 = 16QAM or APSK for DVB-S2
|
||||
// Bit 2: modulation system. 0 = DVB-S/T/C, 1 = DVB-S2/T2/C2
|
||||
// Bit 3..4: DVB-S2: roll-off. 0 = 0.35, 1 = 0.25, 2 = 0.20, 3 = reserved
|
||||
// Bit 5..6: spectral inversion, 0 = undefined, 1 = auto, 2 = normal, 3 = inverted
|
||||
// Bit 7: DVB-S2: pilot symbols, 0 = off, 1 = on
|
||||
// DVB-T2: DVB-T2 Lite, 0 = off, 1 = on
|
||||
int SatModulation = 0;
|
||||
if (channelP->IsSat() && dtp.System()) {
|
||||
switch (dtp.Modulation()) {
|
||||
case 999:
|
||||
SatModulation |= (0 & 0x3) << 0;
|
||||
break;
|
||||
case 2:
|
||||
SatModulation |= (1 & 0x3) << 0;
|
||||
break;
|
||||
case 5:
|
||||
SatModulation |= (2 & 0x3) << 0;
|
||||
break;
|
||||
case 6:
|
||||
SatModulation |= (3 & 0x3) << 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
SatModulation |= (dtp.System() & 0x1) << 2;
|
||||
if (channelP->IsSat() && dtp.System()) {
|
||||
switch (dtp.RollOff()) {
|
||||
case 35:
|
||||
SatModulation |= (0 & 0x3) << 3;
|
||||
break;
|
||||
case 25:
|
||||
SatModulation |= (1 & 0x3) << 3;
|
||||
break;
|
||||
case 20:
|
||||
SatModulation |= (2 & 0x3) << 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (dtp.Inversion()) {
|
||||
case 999:
|
||||
SatModulation |= (1 & 0x3) << 5;
|
||||
break;
|
||||
case 0:
|
||||
SatModulation |= (2 & 0x3) << 5;
|
||||
break;
|
||||
case 1:
|
||||
SatModulation |= (3 & 0x3) << 5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (channelP->IsSat() && dtp.System()) {
|
||||
switch (dtp.Pilot()) {
|
||||
case 0:
|
||||
SatModulation |= (0 & 0x1) << 7;
|
||||
break;
|
||||
case 1:
|
||||
SatModulation |= (1 & 0x1) << 7;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// DiSEqCExt: Word;
|
||||
// DiSEqC Extension, meaning depends on DiSEqC
|
||||
// DiSEqC = 0..6: 0
|
||||
// DiSEqC = 7: Preset Position (DiSEqC 1.2)
|
||||
// DiSEqC = 8: Orbital Position (DiSEqC 1.2, USALS, for calculating motor angle)
|
||||
// Same format as OrbitalPos above
|
||||
// DiSEQC = 9: Orbital Position referencing DiSEqC sequence defined in DiSEqC.xml/ini
|
||||
// Same format as OrbitalPos above
|
||||
int DiSEqCExt = 0;
|
||||
|
||||
// Flags: Byte;
|
||||
// Bit 0: 1 = encrypted channel
|
||||
// Bit 1: reserved, set to 0
|
||||
// Bit 2: 1 = channel broadcasts RDS data
|
||||
// Bit 3: 1 = channel is a video service (even if the Video PID is temporarily = 0)
|
||||
// Bit 4: 1 = channel is an audio service (even if the Audio PID is temporarily = 0)
|
||||
// Bit 5: 1 = audio has a different samplerate than 48 KHz
|
||||
// Bit 6: 1 = bandstacking, internally polarisation is always set to H
|
||||
// Bit 7: 1 = channel entry is an additional audio track of the preceding
|
||||
// channel with bit 7 = 0
|
||||
int Flags = (channelP->Ca() > 0xFF) ? 1 : 0;
|
||||
|
||||
// ChannelGroup: Byte;
|
||||
// 0 = Group A, 1 = Group B, 2 = Group C etc.
|
||||
int ChannelGroup = 0;
|
||||
|
||||
// TransportStream_ID: Word;
|
||||
int TransportStream_ID = channelP->Tid();
|
||||
|
||||
// OriginalNetwork_ID: Word;
|
||||
int OriginalNetwork_ID = channelP->Nid();
|
||||
|
||||
// Substream: Word;
|
||||
// DVB-S/C/T, ATSC, IPTV: 0
|
||||
// DVB-T2: 0 = PLP_ID not set, 1..256: PLP_ID + 1, 257... reserved
|
||||
int Substream = (channelP->IsTerr() && dtp.System()) ? dtp.StreamId() - 1 : 0;
|
||||
|
||||
// OrbitalPos: Word;
|
||||
// DVB-S: orbital position x 10, 0 = undefined, 1..1800 east, 1801..3599 west (1°W = 3599)
|
||||
// DVB-C: 4000..4999
|
||||
// DVB-T: 5000..5999
|
||||
// ATSC: 6000..6999
|
||||
// IPTV: 7000..7999
|
||||
// Stream: 8000..8999
|
||||
int OrbitalPos = 0;
|
||||
if (channelP->IsSat()) {
|
||||
OrbitalPos = cSource::Position(channelP->Source());
|
||||
if (OrbitalPos != 3600)
|
||||
OrbitalPos += 1800;
|
||||
}
|
||||
|
||||
return cString::sprintf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
|
||||
TunerType, Frequency, Symbolrate, LNB_LOF, Tone, Polarity, DiSEqC, FEC, Audio_PID, Video_PID, PMT_PID, Service_ID,
|
||||
SatModulation, DiSEqCExt, Flags, ChannelGroup, TransportStream_ID, OriginalNetwork_ID, Substream, OrbitalPos);
|
||||
return buffer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
1
param.h
1
param.h
@ -11,6 +11,5 @@
|
||||
#include "common.h"
|
||||
|
||||
cString GetTransponderUrlParameters(const cChannel *channelP);
|
||||
cString GetTnrUrlParameters(const cChannel *channelP);
|
||||
|
||||
#endif // __SATIP_PARAM_H
|
||||
|
34
po/ca_ES.po
34
po/ca_ES.po
@ -1,14 +1,14 @@
|
||||
# VDR plugin language source file.
|
||||
# Copyright (C) 2007-2019 Rolf Ahrenberg
|
||||
# Copyright (C) 2007-2015 Rolf Ahrenberg
|
||||
# This file is distributed under the same license as the satip package.
|
||||
# Gabriel Bonich, 2014-2017
|
||||
# Gabriel Bonich, 2014-2015
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 2.4.0\n"
|
||||
"Project-Id-Version: vdr-satip 1.0.2\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2019-10-27 19:12+0200\n"
|
||||
"PO-Revision-Date: 2019-10-27 10:27+0200\n"
|
||||
"POT-Creation-Date: 2015-01-18 01:18+0200\n"
|
||||
"PO-Revision-Date: 2015-01-18 01:18+0200\n"
|
||||
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
|
||||
"Language-Team: Catalan <vdr@linuxtv.org>\n"
|
||||
"Language: ca\n"
|
||||
@ -85,15 +85,6 @@ msgstr "Normal"
|
||||
msgid "high"
|
||||
msgstr "Alt"
|
||||
|
||||
msgid "Unicast"
|
||||
msgstr "Unicast"
|
||||
|
||||
msgid "Multicast"
|
||||
msgstr "Multicast"
|
||||
|
||||
msgid "RTP-over-TCP"
|
||||
msgstr "RTP-per sobre-TCP"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr "Dispositius"
|
||||
|
||||
@ -187,21 +178,6 @@ msgstr "Filtra"
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Definir un filtre mal comportar a la llista negra."
|
||||
|
||||
msgid "Transport mode"
|
||||
msgstr "Tipus de Transmissió"
|
||||
|
||||
msgid ""
|
||||
"Define which transport mode shall be used.\n"
|
||||
"\n"
|
||||
"Unicast, Multicast, RTP-over-TCP"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable frontend reuse"
|
||||
msgstr ""
|
||||
|
||||
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
|
||||
msgstr ""
|
||||
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr "Activa SAT>IP servers:"
|
||||
|
||||
|
53
po/de_DE.po
53
po/de_DE.po
@ -1,14 +1,14 @@
|
||||
# VDR plugin language source file.
|
||||
# Copyright (C) 2007-2019 Rolf Ahrenberg
|
||||
# Copyright (C) 2007-2015 Rolf Ahrenberg
|
||||
# This file is distributed under the same license as the satip package.
|
||||
# Frank Neumann, 2014-2017
|
||||
# Frank Neumann, 2014-2015
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 2.4.0\n"
|
||||
"Project-Id-Version: vdr-satip 1.0.2\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2019-10-27 19:12+0200\n"
|
||||
"PO-Revision-Date: 2019-10-27 10:27+0200\n"
|
||||
"POT-Creation-Date: 2015-01-18 01:18+0200\n"
|
||||
"PO-Revision-Date: 2015-01-18 01:18+0200\n"
|
||||
"Last-Translator: Frank Neumann <fnu@yavdr.org>\n"
|
||||
"Language-Team: German <vdr@linuxtv.org>\n"
|
||||
"Language: de\n"
|
||||
@ -56,7 +56,7 @@ msgid "Creation date"
|
||||
msgstr "Zeitpunkt der Erstellung"
|
||||
|
||||
msgid "SAT>IP Device Status"
|
||||
msgstr "SAT>IP Gerätestatus"
|
||||
msgstr "SAT>IP Geräte Status"
|
||||
|
||||
msgid "SAT>IP Information"
|
||||
msgstr "SAT>IP Informationen"
|
||||
@ -85,20 +85,11 @@ msgstr "normal"
|
||||
msgid "high"
|
||||
msgstr "hoch"
|
||||
|
||||
msgid "Unicast"
|
||||
msgstr "Unicast"
|
||||
|
||||
msgid "Multicast"
|
||||
msgstr "Multicast"
|
||||
|
||||
msgid "RTP-over-TCP"
|
||||
msgstr "RTP-over-TCP"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr "Geräte"
|
||||
|
||||
msgid "Operating mode"
|
||||
msgstr "Betriebsart"
|
||||
msgstr "Betriebsmodus"
|
||||
|
||||
msgid ""
|
||||
"Define the used operating mode for all SAT>IP devices:\n"
|
||||
@ -108,12 +99,12 @@ msgid ""
|
||||
"normal - devices are working within normal parameters\n"
|
||||
"high - devices are working at the highest priority"
|
||||
msgstr ""
|
||||
"Bestimme die Betriebsart für alle SAT>IP Geräte:\n"
|
||||
"Bestimme den Betriebsmodus für alle SAT>IP Geräte:\n"
|
||||
"\n"
|
||||
"aus - Geräte sind deaktiviert\n"
|
||||
"aus - Geräte sind abgeschaltet\n"
|
||||
"niedrig - Geräte arbeiten mit geringster Priorität\n"
|
||||
"normal - Geräte arbeiten innerhalb der gewöhnlichen Parameter\n"
|
||||
"hoch - Geräte arbeiten mit höchster Priorität"
|
||||
"hoch - Geräte arbeiten mit höchste Priorität"
|
||||
|
||||
msgid "Enable CI extension"
|
||||
msgstr "Aktiviere CI Erweiterung"
|
||||
@ -149,7 +140,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Legt fest ob EPG im Hintergrund aktualisiert werden soll oder nicht.\n"
|
||||
"\n"
|
||||
"Diese Einstellung schaltet die automatische EIT Aktualisierung für alle SAT>IP Geräte aus."
|
||||
"Diese Einstellung schaltet die automatische EIT Aktualisierung für alle SAT>IP Geräte."
|
||||
|
||||
msgid "Disabled sources"
|
||||
msgstr "Deaktivierte Quellen"
|
||||
@ -179,31 +170,13 @@ msgid ""
|
||||
msgstr ""
|
||||
"Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\n"
|
||||
"\n"
|
||||
"Bestimmte Abschnittsfilter können unerwünschtes Verhalten mit VDR, z.B. falsche Zeit-Synchronisation, verursachen. Durch das Ausblenden einzelner Filter können nützliche Daten dieser Abschnitte für den VDR erhalten bleiben."
|
||||
"Bestimmte Abschnittsfilter können unerwünschtes Verhalten mit VDR, z.B. falsche Zeit-Synchronisation, verursachen. Durch das Ausblenden einzelner Filter können nützliche Daten dieser Abschnitte für den VDR erhalten werden."
|
||||
|
||||
msgid "Filter"
|
||||
msgstr "Filter"
|
||||
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Bestimme fehlerhafte Filter die ausgeblendet werden sollen."
|
||||
|
||||
msgid "Transport mode"
|
||||
msgstr "Übertragungsart"
|
||||
|
||||
msgid ""
|
||||
"Define which transport mode shall be used.\n"
|
||||
"\n"
|
||||
"Unicast, Multicast, RTP-over-TCP"
|
||||
msgstr ""
|
||||
"Lege die gewünschte Übertragungsart fest.\n"
|
||||
"\n"
|
||||
"Unicast, Multicast, RTP-over-TCP"
|
||||
|
||||
msgid "Enable frontend reuse"
|
||||
msgstr "Frontend Mehrfachnutzung aktivieren"
|
||||
|
||||
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
|
||||
msgstr "Festlegung ob ein Tuner-Frontend für mehrere Kanäle genutzt wird."
|
||||
msgstr "Bestimme einen fehlerhaften Filter der ausgeblendet werden soll."
|
||||
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr "Aktive SAT>IP Server:"
|
||||
|
34
po/es_ES.po
34
po/es_ES.po
@ -1,14 +1,14 @@
|
||||
# VDR plugin language source file.
|
||||
# Copyright (C) 2007-2019 Rolf Ahrenberg
|
||||
# Copyright (C) 2007-2015 Rolf Ahrenberg
|
||||
# This file is distributed under the same license as the satip package.
|
||||
# Gabriel Bonich, 2014-2017
|
||||
# Gabriel Bonich, 2014-2015
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 2.4.0\n"
|
||||
"Project-Id-Version: vdr-satip 1.0.2\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2019-10-27 19:12+0200\n"
|
||||
"PO-Revision-Date: 2019-10-27 10:27+0200\n"
|
||||
"POT-Creation-Date: 2015-01-18 01:18+0200\n"
|
||||
"PO-Revision-Date: 2015-01-18 01:18+0200\n"
|
||||
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
|
||||
"Language-Team: Spanish <vdr@linuxtv.org>\n"
|
||||
"Language: es\n"
|
||||
@ -85,15 +85,6 @@ msgstr "Normal"
|
||||
msgid "high"
|
||||
msgstr "Alto"
|
||||
|
||||
msgid "Unicast"
|
||||
msgstr "Unicast"
|
||||
|
||||
msgid "Multicast"
|
||||
msgstr "Multicast"
|
||||
|
||||
msgid "RTP-over-TCP"
|
||||
msgstr "RTP-antes que-TCP"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr "Dispositivos"
|
||||
|
||||
@ -187,21 +178,6 @@ msgstr "Filtra"
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Define un filtro para poner en la lista negra."
|
||||
|
||||
msgid "Transport mode"
|
||||
msgstr "Tipo de Transmisión"
|
||||
|
||||
msgid ""
|
||||
"Define which transport mode shall be used.\n"
|
||||
"\n"
|
||||
"Unicast, Multicast, RTP-over-TCP"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enable frontend reuse"
|
||||
msgstr ""
|
||||
|
||||
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
|
||||
msgstr ""
|
||||
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr "Activa SAT>IP servers:"
|
||||
|
||||
|
37
po/fi_FI.po
37
po/fi_FI.po
@ -1,14 +1,14 @@
|
||||
# VDR plugin language source file.
|
||||
# Copyright (C) 2007-2019 Rolf Ahrenberg
|
||||
# Copyright (C) 2007-2015 Rolf Ahrenberg
|
||||
# This file is distributed under the same license as the satip package.
|
||||
# Rolf Ahrenberg, 2015-2019
|
||||
# Rolf Ahrenberg, 2015
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 2.4.0\n"
|
||||
"Project-Id-Version: vdr-satip 1.0.2\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2019-10-27 19:12+0200\n"
|
||||
"PO-Revision-Date: 2019-10-27 10:27+0200\n"
|
||||
"POT-Creation-Date: 2015-01-18 01:18+0200\n"
|
||||
"PO-Revision-Date: 2015-01-18 01:18+0200\n"
|
||||
"Last-Translator: Rolf Ahrenberg\n"
|
||||
"Language-Team: Finnish <vdr@linuxtv.org>\n"
|
||||
"Language: fi\n"
|
||||
@ -85,15 +85,6 @@ msgstr "normaali"
|
||||
msgid "high"
|
||||
msgstr "korkea"
|
||||
|
||||
msgid "Unicast"
|
||||
msgstr "Unicast"
|
||||
|
||||
msgid "Multicast"
|
||||
msgstr "Multicast"
|
||||
|
||||
msgid "RTP-over-TCP"
|
||||
msgstr "RTP-over-TCP"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr "Laitteet"
|
||||
|
||||
@ -186,24 +177,6 @@ msgstr "Suodatin"
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle."
|
||||
|
||||
msgid "Transport mode"
|
||||
msgstr "Siirtoyhteystapa"
|
||||
|
||||
msgid ""
|
||||
"Define which transport mode shall be used.\n"
|
||||
"\n"
|
||||
"Unicast, Multicast, RTP-over-TCP"
|
||||
msgstr ""
|
||||
"Määrittele käytettävä siirtoyhteystapa.\n"
|
||||
"\n"
|
||||
"Unicast, Multicast, RTP-over-TCP"
|
||||
|
||||
msgid "Enable frontend reuse"
|
||||
msgstr "Uusiokäytä virittimiä"
|
||||
|
||||
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
|
||||
msgstr "Määrittele virittien uusiokäyttö kanaville, jotka ovat samalla transponderilla."
|
||||
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr "Aktiiviset SAT>IP-palvelimet:"
|
||||
|
||||
|
212
po/pl_PL.po
212
po/pl_PL.po
@ -1,212 +0,0 @@
|
||||
# VDR plugin language source file.
|
||||
# Copyright (C) 2007-2019 Rolf Ahrenberg
|
||||
# This file is distributed under the same license as the vdr-satip package.
|
||||
# Tomasz Maciej Nowak, 2017
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: vdr-satip 2.4.0\n"
|
||||
"Report-Msgid-Bugs-To: <see README>\n"
|
||||
"POT-Creation-Date: 2019-10-27 19:12+0200\n"
|
||||
"PO-Revision-Date: 2019-10-27 10:27+0200\n"
|
||||
"Last-Translator: Tomasz Maciej Nowak <tomek_n@o2.pl>\n"
|
||||
"Language-Team: Polish <vdr@linuxtv.org>\n"
|
||||
"Language: pl_PL\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.8.11\n"
|
||||
|
||||
msgid "PAT (0x00)"
|
||||
msgstr "PAT (0x00)"
|
||||
|
||||
msgid "NIT (0x40)"
|
||||
msgstr "NIT (0x40)"
|
||||
|
||||
msgid "SDT (0x42)"
|
||||
msgstr "SDT (0x42)"
|
||||
|
||||
msgid "EIT (0x4E/0x4F/0x5X/0x6X)"
|
||||
msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
||||
|
||||
msgid "TDT (0x70)"
|
||||
msgstr "TDT (0x70)"
|
||||
|
||||
msgid "SAT>IP information not available!"
|
||||
msgstr "Informacja o SAT>IP niedostępna!"
|
||||
|
||||
msgid "SAT>IP Devices"
|
||||
msgstr "Urządzenia SAT>IP"
|
||||
|
||||
msgid "SAT>IP Server"
|
||||
msgstr "Serwer SAT>IP"
|
||||
|
||||
msgid "Address"
|
||||
msgstr "Adres"
|
||||
|
||||
msgid "Model"
|
||||
msgstr "Model"
|
||||
|
||||
msgid "Description"
|
||||
msgstr "Opis"
|
||||
|
||||
msgid "CI extension"
|
||||
msgstr "Rozszerzenie CI"
|
||||
|
||||
msgid "Creation date"
|
||||
msgstr "Data produkcji"
|
||||
|
||||
msgid "SAT>IP Device Status"
|
||||
msgstr "Status urządzenia SAT>IP"
|
||||
|
||||
msgid "SAT>IP Information"
|
||||
msgstr "SAT>IP - informacje"
|
||||
|
||||
msgid "General"
|
||||
msgstr "Główne"
|
||||
|
||||
msgid "Pids"
|
||||
msgstr "Pidy"
|
||||
|
||||
msgid "Filters"
|
||||
msgstr "Filtry"
|
||||
|
||||
msgid "Bits/bytes"
|
||||
msgstr "Bity/bajty"
|
||||
|
||||
msgid "off"
|
||||
msgstr "wyłączone"
|
||||
|
||||
msgid "low"
|
||||
msgstr "niski"
|
||||
|
||||
msgid "normal"
|
||||
msgstr "normalny"
|
||||
|
||||
msgid "high"
|
||||
msgstr "wysoki"
|
||||
|
||||
msgid "Unicast"
|
||||
msgstr "Unicast"
|
||||
|
||||
msgid "Multicast"
|
||||
msgstr "Multicast"
|
||||
|
||||
msgid "RTP-over-TCP"
|
||||
msgstr "RTP-over-TCP"
|
||||
|
||||
msgid "Button$Devices"
|
||||
msgstr "Urządzenia"
|
||||
|
||||
msgid "Operating mode"
|
||||
msgstr "Tryb pracy"
|
||||
|
||||
msgid ""
|
||||
"Define the used operating mode for all SAT>IP devices:\n"
|
||||
"\n"
|
||||
"off - devices are disabled\n"
|
||||
"low - devices are working at the lowest priority\n"
|
||||
"normal - devices are working within normal parameters\n"
|
||||
"high - devices are working at the highest priority"
|
||||
msgstr ""
|
||||
"Określa tryb pracy wszystkich urządzeń SAT>IP:\n"
|
||||
"\n"
|
||||
"wyłączone - urządzenia są wyłączone\n"
|
||||
"niski - urządzenia pracują z najniższym priorytetem\n"
|
||||
"normalny - urządzenia pracują z normalnymi parametrami\n"
|
||||
"wysoki - urządzenia pracują z najwyższym priorytetem"
|
||||
|
||||
msgid "Enable CI extension"
|
||||
msgstr "Włącz rozszerzenie CI"
|
||||
|
||||
msgid ""
|
||||
"Define whether a CI extension shall be used.\n"
|
||||
"\n"
|
||||
"This setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)."
|
||||
msgstr ""
|
||||
"Określa czy korzystać z rozszerzenia CI.\n"
|
||||
"\n"
|
||||
"To ustawienie włącza obsługę dostępnego czytnika CI/CAM w niektórych urządzeniach SAT>IP (np. Digital Devices OctopusNet)."
|
||||
|
||||
msgid "CI/CAM"
|
||||
msgstr "CI/CAM"
|
||||
|
||||
msgid ""
|
||||
"Define a desired CAM type for the CI slot.\n"
|
||||
"\n"
|
||||
"The '---' option lets SAT>IP hardware do the auto-selection."
|
||||
msgstr ""
|
||||
"Określa typ modułu CAM w czytniku CI.\n"
|
||||
"\n"
|
||||
"Opcja '---' pozwala urządzeniu SAT>IP automatycznie wybrać typ."
|
||||
|
||||
msgid "Enable EPG scanning"
|
||||
msgstr "Włącz skanowanie EPG"
|
||||
|
||||
msgid ""
|
||||
"Define whether the EPG background scanning shall be used.\n"
|
||||
"\n"
|
||||
"This setting disables the automatic EIT scanning functionality for all SAT>IP devices."
|
||||
msgstr ""
|
||||
"Określa czy przeprowadzać skanowanie EPG w tle.\n"
|
||||
"\n"
|
||||
"To ustawienie wyłącza funkcję automatycznego skanowania EIT dla wszystkich urządzeń SAT>IP."
|
||||
|
||||
msgid "Disabled sources"
|
||||
msgstr "Wyłączone źródła"
|
||||
|
||||
msgid "none"
|
||||
msgstr "brak"
|
||||
|
||||
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 ""
|
||||
"Określa liczbę wyłączonych źródeł.\n"
|
||||
"\n"
|
||||
"Serwery SAT>IP mogą nie mieć dostępu do niektórych pozycji satelitarnych, więc tutaj można je wyłączyć."
|
||||
|
||||
msgid "Define a source to be blacklisted."
|
||||
msgstr "Określ źródła do wyłączenia."
|
||||
|
||||
msgid "Disabled filters"
|
||||
msgstr "Wyłączone filtry"
|
||||
|
||||
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 blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||
msgstr ""
|
||||
"Określa liczbę wyłączonych filtrów sekcji.\n"
|
||||
"\n"
|
||||
"Niektóre filtry sekcji mogą powodować niezamierzone efekty w VDR, takie jak zły czas synchronizacji. Poprzez wyłączenie niektórych filtrów, użyteczne dane sekcji będą dostępne do przetworzenia dla VDR."
|
||||
|
||||
msgid "Filter"
|
||||
msgstr "Filtr"
|
||||
|
||||
msgid "Define an ill-behaving filter to be blacklisted."
|
||||
msgstr "Określa filtry powodujące zakłócenia, które mają być wyłączone."
|
||||
|
||||
msgid "Transport mode"
|
||||
msgstr "Tryb"
|
||||
|
||||
msgid ""
|
||||
"Define which transport mode shall be used.\n"
|
||||
"\n"
|
||||
"Unicast, Multicast, RTP-over-TCP"
|
||||
msgstr ""
|
||||
"Określa tryb transmisji.\n"
|
||||
"Unicast, Multicast, RTP-over-TCP."
|
||||
|
||||
msgid "Enable frontend reuse"
|
||||
msgstr ""
|
||||
|
||||
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
|
||||
msgstr ""
|
||||
|
||||
msgid "Active SAT>IP servers:"
|
||||
msgstr "Aktywne serwery SAT>IP:"
|
||||
|
||||
msgid "Help"
|
||||
msgstr "Pomoc"
|
2
poller.c
2
poller.c
@ -79,7 +79,7 @@ void cSatipPoller::Action(void)
|
||||
// Do the thread loop
|
||||
while (Running()) {
|
||||
int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, -1);
|
||||
ERROR_IF_FUNC((nfds == -1 && errno != EINTR), "epoll_wait() failed", break, ;);
|
||||
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) {
|
||||
|
@ -14,11 +14,10 @@ public:
|
||||
virtual ~cSatipPollerIf() {}
|
||||
virtual int GetFd(void) = 0;
|
||||
virtual void Process(void) = 0;
|
||||
virtual void Process(unsigned char *dataP, int lengthP) = 0;
|
||||
virtual cString ToString(void) const = 0;
|
||||
|
||||
private:
|
||||
explicit cSatipPollerIf(const cSatipPollerIf&);
|
||||
cSatipPollerIf(const cSatipPollerIf&);
|
||||
cSatipPollerIf& operator=(const cSatipPollerIf&);
|
||||
};
|
||||
|
||||
|
42
rtcp.c
42
rtcp.c
@ -25,7 +25,7 @@ cSatipRtcp::cSatipRtcp(cSatipTunerIf &tunerP)
|
||||
cSatipRtcp::~cSatipRtcp()
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
FREE_POINTER(bufferM);
|
||||
DELETE_POINTER(bufferM);
|
||||
}
|
||||
|
||||
int cSatipRtcp::GetFd(void)
|
||||
@ -34,38 +34,38 @@ int cSatipRtcp::GetFd(void)
|
||||
return Fd();
|
||||
}
|
||||
|
||||
int cSatipRtcp::GetApplicationOffset(unsigned char *bufferP, int *lengthP)
|
||||
int cSatipRtcp::GetApplicationOffset(int *lengthP)
|
||||
{
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP ? *lengthP : -1, tunerM.GetId());
|
||||
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 = (bufferP[offset] >> 6) & 0x03;
|
||||
unsigned int v = (bufferM[offset] >> 6) & 0x03;
|
||||
// Padding
|
||||
//unsigned int p = (bufferP[offset] >> 5) & 0x01;
|
||||
//unsigned int p = (bufferM[offset] >> 5) & 0x01;
|
||||
// Subtype
|
||||
//unsigned int st = bufferP[offset] & 0x1F;
|
||||
//unsigned int st = bufferM[offset] & 0x1F;
|
||||
// Payload type
|
||||
unsigned int pt = bufferP[offset + 1] & 0xFF;
|
||||
unsigned int pt = bufferM[offset + 1] & 0xFF;
|
||||
// Length
|
||||
unsigned int length = ((bufferP[offset + 2] & 0xFF) << 8) | (bufferP[offset + 3] & 0xFF);
|
||||
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 = ((bufferP[offset + 4] & 0xFF) << 24) | ((bufferP[offset + 5] & 0xFF) << 16) |
|
||||
// ((bufferP[offset + 6] & 0xFF) << 8) | (bufferP[offset + 7] & 0xFF);
|
||||
//unsigned int ssrc = ((bufferM[offset + 4] & 0xFF) << 24) | ((bufferM[offset + 5] & 0xFF) << 16) |
|
||||
// ((bufferM[offset + 6] & 0xFF) << 8) | (bufferM[offset + 7] & 0xFF);
|
||||
// Name
|
||||
if ((bufferP[offset + 8] == 'S') && (bufferP[offset + 9] == 'E') &&
|
||||
(bufferP[offset + 10] == 'S') && (bufferP[offset + 11] == '1')) {
|
||||
if ((bufferM[offset + 8] == 'S') && (bufferM[offset + 9] == 'E') &&
|
||||
(bufferM[offset + 10] == 'S') && (bufferM[offset + 11] == '1')) {
|
||||
// Identifier
|
||||
//unsigned int id = ((bufferP[offset + 12] & 0xFF) << 8) | (bufferP[offset + 13] & 0xFF);
|
||||
//unsigned int id = ((bufferM[offset + 12] & 0xFF) << 8) | (bufferM[offset + 13] & 0xFF);
|
||||
// String length
|
||||
int string_length = ((bufferP[offset + 14] & 0xFF) << 8) | (bufferP[offset + 15] & 0xFF);
|
||||
int string_length = ((bufferM[offset + 14] & 0xFF) << 8) | (bufferM[offset + 15] & 0xFF);
|
||||
if (string_length > 0) {
|
||||
*lengthP = string_length;
|
||||
return (offset + 16);
|
||||
@ -85,20 +85,12 @@ void cSatipRtcp::Process(void)
|
||||
if (bufferM) {
|
||||
int length;
|
||||
while ((length = Read(bufferM, bufferLenM)) > 0) {
|
||||
int offset = GetApplicationOffset(bufferM, &length);
|
||||
int offset = GetApplicationOffset(&length);
|
||||
if (offset >= 0)
|
||||
tunerM.ProcessApplicationData(bufferM + offset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipRtcp::Process(unsigned char *dataP, int lengthP)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
if (dataP && lengthP > 0) {
|
||||
int offset = GetApplicationOffset(dataP, &lengthP);
|
||||
if (offset >= 0)
|
||||
tunerM.ProcessApplicationData(dataP + offset, lengthP);
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
error("Error %d reading in %s", errno, *ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
5
rtcp.h
5
rtcp.h
@ -20,17 +20,16 @@ private:
|
||||
cSatipTunerIf &tunerM;
|
||||
unsigned int bufferLenM;
|
||||
unsigned char *bufferM;
|
||||
int GetApplicationOffset(unsigned char *bufferP, int *lengthP);
|
||||
int GetApplicationOffset(int *lengthP);
|
||||
|
||||
public:
|
||||
explicit cSatipRtcp(cSatipTunerIf &tunerP);
|
||||
cSatipRtcp(cSatipTunerIf &tunerP);
|
||||
virtual ~cSatipRtcp();
|
||||
|
||||
// for internal poller interface
|
||||
public:
|
||||
virtual int GetFd(void);
|
||||
virtual void Process(void);
|
||||
virtual void Process(unsigned char *dataP, int lengthP);
|
||||
virtual cString ToString(void) const;
|
||||
};
|
||||
|
||||
|
28
rtp.c
28
rtp.c
@ -14,8 +14,7 @@
|
||||
#include "rtp.h"
|
||||
|
||||
cSatipRtp::cSatipRtp(cSatipTunerIf &tunerP)
|
||||
: cSatipSocket(SatipConfig.GetRtpRcvBufSize()),
|
||||
tunerM(tunerP),
|
||||
: tunerM(tunerP),
|
||||
bufferLenM(eRtpPacketReadCount * eMaxUdpPacketSizeB),
|
||||
bufferM(MALLOC(unsigned char, bufferLenM)),
|
||||
lastErrorReportM(0),
|
||||
@ -30,7 +29,7 @@ cSatipRtp::cSatipRtp(cSatipTunerIf &tunerP)
|
||||
cSatipRtp::~cSatipRtp()
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
FREE_POINTER(bufferM);
|
||||
DELETE_POINTER(bufferM);
|
||||
}
|
||||
|
||||
int cSatipRtp::GetFd(void)
|
||||
@ -46,7 +45,7 @@ void cSatipRtp::Close(void)
|
||||
|
||||
sequenceNumberM = -1;
|
||||
if (packetErrorsM) {
|
||||
info("Detected %d RTP packet error%s [device %d]", packetErrorsM, packetErrorsM == 1 ? "": "s", tunerM.GetId());
|
||||
info("Detected %d RTP packet errors [device %d]", packetErrorsM, tunerM.GetId());
|
||||
packetErrorsM = 0;
|
||||
lastErrorReportM = time(NULL);
|
||||
}
|
||||
@ -81,7 +80,7 @@ int cSatipRtp::GetHeaderLength(unsigned char *bufferP, unsigned int lengthP)
|
||||
else if ((sequenceNumberM >= 0) && (((sequenceNumberM + 1) % 0xFFFF) != seq)) {
|
||||
packetErrorsM++;
|
||||
if (time(NULL) - lastErrorReportM > eReportIntervalS) {
|
||||
info("Detected %d RTP packet error%s [device %d]", packetErrorsM, packetErrorsM == 1 ? "": "s", tunerM.GetId());
|
||||
info("Detected %d RTP packet errors [device %d]", packetErrorsM, tunerM.GetId());
|
||||
packetErrorsM = 0;
|
||||
lastErrorReportM = time(NULL);
|
||||
}
|
||||
@ -137,28 +136,15 @@ void cSatipRtp::Process(void)
|
||||
}
|
||||
} 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());
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipRtp::Process(unsigned char *dataP, int lengthP)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
if (dataP && lengthP > 0) {
|
||||
uint64_t elapsed;
|
||||
cTimeMs processing(0);
|
||||
int headerlen = GetHeaderLength(dataP, lengthP);
|
||||
if ((headerlen >= 0) && (headerlen < lengthP))
|
||||
tunerM.ProcessVideoData(dataP + headerlen, lengthP - headerlen);
|
||||
|
||||
elapsed = processing.Elapsed();
|
||||
if (elapsed > 1)
|
||||
debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, lengthP, elapsed, tunerM.GetId());
|
||||
}
|
||||
}
|
||||
|
||||
cString cSatipRtp::ToString(void) const
|
||||
{
|
||||
return cString::sprintf("RTP [device %d]", tunerM.GetId());
|
||||
|
3
rtp.h
3
rtp.h
@ -28,7 +28,7 @@ private:
|
||||
int GetHeaderLength(unsigned char *bufferP, unsigned int lengthP);
|
||||
|
||||
public:
|
||||
explicit cSatipRtp(cSatipTunerIf &tunerP);
|
||||
cSatipRtp(cSatipTunerIf &tunerP);
|
||||
virtual ~cSatipRtp();
|
||||
virtual void Close(void);
|
||||
|
||||
@ -36,7 +36,6 @@ public:
|
||||
public:
|
||||
virtual int GetFd(void);
|
||||
virtual void Process(void);
|
||||
virtual void Process(unsigned char *dataP, int lengthP);
|
||||
virtual cString ToString(void) const;
|
||||
};
|
||||
|
||||
|
327
rtsp.c
327
rtsp.c
@ -15,16 +15,9 @@
|
||||
|
||||
cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP)
|
||||
: tunerM(tunerP),
|
||||
headerBufferM(),
|
||||
dataBufferM(),
|
||||
modeM(cmUnicast),
|
||||
handleM(NULL),
|
||||
headerListM(NULL),
|
||||
errorNoMoreM(""),
|
||||
errorOutOfRangeM(""),
|
||||
errorCheckSyntaxM(""),
|
||||
modeM(cSatipConfig::eTransportModeUnicast),
|
||||
interleavedRtpIdM(0),
|
||||
interleavedRtcpIdM(1)
|
||||
headerListM(NULL)
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
Create();
|
||||
@ -36,50 +29,46 @@ cSatipRtsp::~cSatipRtsp()
|
||||
Destroy();
|
||||
}
|
||||
|
||||
size_t cSatipRtsp::HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||
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->headerBufferM.Add(ptrP, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t cSatipRtsp::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||
{
|
||||
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP);
|
||||
size_t len = sizeP * nmembP;
|
||||
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
|
||||
|
||||
if (obj)
|
||||
obj->dataBufferM.Add(ptrP, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t cSatipRtsp::InterleaveCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||
{
|
||||
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP);
|
||||
size_t len = sizeP * nmembP;
|
||||
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
|
||||
|
||||
if (obj && ptrP && len > 0) {
|
||||
char tag = ptrP[0] & 0xFF;
|
||||
if (tag == '$') {
|
||||
int count = ((ptrP[2] & 0xFF) << 8) | (ptrP[3] & 0xFF);
|
||||
if (count > 0) {
|
||||
unsigned int channel = ptrP[1] & 0xFF;
|
||||
u_char *data = (u_char *)&ptrP[4];
|
||||
if (channel == obj->interleavedRtpIdM)
|
||||
obj->tunerM.ProcessRtpData(data, count);
|
||||
else if (channel == obj->interleavedRtcpIdM)
|
||||
obj->tunerM.ProcessRtcpData(data, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
obj->tunerM.ProcessApplicationData((u_char*)ptrP, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -113,21 +102,6 @@ int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, s
|
||||
return 0;
|
||||
}
|
||||
|
||||
cString cSatipRtsp::GetActiveMode(void)
|
||||
{
|
||||
switch (modeM) {
|
||||
case cSatipConfig::eTransportModeUnicast:
|
||||
return "Unicast";
|
||||
case cSatipConfig::eTransportModeMulticast:
|
||||
return "Multicast";
|
||||
case cSatipConfig::eTransportModeRtpOverTcp:
|
||||
return "RTP-over-TCP";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
cString cSatipRtsp::RtspUnescapeString(const char *strP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId());
|
||||
@ -190,44 +164,6 @@ void cSatipRtsp::Reset(void)
|
||||
Create();
|
||||
}
|
||||
|
||||
bool cSatipRtsp::SetInterface(const char *bindAddrP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, bindAddrP, tunerM.GetId());
|
||||
bool result = true;
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
if (handleM && !isempty(bindAddrP)) {
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERFACE, *cString::sprintf("host!%s", bindAddrP));
|
||||
}
|
||||
else {
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERFACE, NULL);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipRtsp::Receive(const char *uriP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||
bool result = false;
|
||||
|
||||
if (handleM && !isempty(uriP) && modeM == cSatipConfig::eTransportModeRtpOverTcp) {
|
||||
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); // FIXME: this really should be CURL_RTSPREQ_RECEIVE, but getting timeout errors
|
||||
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::Options(const char *uriP)
|
||||
{
|
||||
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||
@ -250,9 +186,9 @@ bool cSatipRtsp::Options(const char *uriP)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTcpP)
|
||||
bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP)
|
||||
{
|
||||
debug1("%s (%s, %d, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, useTcpP, tunerM.GetId());
|
||||
debug1("%s (%s, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, tunerM.GetId());
|
||||
bool result = false;
|
||||
|
||||
if (handleM && !isempty(uriP)) {
|
||||
@ -261,17 +197,14 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTc
|
||||
cTimeMs processing(0);
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
switch (SatipConfig.GetTransportMode()) {
|
||||
case cSatipConfig::eTransportModeMulticast:
|
||||
// RTP/AVP;multicast;destination=<multicast group address>;port=<RTP port>-<RTCP port>;ttl=<ttl>[;source=<multicast source address>]
|
||||
transport = cString::sprintf("RTP/AVP;multicast");
|
||||
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>
|
||||
// RTP/AVP/TCP;unicast;client_port=<client RTP port>-<client RTCP port>
|
||||
if (useTcpP)
|
||||
transport = cString::sprintf("RTP/AVP/TCP;unicast;interleaved=%u-%u", interleavedRtpIdM, interleavedRtcpIdM);
|
||||
else
|
||||
transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP);
|
||||
break;
|
||||
}
|
||||
@ -283,25 +216,10 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTc
|
||||
// Set header callback for catching the session and timeout
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipRtsp::HeaderCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
|
||||
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
// Session id is now known - disable header parsing
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
|
||||
if (headerBufferM.Size() > 0) {
|
||||
ParseHeader();
|
||||
headerBufferM.Reset();
|
||||
}
|
||||
if (dataBufferM.Size() > 0) {
|
||||
ParseData();
|
||||
dataBufferM.Reset();
|
||||
}
|
||||
|
||||
result = ValidateLatestResponse(&rc);
|
||||
debug5("%s (%s, %d, %d) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, rc, processing.Elapsed(), tunerM.GetId());
|
||||
@ -335,15 +253,11 @@ bool cSatipRtsp::Describe(const char *uriP)
|
||||
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
|
||||
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);
|
||||
if (dataBufferM.Size() > 0) {
|
||||
tunerM.ProcessApplicationData((u_char *)dataBufferM.Data(), dataBufferM.Size());
|
||||
dataBufferM.Reset();
|
||||
}
|
||||
|
||||
result = ValidateLatestResponse(&rc);
|
||||
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||
@ -364,15 +278,7 @@ bool cSatipRtsp::Play(const char *uriP)
|
||||
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
|
||||
if (dataBufferM.Size() > 0) {
|
||||
ParseData();
|
||||
dataBufferM.Reset();
|
||||
}
|
||||
|
||||
result = ValidateLatestResponse(&rc);
|
||||
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||
@ -393,17 +299,7 @@ bool cSatipRtsp::Teardown(const char *uriP)
|
||||
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
|
||||
SATIP_CURL_EASY_PERFORM(handleM);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
|
||||
if (dataBufferM.Size() > 0) {
|
||||
ParseData();
|
||||
dataBufferM.Reset();
|
||||
}
|
||||
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_CLIENT_CSEQ, 1L);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL);
|
||||
@ -415,153 +311,24 @@ bool cSatipRtsp::Teardown(const char *uriP)
|
||||
return result;
|
||||
}
|
||||
|
||||
void cSatipRtsp::ParseHeader(void)
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
char *s, *p = headerBufferM.Data();
|
||||
char *r = strtok_r(p, "\r\n", &s);
|
||||
|
||||
while (r) {
|
||||
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r);
|
||||
r = skipspace(r);
|
||||
if (strstr(r, "com.ses.streamID")) {
|
||||
int streamid = -1;
|
||||
if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1)
|
||||
tunerM.SetStreamId(streamid);
|
||||
}
|
||||
else if (strstr(r, "Session:")) {
|
||||
int timeout = -1;
|
||||
char *session = NULL;
|
||||
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
|
||||
tunerM.SetSessionTimeout(skipspace(session), timeout * 1000);
|
||||
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
|
||||
tunerM.SetSessionTimeout(skipspace(session), -1);
|
||||
FREE_POINTER(session);
|
||||
}
|
||||
else if (strstr(r, "Transport:")) {
|
||||
CURLcode res = CURLE_OK;
|
||||
int rtp = -1, rtcp = -1, ttl = -1;
|
||||
char *tmp = NULL, *destination = NULL, *source = NULL;
|
||||
interleavedRtpIdM = 0;
|
||||
interleavedRtcpIdM = 1;
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
|
||||
if (sscanf(r, "Transport:%m[^;];unicast;client_port=%11d-%11d", &tmp, &rtp, &rtcp) == 3) {
|
||||
modeM = cSatipConfig::eTransportModeUnicast;
|
||||
tunerM.SetupTransport(rtp, rtcp, NULL, NULL);
|
||||
}
|
||||
else if (sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d;source=%m[^;]", &tmp, &destination, &rtp, &rtcp, &ttl, &source) == 6 ||
|
||||
sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d", &tmp, &destination, &rtp, &rtcp, &ttl) == 5) {
|
||||
modeM = cSatipConfig::eTransportModeMulticast;
|
||||
tunerM.SetupTransport(rtp, rtcp, destination, source);
|
||||
}
|
||||
else if (sscanf(r, "Transport:%m[^;];interleaved=%11d-%11d", &tmp, &rtp, &rtcp) == 3) {
|
||||
interleavedRtpIdM = rtp;
|
||||
interleavedRtcpIdM = rtcp;
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, cSatipRtsp::InterleaveCallback);
|
||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, this);
|
||||
modeM = cSatipConfig::eTransportModeRtpOverTcp;
|
||||
tunerM.SetupTransport(-1, -1, NULL, NULL);
|
||||
}
|
||||
FREE_POINTER(tmp);
|
||||
FREE_POINTER(destination);
|
||||
FREE_POINTER(source);
|
||||
}
|
||||
r = strtok_r(NULL, "\r\n", &s);
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipRtsp::ParseData(void)
|
||||
{
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||
char *s, *p = dataBufferM.Data();
|
||||
char *r = strtok_r(p, "\r\n", &s);
|
||||
|
||||
while (r) {
|
||||
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, dataBufferM.Size(), r);
|
||||
r = skipspace(r);
|
||||
if (strstr(r, "No-More:")) {
|
||||
char *tmp = NULL;
|
||||
if (sscanf(r, "No-More:%m[^;]", &tmp) == 1) {
|
||||
errorNoMoreM = skipspace(tmp);
|
||||
debug3("%s No-More: %s [device %d]", __PRETTY_FUNCTION__, *errorNoMoreM, tunerM.GetId());
|
||||
}
|
||||
FREE_POINTER(tmp);
|
||||
}
|
||||
else if (strstr(r, "Out-of-Range:")) {
|
||||
char *tmp = NULL;
|
||||
if (sscanf(r, "Out-of-Range:%m[^;]", &tmp) == 1) {
|
||||
errorOutOfRangeM = skipspace(tmp);
|
||||
debug3("%s Out-of-Range: %s [device %d]", __PRETTY_FUNCTION__, *errorOutOfRangeM, tunerM.GetId());
|
||||
}
|
||||
FREE_POINTER(tmp);
|
||||
}
|
||||
else if (strstr(r, "Check-Syntax:")) {
|
||||
char *tmp = NULL;
|
||||
if (sscanf(r, "Check-Syntax:%m[^;]", &tmp) == 1) {
|
||||
errorCheckSyntaxM = skipspace(tmp);
|
||||
debug3("%s Check-Syntax: %s [device %d]", __PRETTY_FUNCTION__, *errorCheckSyntaxM, tunerM.GetId());
|
||||
}
|
||||
FREE_POINTER(tmp);
|
||||
}
|
||||
r = strtok_r(NULL, "\r\n", &s);
|
||||
}
|
||||
}
|
||||
|
||||
bool cSatipRtsp::ValidateLatestResponse(long *rcP)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (handleM) {
|
||||
char *url = NULL;
|
||||
long rc = 0;
|
||||
CURLcode res = CURLE_OK;
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
||||
switch (rc) {
|
||||
case 200:
|
||||
if (rc == 200)
|
||||
result = true;
|
||||
break;
|
||||
case 400:
|
||||
// SETUP PLAY TEARDOWN
|
||||
// The message body of the response may contain the "Check-Syntax:" parameter followed
|
||||
// by the malformed syntax
|
||||
if (!isempty(*errorCheckSyntaxM)) {
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
|
||||
error("Check syntax: %s (error code %ld: %s) [device %d]", *errorCheckSyntaxM, rc, url, tunerM.GetId());
|
||||
break;
|
||||
}
|
||||
case 403:
|
||||
// SETUP PLAY TEARDOWN
|
||||
// The message body of the response may contain the "Out-of-Range:" parameter followed
|
||||
// by a space-separated list of the attribute names that are not understood:
|
||||
// "src" "fe" "freq" "pol" "msys" "mtype" "plts" "ro" "sr" "fec" "pids" "addpids" "delpids" "mcast"
|
||||
if (!isempty(*errorOutOfRangeM)) {
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
|
||||
error("Out of range: %s (error code %ld: %s) [device %d]", *errorOutOfRangeM, rc, url, tunerM.GetId());
|
||||
// Reseting the connection wouldn't help anything due to invalid channel configuration, so let it be successful
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
case 503:
|
||||
// SETUP PLAY
|
||||
// The message body of the response may contain the "No-More:" parameter followed
|
||||
// by a space-separated list of the missing ressources: “sessions” "frontends" "pids
|
||||
if (!isempty(*errorNoMoreM)) {
|
||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
|
||||
error("No more: %s (error code %ld: %s) [device %d]", *errorNoMoreM, rc, url, tunerM.GetId());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
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());
|
||||
break;
|
||||
}
|
||||
if (rcP)
|
||||
*rcP = rc;
|
||||
}
|
||||
errorNoMoreM = "";
|
||||
errorOutOfRangeM = "";
|
||||
errorCheckSyntaxM = "";
|
||||
debug1("%s result=%s [device %d]", __PRETTY_FUNCTION__, result ? "ok" : "failed", tunerM.GetId());
|
||||
|
||||
return result;
|
||||
|
25
rtsp.h
25
rtsp.h
@ -15,36 +15,26 @@
|
||||
#error "libcurl is missing required RTSP support"
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "tunerif.h"
|
||||
|
||||
class cSatipRtsp {
|
||||
private:
|
||||
static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
||||
static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
||||
static size_t InterleaveCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
||||
static 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;
|
||||
cSatipMemoryBuffer headerBufferM;
|
||||
cSatipMemoryBuffer dataBufferM;
|
||||
eCommunicationMode modeM;
|
||||
CURL *handleM;
|
||||
struct curl_slist *headerListM;
|
||||
cString errorNoMoreM;
|
||||
cString errorOutOfRangeM;
|
||||
cString errorCheckSyntaxM;
|
||||
int modeM;
|
||||
unsigned int interleavedRtpIdM;
|
||||
unsigned int interleavedRtcpIdM;
|
||||
|
||||
void Create(void);
|
||||
void Destroy(void);
|
||||
void ParseHeader(void);
|
||||
void ParseData(void);
|
||||
bool ValidateLatestResponse(long *rcP);
|
||||
|
||||
// to prevent copy constructor and assignment
|
||||
@ -52,16 +42,13 @@ private:
|
||||
cSatipRtsp& operator=(const cSatipRtsp&);
|
||||
|
||||
public:
|
||||
explicit cSatipRtsp(cSatipTunerIf &tunerP);
|
||||
cSatipRtsp(cSatipTunerIf &tunerP);
|
||||
virtual ~cSatipRtsp();
|
||||
|
||||
cString GetActiveMode(void);
|
||||
cString RtspUnescapeString(const char *strP);
|
||||
void Reset(void);
|
||||
bool SetInterface(const char *bindAddrP);
|
||||
bool Receive(const char *uriP);
|
||||
bool Options(const char *uriP);
|
||||
bool Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTcpP);
|
||||
bool Setup(const char *uriP, int rtpPortP, int rtcpPortP);
|
||||
bool SetSession(const char *sessionP);
|
||||
bool Describe(const char *uriP);
|
||||
bool Play(const char *uriP);
|
||||
|
163
satip.c
163
satip.c
@ -5,7 +5,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <vdr/plugin.h>
|
||||
#include "common.h"
|
||||
@ -20,15 +19,15 @@
|
||||
#warning "CURL version >= 7.36.0 is recommended"
|
||||
#endif
|
||||
|
||||
#if defined(APIVERSNUM) && APIVERSNUM < 20400
|
||||
#error "VDR-2.4.0 API version or greater is required!"
|
||||
#if defined(APIVERSNUM) && APIVERSNUM < 20000
|
||||
#error "VDR-2.0.0 API version or greater is required!"
|
||||
#endif
|
||||
|
||||
#ifndef GITVERSION
|
||||
#define GITVERSION ""
|
||||
#endif
|
||||
|
||||
const char VERSION[] = "2.4.1" GITVERSION;
|
||||
const char VERSION[] = "1.0.2" GITVERSION;
|
||||
static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
|
||||
|
||||
class cPluginSatip : public cPlugin {
|
||||
@ -36,7 +35,6 @@ private:
|
||||
unsigned int deviceCountM;
|
||||
cSatipDiscoverServers *serversM;
|
||||
void ParseServer(const char *paramP);
|
||||
void ParsePortRange(const char *paramP);
|
||||
int ParseCicams(const char *valueP, int *cicamsP);
|
||||
int ParseSources(const char *valueP, int *sourcesP);
|
||||
int ParseFilters(const char *valueP, int *filtersP);
|
||||
@ -64,7 +62,7 @@ public:
|
||||
};
|
||||
|
||||
cPluginSatip::cPluginSatip(void)
|
||||
: deviceCountM(2),
|
||||
: deviceCountM(1),
|
||||
serversM(NULL)
|
||||
{
|
||||
debug16("%s", __PRETTY_FUNCTION__);
|
||||
@ -85,37 +83,10 @@ const char *cPluginSatip::CommandLineHelp(void)
|
||||
// Return a string that describes all known command line options.
|
||||
return " -d <num>, --devices=<number> set number of devices to be created\n"
|
||||
" -t <mode>, --trace=<mode> set the tracing mode\n"
|
||||
" -s <ipaddr>|<model>|<desc>, --server=[<srcaddress>@]<ipaddress>[:<port>]|<model>[:<filter>]|<description>[:<quirk>];...\n"
|
||||
" define hard-coded SAT>IP server(s)\n\n"
|
||||
" srcaddress (Optional) Source address can be used to define used\n"
|
||||
" networking interface on a host, e.g. 127.0.0.1.\n"
|
||||
" ipaddress IP address of SAT>IP server, e.g. 127.0.0.1.\n"
|
||||
" port (Optional) IP port number of SAT>IP server, e.g 443.\n"
|
||||
" model Model defines DVB modulation system (DVBS2,\n"
|
||||
" DVBT2, DVBT, DVBC) and number of available\n"
|
||||
" frontends separated by a hyphen, e.g. DVBT2-4.\n"
|
||||
" filter (Optional) Filter can be used to limit satellite frontends\n"
|
||||
" to certain satellite position, e.g. S19.2E.\n"
|
||||
" description Friendly name of SAT>IP server. This is used\n"
|
||||
" for autodetection of quirks.\n"
|
||||
" quirk (Optional) Quirks are non-standard compliant features and\n"
|
||||
" bug fixes of SAT>IP server defined by a\n"
|
||||
" hexadecimal number. Multiple quirks can be\n"
|
||||
" defined by combining values by addition:\n\n"
|
||||
" 0x01: Fix session id bug\n"
|
||||
" 0x02: Fix play parameter (addpids/delpids) bug\n"
|
||||
" 0x04: Fix frontend locking bug\n"
|
||||
" 0x08: Support for RTP over TCP\n"
|
||||
" 0x10: Support the X_PMT protocol extension\n"
|
||||
" 0x20: Support the CI TNR protocol extension\n"
|
||||
" 0x40: Fix auto-detection of pilot tones bug\n"
|
||||
" 0x80: Fix re-tuning bug by teardowning a session\n"
|
||||
" -D, --detach set the detached mode on\n"
|
||||
" -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>|<model2>|<desc2>\n"
|
||||
" define hard-coded SAT>IP server(s)"
|
||||
" -S, --single set the single model server mode on\n"
|
||||
" -n, --noquirks disable autodetection of the server quirks\n"
|
||||
" -p, --portrange=<start>-<end> set a range of ports used for the RT[C]P server\n"
|
||||
" a minimum of 2 ports per device is required.\n"
|
||||
" -r, --rcvbuf override the size of the RTP receive buffer in bytes\n";
|
||||
" -n, --noquirks disable all the server quirks\n";
|
||||
}
|
||||
|
||||
bool cPluginSatip::ProcessArgs(int argc, char *argv[])
|
||||
@ -126,18 +97,14 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
|
||||
{ "devices", required_argument, NULL, 'd' },
|
||||
{ "trace", required_argument, NULL, 't' },
|
||||
{ "server", required_argument, NULL, 's' },
|
||||
{ "portrange",required_argument, NULL, 'p' },
|
||||
{ "rcvbuf", required_argument, NULL, 'r' },
|
||||
{ "detach", no_argument, NULL, 'D' },
|
||||
{ "single", no_argument, NULL, 'S' },
|
||||
{ "noquirks", no_argument, NULL, 'n' },
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
cString server;
|
||||
cString portrange;
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "d:t:s:p:r:DSn", long_options, NULL)) != -1) {
|
||||
while ((c = getopt_long(argc, argv, "d:t:s:Sn", long_options, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
deviceCountM = strtol(optarg, NULL, 0);
|
||||
@ -148,27 +115,16 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[])
|
||||
case 's':
|
||||
server = optarg;
|
||||
break;
|
||||
case 'D':
|
||||
SatipConfig.SetDetachedMode(true);
|
||||
break;
|
||||
case 'S':
|
||||
SatipConfig.SetUseSingleModelServers(true);
|
||||
break;
|
||||
case 'n':
|
||||
SatipConfig.SetDisableServerQuirks(true);
|
||||
break;
|
||||
case 'p':
|
||||
portrange = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
SatipConfig.SetRtpRcvBufSize(strtol(optarg, NULL, 0));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!isempty(*portrange))
|
||||
ParsePortRange(portrange);
|
||||
// this must be done after all parameters are parsed
|
||||
if (!isempty(*server))
|
||||
ParseServer(*server);
|
||||
@ -261,9 +217,7 @@ void cPluginSatip::ParseServer(const char *paramP)
|
||||
while (r) {
|
||||
r = skipspace(r);
|
||||
debug3("%s server[%d]=%s", __PRETTY_FUNCTION__, n, r);
|
||||
cString sourceAddr, serverAddr, serverModel, serverFilters, serverDescription;
|
||||
int serverQuirk = cSatipServer::eSatipQuirkNone;
|
||||
int serverPort = SATIP_DEFAULT_RTSP_PORT;
|
||||
cString serverAddr, serverModel, serverDescription;
|
||||
int n2 = 0;
|
||||
char *s2, *p2 = r;
|
||||
char *r2 = strtok_r(p2, "|", &s2);
|
||||
@ -271,40 +225,13 @@ void cPluginSatip::ParseServer(const char *paramP)
|
||||
debug3("%s param[%d]=%s", __PRETTY_FUNCTION__, n2, r2);
|
||||
switch (n2++) {
|
||||
case 0:
|
||||
{
|
||||
char *r3 = strchr(r2, '@');
|
||||
if (r3) {
|
||||
*r3 = 0;
|
||||
sourceAddr = r2;
|
||||
r2 = r3 + 1;
|
||||
}
|
||||
serverAddr = r2;
|
||||
r3 = strchr(r2, ':');
|
||||
if (r3) {
|
||||
serverPort = strtol(r3 + 1, NULL, 0);
|
||||
serverAddr = serverAddr.Truncate(r3 - r2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
serverModel = r2;
|
||||
char *r3 = strchr(r2, ':');
|
||||
if (r3) {
|
||||
serverFilters = r3 + 1;
|
||||
serverModel = serverModel.Truncate(r3 - r2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
serverDescription = r2;
|
||||
char *r3 = strchr(r2, ':');
|
||||
if (r3) {
|
||||
serverQuirk = strtol(r3 + 1, NULL, 0);
|
||||
serverDescription = serverDescription.Truncate(r3 - r2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -312,10 +239,10 @@ void cPluginSatip::ParseServer(const char *paramP)
|
||||
r2 = strtok_r(NULL, "|", &s2);
|
||||
}
|
||||
if (*serverAddr && *serverModel && *serverDescription) {
|
||||
debug1("%s srcaddr=%s ipaddr=%s port=%d model=%s (%s) desc=%s (%d)", __PRETTY_FUNCTION__, *sourceAddr, *serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk);
|
||||
debug1("%s ipaddr=%s model=%s desc=%s", __PRETTY_FUNCTION__, *serverAddr, *serverModel, *serverDescription);
|
||||
if (!serversM)
|
||||
serversM = new cSatipDiscoverServers();
|
||||
serversM->Add(new cSatipDiscoverServer(*sourceAddr, *serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk));
|
||||
serversM->Add(new cSatipDiscoverServer(*serverAddr, *serverModel, *serverDescription));
|
||||
}
|
||||
++n;
|
||||
r = strtok_r(NULL, ";", &s);
|
||||
@ -323,37 +250,6 @@ void cPluginSatip::ParseServer(const char *paramP)
|
||||
FREE_POINTER(p);
|
||||
}
|
||||
|
||||
void cPluginSatip::ParsePortRange(const char *paramP)
|
||||
{
|
||||
char *s, *p = skipspace(paramP);
|
||||
char *r = strtok_r(p, "-", &s);
|
||||
unsigned int rangeStart = 0;
|
||||
unsigned int rangeStop = 0;
|
||||
if (r) {
|
||||
rangeStart = strtol(r, NULL, 0);
|
||||
r = strtok_r(NULL, "-", &s);
|
||||
}
|
||||
if (r)
|
||||
rangeStop = strtol(r, NULL, 0);
|
||||
else {
|
||||
error("Port range argument not valid '%s'", paramP);
|
||||
rangeStart = 0;
|
||||
rangeStop = 0;
|
||||
}
|
||||
if (rangeStart % 2) {
|
||||
error("The given range start port must be even!");
|
||||
rangeStart = 0;
|
||||
rangeStop = 0;
|
||||
}
|
||||
else if (rangeStop - rangeStart + 1 < deviceCountM * 2) {
|
||||
error("The given port range is to small: %d < %d!", rangeStop - rangeStart + 1, deviceCountM * 2);
|
||||
rangeStart = 0;
|
||||
rangeStop = 0;
|
||||
}
|
||||
SatipConfig.SetPortRangeStart(rangeStart);
|
||||
SatipConfig.SetPortRangeStop(rangeStop);
|
||||
}
|
||||
|
||||
int cPluginSatip::ParseCicams(const char *valueP, int *cicamsP)
|
||||
{
|
||||
debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP);
|
||||
@ -415,8 +311,6 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
|
||||
SatipConfig.SetOperatingMode(atoi(valueP));
|
||||
else if (!strcasecmp(nameP, "EnableCIExtension"))
|
||||
SatipConfig.SetCIExtension(atoi(valueP));
|
||||
else if (!strcasecmp(nameP, "EnableFrontendReuse"))
|
||||
SatipConfig.SetFrontendReuse(atoi(valueP));
|
||||
else if (!strcasecmp(nameP, "CICAM")) {
|
||||
int Cicams[MAX_CICAM_COUNT];
|
||||
for (unsigned int i = 0; i < ELEMENTS(Cicams); ++i)
|
||||
@ -443,8 +337,6 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
|
||||
for (unsigned int i = 0; i < DisabledFiltersCount; ++i)
|
||||
SatipConfig.SetDisabledFilters(i, DisabledFilters[i]);
|
||||
}
|
||||
else if (!strcasecmp(nameP, "TransportMode"))
|
||||
SatipConfig.SetTransportMode(atoi(valueP));
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
@ -474,12 +366,8 @@ const char **cPluginSatip::SVDRPHelpPages(void)
|
||||
" Lists status information of SAT>IP devices.\n",
|
||||
"CONT\n"
|
||||
" Shows SAT>IP device count.\n",
|
||||
"OPER [ off | low | normal | high ]\n"
|
||||
" Gets and(or sets operating mode of SAT>IP devices.\n",
|
||||
"ATTA\n"
|
||||
" Attach active SAT>IP servers.\n",
|
||||
"DETA\n"
|
||||
" Detachs active SAT>IP servers.\n",
|
||||
"OPER\n"
|
||||
" Toggles operating mode of SAT>IP devices.\n",
|
||||
"TRAC [ <mode> ]\n"
|
||||
" Gets and/or sets used tracing mode.\n",
|
||||
NULL
|
||||
@ -546,19 +434,8 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
|
||||
}
|
||||
else if (strcasecmp(commandP, "OPER") == 0) {
|
||||
cString mode;
|
||||
unsigned int oper = SatipConfig.GetOperatingMode();
|
||||
if (optionP && *optionP) {
|
||||
if (strcasecmp(optionP, "off") == 0)
|
||||
oper = cSatipConfig::eOperatingModeOff;
|
||||
else if (strcasecmp(optionP, "low") == 0)
|
||||
oper = cSatipConfig::eOperatingModeLow;
|
||||
else if (strcasecmp(optionP, "normal") == 0)
|
||||
oper = cSatipConfig::eOperatingModeNormal;
|
||||
else if (strcasecmp(optionP, "high") == 0)
|
||||
oper = cSatipConfig::eOperatingModeHigh;
|
||||
SatipConfig.SetOperatingMode(oper);
|
||||
}
|
||||
switch (oper) {
|
||||
SatipConfig.ToggleOperatingMode();
|
||||
switch (SatipConfig.GetOperatingMode()) {
|
||||
case cSatipConfig::eOperatingModeOff:
|
||||
mode = "off";
|
||||
break;
|
||||
@ -577,16 +454,6 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
|
||||
}
|
||||
return cString::sprintf("SATIP operating mode: %s\n", *mode);
|
||||
}
|
||||
else if (strcasecmp(commandP, "ATTA") == 0) {
|
||||
SatipConfig.SetDetachedMode(false);
|
||||
info("SATIP servers attached");
|
||||
return cString("SATIP servers attached");
|
||||
}
|
||||
else if (strcasecmp(commandP, "DETA") == 0) {
|
||||
SatipConfig.SetDetachedMode(true);
|
||||
info("SATIP servers detached");
|
||||
return cString("SATIP servers detached");
|
||||
}
|
||||
else if (strcasecmp(commandP, "TRAC") == 0) {
|
||||
if (optionP && *optionP)
|
||||
SatipConfig.SetTraceMode(strtol(optionP, NULL, 0));
|
||||
|
146
sectionfilter.c
146
sectionfilter.c
@ -18,14 +18,35 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
|
||||
secLenM(0),
|
||||
tsFeedpM(0),
|
||||
pidM(pidP),
|
||||
tidM(tidP),
|
||||
maskM(maskP),
|
||||
ringBufferM(new cRingBufferFrame(eDmxMaxSectionCount * eDmxMaxSectionSize)),
|
||||
deviceIndexM(deviceIndexP)
|
||||
{
|
||||
debug16("%s (%d, %d, %d, %d) [device %d]", __PRETTY_FUNCTION__, deviceIndexM, pidM, tidP, maskP, deviceIndexM);
|
||||
int i;
|
||||
|
||||
memset(secBufBaseM, 0, sizeof(secBufBaseM));
|
||||
memset(filterValueM, 0, sizeof(filterValueM));
|
||||
memset(filterMaskM, 0, sizeof(filterMaskM));
|
||||
memset(filterModeM, 0, sizeof(filterModeM));
|
||||
memset(maskAndModeM, 0, sizeof(maskAndModeM));
|
||||
memset(maskAndNotModeM, 0, sizeof(maskAndNotModeM));
|
||||
|
||||
filterValueM[0] = tidP;
|
||||
filterMaskM[0] = maskP;
|
||||
|
||||
// Invert the filter
|
||||
for (i = 0; i < eDmxMaxFilterSize; ++i)
|
||||
filterValueM[i] ^= 0xFF;
|
||||
|
||||
uint8_t doneq = 0;
|
||||
for (i = 0; i < eDmxMaxFilterSize; ++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];
|
||||
}
|
||||
doneqM = doneq ? 1 : 0;
|
||||
|
||||
// Create sockets
|
||||
socketM[0] = socketM[1] = -1;
|
||||
@ -68,13 +89,21 @@ void cSatipSectionFilter::New(void)
|
||||
int cSatipSectionFilter::Filter(void)
|
||||
{
|
||||
if (secBufM) {
|
||||
if ((tidM & maskM) == (secBufM[0] & maskM)) {
|
||||
if (ringBufferM && (secLenM > 0)) {
|
||||
cFrame* section = new cFrame(secBufM, secLenM);
|
||||
if (!ringBufferM->Put(section))
|
||||
DELETE_POINTER(section);
|
||||
}
|
||||
int i;
|
||||
uint8_t neq = 0;
|
||||
|
||||
for (i = 0; i < eDmxMaxFilterSize; ++i) {
|
||||
uint8_t calcxor = (uint8_t)(filterValueM[i] ^ secBufM[i]);
|
||||
if (maskAndModeM[i] & calcxor)
|
||||
return 0;
|
||||
neq |= (maskAndNotModeM[i] & calcxor);
|
||||
}
|
||||
|
||||
if (doneqM && !neq)
|
||||
return 0;
|
||||
|
||||
if (ringBufferM && (secLenM > 0))
|
||||
ringBufferM->Put(new cFrame(secBufM, secLenM));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -97,7 +126,7 @@ int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
|
||||
if (tsFeedpM + lenP > eDmxMaxSectionFeedSize)
|
||||
lenP = (uint8_t)(eDmxMaxSectionFeedSize - tsFeedpM);
|
||||
|
||||
if (lenP == 0)
|
||||
if (lenP <= 0)
|
||||
return 0;
|
||||
|
||||
memcpy(secBufBaseM + tsFeedpM, bufP, lenP);
|
||||
@ -112,7 +141,7 @@ int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
|
||||
|
||||
for (n = 0; secBufpM + 2 < limit; ++n) {
|
||||
uint16_t seclen = GetLength(secBufM);
|
||||
if ((seclen > eDmxMaxSectionSize) || ((seclen + secBufpM) > limit))
|
||||
if ((seclen <= 0) || (seclen > eDmxMaxSectionSize) || ((seclen + secBufpM) > limit))
|
||||
return 0;
|
||||
secLenM = seclen;
|
||||
if (pusiSeenM)
|
||||
@ -180,28 +209,27 @@ void cSatipSectionFilter::Process(const uint8_t* dataP)
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipSectionFilter::Send(void)
|
||||
bool cSatipSectionFilter::Send(void)
|
||||
{
|
||||
bool result = false;
|
||||
cFrame *section = ringBufferM->Get();
|
||||
if (section) {
|
||||
uchar *data = section->Data();
|
||||
int count = section->Count();
|
||||
if (data && (count > 0) && (socketM[1] >= 0) && (socketM[0] >= 0)) {
|
||||
if (send(socketM[1], data, count, MSG_EOR) > 0) {
|
||||
// Update statistics
|
||||
AddSectionStatistic(count, 1);
|
||||
}
|
||||
else if (errno != EAGAIN)
|
||||
error("failed to send section data (%i bytes) [device=%d]", count, deviceIndexM);
|
||||
}
|
||||
ssize_t len = send(socketM[1], data, count, MSG_EOR);
|
||||
ERROR_IF(len < 0 && errno != EAGAIN, "send()");
|
||||
if (len > 0) {
|
||||
ringBufferM->Drop(section);
|
||||
result = !!ringBufferM->Available();
|
||||
// Update statistics
|
||||
AddSectionStatistic(len, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int cSatipSectionFilter::Available(void) const
|
||||
{
|
||||
return ringBufferM->Available();
|
||||
}
|
||||
|
||||
cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP)
|
||||
: cThread(cString::sprintf("SATIP#%d section handler", deviceIndexP)),
|
||||
@ -239,48 +267,30 @@ cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
|
||||
Delete(i);
|
||||
}
|
||||
|
||||
void cSatipSectionFilterHandler::SendAll(void)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
bool pendingData;
|
||||
do {
|
||||
pendingData = false;
|
||||
|
||||
// zero polling structures
|
||||
memset(pollFdsM, 0, sizeof(pollFdsM));
|
||||
|
||||
// assemble all handlers to poll (use -1 to ignore handlers)
|
||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||
if (filtersM[i] && filtersM[i]->Available() != 0) {
|
||||
pollFdsM[i].fd = filtersM[i]->GetFd();
|
||||
pollFdsM[i].events = POLLOUT;
|
||||
pendingData = true;
|
||||
}
|
||||
else
|
||||
pollFdsM[i].fd = -1;
|
||||
}
|
||||
|
||||
// exit if there isn't any pending data or we time out
|
||||
if (!pendingData || poll(pollFdsM, eMaxSecFilterCount, eSecFilterSendTimeoutMs) <= 0)
|
||||
return;
|
||||
|
||||
// send data (if available)
|
||||
for (unsigned int i = 0; i < eMaxSecFilterCount && pendingData; ++i) {
|
||||
if (pollFdsM[i].revents & POLLOUT)
|
||||
filtersM[i]->Send();
|
||||
}
|
||||
} while (pendingData);
|
||||
}
|
||||
|
||||
void cSatipSectionFilterHandler::Action(void)
|
||||
{
|
||||
debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
bool processed = false;
|
||||
// Do the thread loop
|
||||
while (Running()) {
|
||||
uchar *p = NULL;
|
||||
// Send demuxed section packets through all filters
|
||||
bool retry = false;
|
||||
mutexM.Lock();
|
||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||
if (filtersM[i] && filtersM[i]->Send())
|
||||
retry = true;
|
||||
}
|
||||
mutexM.Unlock();
|
||||
if (retry)
|
||||
continue;
|
||||
// Read one TS packet
|
||||
if (ringBufferM) {
|
||||
int len = 0;
|
||||
// Process all pending TS packets
|
||||
while ((p = ringBufferM->Get(len)) != NULL) {
|
||||
if (processed) {
|
||||
ringBufferM->Del(TS_SIZE);
|
||||
processed = false;
|
||||
}
|
||||
uchar *p = ringBufferM->Get(len);
|
||||
if (p && (len >= TS_SIZE)) {
|
||||
if (*p != TS_SYNC_BYTE) {
|
||||
for (int i = 1; i < len; ++i) {
|
||||
@ -300,12 +310,11 @@ void cSatipSectionFilterHandler::Action(void)
|
||||
filtersM[i]->Process(p);
|
||||
}
|
||||
mutexM.Unlock();
|
||||
ringBufferM->Del(TS_SIZE);
|
||||
processed = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Send demuxed section packets through all filters
|
||||
SendAll();
|
||||
cCondWait::SleepMs(10); // to avoid busy loop and reduce cpu load
|
||||
}
|
||||
debug1("%s Exiting [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||
}
|
||||
@ -329,19 +338,6 @@ cString cSatipSectionFilterHandler::GetInformation(void)
|
||||
return s;
|
||||
}
|
||||
|
||||
bool cSatipSectionFilterHandler::Exists(u_short pidP)
|
||||
{
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||
if (filtersM[i] && (pidP == filtersM[i]->GetPid())) {
|
||||
debug12("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipSectionFilterHandler::Delete(unsigned int indexP)
|
||||
{
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);
|
||||
|
@ -8,7 +8,6 @@
|
||||
#ifndef __SATIP_SECTIONFILTER_H
|
||||
#define __SATIP_SECTIONFILTER_H
|
||||
|
||||
#include <poll.h>
|
||||
#include <vdr/device.h>
|
||||
|
||||
#include "common.h"
|
||||
@ -33,13 +32,18 @@ private:
|
||||
uint16_t secLenM;
|
||||
uint16_t tsFeedpM;
|
||||
uint16_t pidM;
|
||||
uint8_t tidM;
|
||||
uint8_t maskM;
|
||||
|
||||
cRingBufferFrame *ringBufferM;
|
||||
int deviceIndexM;
|
||||
int socketM[2];
|
||||
|
||||
uint8_t filterValueM[eDmxMaxFilterSize];
|
||||
uint8_t filterMaskM[eDmxMaxFilterSize];
|
||||
uint8_t filterModeM[eDmxMaxFilterSize];
|
||||
|
||||
uint8_t maskAndModeM[eDmxMaxFilterSize];
|
||||
uint8_t maskAndNotModeM[eDmxMaxFilterSize];
|
||||
|
||||
inline uint16_t GetLength(const uint8_t *dataP);
|
||||
void New(void);
|
||||
int Filter(void);
|
||||
@ -51,27 +55,23 @@ public:
|
||||
cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP);
|
||||
virtual ~cSatipSectionFilter();
|
||||
void Process(const uint8_t* dataP);
|
||||
void Send(void);
|
||||
bool Send(void);
|
||||
int GetFd(void) { return socketM[0]; }
|
||||
uint16_t GetPid(void) const { return pidM; }
|
||||
int Available(void) const;
|
||||
};
|
||||
|
||||
class cSatipSectionFilterHandler : public cThread {
|
||||
private:
|
||||
enum {
|
||||
eMaxSecFilterCount = 32,
|
||||
eSecFilterSendTimeoutMs = 10
|
||||
eMaxSecFilterCount = 32
|
||||
};
|
||||
cRingBufferLinear *ringBufferM;
|
||||
cMutex mutexM;
|
||||
int deviceIndexM;
|
||||
cSatipSectionFilter *filtersM[eMaxSecFilterCount];
|
||||
struct pollfd pollFdsM[eMaxSecFilterCount];
|
||||
|
||||
bool Delete(unsigned int indexP);
|
||||
bool IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const;
|
||||
void SendAll(void);
|
||||
|
||||
protected:
|
||||
virtual void Action(void);
|
||||
@ -80,7 +80,6 @@ public:
|
||||
cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP);
|
||||
virtual ~cSatipSectionFilterHandler();
|
||||
cString GetInformation(void);
|
||||
bool Exists(u_short pidP);
|
||||
int Open(u_short pidP, u_char tidP, u_char maskP);
|
||||
void Close(int handleP);
|
||||
int GetPid(int handleP);
|
||||
|
496
server.c
496
server.c
@ -12,229 +12,77 @@
|
||||
#include "log.h"
|
||||
#include "server.h"
|
||||
|
||||
// --- cSatipFrontend ---------------------------------------------------------
|
||||
|
||||
cSatipFrontend::cSatipFrontend(const int indexP, const char *descriptionP)
|
||||
: indexM(indexP),
|
||||
transponderM(0),
|
||||
deviceIdM(-1),
|
||||
descriptionM(descriptionP)
|
||||
{
|
||||
}
|
||||
|
||||
cSatipFrontend::~cSatipFrontend()
|
||||
{
|
||||
}
|
||||
|
||||
// --- cSatipFrontends --------------------------------------------------------
|
||||
|
||||
bool cSatipFrontends::Matches(int deviceIdP, int transponderP)
|
||||
{
|
||||
for (cSatipFrontend *f = First(); f; f = Next(f)) {
|
||||
if (f->Attached() && (f->DeviceId() == deviceIdP) && (f->Transponder() == transponderP))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipFrontends::Assign(int deviceIdP, int transponderP)
|
||||
{
|
||||
cSatipFrontend *tmp = NULL;
|
||||
// Prefer any used one
|
||||
for (cSatipFrontend *f = First(); f; f = Next(f)) {
|
||||
if (f->DeviceId() == deviceIdP) { // give deviceID priority, but take detached frontend if deviceID ist not yet attached
|
||||
tmp = f;
|
||||
break;
|
||||
}
|
||||
if (!f->Attached()) {
|
||||
tmp = f;
|
||||
}
|
||||
}
|
||||
if (tmp) {
|
||||
tmp->SetTransponder(transponderP);
|
||||
debug9("%s assigned TP %d to %s/#%d", __PRETTY_FUNCTION__, transponderP, *tmp->Description(), tmp->Index());
|
||||
return true;
|
||||
}
|
||||
error("no assignable frontend found [device %u]", deviceIdP);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipFrontends::Attach(int deviceIdP, int transponderP)
|
||||
{
|
||||
cSatipFrontend *tmp = NULL;
|
||||
for (cSatipFrontend *f = First(); f; f = Next(f)) {
|
||||
if (f->Transponder() == transponderP) {
|
||||
tmp = f;
|
||||
if (f->DeviceId() == deviceIdP) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp) {
|
||||
tmp->Attach(deviceIdP);
|
||||
debug9("%s attached deviceId %d (TP %d) to %s/#%d", __PRETTY_FUNCTION__, deviceIdP, transponderP, *tmp->Description(), tmp->Index());
|
||||
return true;
|
||||
}
|
||||
error("%s no Frontend found for attaching deviceID %d (TP %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipFrontends::Detach(int deviceIdP, int transponderP)
|
||||
{
|
||||
for (cSatipFrontend *f = First(); f; f = Next(f)) {
|
||||
if (f->Transponder() == transponderP) {
|
||||
f->Detach(deviceIdP);
|
||||
debug9("%s detached deviceID %d (TP %d) from %s/#%d", __PRETTY_FUNCTION__, deviceIdP, transponderP, *f->Description(), f->Index());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- cSatipServer -----------------------------------------------------------
|
||||
|
||||
cSatipServer::cSatipServer(const char *srcAddressP, const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP)
|
||||
: srcAddressM((srcAddressP && *srcAddressP) ? srcAddressP : ""),
|
||||
addressM((addressP && *addressP) ? addressP : "0.0.0.0"),
|
||||
cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char *descriptionP)
|
||||
: addressM((addressP && *addressP) ? addressP : "0.0.0.0"),
|
||||
modelM((modelP && *modelP) ? modelP : "DVBS-1"),
|
||||
filtersM((filtersP && *filtersP) ? filtersP : ""),
|
||||
descriptionM(!isempty(descriptionP) ? descriptionP : "MyBrokenHardware"),
|
||||
quirksM(""),
|
||||
portM(portP),
|
||||
quirkM(quirkP),
|
||||
hasCiM(false),
|
||||
activeM(true),
|
||||
modelTypeM(eSatipModelTypeNone),
|
||||
quirkM(eSatipQuirkNone),
|
||||
useCountM(0),
|
||||
transponderM(0),
|
||||
createdM(time(NULL)),
|
||||
lastSeenM(0)
|
||||
{
|
||||
memset(sourceFiltersM, 0, sizeof(sourceFiltersM));
|
||||
if (!isempty(*filtersM)) {
|
||||
char *s, *p = strdup(*filtersM);
|
||||
char *r = strtok_r(p, ",", &s);
|
||||
unsigned int i = 0;
|
||||
while (r) {
|
||||
int t = cSource::FromString(skipspace(r));
|
||||
if (t && i < ELEMENTS(sourceFiltersM))
|
||||
sourceFiltersM[i++] = t;
|
||||
r = strtok_r(NULL, ",", &s);
|
||||
}
|
||||
if (i) {
|
||||
filtersM = "";
|
||||
for (unsigned int j = 0; j < i; ++j)
|
||||
filtersM = cString::sprintf("%s%s%s", *filtersM, isempty(*filtersM) ? "" : ",", *cSource::ToString(sourceFiltersM[j]));
|
||||
debug3("%s filters=%s", __PRETTY_FUNCTION__, *filtersM);
|
||||
}
|
||||
FREE_POINTER(p);
|
||||
}
|
||||
memset(modelCountM, 0, sizeof(modelCountM));
|
||||
if (!SatipConfig.GetDisableServerQuirks()) {
|
||||
debug3("%s quirks=%s", __PRETTY_FUNCTION__, *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, "Multibox-") || // Inverto IDL-400s: Multibox-<MMAACC>:SAT>IP
|
||||
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
|
||||
)
|
||||
quirkM |= eSatipQuirkSessionId;
|
||||
// These devices contain support for RTP over TCP:
|
||||
if (strstr(*descriptionM, "minisatip") || // minisatip server
|
||||
strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
|
||||
)
|
||||
quirkM |= eSatipQuirkRtpOverTcp;
|
||||
// These devices contain a play (add/delpids) parameter bug:
|
||||
if (strstr(*descriptionM, "FRITZ!WLAN Repeater DVB-C") || // FRITZ!WLAN Repeater DVB-C
|
||||
strstr(*descriptionM, "fritzdvbc") // FRITZ!WLAN Repeater DVB-C (old firmware)
|
||||
)
|
||||
if (strstr(*descriptionM, "fritzdvbc")) // Fritz!WLAN Repeater DVB-C
|
||||
quirkM |= eSatipQuirkPlayPids;
|
||||
// These devices contain a frontend locking bug:
|
||||
if (strstr(*descriptionM, "FRITZ!WLAN Repeater DVB-C") || // FRITZ!WLAN Repeater DVB-C
|
||||
strstr(*descriptionM, "fritzdvbc") || // FRITZ!WLAN Repeater DVB-C (old firmware)
|
||||
strstr(*descriptionM, "Schwaiger Sat>IP Server") // Schwaiger MS41IP
|
||||
)
|
||||
if (strstr(*descriptionM, "fritzdvbc")) // Fritz!WLAN Repeater DVB-C
|
||||
quirkM |= eSatipQuirkForceLock;
|
||||
// These devices support the X_PMT protocol extension:
|
||||
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
|
||||
strstr(*descriptionM, "minisatip") // minisatip server
|
||||
)
|
||||
quirkM |= eSatipQuirkCiXpmt;
|
||||
// These devices support the TNR protocol extension:
|
||||
if (strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
|
||||
)
|
||||
quirkM |= eSatipQuirkCiTnr;
|
||||
// These devices don't support auto-detection of pilot tones:
|
||||
if (strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
|
||||
strstr(*descriptionM, "DIGIBIT") || // Telestar Digibit R1
|
||||
strstr(*descriptionM, "Multibox-") || // Inverto IDL-400s: Multibox-<MMAACC>:SAT>IP
|
||||
strstr(*descriptionM, "Triax SatIP Converter") || // Triax TSS 400
|
||||
strstr(*descriptionM, "KATHREIN SatIP Server") // Kathrein ExIP 414/E
|
||||
)
|
||||
quirkM |= eSatipQuirkForcePilot;
|
||||
// These devices require TEARDOWN before new PLAY command:
|
||||
if (strstr(*descriptionM, "FRITZ!WLAN Repeater DVB-C") || // FRITZ!WLAN Repeater DVB-C
|
||||
strstr(*descriptionM, "fritzdvbc") // FRITZ!WLAN Repeater DVB-C (old firmware)
|
||||
)
|
||||
quirkM |= eSatipQuirkTearAndPlay;
|
||||
}
|
||||
if ((quirkM & eSatipQuirkMask) & eSatipQuirkSessionId)
|
||||
quirksM = cString::sprintf("%s%sSessionId", *quirksM, isempty(*quirksM) ? "" : ",");
|
||||
if ((quirkM & eSatipQuirkMask) & eSatipQuirkPlayPids)
|
||||
quirksM = cString::sprintf("%s%sPlayPids", *quirksM, isempty(*quirksM) ? "" : ",");
|
||||
if ((quirkM & eSatipQuirkMask) & eSatipQuirkForceLock)
|
||||
quirksM = cString::sprintf("%s%sForceLock", *quirksM, isempty(*quirksM) ? "" : ",");
|
||||
if ((quirkM & eSatipQuirkMask) & eSatipQuirkRtpOverTcp)
|
||||
quirksM = cString::sprintf("%s%sRtpOverTcp", *quirksM, isempty(*quirksM) ? "" : ",");
|
||||
if ((quirkM & eSatipQuirkMask) & eSatipQuirkCiXpmt)
|
||||
quirksM = cString::sprintf("%s%sCiXpmt", *quirksM, isempty(*quirksM) ? "" : ",");
|
||||
if ((quirkM & eSatipQuirkMask) & eSatipQuirkCiTnr)
|
||||
quirksM = cString::sprintf("%s%sCiTnr", *quirksM, isempty(*quirksM) ? "" : ",");
|
||||
if ((quirkM & eSatipQuirkMask) & eSatipQuirkForcePilot)
|
||||
quirksM = cString::sprintf("%s%sForcePilot", *quirksM, isempty(*quirksM) ? "" : ",");
|
||||
debug3("%s description=%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM, *quirksM);
|
||||
// These devices support external CI
|
||||
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
|
||||
strstr(*descriptionM, "minisatip") || // minisatip server
|
||||
strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
|
||||
) {
|
||||
hasCiM = true;
|
||||
if (quirkM != eSatipQuirkNone)
|
||||
info("Malfunctioning '%s' server detected! Please, fix the firmware.", *descriptionM);
|
||||
}
|
||||
// These devices support the X_PMT protocol extension
|
||||
if (strstr(*descriptionM, "OctopusNet")) // Digital Devices OctopusNet
|
||||
quirkM |= eSatipQuirkUseXCI;
|
||||
char *s, *p = strdup(*modelM);
|
||||
char *r = strtok_r(p, ",", &s);
|
||||
while (r) {
|
||||
char *c;
|
||||
if (c = strstr(r, "DVBS2-")) {
|
||||
int count = atoi(c + 6);
|
||||
for (int i = 1; i <= count; ++i)
|
||||
frontendsM[eSatipFrontendDVBS2].Add(new cSatipFrontend(i, "DVB-S2"));
|
||||
if (strstr(r, "DVBS2-")) {
|
||||
modelTypeM |= eSatipModelTypeDVBS2;
|
||||
if (char *c = strstr(r, "-"))
|
||||
modelCountM[eSatipModuleDVBS2] = atoi(++c);
|
||||
}
|
||||
else if (c = strstr(r, "DVBT-")) {
|
||||
int count = atoi(c + 5);
|
||||
for (int i = 1; i <= count; ++i)
|
||||
frontendsM[eSatipFrontendDVBT].Add(new cSatipFrontend(i, "DVB-T"));
|
||||
else if (strstr(r, "DVBT2-")) {
|
||||
modelTypeM |= eSatipModelTypeDVBT2;
|
||||
if (char *c = strstr(r, "-"))
|
||||
modelCountM[eSatipModuleDVBT2] = atoi(++c);
|
||||
modelTypeM |= eSatipModelTypeDVBT;
|
||||
modelCountM[eSatipModuleDVBT] = modelCountM[eSatipModuleDVBT2];
|
||||
}
|
||||
else if (c = strstr(r, "DVBT2-")) {
|
||||
int count = atoi(c + 6);
|
||||
for (int i = 1; i <= count; ++i)
|
||||
frontendsM[eSatipFrontendDVBT2].Add(new cSatipFrontend(i, "DVB-T2"));
|
||||
else if (strstr(r, "DVBT-")) {
|
||||
modelTypeM |= eSatipModelTypeDVBT;
|
||||
if (char *c = strstr(r, "-"))
|
||||
modelCountM[eSatipModuleDVBT] = atoi(++c);
|
||||
}
|
||||
else if (c = strstr(r, "DVBC-")) {
|
||||
int count = atoi(c + 5);
|
||||
for (int i = 1; i <= count; ++i)
|
||||
frontendsM[eSatipFrontendDVBC].Add(new cSatipFrontend(i, "DVB-C"));
|
||||
else if (strstr(r, "DVBC2-")) {
|
||||
modelTypeM |= eSatipModelTypeDVBC2;
|
||||
if (char *c = strstr(r, "-"))
|
||||
modelCountM[eSatipModuleDVBC2] = atoi(++c);
|
||||
modelTypeM |= eSatipModelTypeDVBC;
|
||||
modelCountM[eSatipModuleDVBC] = modelCountM[eSatipModuleDVBC2];
|
||||
}
|
||||
else if (c = strstr(r, "DVBC2-")) {
|
||||
int count = atoi(c + 6);
|
||||
for (int i = 1; i <= count; ++i)
|
||||
frontendsM[eSatipFrontendDVBC2].Add(new cSatipFrontend(i, "DVB-C2"));
|
||||
}
|
||||
else if (c = strstr(r, "ATSC-")) {
|
||||
int count = atoi(c + 5);
|
||||
for (int i = 1; i <= count; ++i)
|
||||
frontendsM[eSatipFrontendATSC].Add(new cSatipFrontend(i, "ATSC"));
|
||||
else if (strstr(r, "DVBC-")) {
|
||||
modelTypeM |= eSatipModelTypeDVBC;
|
||||
if (char *c = strstr(r, "-"))
|
||||
modelCountM[eSatipModuleDVBC] = atoi(++c);
|
||||
}
|
||||
r = strtok_r(NULL, ",", &s);
|
||||
}
|
||||
FREE_POINTER(p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
cSatipServer::~cSatipServer()
|
||||
@ -253,126 +101,12 @@ int cSatipServer::Compare(const cListObject &listObjectP) const
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipServer::IsValidSource(int sourceP)
|
||||
void cSatipServer::Use(bool onOffP)
|
||||
{
|
||||
if (sourceFiltersM[0]) {
|
||||
for (unsigned int i = 0; i < ELEMENTS(sourceFiltersM); ++i) {
|
||||
if (sourceP == sourceFiltersM[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipServer::Assign(int deviceIdP, int sourceP, int systemP, int transponderP)
|
||||
{
|
||||
bool result = false;
|
||||
if (IsValidSource(sourceP)) {
|
||||
if (cSource::IsType(sourceP, 'S'))
|
||||
result = frontendsM[eSatipFrontendDVBS2].Assign(deviceIdP, transponderP);
|
||||
else if (cSource::IsType(sourceP, 'T')) {
|
||||
if (systemP)
|
||||
result = frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
|
||||
if (onOffP)
|
||||
++useCountM;
|
||||
else
|
||||
result = frontendsM[eSatipFrontendDVBT].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
|
||||
}
|
||||
else if (cSource::IsType(sourceP, 'C')) {
|
||||
if (systemP)
|
||||
result = frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
|
||||
else
|
||||
result = frontendsM[eSatipFrontendDVBC].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
|
||||
}
|
||||
else if (cSource::IsType(sourceP, 'A'))
|
||||
result = frontendsM[eSatipFrontendATSC].Assign(deviceIdP, transponderP);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipServer::Matches(int sourceP)
|
||||
{
|
||||
if (IsValidSource(sourceP)) {
|
||||
if (cSource::IsType(sourceP, 'S'))
|
||||
return GetModulesDVBS2();
|
||||
else if (cSource::IsType(sourceP, 'T'))
|
||||
return GetModulesDVBT() || GetModulesDVBT2();
|
||||
else if (cSource::IsType(sourceP, 'C'))
|
||||
return GetModulesDVBC() || GetModulesDVBC2();
|
||||
else if (cSource::IsType(sourceP, 'A'))
|
||||
return GetModulesATSC();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipServer::Matches(int deviceIdP, int sourceP, int systemP, int transponderP)
|
||||
{
|
||||
bool result = false;
|
||||
if (IsValidSource(sourceP)) {
|
||||
if (cSource::IsType(sourceP, 'S'))
|
||||
result = frontendsM[eSatipFrontendDVBS2].Matches(deviceIdP, transponderP);
|
||||
else if (cSource::IsType(sourceP, 'T')) {
|
||||
if (systemP)
|
||||
result = frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
|
||||
else
|
||||
result = frontendsM[eSatipFrontendDVBT].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
|
||||
}
|
||||
else if (cSource::IsType(sourceP, 'C')) {
|
||||
if (systemP)
|
||||
result = frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
|
||||
else
|
||||
result = frontendsM[eSatipFrontendDVBC].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
|
||||
}
|
||||
else if (cSource::IsType(sourceP, 'A'))
|
||||
result = frontendsM[eSatipFrontendATSC].Matches(deviceIdP, transponderP);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void cSatipServer::Attach(int deviceIdP, int transponderP)
|
||||
{
|
||||
for (int i = 0; i < eSatipFrontendCount; ++i) {
|
||||
if (frontendsM[i].Attach(deviceIdP, transponderP))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipServer::Detach(int deviceIdP, int transponderP)
|
||||
{
|
||||
for (int i = 0; i < eSatipFrontendCount; ++i) {
|
||||
if (frontendsM[i].Detach(deviceIdP, transponderP))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int cSatipServer::GetModulesDVBS2(void)
|
||||
{
|
||||
return frontendsM[eSatipFrontendDVBS2].Count();
|
||||
}
|
||||
|
||||
int cSatipServer::GetModulesDVBT(void)
|
||||
{
|
||||
return frontendsM[eSatipFrontendDVBT].Count();
|
||||
}
|
||||
|
||||
int cSatipServer::GetModulesDVBT2(void)
|
||||
{
|
||||
return frontendsM[eSatipFrontendDVBT2].Count();
|
||||
}
|
||||
|
||||
int cSatipServer::GetModulesDVBC(void)
|
||||
{
|
||||
return frontendsM[eSatipFrontendDVBC].Count();
|
||||
}
|
||||
|
||||
int cSatipServer::GetModulesDVBC2(void)
|
||||
{
|
||||
return frontendsM[eSatipFrontendDVBC2].Count();
|
||||
}
|
||||
|
||||
int cSatipServer::GetModulesATSC(void)
|
||||
{
|
||||
return frontendsM[eSatipFrontendATSC].Count();
|
||||
--useCountM;
|
||||
}
|
||||
|
||||
// --- cSatipServers ----------------------------------------------------------
|
||||
@ -380,32 +114,49 @@ int cSatipServer::GetModulesATSC(void)
|
||||
cSatipServer *cSatipServers::Find(cSatipServer *serverP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s->Compare(*serverP) == 0)
|
||||
if (s == serverP)
|
||||
return s;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cSatipServer *cSatipServers::Find(int sourceP)
|
||||
cSatipServer *cSatipServers::Find(int sourceP, int transponderP, int systemP)
|
||||
{
|
||||
cSatipServer *result = NULL;
|
||||
int model = 0;
|
||||
if (cSource::IsType(sourceP, 'S'))
|
||||
model |= cSatipServer::eSatipModelTypeDVBS2;
|
||||
else if (cSource::IsType(sourceP, 'T')) {
|
||||
if (systemP < 0)
|
||||
model |= cSatipServer::eSatipModelTypeDVBT2 | cSatipServer::eSatipModelTypeDVBT;
|
||||
else
|
||||
model |= systemP ? cSatipServer::eSatipModelTypeDVBT2 : cSatipServer::eSatipModelTypeDVBT;
|
||||
}
|
||||
else if (cSource::IsType(sourceP, 'C'))
|
||||
model |= cSatipServer::eSatipModelTypeDVBC;
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s->Matches(sourceP))
|
||||
if (s->Match(model) && s->Used() && (s->Transponder() == transponderP))
|
||||
return s;
|
||||
}
|
||||
return NULL;
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s->Match(model)) {
|
||||
result = s;
|
||||
if (!s->Used()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
cSatipServer *cSatipServers::Assign(int deviceIdP, int sourceP, int transponderP, int systemP)
|
||||
void cSatipServers::SetTransponder(cSatipServer *serverP, int transponderP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s->IsActive() && s->Matches(deviceIdP, sourceP, systemP, transponderP))
|
||||
return s;
|
||||
if (s == serverP) {
|
||||
s->SetTransponder(transponderP);
|
||||
break;
|
||||
}
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s->IsActive() && s->Assign(deviceIdP, sourceP, systemP, transponderP))
|
||||
return s;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cSatipServer *cSatipServers::Update(cSatipServer *serverP)
|
||||
@ -419,60 +170,16 @@ cSatipServer *cSatipServers::Update(cSatipServer *serverP)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cSatipServers::Activate(cSatipServer *serverP, bool onOffP)
|
||||
void cSatipServers::Use(cSatipServer *serverP, bool onOffP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
s->Activate(onOffP);
|
||||
s->Use(onOffP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipServers::Attach(cSatipServer *serverP, int deviceIdP, int transponderP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
s->Attach(deviceIdP, transponderP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cSatipServers::Detach(cSatipServer *serverP, int deviceIdP, int transponderP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
s->Detach(deviceIdP, transponderP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cSatipServers::IsQuirk(cSatipServer *serverP, int quirkP)
|
||||
{
|
||||
bool result = false;
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
result = s->Quirk(quirkP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cSatipServers::HasCI(cSatipServer *serverP)
|
||||
{
|
||||
bool result = false;
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
result = s->HasCI();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void cSatipServers::Cleanup(uint64_t intervalMsP)
|
||||
{
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
@ -483,42 +190,6 @@ void cSatipServers::Cleanup(uint64_t intervalMsP)
|
||||
}
|
||||
}
|
||||
|
||||
cString cSatipServers::GetSrcAddress(cSatipServer *serverP)
|
||||
{
|
||||
cString address = "";
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
address = s->SrcAddress();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
cString cSatipServers::GetAddress(cSatipServer *serverP)
|
||||
{
|
||||
cString address = "";
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
address = s->Address();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
int cSatipServers::GetPort(cSatipServer *serverP)
|
||||
{
|
||||
int port = SATIP_DEFAULT_RTSP_PORT;
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
if (s == serverP) {
|
||||
port = s->Port();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
cString cSatipServers::GetString(cSatipServer *serverP)
|
||||
{
|
||||
cString list = "";
|
||||
@ -535,10 +206,7 @@ cString cSatipServers::List(void)
|
||||
{
|
||||
cString list = "";
|
||||
for (cSatipServer *s = First(); s; s = Next(s))
|
||||
if (isempty(s->SrcAddress()))
|
||||
list = cString::sprintf("%s%c %s|%s|%s\n", *list, s->IsActive() ? '+' : '-', s->Address(), s->Model(), s->Description());
|
||||
else
|
||||
list = cString::sprintf("%s%c %s@%s|%s|%s\n", *list, s->IsActive() ? '+' : '-', s->SrcAddress(), s->Address(), s->Model(), s->Description());
|
||||
list = cString::sprintf("%s%s|%s|%s\n", *list, s->Address(), s->Model(), s->Description());
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -547,17 +215,13 @@ int cSatipServers::NumProvidedSystems(void)
|
||||
int count = 0;
|
||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||
// DVB-S2: qpsk, 8psk, 16apsk, 32apsk
|
||||
count += s->GetModulesDVBS2() * 4;
|
||||
// DVB-T: qpsk, qam16, qam64
|
||||
count += s->GetModulesDVBT() * 3;
|
||||
count += s->Satellite() * 4;
|
||||
// DVB-T2: qpsk, qam16, qam64, qam256
|
||||
count += s->GetModulesDVBT2() * 4;
|
||||
// DVB-C: qam64, qam128, qam256
|
||||
count += s->GetModulesDVBC() * 3;
|
||||
// DVB-T: qpsk, qam16, qam64
|
||||
count += s->Terrestrial2() ? s->Terrestrial2() * 4 : s->Terrestrial() * 3;
|
||||
// DVB-C2: qam16, qam32, qam64, qam128, qam256
|
||||
count += s->GetModulesDVBC2() * 5;
|
||||
// ATSC: 8vbs, 16vbs, qam256
|
||||
count += s->GetModulesATSC() * 3;
|
||||
// DVB-C: qam64, qam128, qam256
|
||||
count += s->Cable2() ? s->Cable2() * 5 : s->Cable() * 3;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
131
server.h
131
server.h
@ -8,71 +8,28 @@
|
||||
#ifndef __SATIP_SERVER_H
|
||||
#define __SATIP_SERVER_H
|
||||
|
||||
class cSatipServer;
|
||||
|
||||
// --- cSatipFrontend ---------------------------------------------------------
|
||||
|
||||
class cSatipFrontend : public cListObject {
|
||||
private:
|
||||
int indexM;
|
||||
int transponderM;
|
||||
int deviceIdM;
|
||||
cString descriptionM;
|
||||
|
||||
public:
|
||||
cSatipFrontend(const int indexP, const char *descriptionP);
|
||||
virtual ~cSatipFrontend();
|
||||
void Attach(int deviceIdP) { deviceIdM = deviceIdP; }
|
||||
void Detach(int deviceIdP) { if (deviceIdP == deviceIdM) deviceIdM = -1; }
|
||||
cString Description(void) { return descriptionM; }
|
||||
bool Attached(void) { return (deviceIdM >= 0); }
|
||||
int Index(void) { return indexM; }
|
||||
int Transponder(void) { return transponderM; }
|
||||
int DeviceId(void) { return deviceIdM; }
|
||||
void SetTransponder(int transponderP) { transponderM = transponderP; }
|
||||
};
|
||||
|
||||
// --- cSatipFrontends --------------------------------------------------------
|
||||
|
||||
class cSatipFrontends : public cList<cSatipFrontend> {
|
||||
public:
|
||||
bool Matches(int deviceIdP, int transponderP);
|
||||
bool Assign(int deviceIdP, int transponderP);
|
||||
bool Attach(int deviceIdP, int transponderP);
|
||||
bool Detach(int deviceIdP, int transponderP);
|
||||
};
|
||||
|
||||
// --- cSatipServer -----------------------------------------------------------
|
||||
|
||||
class cSatipServer : public cListObject {
|
||||
private:
|
||||
enum eSatipFrontend {
|
||||
eSatipFrontendDVBS2 = 0,
|
||||
eSatipFrontendDVBT,
|
||||
eSatipFrontendDVBT2,
|
||||
eSatipFrontendDVBC,
|
||||
eSatipFrontendDVBC2,
|
||||
eSatipFrontendATSC,
|
||||
eSatipFrontendCount
|
||||
enum eSatipModule {
|
||||
eSatipModuleDVBS2 = 0,
|
||||
eSatipModuleDVBT,
|
||||
eSatipModuleDVBT2,
|
||||
eSatipModuleDVBC,
|
||||
eSatipModuleDVBC2,
|
||||
eSatipModuleCount
|
||||
};
|
||||
enum {
|
||||
eSatipMaxSourceFilters = 16
|
||||
};
|
||||
cString srcAddressM;
|
||||
cString addressM;
|
||||
cString modelM;
|
||||
cString filtersM;
|
||||
cString descriptionM;
|
||||
cString quirksM;
|
||||
cSatipFrontends frontendsM[eSatipFrontendCount];
|
||||
int sourceFiltersM[eSatipMaxSourceFilters];
|
||||
int portM;
|
||||
int modelCountM[eSatipModuleCount];
|
||||
int modelTypeM;
|
||||
int quirkM;
|
||||
bool hasCiM;
|
||||
bool activeM;
|
||||
int useCountM;
|
||||
int transponderM;
|
||||
time_t createdM;
|
||||
cTimeMs lastSeenM;
|
||||
bool IsValidSource(int sourceP);
|
||||
|
||||
public:
|
||||
enum eSatipQuirk {
|
||||
@ -80,39 +37,36 @@ public:
|
||||
eSatipQuirkSessionId = 0x01,
|
||||
eSatipQuirkPlayPids = 0x02,
|
||||
eSatipQuirkForceLock = 0x04,
|
||||
eSatipQuirkRtpOverTcp = 0x08,
|
||||
eSatipQuirkCiXpmt = 0x10,
|
||||
eSatipQuirkCiTnr = 0x20,
|
||||
eSatipQuirkForcePilot = 0x40,
|
||||
eSatipQuirkTearAndPlay = 0x80,
|
||||
eSatipQuirkMask = 0xFF
|
||||
eSatipQuirkUseXCI = 0x08,
|
||||
eSatipQuirkMask = 0x0F
|
||||
};
|
||||
cSatipServer(const char *srcAddressP, const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP);
|
||||
enum eSatipModelType {
|
||||
eSatipModelTypeNone = 0x00,
|
||||
eSatipModelTypeDVBS2 = 0x01,
|
||||
eSatipModelTypeDVBT = 0x02,
|
||||
eSatipModelTypeDVBT2 = 0x04,
|
||||
eSatipModelTypeDVBC = 0x08,
|
||||
eSatipModelTypeDVBC2 = 0x10,
|
||||
eSatipModelTypeMask = 0xFF
|
||||
};
|
||||
cSatipServer(const char *addressP, const char *modelP, const char *descriptionP);
|
||||
virtual ~cSatipServer();
|
||||
virtual int Compare(const cListObject &listObjectP) const;
|
||||
bool Assign(int deviceIdP, int sourceP, int systemP, int transponderP);
|
||||
bool Matches(int sourceP);
|
||||
bool Matches(int deviceIdP, int sourceP, int systemP, int transponderP);
|
||||
void Attach(int deviceIdP, int transponderP);
|
||||
void Detach(int deviceIdP, int transponderP);
|
||||
int GetModulesDVBS2(void);
|
||||
int GetModulesDVBT(void);
|
||||
int GetModulesDVBT2(void);
|
||||
int GetModulesDVBC(void);
|
||||
int GetModulesDVBC2(void);
|
||||
int GetModulesATSC(void);
|
||||
void Activate(bool onOffP) { activeM = onOffP; }
|
||||
const char *SrcAddress(void) { return *srcAddressM; }
|
||||
const char *Address(void) { return *addressM; }
|
||||
void Use(bool onOffP);
|
||||
void SetTransponder(const int transponderP) { transponderM = transponderP; }
|
||||
int Transponder(void) { return transponderM; }
|
||||
bool Used(void) { return !!useCountM; }
|
||||
const char *Address() { return *addressM; }
|
||||
const char *Model(void) { return *modelM; }
|
||||
const char *Filters(void) { return *filtersM; }
|
||||
const char *Description(void) { return *descriptionM; }
|
||||
const char *Quirks(void) { return *quirksM; }
|
||||
int Port(void) { return portM; }
|
||||
const char *Description() { return *descriptionM; }
|
||||
bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); }
|
||||
bool HasQuirk(void) { return (quirkM != eSatipQuirkNone); }
|
||||
bool HasCI(void) { return hasCiM; }
|
||||
bool IsActive(void) { return activeM; }
|
||||
int ModelType(void) { return modelTypeM; }
|
||||
bool Match(int modelP) { return ((modelP & eSatipModelTypeMask) & modelTypeM); }
|
||||
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; }
|
||||
void Update(void) { lastSeenM.Set(); }
|
||||
uint64_t LastSeen(void) { return lastSeenM.Elapsed(); }
|
||||
time_t Created(void) { return createdM; }
|
||||
@ -123,19 +77,12 @@ public:
|
||||
class cSatipServers : public cList<cSatipServer> {
|
||||
public:
|
||||
cSatipServer *Find(cSatipServer *serverP);
|
||||
cSatipServer *Find(int sourceP);
|
||||
cSatipServer *Assign(int deviceIdP, int sourceP, int transponderP, int systemP);
|
||||
cSatipServer *Find(int sourceP, int transponderP, int systemP);
|
||||
void SetTransponder(cSatipServer *serverP, int transponderP);
|
||||
cSatipServer *Update(cSatipServer *serverP);
|
||||
void Activate(cSatipServer *serverP, bool onOffP);
|
||||
void Attach(cSatipServer *serverP, int deviceIdP, int transponderP);
|
||||
void Detach(cSatipServer *serverP, int deviceIdP, int transponderP);
|
||||
bool IsQuirk(cSatipServer *serverP, int quirkP);
|
||||
bool HasCI(cSatipServer *serverP);
|
||||
void Use(cSatipServer *serverP, bool onOffP);
|
||||
void Cleanup(uint64_t intervalMsP = 0);
|
||||
cString GetAddress(cSatipServer *serverP);
|
||||
cString GetSrcAddress(cSatipServer *serverP);
|
||||
cString GetString(cSatipServer *serverP);
|
||||
int GetPort(cSatipServer *serverP);
|
||||
cString List(void);
|
||||
int NumProvidedSystems(void);
|
||||
};
|
||||
|
51
setup.c
51
setup.c
@ -86,8 +86,6 @@ eOSState cSatipEditSrcItem::ProcessKey(eKeys Key)
|
||||
class cSatipServerInfo : public cOsdMenu
|
||||
{
|
||||
private:
|
||||
cSatipServer *serverM;
|
||||
int activeM;
|
||||
cString addressM;
|
||||
cString modelM;
|
||||
cString descriptionM;
|
||||
@ -96,19 +94,17 @@ private:
|
||||
void Setup(void);
|
||||
|
||||
public:
|
||||
explicit cSatipServerInfo(cSatipServer *serverP);
|
||||
cSatipServerInfo(cSatipServer *serverP);
|
||||
virtual ~cSatipServerInfo();
|
||||
virtual eOSState ProcessKey(eKeys keyP);
|
||||
};
|
||||
|
||||
cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP)
|
||||
: cOsdMenu(tr("SAT>IP Server"), 20),
|
||||
serverM(serverP),
|
||||
activeM(serverP && serverP->IsActive()),
|
||||
addressM(serverP ? (isempty(serverP->SrcAddress()) ? serverP->Address() : *cString::sprintf("%s@%s", serverP->SrcAddress(), serverP->Address())) : "---"),
|
||||
addressM(serverP ? serverP->Address() : "---"),
|
||||
modelM(serverP ? serverP->Model() : "---"),
|
||||
descriptionM(serverP ? serverP->Description() : "---"),
|
||||
ciExtensionM(serverP && serverP->HasCI() ? trVDR("yes") : trVDR("no")),
|
||||
ciExtensionM(serverP && serverP->Quirk(cSatipServer::eSatipQuirkUseXCI) ? trVDR("yes") : trVDR("no")),
|
||||
createdM(serverP ? serverP->Created() : 0)
|
||||
{
|
||||
SetMenuCategory(mcSetupPlugins);
|
||||
@ -122,7 +118,6 @@ cSatipServerInfo::~cSatipServerInfo()
|
||||
|
||||
void cSatipServerInfo::Setup(void)
|
||||
{
|
||||
Add(new cMenuEditBoolItem(trVDR("Active"), &activeM));
|
||||
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Address"), *addressM), osUnknown, false));
|
||||
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Model"), *modelM), osUnknown, false));
|
||||
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Description"), *descriptionM), osUnknown, false));
|
||||
@ -132,7 +127,6 @@ void cSatipServerInfo::Setup(void)
|
||||
|
||||
eOSState cSatipServerInfo::ProcessKey(eKeys keyP)
|
||||
{
|
||||
int oldActive = activeM;
|
||||
eOSState state = cOsdMenu::ProcessKey(keyP);
|
||||
|
||||
if (state == osUnknown) {
|
||||
@ -141,12 +135,6 @@ eOSState cSatipServerInfo::ProcessKey(eKeys keyP)
|
||||
default: state = osContinue; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyP != kNone && oldActive != activeM) {
|
||||
cSatipDiscover::GetInstance()->ActivateServer(serverM, activeM);
|
||||
Setup();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -157,7 +145,7 @@ private:
|
||||
cSatipServer *serverM;
|
||||
|
||||
public:
|
||||
explicit cSatipServerItem(cSatipServer *serverP);
|
||||
cSatipServerItem(cSatipServer *serverP);
|
||||
cSatipServer *Server(void) { return serverM; }
|
||||
virtual void SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP);
|
||||
};
|
||||
@ -167,7 +155,7 @@ cSatipServerItem::cSatipServerItem(cSatipServer *serverP)
|
||||
{
|
||||
SetSelectable(true);
|
||||
// Must begin with a '#' character!
|
||||
SetText(*cString::sprintf("%s %s (%s)\t%s", serverM->IsActive() ? "+" : "-", isempty(serverM->SrcAddress()) ? serverM->Address() : *cString::sprintf("%s@%s", serverM->SrcAddress(), serverM->Address()), serverM->Model(), serverM->Description()));
|
||||
SetText(*cString::sprintf("# %s (%s)\t%s", serverM->Address(), serverM->Model(), serverM->Description()));
|
||||
}
|
||||
|
||||
void cSatipServerItem::SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP)
|
||||
@ -342,12 +330,9 @@ eOSState cSatipMenuInfo::ProcessKey(eKeys keyP)
|
||||
// --- cSatipPluginSetup ------------------------------------------------------
|
||||
|
||||
cSatipPluginSetup::cSatipPluginSetup()
|
||||
: detachedModeM(SatipConfig.GetDetachedMode()),
|
||||
deviceCountM(0),
|
||||
: deviceCountM(0),
|
||||
operatingModeM(SatipConfig.GetOperatingMode()),
|
||||
transportModeM(SatipConfig.GetTransportMode()),
|
||||
ciExtensionM(SatipConfig.GetCIExtension()),
|
||||
frontendReuseM(SatipConfig.GetFrontendReuse()),
|
||||
eitScanM(SatipConfig.GetEITScan()),
|
||||
numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()),
|
||||
numDisabledFiltersM(SatipConfig.GetDisabledFiltersCount())
|
||||
@ -357,9 +342,6 @@ cSatipPluginSetup::cSatipPluginSetup()
|
||||
operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low");
|
||||
operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal");
|
||||
operatingModeTextsM[cSatipConfig::eOperatingModeHigh] = tr("high");
|
||||
transportModeTextsM[cSatipConfig::eTransportModeUnicast] = tr("Unicast");
|
||||
transportModeTextsM[cSatipConfig::eTransportModeMulticast] = tr("Multicast");
|
||||
transportModeTextsM[cSatipConfig::eTransportModeRtpOverTcp] = tr("RTP-over-TCP");
|
||||
for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i)
|
||||
cicamsM[i] = SatipConfig.GetCICAM(i);
|
||||
for (unsigned int i = 0; i < ELEMENTS(ca_systems_table); ++i)
|
||||
@ -417,24 +399,15 @@ void cSatipPluginSetup::Setup(void)
|
||||
helpM.Append(tr("Define an ill-behaving filter to be blacklisted."));
|
||||
}
|
||||
}
|
||||
Add(new cMenuEditStraItem(tr("Transport mode"), &transportModeM, ELEMENTS(transportModeTextsM), transportModeTextsM));
|
||||
helpM.Append(tr("Define which transport mode shall be used.\n\nUnicast, Multicast, RTP-over-TCP"));
|
||||
|
||||
Add(new cMenuEditBoolItem(tr("Enable frontend reuse"), &frontendReuseM));
|
||||
helpM.Append(tr("Define whether reusing a frontend for multiple channels in a transponder should be enabled."));
|
||||
|
||||
Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false));
|
||||
helpM.Append("");
|
||||
|
||||
detachedModeM = SatipConfig.GetDetachedMode();
|
||||
if (!detachedModeM) {
|
||||
cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers();
|
||||
deviceCountM = servers->Count();
|
||||
for (cSatipServer *s = servers->First(); s; s = servers->Next(s)) {
|
||||
Add(new cSatipServerItem(s));
|
||||
helpM.Append("");
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrent(Get(current));
|
||||
Display();
|
||||
@ -484,17 +457,14 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
|
||||
bool hadSubMenu = HasSubMenu();
|
||||
int oldOperatingMode = operatingModeM;
|
||||
int oldCiExtension = ciExtensionM;
|
||||
int oldFrontendReuse = frontendReuseM;
|
||||
int oldNumDisabledSources = numDisabledSourcesM;
|
||||
int oldNumDisabledFilters = numDisabledFiltersM;
|
||||
eOSState state = cMenuSetupPage::ProcessKey(keyP);
|
||||
|
||||
// Ugly hack with hardcoded '+/-' characters :(
|
||||
// Ugly hack with hardcoded '#' character :(
|
||||
const char *p = Get(Current())->Text();
|
||||
if (!hadSubMenu && !HasSubMenu() && p && (*p == '+' || *p == '-') && (keyP == kOk))
|
||||
if (!hadSubMenu && !HasSubMenu() && (*p == '#') && (keyP == kOk))
|
||||
return DeviceInfo();
|
||||
if (hadSubMenu && !HasSubMenu())
|
||||
Setup();
|
||||
|
||||
if (state == osUnknown) {
|
||||
switch (keyP) {
|
||||
@ -510,7 +480,7 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
|
||||
if ((keyP == kNone) && (cSatipDiscover::GetInstance()->GetServers()->Count() != deviceCountM))
|
||||
Setup();
|
||||
|
||||
if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode) || (ciExtensionM != oldCiExtension) || ( oldFrontendReuse != frontendReuseM) || (detachedModeM != SatipConfig.GetDetachedMode()))) {
|
||||
if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode) || (ciExtensionM != oldCiExtension))) {
|
||||
while ((numDisabledSourcesM < oldNumDisabledSources) && (oldNumDisabledSources > 0))
|
||||
disabledSourcesM[--oldNumDisabledSources] = cSource::stNone;
|
||||
while ((numDisabledFiltersM < oldNumDisabledFilters) && (oldNumDisabledFilters > 0))
|
||||
@ -573,16 +543,13 @@ void cSatipPluginSetup::Store(void)
|
||||
{
|
||||
// Store values into setup.conf
|
||||
SetupStore("OperatingMode", operatingModeM);
|
||||
SetupStore("TransportMode", transportModeM);
|
||||
SetupStore("EnableCIExtension", ciExtensionM);
|
||||
SetupStore("EnableFrontendReuse", frontendReuseM);
|
||||
SetupStore("EnableEITScan", eitScanM);
|
||||
StoreCicams("CICAM", cicamsM);
|
||||
StoreSources("DisabledSources", disabledSourcesM);
|
||||
StoreFilters("DisabledFilters", disabledFilterIndexesM);
|
||||
// Update global config
|
||||
SatipConfig.SetOperatingMode(operatingModeM);
|
||||
SatipConfig.SetTransportMode(transportModeM);
|
||||
SatipConfig.SetCIExtension(ciExtensionM);
|
||||
SatipConfig.SetEITScan(eitScanM);
|
||||
for (int i = 0; i < MAX_CICAM_COUNT; ++i)
|
||||
|
4
setup.h
4
setup.h
@ -15,14 +15,10 @@
|
||||
class cSatipPluginSetup : public cMenuSetupPage
|
||||
{
|
||||
private:
|
||||
bool detachedModeM;
|
||||
int deviceCountM;
|
||||
int operatingModeM;
|
||||
int transportModeM;
|
||||
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];
|
||||
const char *transportModeTextsM[cSatipConfig::eTransportModeCount];
|
||||
int ciExtensionM;
|
||||
int frontendReuseM;
|
||||
int cicamsM[MAX_CICAM_COUNT];
|
||||
const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE];
|
||||
int eitScanM;
|
||||
|
195
socket.c
195
socket.c
@ -19,35 +19,9 @@
|
||||
#include "log.h"
|
||||
#include "socket.h"
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
#if defined(__GLIBC_PREREQ)
|
||||
#if !__GLIBC_PREREQ(2,12)
|
||||
#define __SATIP_DISABLE_RECVMMSG__
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
cSatipSocket::cSatipSocket()
|
||||
: socketPortM(0),
|
||||
socketDescM(-1),
|
||||
isMulticastM(false),
|
||||
useSsmM(false),
|
||||
streamAddrM(htonl(INADDR_ANY)),
|
||||
sourceAddrM(htonl(INADDR_ANY)),
|
||||
rcvBufSizeM(0)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
||||
}
|
||||
|
||||
cSatipSocket::cSatipSocket(size_t rcvBufSizeP)
|
||||
: socketPortM(0),
|
||||
socketDescM(-1),
|
||||
isMulticastM(false),
|
||||
useSsmM(false),
|
||||
streamAddrM(htonl(INADDR_ANY)),
|
||||
sourceAddrM(htonl(INADDR_ANY)),
|
||||
rcvBufSizeM(rcvBufSizeP)
|
||||
socketDescM(-1)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
||||
@ -60,17 +34,10 @@ cSatipSocket::~cSatipSocket()
|
||||
Close();
|
||||
}
|
||||
|
||||
bool cSatipSocket::Open(const int portP, const bool reuseP)
|
||||
bool cSatipSocket::Open(const int portP)
|
||||
{
|
||||
// If socket is there already and it is bound to a different port, it must
|
||||
// be closed first
|
||||
if (portP != socketPortM) {
|
||||
debug1("%s (%d, %d) Socket tear-down", __PRETTY_FUNCTION__, portP, reuseP);
|
||||
Close();
|
||||
}
|
||||
// Bind to the socket if it is not active already
|
||||
if (socketDescM < 0) {
|
||||
int yes;
|
||||
socklen_t len = sizeof(sockAddrM);
|
||||
// Create socket
|
||||
socketDescM = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
@ -79,24 +46,9 @@ bool cSatipSocket::Open(const int portP, const bool reuseP)
|
||||
ERROR_IF_FUNC(fcntl(socketDescM, F_SETFL, O_NONBLOCK), "fcntl(O_NONBLOCK)",
|
||||
Close(), return false);
|
||||
// Allow multiple sockets to use the same PORT number
|
||||
yes = reuseP;
|
||||
int yes = 1;
|
||||
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0,
|
||||
"setsockopt(SO_REUSEADDR)", Close(), return false);
|
||||
yes = reuseP;
|
||||
#ifdef SO_REUSEPORT
|
||||
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0 && errno != ENOPROTOOPT,
|
||||
"setsockopt(SO_REUSEPORT)", Close(), return false);
|
||||
#endif
|
||||
#ifndef __FreeBSD__
|
||||
// Allow packet information to be fetched
|
||||
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0,
|
||||
"setsockopt(IP_PKTINFO)", Close(), return false);
|
||||
#endif // __FreeBSD__
|
||||
// Tweak receive buffer size if requested
|
||||
if (rcvBufSizeM > 0) {
|
||||
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_RCVBUF, &rcvBufSizeM, sizeof(rcvBufSizeM)) < 0,
|
||||
"setsockopt(SO_RCVBUF)", Close(), return false);
|
||||
}
|
||||
// Bind socket
|
||||
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
||||
sockAddrM.sin_family = AF_INET;
|
||||
@ -105,41 +57,23 @@ bool cSatipSocket::Open(const int portP, const bool reuseP)
|
||||
ERROR_IF_FUNC(bind(socketDescM, (struct sockaddr *)&sockAddrM, sizeof(sockAddrM)) < 0,
|
||||
"bind()", Close(), return false);
|
||||
// Update socket port
|
||||
ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0,
|
||||
ERROR_IF_FUNC(getsockname(socketDescM,(struct sockaddr*)&sockAddrM, &len) < 0,
|
||||
"getsockname()", Close(), return false);
|
||||
socketPortM = ntohs(sockAddrM.sin_port);
|
||||
isMulticastM = false;
|
||||
}
|
||||
debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipSocket::OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP)
|
||||
{
|
||||
debug1("%s (%d, %s, %s)", __PRETTY_FUNCTION__, portP, streamAddrP, sourceAddrP);
|
||||
if (Open(portP)) {
|
||||
CheckAddress(streamAddrP, &streamAddrM);
|
||||
if (!isempty(sourceAddrP))
|
||||
useSsmM = CheckAddress(sourceAddrP, &sourceAddrM);
|
||||
return Join();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cSatipSocket::Close(void)
|
||||
{
|
||||
debug1("%s socketPort=%d", __PRETTY_FUNCTION__, socketPortM);
|
||||
debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM);
|
||||
// Check if socket exists
|
||||
if (socketDescM >= 0) {
|
||||
Leave();
|
||||
close(socketDescM);
|
||||
socketDescM = -1;
|
||||
socketPortM = 0;
|
||||
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
||||
streamAddrM = htonl(INADDR_ANY);
|
||||
sourceAddrM = htonl(INADDR_ANY);
|
||||
isMulticastM = false;
|
||||
useSsmM = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,96 +96,6 @@ bool cSatipSocket::Flush(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipSocket::CheckAddress(const char *addrP, in_addr_t *inAddrP)
|
||||
{
|
||||
if (inAddrP) {
|
||||
// First try only the IP address
|
||||
*inAddrP = inet_addr(addrP);
|
||||
if (*inAddrP == htonl(INADDR_NONE)) {
|
||||
debug1("%s (%s, ) Cannot convert to address", __PRETTY_FUNCTION__, addrP);
|
||||
// It may be a host name, get the name
|
||||
struct hostent *host = gethostbyname(addrP);
|
||||
if (!host) {
|
||||
char tmp[64];
|
||||
error("gethostbyname() failed: %s is not valid address: %s", addrP,
|
||||
strerror_r(h_errno, tmp, sizeof(tmp)));
|
||||
return false;
|
||||
}
|
||||
*inAddrP = inet_addr(*host->h_addr_list);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cSatipSocket::Join(void)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Check if socket exists
|
||||
if (socketDescM >= 0 && !isMulticastM) {
|
||||
// Join a new multicast group
|
||||
if (useSsmM) {
|
||||
// Source-specific multicast (SSM) is used
|
||||
struct group_source_req gsr;
|
||||
struct sockaddr_in *grp;
|
||||
struct sockaddr_in *src;
|
||||
gsr.gsr_interface = 0; // if_nametoindex("any") ?
|
||||
grp = (struct sockaddr_in*)&gsr.gsr_group;
|
||||
grp->sin_family = AF_INET;
|
||||
grp->sin_addr.s_addr = streamAddrM;
|
||||
grp->sin_port = 0;
|
||||
src = (struct sockaddr_in*)&gsr.gsr_source;
|
||||
src->sin_family = AF_INET;
|
||||
src->sin_addr.s_addr = sourceAddrM;
|
||||
src->sin_port = 0;
|
||||
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_JOIN_SOURCE_GROUP)", return false);
|
||||
}
|
||||
else {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = streamAddrM;
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false);
|
||||
}
|
||||
// Update multicasting flag
|
||||
isMulticastM = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipSocket::Leave(void)
|
||||
{
|
||||
debug1("%s", __PRETTY_FUNCTION__);
|
||||
// Check if socket exists
|
||||
if (socketDescM >= 0 && isMulticastM) {
|
||||
// Leave the existing multicast group
|
||||
if (useSsmM) {
|
||||
// Source-specific multicast (SSM) is used
|
||||
struct group_source_req gsr;
|
||||
struct sockaddr_in *grp;
|
||||
struct sockaddr_in *src;
|
||||
gsr.gsr_interface = 0; // if_nametoindex("any") ?
|
||||
grp = (struct sockaddr_in*)&gsr.gsr_group;
|
||||
grp->sin_family = AF_INET;
|
||||
grp->sin_addr.s_addr = streamAddrM;
|
||||
grp->sin_port = 0;
|
||||
src = (struct sockaddr_in*)&gsr.gsr_source;
|
||||
src->sin_family = AF_INET;
|
||||
src->sin_addr.s_addr = sourceAddrM;
|
||||
src->sin_port = 0;
|
||||
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_LEAVE_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_LEAVE_SOURCE_GROUP)", return false);
|
||||
}
|
||||
else {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = streamAddrM;
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false);
|
||||
}
|
||||
// Update multicasting flag
|
||||
isMulticastM = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||
{
|
||||
debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP);
|
||||
@ -282,41 +126,22 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||
|
||||
if (socketDescM && bufferAddrP && (bufferLenP > 0))
|
||||
len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT);
|
||||
if (len > 0) {
|
||||
#ifndef __FreeBSD__
|
||||
if (isMulticastM) {
|
||||
// Process auxiliary received data and validate source address
|
||||
for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
|
||||
if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
|
||||
struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||
if ((i->ipi_addr.s_addr == streamAddrM) || (htonl(INADDR_ANY) == streamAddrM))
|
||||
if (len > 0)
|
||||
return len;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif // __FreeBSD__
|
||||
return len;
|
||||
}
|
||||
} while (len > 0);
|
||||
ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1);
|
||||
ERROR_IF_RET(len < 0 && errno != EAGAIN, "recvmsg()", return -1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP)
|
||||
{
|
||||
debug16("%s (, , %d, %d)", __PRETTY_FUNCTION__, elementCountP, elementBufferSizeP);
|
||||
int count = -1;
|
||||
#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,12)
|
||||
// Error out if socket not initialized
|
||||
if (socketDescM <= 0) {
|
||||
error("%s Invalid socket", __PRETTY_FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
if (!bufferAddrP || !elementRecvSizeP || !elementCountP || !elementBufferSizeP) {
|
||||
error("%s Invalid parameter(s)", __PRETTY_FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
#ifndef __SATIP_DISABLE_RECVMMSG__
|
||||
// Initialize iov and msgh structures
|
||||
struct mmsghdr mmsgh[elementCountP];
|
||||
struct iovec iov[elementCountP];
|
||||
@ -329,12 +154,14 @@ int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRec
|
||||
}
|
||||
|
||||
// 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;
|
||||
#else
|
||||
count = 0;
|
||||
int count = 0;
|
||||
while (count < (int)elementCountP) {
|
||||
int len = Read(bufferAddrP + count * elementBufferSizeP, elementBufferSizeP);
|
||||
if (len < 0)
|
||||
|
14
socket.h
14
socket.h
@ -15,26 +15,14 @@ private:
|
||||
int socketPortM;
|
||||
int socketDescM;
|
||||
struct sockaddr_in sockAddrM;
|
||||
bool isMulticastM;
|
||||
bool useSsmM;
|
||||
in_addr_t streamAddrM;
|
||||
in_addr_t sourceAddrM;
|
||||
size_t rcvBufSizeM;
|
||||
|
||||
bool CheckAddress(const char *addrP, in_addr_t *inAddrP);
|
||||
bool Join(void);
|
||||
bool Leave(void);
|
||||
|
||||
public:
|
||||
cSatipSocket();
|
||||
explicit cSatipSocket(size_t rcvBufSizeP);
|
||||
virtual ~cSatipSocket();
|
||||
bool Open(const int portP = 0, const bool reuseP = false);
|
||||
bool OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP);
|
||||
bool Open(const int portP = 0);
|
||||
virtual void Close(void);
|
||||
int Fd(void) { return socketDescM; }
|
||||
int Port(void) { return socketPortM; }
|
||||
bool IsMulticast(void) { return isMulticastM; }
|
||||
bool IsOpen(void) { return (socketDescM >= 0); }
|
||||
bool Flush(void);
|
||||
int Read(unsigned char *bufferAddrP, unsigned int bufferLenP);
|
||||
|
246
tuner.c
246
tuner.c
@ -25,28 +25,21 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
|
||||
rtcpM(*this),
|
||||
streamAddrM(""),
|
||||
streamParamM(""),
|
||||
lastAddrM(""),
|
||||
lastParamM(""),
|
||||
tnrParamM(""),
|
||||
streamPortM(SATIP_DEFAULT_RTSP_PORT),
|
||||
currentServerM(NULL, deviceP.GetId(), 0),
|
||||
nextServerM(NULL, deviceP.GetId(), 0),
|
||||
currentServerM(NULL),
|
||||
nextServerM(NULL),
|
||||
mutexM(),
|
||||
reConnectM(),
|
||||
keepAliveM(),
|
||||
statusUpdateM(),
|
||||
pidUpdateCacheM(),
|
||||
setupTimeoutM(-1),
|
||||
sessionM(""),
|
||||
currentStateM(tsIdle),
|
||||
internalStateM(),
|
||||
externalStateM(),
|
||||
timeoutM(eMinKeepAliveIntervalMs - eKeepAlivePreBufferMs),
|
||||
timeoutM(eMinKeepAliveIntervalMs),
|
||||
hasLockM(false),
|
||||
signalStrengthDBmM(0.0),
|
||||
signalStrengthM(-1),
|
||||
signalQualityM(-1),
|
||||
frontendIdM(-1),
|
||||
streamIdM(-1),
|
||||
pmtPidM(-1),
|
||||
addPidsM(),
|
||||
@ -56,16 +49,12 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
|
||||
debug1("%s (, %d) [device %d]", __PRETTY_FUNCTION__, packetLenP, deviceIdM);
|
||||
|
||||
// Open sockets
|
||||
int i = SatipConfig.GetPortRangeStart() ? SatipConfig.GetPortRangeStop() - SatipConfig.GetPortRangeStart() - 1 : 100;
|
||||
int port = SatipConfig.GetPortRangeStart();
|
||||
int i = 100;
|
||||
while (i-- > 0) {
|
||||
// RTP must use an even port number
|
||||
if (rtpM.Open(port) && (rtpM.Port() % 2 == 0) && rtcpM.Open(rtpM.Port() + 1))
|
||||
if (rtpM.Open(0) && rtcpM.Open(rtpM.Port() + 1))
|
||||
break;
|
||||
rtpM.Close();
|
||||
rtcpM.Close();
|
||||
if (SatipConfig.GetPortRangeStart())
|
||||
port += 2;
|
||||
}
|
||||
if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) {
|
||||
error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM);
|
||||
@ -101,10 +90,6 @@ cSatipTuner::~cSatipTuner()
|
||||
void cSatipTuner::Action(void)
|
||||
{
|
||||
debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
bool lastIdleStatus = false;
|
||||
cTimeMs idleCheck(eIdleCheckTimeoutMs);
|
||||
cTimeMs tuning(eTuningTimeoutMs);
|
||||
reConnectM.Set(eConnectTimeoutMs);
|
||||
// Do the thread loop
|
||||
while (Running()) {
|
||||
@ -120,10 +105,7 @@ void cSatipTuner::Action(void)
|
||||
break;
|
||||
case tsSet:
|
||||
debug4("%s: tsSet [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkTearAndPlay))
|
||||
Disconnect();
|
||||
if (Connect()) {
|
||||
tuning.Set(eTuningTimeoutMs);
|
||||
RequestState(tsTuned, smInternal);
|
||||
UpdatePids(true);
|
||||
}
|
||||
@ -132,26 +114,18 @@ void cSatipTuner::Action(void)
|
||||
break;
|
||||
case tsTuned:
|
||||
debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
deviceM->SetChannelTuned();
|
||||
reConnectM.Set(eConnectTimeoutMs);
|
||||
idleCheck.Set(eIdleCheckTimeoutMs);
|
||||
lastIdleStatus = false;
|
||||
// Read reception statistics via DESCRIBE and RTCP
|
||||
if (hasLockM || ReadReceptionStatus()) {
|
||||
// Quirk for devices without valid reception data
|
||||
if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkForceLock)) {
|
||||
if (currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkForceLock)) {
|
||||
hasLockM = true;
|
||||
signalStrengthDBmM = eDefaultSignalStrengthDBm;
|
||||
signalStrengthM = eDefaultSignalStrength;
|
||||
signalQualityM = eDefaultSignalQuality;
|
||||
}
|
||||
if (hasLockM)
|
||||
RequestState(tsLocked, smInternal);
|
||||
}
|
||||
else if (tuning.TimedOut()) {
|
||||
error("Tuning timeout - retuning [device %d]", deviceIdM);
|
||||
RequestState(tsSet, smInternal);
|
||||
}
|
||||
break;
|
||||
case tsLocked:
|
||||
debug4("%s: tsLocked [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
@ -170,17 +144,6 @@ void cSatipTuner::Action(void)
|
||||
RequestState(tsSet, smInternal);
|
||||
break;
|
||||
}
|
||||
if (idleCheck.TimedOut()) {
|
||||
bool currentIdleStatus = deviceM->IsIdle();
|
||||
if (lastIdleStatus && currentIdleStatus) {
|
||||
info("Idle timeout - releasing [device %d]", deviceIdM);
|
||||
RequestState(tsRelease, smInternal);
|
||||
}
|
||||
lastIdleStatus = currentIdleStatus;
|
||||
idleCheck.Set(eIdleCheckTimeoutMs);
|
||||
break;
|
||||
}
|
||||
Receive();
|
||||
break;
|
||||
default:
|
||||
error("Unknown tuner status %d [device %d]", currentStateM, deviceIdM);
|
||||
@ -197,6 +160,8 @@ bool cSatipTuner::Open(void)
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
RequestState(tsSet, smExternal);
|
||||
|
||||
// return always true
|
||||
return true;
|
||||
}
|
||||
@ -206,7 +171,6 @@ bool cSatipTuner::Close(void)
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
if (setupTimeoutM.TimedOut())
|
||||
RequestState(tsRelease, smExternal);
|
||||
|
||||
// return always true
|
||||
@ -219,42 +183,32 @@ bool cSatipTuner::Connect(void)
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
if (!isempty(*streamAddrM)) {
|
||||
cString connectionUri = GetBaseUrl(*streamAddrM, streamPortM);
|
||||
tnrParamM = "";
|
||||
cString connectionUri = cString::sprintf("rtsp://%s/", *streamAddrM);
|
||||
// Just retune
|
||||
if (streamIdM >= 0) {
|
||||
if (!strcmp(*streamParamM, *lastParamM) && hasLockM) {
|
||||
debug1("%s Identical parameters [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
//return true; // fall through because detection does not work reliably
|
||||
}
|
||||
cString uri = cString::sprintf("%sstream=%d?%s", *connectionUri, streamIdM, *streamParamM);
|
||||
debug1("%s Retuning [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
if (rtspM.Play(*uri)) {
|
||||
keepAliveM.Set(timeoutM);
|
||||
lastParamM = streamParamM;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (rtspM.SetInterface(nextServerM.IsValid() ? *nextServerM.GetSrcAddress() : NULL) && rtspM.Options(*connectionUri)) {
|
||||
else if (rtspM.Options(*connectionUri)) {
|
||||
cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM);
|
||||
bool useTcp = SatipConfig.IsTransportModeRtpOverTcp() && nextServerM.IsValid() && nextServerM.IsQuirk(cSatipServer::eSatipQuirkRtpOverTcp);
|
||||
// Flush any old content
|
||||
//rtpM.Flush();
|
||||
//rtcpM.Flush();
|
||||
if (useTcp)
|
||||
debug1("%s Requesting TCP [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port(), useTcp)) {
|
||||
lastParamM = streamParamM;
|
||||
rtpM.Flush();
|
||||
rtcpM.Flush();
|
||||
if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port())) {
|
||||
keepAliveM.Set(timeoutM);
|
||||
if (nextServerM.IsValid()) {
|
||||
if (nextServerM) {
|
||||
cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
|
||||
currentServerM = nextServerM;
|
||||
nextServerM.Reset();
|
||||
nextServerM = NULL;
|
||||
}
|
||||
lastAddrM = connectionUri;
|
||||
currentServerM.Attach();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
rtspM.Reset();
|
||||
streamIdM = -1;
|
||||
error("Connect failed [device %d]", deviceIdM);
|
||||
@ -268,8 +222,8 @@ bool cSatipTuner::Disconnect(void)
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
|
||||
if (!isempty(*lastAddrM) && (streamIdM >= 0)) {
|
||||
cString uri = cString::sprintf("%sstream=%d", *lastAddrM, streamIdM);
|
||||
if (!isempty(*streamAddrM) && (streamIdM >= 0)) {
|
||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||
rtspM.Teardown(*uri);
|
||||
// some devices requires a teardown for TCP connection also
|
||||
rtspM.Reset();
|
||||
@ -278,14 +232,13 @@ bool cSatipTuner::Disconnect(void)
|
||||
|
||||
// Reset signal parameters
|
||||
hasLockM = false;
|
||||
signalStrengthDBmM = 0.0;
|
||||
signalStrengthM = -1;
|
||||
signalQualityM = -1;
|
||||
frontendIdM = -1;
|
||||
|
||||
currentServerM.Detach();
|
||||
if (currentServerM)
|
||||
cSatipDiscover::GetInstance()->UseServer(currentServerM, false);
|
||||
statusUpdateM.Set(0);
|
||||
timeoutM = eMinKeepAliveIntervalMs - eKeepAlivePreBufferMs;
|
||||
timeoutM = eMinKeepAliveIntervalMs;
|
||||
pmtPidM = -1;
|
||||
addPidsM.Clear();
|
||||
delPidsM.Clear();
|
||||
@ -315,11 +268,6 @@ void cSatipTuner::ProcessVideoData(u_char *bufferP, int lengthP)
|
||||
reConnectM.Set(eConnectTimeoutMs);
|
||||
}
|
||||
|
||||
void cSatipTuner::ProcessRtpData(u_char *bufferP, int lengthP)
|
||||
{
|
||||
rtpM.Process(bufferP, lengthP);
|
||||
}
|
||||
|
||||
void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
|
||||
{
|
||||
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM);
|
||||
@ -337,9 +285,6 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
|
||||
if (c) {
|
||||
int value;
|
||||
|
||||
// feID:
|
||||
frontendIdM = atoi(c + 7);
|
||||
|
||||
// level:
|
||||
// Numerical value between 0 and 255
|
||||
// An incoming L-band satellite signal of
|
||||
@ -348,9 +293,8 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
|
||||
// No signal corresponds to 0
|
||||
c = strstr(c, ",");
|
||||
value = min(atoi(++c), 255);
|
||||
signalStrengthDBmM = (value >= 0) ? 40.0 * (value - 32) / 192.0 - 65.0 : 0.0;
|
||||
// Scale value to 0-100
|
||||
signalStrengthM = (value >= 0) ? value * 100 / 255 : -1;
|
||||
signalStrengthM = (value >= 0) ? (value * 100 / 255) : -1;
|
||||
|
||||
// lock:
|
||||
// lock Set to one of the following values:
|
||||
@ -374,11 +318,6 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
|
||||
reConnectM.Set(eConnectTimeoutMs);
|
||||
}
|
||||
|
||||
void cSatipTuner::ProcessRtcpData(u_char *bufferP, int lengthP)
|
||||
{
|
||||
rtcpM.Process(bufferP, lengthP);
|
||||
}
|
||||
|
||||
void cSatipTuner::SetStreamId(int streamIdP)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
@ -391,51 +330,9 @@ void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, sessionP, timeoutP, deviceIdM);
|
||||
sessionM = sessionP;
|
||||
if (nextServerM.IsQuirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0"))
|
||||
if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0"))
|
||||
rtspM.SetSession(SkipZeroes(*sessionM));
|
||||
timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
|
||||
timeoutM -= eKeepAlivePreBufferMs;
|
||||
}
|
||||
|
||||
void cSatipTuner::SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP)
|
||||
{
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
debug1("%s (%d, %d, %s, %s) [device %d]", __PRETTY_FUNCTION__, rtpPortP, rtcpPortP, streamAddrP, sourceAddrP, deviceIdM);
|
||||
bool multicast = !isempty(streamAddrP);
|
||||
// Adapt RTP to any transport media change
|
||||
if (multicast != rtpM.IsMulticast() || rtpPortP != rtpM.Port()) {
|
||||
cSatipPoller::GetInstance()->Unregister(rtpM);
|
||||
if (rtpPortP >= 0) {
|
||||
rtpM.Close();
|
||||
if (multicast)
|
||||
rtpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP);
|
||||
else
|
||||
rtpM.Open(rtpPortP);
|
||||
cSatipPoller::GetInstance()->Register(rtpM);
|
||||
}
|
||||
}
|
||||
// Adapt RTCP to any transport media change
|
||||
if (multicast != rtcpM.IsMulticast() || rtcpPortP != rtcpM.Port()) {
|
||||
cSatipPoller::GetInstance()->Unregister(rtcpM);
|
||||
if (rtcpPortP >= 0) {
|
||||
rtcpM.Close();
|
||||
if (multicast)
|
||||
rtcpM.OpenMulticast(rtcpPortP, streamAddrP, sourceAddrP);
|
||||
else
|
||||
rtcpM.Open(rtcpPortP);
|
||||
cSatipPoller::GetInstance()->Register(rtcpM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cString cSatipTuner::GetBaseUrl(const char *addressP, const int portP)
|
||||
{
|
||||
debug16("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, addressP, portP, deviceIdM);
|
||||
|
||||
if (portP != SATIP_DEFAULT_RTSP_PORT)
|
||||
return cString::sprintf("rtsp://%s:%d/", addressP, portP);
|
||||
|
||||
return cString::sprintf("rtsp://%s/", addressP);
|
||||
}
|
||||
|
||||
int cSatipTuner::GetId(void)
|
||||
@ -444,28 +341,18 @@ int cSatipTuner::GetId(void)
|
||||
return deviceIdM;
|
||||
}
|
||||
|
||||
bool cSatipTuner::SetSource(cSatipServer *serverP, const int transponderP, const char *parameterP, const int indexP)
|
||||
bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const int indexP)
|
||||
{
|
||||
debug1("%s (%d, %s, %d) [device %d]", __PRETTY_FUNCTION__, transponderP, parameterP, indexP, deviceIdM);
|
||||
debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, parameterP, indexP, deviceIdM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (serverP) {
|
||||
nextServerM.Set(serverP, transponderP);
|
||||
if (!isempty(*nextServerM.GetAddress()) && !isempty(parameterP)) {
|
||||
nextServerM = cSatipDiscover::GetInstance()->GetServer(serverP);
|
||||
if (nextServerM && !isempty(nextServerM->Address()) && !isempty(parameterP)) {
|
||||
// Update stream address and parameter
|
||||
streamAddrM = rtspM.RtspUnescapeString(*nextServerM.GetAddress());
|
||||
streamAddrM = rtspM.RtspUnescapeString(nextServerM->Address());
|
||||
streamParamM = rtspM.RtspUnescapeString(parameterP);
|
||||
streamPortM = nextServerM.GetPort();
|
||||
// Modify parameter if required
|
||||
if (nextServerM.IsQuirk(cSatipServer::eSatipQuirkForcePilot) && strstr(parameterP, "msys=dvbs2") && !strstr(parameterP, "plts="))
|
||||
streamParamM = rtspM.RtspUnescapeString(*cString::sprintf("%s&plts=on", parameterP));
|
||||
// Reconnect
|
||||
if (!isempty(*lastAddrM)) {
|
||||
cString connectionUri = GetBaseUrl(*streamAddrM, streamPortM);
|
||||
if (strcmp(*connectionUri, *lastAddrM))
|
||||
RequestState(tsRelease, smInternal);
|
||||
}
|
||||
RequestState(tsSet, smExternal);
|
||||
setupTimeoutM.Set(eSetupTimeoutMs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -502,30 +389,22 @@ bool cSatipTuner::UpdatePids(bool forceP)
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) &&
|
||||
!isempty(*streamAddrM) && (streamIdM > 0)) {
|
||||
cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM);
|
||||
bool useci = (SatipConfig.GetCIExtension() && currentServerM.HasCI());
|
||||
bool usedummy = currentServerM.IsQuirk(cSatipServer::eSatipQuirkPlayPids);
|
||||
bool paramadded = false;
|
||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||
bool useci = (SatipConfig.GetCIExtension() && !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkUseXCI)));
|
||||
bool usedummy = !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkPlayPids));
|
||||
if (forceP || usedummy) {
|
||||
if (pidsM.Size()) {
|
||||
uri = cString::sprintf("%s%spids=%s", *uri, paramadded ? "&" : "?", *pidsM.ListPids());
|
||||
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);
|
||||
paramadded = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (addPidsM.Size()) {
|
||||
uri = cString::sprintf("%s%saddpids=%s", *uri, paramadded ? "&" : "?", *addPidsM.ListPids());
|
||||
paramadded = true;
|
||||
}
|
||||
if (delPidsM.Size()) {
|
||||
uri = cString::sprintf("%s%sdelpids=%s", *uri, paramadded ? "&" : "?", *delPidsM.ListPids());
|
||||
paramadded = true;
|
||||
}
|
||||
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());
|
||||
}
|
||||
if (useci) {
|
||||
if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkCiXpmt)) {
|
||||
// CI extension parameters:
|
||||
// - x_pmt : specifies the PMT of the service you want the CI to decode
|
||||
// - x_ci : specfies which CI slot (1..n) to use
|
||||
@ -535,29 +414,15 @@ bool cSatipTuner::UpdatePids(bool forceP)
|
||||
int pid = deviceM->GetPmtPid();
|
||||
if ((pid > 0) && (pid != pmtPidM)) {
|
||||
int slot = deviceM->GetCISlot();
|
||||
uri = cString::sprintf("%s%sx_pmt=%d", *uri, paramadded ? "&" : "?", pid);
|
||||
uri = cString::sprintf("%s&x_pmt=%d", *uri, pid);
|
||||
if (slot > 0)
|
||||
uri = cString::sprintf("%s&x_ci=%d", *uri, slot);
|
||||
paramadded = true;
|
||||
}
|
||||
pmtPidM = pid;
|
||||
}
|
||||
else if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkCiTnr)) {
|
||||
// CI extension parameters:
|
||||
// - tnr : specifies a channel config entry
|
||||
cString param = deviceM->GetTnrParameterString();
|
||||
if (!isempty(*param) && strcmp(*tnrParamM, *param) != 0) {
|
||||
uri = cString::sprintf("%s%stnr=%s", *uri, paramadded ? "&" : "?", *param);
|
||||
paramadded = true;
|
||||
}
|
||||
tnrParamM = param;
|
||||
}
|
||||
}
|
||||
if (paramadded) {
|
||||
pidUpdateCacheM.Set(ePidUpdateIntervalMs);
|
||||
if (!rtspM.Play(*uri))
|
||||
return false;
|
||||
}
|
||||
addPidsM.Clear();
|
||||
delPidsM.Clear();
|
||||
}
|
||||
@ -565,19 +430,6 @@ bool cSatipTuner::UpdatePids(bool forceP)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::Receive(void)
|
||||
{
|
||||
debug16("%s tunerState=%s [device %d]", __PRETTY_FUNCTION__, TunerStateString(currentStateM), deviceIdM);
|
||||
cMutexLock MutexLock(&mutexM);
|
||||
if (!isempty(*streamAddrM)) {
|
||||
cString uri = GetBaseUrl(*streamAddrM, streamPortM);
|
||||
if (!rtspM.Receive(*uri))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cSatipTuner::KeepAlive(bool forceP)
|
||||
{
|
||||
debug16("%s (%d) tunerState=%s [device %d]", __PRETTY_FUNCTION__, forceP, TunerStateString(currentStateM), deviceIdM);
|
||||
@ -587,7 +439,7 @@ bool cSatipTuner::KeepAlive(bool forceP)
|
||||
forceP = true;
|
||||
}
|
||||
if (forceP && !isempty(*streamAddrM)) {
|
||||
cString uri = GetBaseUrl(*streamAddrM, streamPortM);
|
||||
cString uri = cString::sprintf("rtsp://%s/", *streamAddrM);
|
||||
if (!rtspM.Options(*uri))
|
||||
return false;
|
||||
}
|
||||
@ -604,7 +456,7 @@ bool cSatipTuner::ReadReceptionStatus(bool forceP)
|
||||
forceP = true;
|
||||
}
|
||||
if (forceP && !isempty(*streamAddrM) && (streamIdM > 0)) {
|
||||
cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM);
|
||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||
if (rtspM.Describe(*uri))
|
||||
return true;
|
||||
}
|
||||
@ -706,24 +558,12 @@ const char *cSatipTuner::TunerStateString(eTunerState stateP)
|
||||
return "---";
|
||||
}
|
||||
|
||||
int cSatipTuner::FrontendId(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return frontendIdM;
|
||||
}
|
||||
|
||||
int cSatipTuner::SignalStrength(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return signalStrengthM;
|
||||
}
|
||||
|
||||
double cSatipTuner::SignalStrengthDBm(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return signalStrengthDBmM;
|
||||
}
|
||||
|
||||
int cSatipTuner::SignalQuality(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
@ -739,11 +579,11 @@ bool cSatipTuner::HasLock(void)
|
||||
cString cSatipTuner::GetSignalStatus(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return cString::sprintf("lock=%d strength=%d quality=%d frontend=%d", HasLock(), SignalStrength(), SignalQuality(), FrontendId());
|
||||
return cString::sprintf("lock=%d strength=%d quality=%d", HasLock(), SignalStrength(), SignalQuality());
|
||||
}
|
||||
|
||||
cString cSatipTuner::GetInformation(void)
|
||||
{
|
||||
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||
return (currentStateM >= tsTuned) ? cString::sprintf("%s?%s (%s) [stream=%d]", *GetBaseUrl(*streamAddrM, streamPortM), *streamParamM, *rtspM.GetActiveMode(), streamIdM) : "connection failed";
|
||||
return (currentStateM >= tsTuned) ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed";
|
||||
}
|
||||
|
85
tuner.h
85
tuner.h
@ -8,11 +8,11 @@
|
||||
#ifndef __SATIP_TUNER_H
|
||||
#define __SATIP_TUNER_H
|
||||
|
||||
#include <vdr/config.h> // APIVERSNUM
|
||||
#include <vdr/thread.h>
|
||||
#include <vdr/tools.h>
|
||||
|
||||
#include "deviceif.h"
|
||||
#include "discover.h"
|
||||
#include "rtp.h"
|
||||
#include "rtcp.h"
|
||||
#include "rtsp.h"
|
||||
@ -27,6 +27,33 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
#if defined(APIVERSNUM) && APIVERSNUM < 20107
|
||||
int IndexOf(const int &pidP)
|
||||
{
|
||||
for (int i = 0; i < Size(); ++i) {
|
||||
if (pidP == At(i))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
bool RemoveElement(const int &pidP)
|
||||
{
|
||||
int i = IndexOf(pidP);
|
||||
if (i >= 0) {
|
||||
Remove(i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool AppendUnique(int pidP)
|
||||
{
|
||||
if (IndexOf(pidP) < 0) {
|
||||
Append(pidP);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
void RemovePid(const int &pidP)
|
||||
{
|
||||
if (RemoveElement(pidP))
|
||||
@ -49,48 +76,18 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class cSatipTunerServer
|
||||
{
|
||||
private:
|
||||
cSatipServer *serverM;
|
||||
int deviceIdM;
|
||||
int transponderM;
|
||||
|
||||
public:
|
||||
cSatipTunerServer(cSatipServer *serverP, const int deviceIdP, const int transponderP) : serverM(serverP), deviceIdM(deviceIdP), transponderM(transponderP) {}
|
||||
~cSatipTunerServer() {}
|
||||
cSatipTunerServer(const cSatipTunerServer &objP) { serverM = NULL; deviceIdM = -1; transponderM = 0; }
|
||||
cSatipTunerServer& operator= (const cSatipTunerServer &objP) { serverM = objP.serverM; deviceIdM = objP.deviceIdM; transponderM = objP.transponderM; return *this; }
|
||||
bool IsValid(void) { return !!serverM; }
|
||||
bool IsQuirk(int quirkP) { return (serverM && cSatipDiscover::GetInstance()->IsServerQuirk(serverM, quirkP)); }
|
||||
bool HasCI(void) { return (serverM && cSatipDiscover::GetInstance()->HasServerCI(serverM)); }
|
||||
void Attach(void) { if (serverM) cSatipDiscover::GetInstance()->AttachServer(serverM, deviceIdM, transponderM); }
|
||||
void Detach(void) { if (serverM) cSatipDiscover::GetInstance()->DetachServer(serverM, deviceIdM, transponderM); }
|
||||
void Set(cSatipServer *serverP, const int transponderP) { serverM = serverP; transponderM = transponderP; }
|
||||
void Reset(void) { serverM = NULL; transponderM = 0; }
|
||||
cString GetAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerAddress(serverM) : ""; }
|
||||
cString GetSrcAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetSourceAddress(serverM) : ""; }
|
||||
int GetPort(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerPort(serverM) : SATIP_DEFAULT_RTSP_PORT; }
|
||||
cString GetInfo(void) { return cString::sprintf("server=%s deviceid=%d transponder=%d", serverM ? "assigned" : "null", deviceIdM, transponderM); }
|
||||
};
|
||||
|
||||
class cSatipTuner : public cThread, public cSatipTunerStatistics, public cSatipTunerIf
|
||||
{
|
||||
private:
|
||||
enum {
|
||||
eDummyPid = 100,
|
||||
eDefaultSignalStrengthDBm = -25,
|
||||
eDefaultSignalStrength = 224,
|
||||
eDefaultSignalQuality = 15,
|
||||
eDefaultSignalStrength = 15,
|
||||
eDefaultSignalQuality = 224,
|
||||
eSleepTimeoutMs = 250, // in milliseconds
|
||||
eStatusUpdateTimeoutMs = 1000, // in milliseconds
|
||||
ePidUpdateIntervalMs = 250, // in milliseconds
|
||||
eConnectTimeoutMs = 5000, // in milliseconds
|
||||
eIdleCheckTimeoutMs = 15000, // in milliseconds
|
||||
eTuningTimeoutMs = 20000, // in milliseconds
|
||||
eMinKeepAliveIntervalMs = 30000, // in milliseconds
|
||||
eKeepAlivePreBufferMs = 2000, // in milliseconds
|
||||
eSetupTimeoutMs = 2000 // in milliseconds
|
||||
eMinKeepAliveIntervalMs = 30000 // in milliseconds
|
||||
};
|
||||
enum eTunerState { tsIdle, tsRelease, tsSet, tsTuned, tsLocked };
|
||||
enum eStateMode { smInternal, smExternal };
|
||||
@ -103,28 +100,21 @@ private:
|
||||
cSatipRtcp rtcpM;
|
||||
cString streamAddrM;
|
||||
cString streamParamM;
|
||||
cString lastAddrM;
|
||||
cString lastParamM;
|
||||
cString tnrParamM;
|
||||
int streamPortM;
|
||||
cSatipTunerServer currentServerM;
|
||||
cSatipTunerServer nextServerM;
|
||||
cSatipServer *currentServerM;
|
||||
cSatipServer *nextServerM;
|
||||
cMutex mutexM;
|
||||
cTimeMs reConnectM;
|
||||
cTimeMs keepAliveM;
|
||||
cTimeMs statusUpdateM;
|
||||
cTimeMs pidUpdateCacheM;
|
||||
cTimeMs setupTimeoutM;
|
||||
cString sessionM;
|
||||
eTunerState currentStateM;
|
||||
cVector<eTunerState> internalStateM;
|
||||
cVector<eTunerState> externalStateM;
|
||||
int timeoutM;
|
||||
bool hasLockM;
|
||||
double signalStrengthDBmM;
|
||||
int signalStrengthM;
|
||||
int signalQualityM;
|
||||
int frontendIdM;
|
||||
int streamIdM;
|
||||
int pmtPidM;
|
||||
cSatipPid addPidsM;
|
||||
@ -133,7 +123,6 @@ private:
|
||||
|
||||
bool Connect(void);
|
||||
bool Disconnect(void);
|
||||
bool Receive(void);
|
||||
bool KeepAlive(bool forceP = false);
|
||||
bool ReadReceptionStatus(bool forceP = false);
|
||||
bool UpdatePids(bool forceP = false);
|
||||
@ -142,7 +131,6 @@ private:
|
||||
bool RequestState(eTunerState stateP, eStateMode modeP);
|
||||
const char *StateModeString(eStateMode modeP);
|
||||
const char *TunerStateString(eTunerState stateP);
|
||||
cString GetBaseUrl(const char *addressP, const int portP);
|
||||
|
||||
protected:
|
||||
virtual void Action(void);
|
||||
@ -151,13 +139,11 @@ public:
|
||||
cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP);
|
||||
virtual ~cSatipTuner();
|
||||
bool IsTuned(void) const { return (currentStateM >= tsTuned); }
|
||||
bool SetSource(cSatipServer *serverP, const int transponderP, const char *parameterP, const int indexP);
|
||||
bool SetSource(cSatipServer *serverP, const char *parameterP, const int indexP);
|
||||
bool SetPid(int pidP, int typeP, bool onP);
|
||||
bool Open(void);
|
||||
bool Close(void);
|
||||
int FrontendId(void);
|
||||
int SignalStrength(void);
|
||||
double SignalStrengthDBm(void);
|
||||
int SignalQuality(void);
|
||||
bool HasLock(void);
|
||||
cString GetSignalStatus(void);
|
||||
@ -167,11 +153,8 @@ public:
|
||||
public:
|
||||
virtual void ProcessVideoData(u_char *bufferP, int lengthP);
|
||||
virtual void ProcessApplicationData(u_char *bufferP, int lengthP);
|
||||
virtual void ProcessRtpData(u_char *bufferP, int lengthP);
|
||||
virtual void ProcessRtcpData(u_char *bufferP, int lengthP);
|
||||
virtual void SetStreamId(int streamIdP);
|
||||
virtual void SetSessionTimeout(const char *sessionP, int timeoutP);
|
||||
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP);
|
||||
virtual int GetId(void);
|
||||
};
|
||||
|
||||
|
@ -14,15 +14,12 @@ public:
|
||||
virtual ~cSatipTunerIf() {}
|
||||
virtual void ProcessVideoData(u_char *bufferP, int lengthP) = 0;
|
||||
virtual void ProcessApplicationData(u_char *bufferP, int lengthP) = 0;
|
||||
virtual void ProcessRtpData(u_char *bufferP, int lengthP) = 0;
|
||||
virtual void ProcessRtcpData(u_char *bufferP, int lengthP) = 0;
|
||||
virtual void SetStreamId(int streamIdP) = 0;
|
||||
virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0;
|
||||
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP) = 0;
|
||||
virtual int GetId(void) = 0;
|
||||
|
||||
private:
|
||||
explicit cSatipTunerIf(const cSatipTunerIf&);
|
||||
cSatipTunerIf(const cSatipTunerIf&);
|
||||
cSatipTunerIf& operator=(const cSatipTunerIf&);
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user