mirror of
https://github.com/rofafor/vdr-plugin-satip.git
synced 2023-10-10 11:37:42 +00:00
Compare commits
156 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
46bfc805e6 | ||
|
30925337cb | ||
|
63e47ad24a | ||
|
14123e160f | ||
|
278d0478cf | ||
|
9989c36eee | ||
|
d2064f0c04 | ||
|
714d3ed902 | ||
|
b466d6836e | ||
|
184ddf2a53 | ||
|
65a2158051 | ||
|
e833ca6fdd | ||
|
c9abfddf11 | ||
|
fb7a7fe3a2 | ||
|
3b9269e9de | ||
|
09e6c272cd | ||
|
266aadb999 | ||
|
aed5a7820a | ||
|
bcb11b6257 | ||
|
21261f8042 | ||
|
2f11ad7a98 | ||
|
83a0233780 | ||
|
6f3715eb8b | ||
|
92991cd144 | ||
|
304addbc00 | ||
|
26ff10ce1e | ||
|
e654b3bbd2 | ||
|
acea8748a4 | ||
|
755f1049bb | ||
|
2f6315280f | ||
|
695dd53bfc | ||
|
5fef77518e | ||
|
791767f02b | ||
|
0d52649dbd | ||
|
0c03c1b8d4 | ||
|
db59aa9c29 | ||
|
0fd559ce79 | ||
|
e10ce57210 | ||
|
c7f4b265d5 | ||
|
35c0f25c38 | ||
|
dadd26f980 | ||
|
5c5f21631f | ||
|
29eaf994f8 | ||
|
f884b23f7c | ||
|
1bc2dc01fd | ||
|
eba49c979f | ||
|
3475c179d1 | ||
|
4cb25ce93c | ||
|
c5499ce1da | ||
|
fa226b0d2f | ||
|
4b714196f3 | ||
|
9cace319a3 | ||
|
01d2afcfc2 | ||
|
8ea561a021 | ||
|
d23578cea9 | ||
|
629c4ff378 | ||
|
2d997b3fdd | ||
|
7f9d016b52 | ||
|
778f3bd84a | ||
|
382e1dedef | ||
|
fecbd3cbd4 | ||
|
7c1aa732b4 | ||
|
395390fb32 | ||
|
913cdbef66 | ||
|
60a2b1fecf | ||
|
b9d89b8c1d | ||
|
d0ffc3e1a5 | ||
|
46db1dea11 | ||
|
dd320af7f2 | ||
|
d6ffffd932 | ||
|
7f9060a4cb | ||
|
097a607389 | ||
|
45b3166729 | ||
|
38f815d439 | ||
|
23dce9e205 | ||
|
796a047401 | ||
|
b62a25597b | ||
|
81f6af3bdf | ||
|
9a40a8eeec | ||
|
0668fb7a15 | ||
|
735e7487d3 | ||
|
d48fe3bced | ||
|
98437ce57e | ||
|
f6ab251294 | ||
|
0fe1722dee | ||
|
9b88c0d55f | ||
|
e6e185cbd7 | ||
|
561ca26098 | ||
|
4600a2a070 | ||
|
52f54d2177 | ||
|
8415075de9 | ||
|
eea0aa33bd | ||
|
cdb2e0e3b4 | ||
|
e0727516ce | ||
|
fde3198997 | ||
|
c966d28d13 | ||
|
6d68ef3e49 | ||
|
1642f59980 | ||
|
80abbddae7 | ||
|
8bd4a1a67d | ||
|
3a16e57f87 | ||
|
1244397365 | ||
|
1f528cf7e1 | ||
|
5d697c36dc | ||
|
005fa59dd6 | ||
|
6d64a8b0a7 | ||
|
4e2e6d0b9b | ||
|
ade52d5a22 | ||
|
524b21e042 | ||
|
0896df33e6 | ||
|
111a1ff16d | ||
|
8d198178bb | ||
|
ec596a02b8 | ||
|
8ec972d4ee | ||
|
54f8b4f0a6 | ||
|
f5015bcfba | ||
|
443dd9706a | ||
|
2dcf3bbd6a | ||
|
12d61d37cf | ||
|
a94d25b635 | ||
|
6b2090e9ad | ||
|
5c051d919b | ||
|
02bf42b006 | ||
|
adddf3e4e7 | ||
|
3a742f1f14 | ||
|
82fe5c59c8 | ||
|
304f1d4af6 | ||
|
4a9a36a9c2 | ||
|
daa2f903c8 | ||
|
d36597954a | ||
|
0bf841555b | ||
|
0431806f24 | ||
|
ede0294943 | ||
|
e05801b464 | ||
|
e51650cd0a | ||
|
45d0227d2b | ||
|
7110cee7a9 | ||
|
a9109d750c | ||
|
ac4ab867d9 | ||
|
2f723e0f66 | ||
|
72a5ad34fb | ||
|
123fc5f96b | ||
|
cf930286c2 | ||
|
2308fc4a65 | ||
|
04e7648c01 | ||
|
18ca0beaa7 | ||
|
aeb8f24474 | ||
|
bde88d78b1 | ||
|
30e8040f99 | ||
|
5795bb58af | ||
|
d81f700194 | ||
|
0de0be5ae4 | ||
|
92b2c63f0d | ||
|
c4d82eac36 | ||
|
3630a9f78a | ||
|
c8497e1fce |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,3 +4,6 @@
|
|||||||
*~
|
*~
|
||||||
po/*.pot
|
po/*.pot
|
||||||
po/*.mo
|
po/*.mo
|
||||||
|
.settings
|
||||||
|
.cproject
|
||||||
|
.project
|
||||||
|
44
HISTORY
44
HISTORY
@@ -64,3 +64,47 @@ VDR Plugin 'satip' Revision History
|
|||||||
|
|
||||||
- Added a validity check for the session member.
|
- Added a validity check for the session member.
|
||||||
- Added a session id quirk for Triax TSS 400.
|
- Added a session id quirk for Triax TSS 400.
|
||||||
|
|
||||||
|
2014-12-24: Version 1.0.0
|
||||||
|
|
||||||
|
- Fixed the cable only device detection.
|
||||||
|
- Added support for blacklisted sources.
|
||||||
|
- Fixed server reuse for active transponders.
|
||||||
|
- Added a preliminary support for Fritz!WLAN
|
||||||
|
Repeater DVB-C (Thanks to Christian Wick).
|
||||||
|
- Added a preliminary support for Telestar
|
||||||
|
Digibit R1 (Thanks to Dirk Wagner).
|
||||||
|
- Added a new device status menu.
|
||||||
|
- Added support for SAT>IP frontend selection via
|
||||||
|
Radio ID.
|
||||||
|
- Added command-line switches for manually defining
|
||||||
|
used SAT>IP servers and setting used tracing mode.
|
||||||
|
- Added new STAT and TRAC commands into the SVDRP
|
||||||
|
interface.
|
||||||
|
- Refactored the tuner implementation.
|
||||||
|
- Updated against SAT>IP protocol specification
|
||||||
|
version 1.2.1.
|
||||||
|
- Refactored input thread to increase performance.
|
||||||
|
- Added plenty of performance tweaks (Thanks to
|
||||||
|
Stefan Schallenberg).
|
||||||
|
- Fixed EIT scan (Thanks to Stefan Schallenberg).
|
||||||
|
|
||||||
|
2015-01-10: Version 1.0.1
|
||||||
|
|
||||||
|
- Updated the command-line help and README.
|
||||||
|
- Fixed the server teardown.
|
||||||
|
- Removed the unnecessary config directory definition.
|
||||||
|
- Added a fallback for older glibc libraries.
|
||||||
|
- Improved pid selection performance.
|
||||||
|
- Added support for Digital Devices CI extension.
|
||||||
|
|
||||||
|
2015-01-18: Version 1.0.2
|
||||||
|
|
||||||
|
- Added configurable CI slots.
|
||||||
|
- Fixed parsing of the setup values.
|
||||||
|
- Added an option to disable sources via sources.conf.
|
||||||
|
- Added a command-line option to disable all the
|
||||||
|
SAT>IP server quirks.
|
||||||
|
- Updated Spanish and Catalan translations (Thanks to
|
||||||
|
Gabriel Bonich).
|
||||||
|
- Updated German translations (Thanks to Frank Neumann).
|
||||||
|
7
Makefile
7
Makefile
@@ -76,8 +76,10 @@ LIBS += -lpugixml
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef SATIP_DEBUG
|
ifdef SATIP_DEBUG
|
||||||
|
ifeq ($(SATIP_DEBUG),1)
|
||||||
DEFINES += -DDEBUG
|
DEFINES += -DDEBUG
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(strip $(GITTAG)),)
|
ifneq ($(strip $(GITTAG)),)
|
||||||
DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"'
|
DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"'
|
||||||
@@ -88,8 +90,9 @@ all-redirect: all
|
|||||||
|
|
||||||
### The object files (add further files here):
|
### The object files (add further files here):
|
||||||
|
|
||||||
OBJS = $(PLUGIN).o common.o config.o device.o discover.o param.o \
|
OBJS = $(PLUGIN).o common.o config.o device.o discover.o msearch.o param.o \
|
||||||
sectionfilter.o server.o setup.o socket.o statistics.o tuner.o
|
poller.o rtp.o rtcp.o rtsp.o sectionfilter.o server.o setup.o socket.o \
|
||||||
|
statistics.o tuner.o
|
||||||
|
|
||||||
### The main target:
|
### The main target:
|
||||||
|
|
||||||
|
55
README
55
README
@@ -23,8 +23,13 @@ Requirements:
|
|||||||
TinyXML - a simple, small, C++ XML parser
|
TinyXML - a simple, small, C++ XML parser
|
||||||
http://www.grinninglizard.com/tinyxml/
|
http://www.grinninglizard.com/tinyxml/
|
||||||
|
|
||||||
|
- Glibc >= 2.12 - the GNU C library (recvmmsg)
|
||||||
|
http://www.gnu.org/software/libc/
|
||||||
|
|
||||||
- VDR >= 2.1.4 for scrambled channels
|
- VDR >= 2.1.4 for scrambled channels
|
||||||
|
|
||||||
|
- VDR >= 2.1.7 for external CI
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
|
|
||||||
This plugin integrates SAT>IP network devices seamlessly into VDR.
|
This plugin integrates SAT>IP network devices seamlessly into VDR.
|
||||||
@@ -44,10 +49,21 @@ The plugin accepts a "--devices" (-d) command-line parameter defaulting
|
|||||||
to one. 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.
|
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. 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:
|
||||||
|
|
||||||
|
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
|
SAT>IP satellite positions (aka. signal sources) shall be defined via
|
||||||
sources.conf. If the source description begins with a number, it's used
|
sources.conf. If the source description begins with a number, it's used
|
||||||
as SAT>IP signal source selection parameter. Otherwise, the default
|
as SAT>IP signal source selection parameter. A special number zero can
|
||||||
parameter is one:
|
be used to disable the source. Otherwise, the default parameter is one:
|
||||||
|
|
||||||
S19.2E Astra 1KR/1L/1M/2C
|
S19.2E Astra 1KR/1L/1M/2C
|
||||||
=> Signal source = 1
|
=> Signal source = 1
|
||||||
@@ -58,6 +74,14 @@ S19.2E 2
|
|||||||
S19.2E 3 Astra 1KR/1L/1M/2C
|
S19.2E 3 Astra 1KR/1L/1M/2C
|
||||||
=> Signal source = 3
|
=> Signal source = 3
|
||||||
|
|
||||||
|
S19.2E 0 Astra 1KR/1L/1M/2C
|
||||||
|
=> Source is disabled
|
||||||
|
|
||||||
|
A channel can be assigned into a specific SAT>IP frontend by giving the
|
||||||
|
identifier number in RID field of a channels.conf entry:
|
||||||
|
FE = RID % 100
|
||||||
|
Valid range: 1 ... 99
|
||||||
|
|
||||||
Setup menu:
|
Setup menu:
|
||||||
|
|
||||||
- Operating mode = off If you want exclude all SAT>IP devices
|
- Operating mode = off If you want exclude all SAT>IP devices
|
||||||
@@ -68,19 +92,30 @@ Setup menu:
|
|||||||
option to "low". Similarly, the "high"
|
option to "low". Similarly, the "high"
|
||||||
value prefers the SAT>IP over the local
|
value prefers the SAT>IP over the local
|
||||||
DVB cards when selecting available devices.
|
DVB cards when selecting available devices.
|
||||||
|
- Use CI extension = no If you want to use the CI extension found
|
||||||
|
in some SAT>IP hardware (e.g. Digital
|
||||||
|
Devices OctopusNet), set this option to
|
||||||
|
"yes".
|
||||||
|
- CICAM #<slot> = <system> If you want to assign a CA system into
|
||||||
|
a specific CI slot, set this option to
|
||||||
|
a named one. Use "---" for autoselection.
|
||||||
- Enable EPG scanning = yes If you want exclude all SAT>IP devices
|
- Enable EPG scanning = yes If you want exclude all SAT>IP devices
|
||||||
from VDR's EIT background scanning, set
|
from VDR's EIT background scanning, set
|
||||||
this option to "no".
|
this option to "no".
|
||||||
|
- Disabled sources = none If your SAT>IP servers don't have certain
|
||||||
|
satellite positions available you can
|
||||||
|
disable them via this option.
|
||||||
- Disabled filters = none Certain section filters might cause some
|
- Disabled filters = none Certain section filters might cause some
|
||||||
unwanted behaviour to VDR such as time
|
unwanted behaviour to VDR such as time
|
||||||
being falsely synchronized etc. This option
|
being falsely synchronized etc. This option
|
||||||
allows creation of blacklists of ill-behaving
|
allows creation of blacklists of ill-behaving
|
||||||
filters. If this option is set to a non-zero
|
filters. If this option is set to a non-zero
|
||||||
value, the menu page will contain that many
|
value, the menu page will contain that many
|
||||||
"Disable filter" options which allow you
|
"Disable filter" options which allow you
|
||||||
to disable the individual section filters.
|
to disable the individual section filters.
|
||||||
Valid range: "none" = 0 ... 7
|
Valid range: "none" = 0 ... 7
|
||||||
- [Red:Scan] Forces network scanning of SAT>IP hardware.
|
- [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.
|
- [Blue:Info] Opens SAT>IP information/statistics menu.
|
||||||
- [Ok] Opens information menu of selected SAT>IP
|
- [Ok] Opens information menu of selected SAT>IP
|
||||||
device.
|
device.
|
||||||
@@ -97,10 +132,6 @@ Notes:
|
|||||||
- The stream id "-1" states about unsuccessful tuning. This might be a
|
- The stream id "-1" states about unsuccessful tuning. This might be a
|
||||||
result of invalid channel parameters or lack of free SAT>IP tuners.
|
result of invalid channel parameters or lack of free SAT>IP tuners.
|
||||||
|
|
||||||
- SAT>IP specification 1.2 doesn't support DVB-C/DVB-C2 receivers yet,
|
|
||||||
but DVB-C (KABEL>IP) is supported for Digital Devices Octopus Net
|
|
||||||
devices.
|
|
||||||
|
|
||||||
- If the plugin doesn't detect your SAT>IP network device, make sure
|
- If the plugin doesn't detect your SAT>IP network device, make sure
|
||||||
your setup doesn't have firewalled the UDP port 1900.
|
your setup doesn't have firewalled the UDP port 1900.
|
||||||
|
|
||||||
@@ -108,6 +139,16 @@ Notes:
|
|||||||
direct access to any DVB card devices. The integrated CAM slot in
|
direct access to any DVB card devices. The integrated CAM slot in
|
||||||
Octopus Net devices isn't supported.
|
Octopus Net devices isn't supported.
|
||||||
|
|
||||||
|
- Tracing can be set on/off dynamically via command-line switch or
|
||||||
|
SVDRP command.
|
||||||
|
|
||||||
|
- OctopusNet firmware 1.0.40 or greater recommended.
|
||||||
|
|
||||||
|
- Inverto OEM firmware 1.17.0.120 or greater recommended.
|
||||||
|
The firmware 1.16.0.120 can be downloaded and installed
|
||||||
|
from their webpage: http://www.inverto.tv/support/
|
||||||
|
An update to a newer firmware should be offered afterwards.
|
||||||
|
|
||||||
Acknowledgements:
|
Acknowledgements:
|
||||||
|
|
||||||
- Big thanks to Digital Devices GmbH for providing the Octopus Net
|
- Big thanks to Digital Devices GmbH for providing the Octopus Net
|
||||||
|
64
common.c
64
common.c
@@ -79,10 +79,72 @@ cString ChangeCase(const cString &strP, bool upperP)
|
|||||||
|
|
||||||
const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE] =
|
const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE] =
|
||||||
{
|
{
|
||||||
/* description tag pid tid mask */
|
// description tag pid tid mask
|
||||||
{trNOOP("PAT (0x00)"), "PAT", 0x00, 0x00, 0xFF},
|
{trNOOP("PAT (0x00)"), "PAT", 0x00, 0x00, 0xFF},
|
||||||
{trNOOP("NIT (0x40)"), "NIT", 0x10, 0x40, 0xFF},
|
{trNOOP("NIT (0x40)"), "NIT", 0x10, 0x40, 0xFF},
|
||||||
{trNOOP("SDT (0x42)"), "SDT", 0x11, 0x42, 0xFF},
|
{trNOOP("SDT (0x42)"), "SDT", 0x11, 0x42, 0xFF},
|
||||||
{trNOOP("EIT (0x4E/0x4F/0x5X/0x6X)"), "EIT", 0x12, 0x40, 0xC0},
|
{trNOOP("EIT (0x4E/0x4F/0x5X/0x6X)"), "EIT", 0x12, 0x40, 0xC0},
|
||||||
{trNOOP("TDT (0x70)"), "TDT", 0x14, 0x70, 0xFF},
|
{trNOOP("TDT (0x70)"), "TDT", 0x14, 0x70, 0xFF},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ca_systems_table_type ca_systems_table[CA_SYSTEMS_TABLE_SIZE] =
|
||||||
|
{
|
||||||
|
// http://www.dvb.org/index.php?id=174
|
||||||
|
// http://en.wikipedia.org/wiki/Conditional_access_system
|
||||||
|
// start end description
|
||||||
|
{0x0000, 0x0000, "---" }, // 0
|
||||||
|
{0x0100, 0x01FF, "SECA Mediaguard (100..1FF)"}, // 1
|
||||||
|
{0x0464, 0x0464, "EuroDec (464)" }, // 2
|
||||||
|
{0x0500, 0x05FF, "Viaccess (500..5FF)" }, // 3
|
||||||
|
{0x0600, 0x06FF, "Irdeto (600..6FF)" }, // 4
|
||||||
|
{0x0700, 0x07FF, "DigiCipher 2 (700..7FF)" }, // 5
|
||||||
|
{0x0900, 0x09FF, "NDS Videoguard (900..9FF)" }, // 6
|
||||||
|
{0x0B00, 0x0BFF, "Conax (B00..BFF)" }, // 7
|
||||||
|
{0x0D00, 0x0DFF, "CryptoWorks (D00..DFF)" }, // 8
|
||||||
|
{0x0E00, 0x0EFF, "PowerVu (E00..EFF)" }, // 9
|
||||||
|
{0x1000, 0x10FF, "RAS (1000..10FF)" }, // 10
|
||||||
|
{0x1200, 0x12FF, "NagraVision (1200..12FF)" }, // 11
|
||||||
|
{0x1700, 0x17FF, "VCAS (1700..17FF)" }, // 12
|
||||||
|
{0x1800, 0x18FF, "NagraVision (1800..18FF)" }, // 13
|
||||||
|
{0x22F0, 0x22F0, "Codicrypt (22F0)" }, // 14
|
||||||
|
{0x2600, 0x2600, "BISS (2600)" }, // 15
|
||||||
|
{0x2719, 0x2719, "VanyaCas (2719)" }, // 16
|
||||||
|
{0x4347, 0x4347, "CryptOn (4347)" }, // 17
|
||||||
|
{0x4800, 0x4800, "Accessgate (4800)" }, // 18
|
||||||
|
{0x4900, 0x4900, "China Crypt (4900)" }, // 19
|
||||||
|
{0x4A02, 0x4A02, "Tongfang (4A02)" }, // 20
|
||||||
|
{0x4A10, 0x4A10, "EasyCas (4A10)" }, // 21
|
||||||
|
{0x4A20, 0x4A20, "AlphaCrypt (4A20)" }, // 22
|
||||||
|
{0x4A60, 0x4A60, "SkyCrypt (4A60)" }, // 23
|
||||||
|
{0x4A61, 0x4A61, "Neotioncrypt (4A61)" }, // 24
|
||||||
|
{0x4A62, 0x4A62, "SkyCrypt (4A62)" }, // 25
|
||||||
|
{0x4A63, 0x4A63, "Neotion SHL (4A63)" }, // 26
|
||||||
|
{0x4A64, 0x4A6F, "SkyCrypt (4A64)" }, // 27
|
||||||
|
{0x4A70, 0x4A70, "DreamCrypt (4A70)" }, // 28
|
||||||
|
{0x4A80, 0x4A80, "ThalesCrypt (4A80)" }, // 29
|
||||||
|
{0x4AA1, 0x4AA1, "KeyFly (4AA1)" }, // 30
|
||||||
|
{0x4ABF, 0x4ABF, "CTI-CAS (4ABF)" }, // 31
|
||||||
|
{0x4AC1, 0x4AC1, "Latens (4AC1)" }, // 32
|
||||||
|
{0x4AD0, 0x4AD1, "X-Crypt (4AD0)" }, // 33
|
||||||
|
{0x4AD4, 0x4AD4, "OmniCrypt (4AD4)" }, // 34
|
||||||
|
{0x4AE0, 0x4AE1, "Z-Crypt (4AE0)" }, // 35
|
||||||
|
{0x4AE4, 0x4AE4, "CoreCrypt (4AE4)" }, // 36
|
||||||
|
{0x4AE5, 0x4AE5, "PRO-Crypt (4AE5)" }, // 37
|
||||||
|
{0x4AEA, 0x4AEA, "Cryptoguard (4AEA)" }, // 38
|
||||||
|
{0x4AEB, 0x4AEB, "Abel Quintic (4AEB)" }, // 39
|
||||||
|
{0x4AF0, 0x4AF0, "ABV (4AF0)" }, // 40
|
||||||
|
{0x5500, 0x5500, "Z-Crypt (5500)" }, // 41
|
||||||
|
{0x5501, 0x5501, "Griffin (5501)" }, // 42
|
||||||
|
{0x5581, 0x5581, "Bulcrypt (5581)" }, // 43
|
||||||
|
{0x7BE1, 0x7BE1, "DRE-Crypt (7BE1)" }, // 44
|
||||||
|
{0xA101, 0xA101, "RosCrypt-M (A101)" }, // 45
|
||||||
|
{0xEAD0, 0xEAD0, "VanyaCas (EAD0)" }, // 46
|
||||||
|
};
|
||||||
|
|
||||||
|
bool checkCASystem(unsigned int cicamP, int caidP)
|
||||||
|
{
|
||||||
|
// always skip the first row
|
||||||
|
if ((cicamP > 0) && (cicamP < ELEMENTS(ca_systems_table)))
|
||||||
|
return ((caidP >= ca_systems_table[cicamP].start) && (caidP <= ca_systems_table[cicamP].end));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
36
common.h
36
common.h
@@ -8,23 +8,14 @@
|
|||||||
#ifndef __SATIP_COMMON_H
|
#ifndef __SATIP_COMMON_H
|
||||||
#define __SATIP_COMMON_H
|
#define __SATIP_COMMON_H
|
||||||
|
|
||||||
|
#include <vdr/device.h>
|
||||||
#include <vdr/tools.h>
|
#include <vdr/tools.h>
|
||||||
#include <vdr/config.h>
|
#include <vdr/config.h>
|
||||||
#include <vdr/i18n.h>
|
#include <vdr/i18n.h>
|
||||||
|
|
||||||
#ifdef DEBUG
|
#define SATIP_MAX_DEVICES MAXDEVICES
|
||||||
#define debug(x...) dsyslog("SATIP: " x);
|
|
||||||
#define info(x...) isyslog("SATIP: " x);
|
|
||||||
#define error(x...) esyslog("ERROR: " x);
|
|
||||||
#else
|
|
||||||
#define debug(x...) ;
|
|
||||||
#define info(x...) isyslog("SATIP: " x);
|
|
||||||
#define error(x...) esyslog("ERROR: " x);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
|
#define SATIP_BUFFER_SIZE KILOBYTE(1024)
|
||||||
|
|
||||||
#define SATIP_BUFFER_SIZE MEGABYTE(1)
|
|
||||||
|
|
||||||
#define SATIP_DEVICE_INFO_ALL 0
|
#define SATIP_DEVICE_INFO_ALL 0
|
||||||
#define SATIP_DEVICE_INFO_GENERAL 1
|
#define SATIP_DEVICE_INFO_GENERAL 1
|
||||||
@@ -36,8 +27,12 @@
|
|||||||
#define SATIP_STATS_ACTIVE_PIDS_COUNT 10
|
#define SATIP_STATS_ACTIVE_PIDS_COUNT 10
|
||||||
#define SATIP_STATS_ACTIVE_FILTERS_COUNT 10
|
#define SATIP_STATS_ACTIVE_FILTERS_COUNT 10
|
||||||
|
|
||||||
|
#define MAX_DISABLED_SOURCES_COUNT 25
|
||||||
#define SECTION_FILTER_TABLE_SIZE 5
|
#define SECTION_FILTER_TABLE_SIZE 5
|
||||||
|
|
||||||
|
#define MAX_CICAM_COUNT 2
|
||||||
|
#define CA_SYSTEMS_TABLE_SIZE 47
|
||||||
|
|
||||||
#define SATIP_CURL_EASY_GETINFO(X, Y, Z) \
|
#define SATIP_CURL_EASY_GETINFO(X, Y, Z) \
|
||||||
if ((res = curl_easy_getinfo((X), (Y), (Z))) != CURLE_OK) { \
|
if ((res = curl_easy_getinfo((X), (Y), (Z))) != CURLE_OK) { \
|
||||||
error("curl_easy_getinfo(%s) [%s,%d] failed: %s (%d)", #Y, __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
error("curl_easy_getinfo(%s) [%s,%d] failed: %s (%d)", #Y, __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
||||||
@@ -45,19 +40,19 @@
|
|||||||
|
|
||||||
#define SATIP_CURL_EASY_SETOPT(X, Y, Z) \
|
#define SATIP_CURL_EASY_SETOPT(X, Y, Z) \
|
||||||
if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { \
|
if ((res = curl_easy_setopt((X), (Y), (Z))) != CURLE_OK) { \
|
||||||
error("curl_easy_setopt(%s, %s) [%s,%d] failed: %s (%d)", #Y, #Z, __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
esyslog("curl_easy_setopt(%s, %s) [%s,%d] failed: %s (%d)", #Y, #Z, __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SATIP_CURL_EASY_PERFORM(X) \
|
#define SATIP_CURL_EASY_PERFORM(X) \
|
||||||
if ((res = curl_easy_perform((X))) != CURLE_OK) { \
|
if ((res = curl_easy_perform((X))) != CURLE_OK) { \
|
||||||
error("curl_easy_perform() [%s,%d] failed: %s (%d)", __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
esyslog("curl_easy_perform() [%s,%d] failed: %s (%d)", __FILE__, __LINE__, curl_easy_strerror(res), res); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ERROR_IF_FUNC(exp, errstr, func, ret) \
|
#define ERROR_IF_FUNC(exp, errstr, func, ret) \
|
||||||
do { \
|
do { \
|
||||||
if (exp) { \
|
if (exp) { \
|
||||||
char tmp[64]; \
|
char tmp[64]; \
|
||||||
error("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
|
esyslog("[%s,%d]: "errstr": %s", __FILE__, __LINE__, \
|
||||||
strerror_r(errno, tmp, sizeof(tmp))); \
|
strerror_r(errno, tmp, sizeof(tmp))); \
|
||||||
func; \
|
func; \
|
||||||
ret; \
|
ret; \
|
||||||
@@ -87,7 +82,7 @@
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
|
#define ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
|
||||||
|
|
||||||
uint16_t ts_pid(const uint8_t *bufP);
|
uint16_t ts_pid(const uint8_t *bufP);
|
||||||
uint8_t payload(const uint8_t *bufP);
|
uint8_t payload(const uint8_t *bufP);
|
||||||
@@ -106,6 +101,15 @@ struct section_filter_table_type {
|
|||||||
|
|
||||||
extern const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE];
|
extern const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE];
|
||||||
|
|
||||||
|
struct ca_systems_table_type {
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
const char *description;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const ca_systems_table_type ca_systems_table[CA_SYSTEMS_TABLE_SIZE];
|
||||||
|
extern bool checkCASystem(unsigned int cicamP, int caidP);
|
||||||
|
|
||||||
extern const char VERSION[];
|
extern const char VERSION[];
|
||||||
|
|
||||||
#endif // __SATIP_COMMON_H
|
#endif // __SATIP_COMMON_H
|
||||||
|
56
config.c
56
config.c
@@ -6,41 +6,73 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "discover.h"
|
#include "discover.h"
|
||||||
|
#include "log.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
cSatipConfig SatipConfig;
|
cSatipConfig SatipConfig;
|
||||||
|
|
||||||
cSatipConfig::cSatipConfig(void)
|
cSatipConfig::cSatipConfig(void)
|
||||||
: operatingModeM(eOperatingModeLow),
|
: operatingModeM(eOperatingModeLow),
|
||||||
|
traceModeM(eTraceModeNormal),
|
||||||
|
ciExtensionM(0),
|
||||||
eitScanM(1),
|
eitScanM(1),
|
||||||
useBytesM(1)
|
useBytesM(1),
|
||||||
|
disableServerQuirksM(false),
|
||||||
|
useSingleModelServersM(false)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < ARRAY_SIZE(disabledFiltersM); ++i)
|
for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i)
|
||||||
|
cicamsM[i] = 0;
|
||||||
|
for (unsigned int i = 0; i < ELEMENTS(disabledSourcesM); ++i)
|
||||||
|
disabledSourcesM[i] = cSource::stNone;
|
||||||
|
for (unsigned int i = 0; i < ELEMENTS(disabledFiltersM); ++i)
|
||||||
disabledFiltersM[i] = -1;
|
disabledFiltersM[i] = -1;
|
||||||
memset(configDirectoryM, 0, sizeof(configDirectoryM));
|
}
|
||||||
|
|
||||||
|
int cSatipConfig::GetCICAM(unsigned int indexP) const
|
||||||
|
{
|
||||||
|
return (indexP < ELEMENTS(cicamsM)) ? cicamsM[indexP] : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipConfig::SetCICAM(unsigned int indexP, int cicamP)
|
||||||
|
{
|
||||||
|
if (indexP < ELEMENTS(cicamsM))
|
||||||
|
cicamsM[indexP] = cicamP;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cSatipConfig::GetDisabledSourcesCount(void) const
|
||||||
|
{
|
||||||
|
unsigned int n = 0;
|
||||||
|
while ((n < ELEMENTS(disabledSourcesM) && (disabledSourcesM[n] != cSource::stNone)))
|
||||||
|
n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cSatipConfig::GetDisabledSources(unsigned int indexP) const
|
||||||
|
{
|
||||||
|
return (indexP < ELEMENTS(disabledSourcesM)) ? disabledSourcesM[indexP] : cSource::stNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipConfig::SetDisabledSources(unsigned int indexP, int sourceP)
|
||||||
|
{
|
||||||
|
if (indexP < ELEMENTS(disabledSourcesM))
|
||||||
|
disabledSourcesM[indexP] = sourceP;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cSatipConfig::GetDisabledFiltersCount(void) const
|
unsigned int cSatipConfig::GetDisabledFiltersCount(void) const
|
||||||
{
|
{
|
||||||
unsigned int n = 0;
|
unsigned int n = 0;
|
||||||
while ((n < ARRAY_SIZE(disabledFiltersM) && (disabledFiltersM[n] != -1)))
|
while ((n < ELEMENTS(disabledFiltersM) && (disabledFiltersM[n] != -1)))
|
||||||
n++;
|
n++;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cSatipConfig::GetDisabledFilters(unsigned int indexP) const
|
int cSatipConfig::GetDisabledFilters(unsigned int indexP) const
|
||||||
{
|
{
|
||||||
return (indexP < ARRAY_SIZE(disabledFiltersM)) ? disabledFiltersM[indexP] : -1;
|
return (indexP < ELEMENTS(disabledFiltersM)) ? disabledFiltersM[indexP] : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipConfig::SetDisabledFilters(unsigned int indexP, int numberP)
|
void cSatipConfig::SetDisabledFilters(unsigned int indexP, int numberP)
|
||||||
{
|
{
|
||||||
if (indexP < ARRAY_SIZE(disabledFiltersM))
|
if (indexP < ELEMENTS(disabledFiltersM))
|
||||||
disabledFiltersM[indexP] = numberP;
|
disabledFiltersM[indexP] = numberP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipConfig::SetConfigDirectory(const char *directoryP)
|
|
||||||
{
|
|
||||||
debug("cSatipConfig::%s(%s)", __FUNCTION__, directoryP);
|
|
||||||
ERROR_IF(!realpath(directoryP, configDirectoryM), "Cannot canonicalize configuration directory");
|
|
||||||
}
|
|
||||||
|
45
config.h
45
config.h
@@ -15,19 +15,44 @@ class cSatipConfig
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
unsigned int operatingModeM;
|
unsigned int operatingModeM;
|
||||||
|
unsigned int traceModeM;
|
||||||
|
unsigned int ciExtensionM;
|
||||||
unsigned int eitScanM;
|
unsigned int eitScanM;
|
||||||
unsigned int useBytesM;
|
unsigned int useBytesM;
|
||||||
|
bool disableServerQuirksM;
|
||||||
|
bool useSingleModelServersM;
|
||||||
|
int cicamsM[MAX_CICAM_COUNT];
|
||||||
|
int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT];
|
||||||
int disabledFiltersM[SECTION_FILTER_TABLE_SIZE];
|
int disabledFiltersM[SECTION_FILTER_TABLE_SIZE];
|
||||||
char configDirectoryM[PATH_MAX];
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum {
|
enum eOperatingMode {
|
||||||
eOperatingModeOff = 0,
|
eOperatingModeOff = 0,
|
||||||
eOperatingModeLow,
|
eOperatingModeLow,
|
||||||
eOperatingModeNormal,
|
eOperatingModeNormal,
|
||||||
eOperatingModeHigh,
|
eOperatingModeHigh,
|
||||||
eOperatingModeCount
|
eOperatingModeCount
|
||||||
};
|
};
|
||||||
|
enum eTraceMode {
|
||||||
|
eTraceModeNormal = 0x0000,
|
||||||
|
eTraceModeDebug1 = 0x0001,
|
||||||
|
eTraceModeDebug2 = 0x0002,
|
||||||
|
eTraceModeDebug3 = 0x0004,
|
||||||
|
eTraceModeDebug4 = 0x0008,
|
||||||
|
eTraceModeDebug5 = 0x0010,
|
||||||
|
eTraceModeDebug6 = 0x0020,
|
||||||
|
eTraceModeDebug7 = 0x0040,
|
||||||
|
eTraceModeDebug8 = 0x0080,
|
||||||
|
eTraceModeDebug9 = 0x0100,
|
||||||
|
eTraceModeDebug10 = 0x0200,
|
||||||
|
eTraceModeDebug11 = 0x0400,
|
||||||
|
eTraceModeDebug12 = 0x0800,
|
||||||
|
eTraceModeDebug13 = 0x1000,
|
||||||
|
eTraceModeDebug14 = 0x2000,
|
||||||
|
eTraceModeDebug15 = 0x4000,
|
||||||
|
eTraceModeDebug16 = 0x8000,
|
||||||
|
eTraceModeMask = 0xFFFF
|
||||||
|
};
|
||||||
cSatipConfig();
|
cSatipConfig();
|
||||||
unsigned int GetOperatingMode(void) const { return operatingModeM; }
|
unsigned int GetOperatingMode(void) const { return operatingModeM; }
|
||||||
bool IsOperatingModeOff(void) const { return (operatingModeM == eOperatingModeOff); }
|
bool IsOperatingModeOff(void) const { return (operatingModeM == eOperatingModeOff); }
|
||||||
@@ -35,16 +60,28 @@ public:
|
|||||||
bool IsOperatingModeNormal(void) const { return (operatingModeM == eOperatingModeNormal); }
|
bool IsOperatingModeNormal(void) const { return (operatingModeM == eOperatingModeNormal); }
|
||||||
bool IsOperatingModeHigh(void) const { return (operatingModeM == eOperatingModeHigh); }
|
bool IsOperatingModeHigh(void) const { return (operatingModeM == eOperatingModeHigh); }
|
||||||
void ToggleOperatingMode(void) { operatingModeM = (operatingModeM + 1) % eOperatingModeCount; }
|
void ToggleOperatingMode(void) { operatingModeM = (operatingModeM + 1) % eOperatingModeCount; }
|
||||||
|
unsigned int GetTraceMode(void) const { return traceModeM; }
|
||||||
|
bool IsTraceMode(eTraceMode modeP) const { return (traceModeM & modeP); }
|
||||||
|
unsigned int GetCIExtension(void) const { return ciExtensionM; }
|
||||||
|
int GetCICAM(unsigned int indexP) const;
|
||||||
unsigned int GetEITScan(void) const { return eitScanM; }
|
unsigned int GetEITScan(void) const { return eitScanM; }
|
||||||
unsigned int GetUseBytes(void) const { return useBytesM; }
|
unsigned int GetUseBytes(void) const { return useBytesM; }
|
||||||
const char *GetConfigDirectory(void) const { return configDirectoryM; }
|
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;
|
unsigned int GetDisabledFiltersCount(void) const;
|
||||||
int GetDisabledFilters(unsigned int indexP) const;
|
int GetDisabledFilters(unsigned int indexP) const;
|
||||||
|
|
||||||
void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; }
|
void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; }
|
||||||
|
void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); }
|
||||||
|
void SetCIExtension(unsigned int onOffP) { ciExtensionM = onOffP; }
|
||||||
|
void SetCICAM(unsigned int indexP, int cicamP);
|
||||||
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; }
|
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; }
|
||||||
void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; }
|
void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; }
|
||||||
void SetConfigDirectory(const char *directoryP);
|
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 SetDisabledFilters(unsigned int indexP, int numberP);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
181
device.c
181
device.c
@@ -5,13 +5,14 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <vdr/menu.h> // cRecordControl
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "discover.h"
|
#include "discover.h"
|
||||||
|
#include "log.h"
|
||||||
#include "param.h"
|
#include "param.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
#define SATIP_MAX_DEVICES MAXDEVICES
|
|
||||||
|
|
||||||
static cSatipDevice * SatipDevicesS[SATIP_MAX_DEVICES] = { NULL };
|
static cSatipDevice * SatipDevicesS[SATIP_MAX_DEVICES] = { NULL };
|
||||||
|
|
||||||
cSatipDevice::cSatipDevice(unsigned int indexP)
|
cSatipDevice::cSatipDevice(unsigned int indexP)
|
||||||
@@ -25,11 +26,11 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
|
|||||||
{
|
{
|
||||||
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
|
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
|
||||||
bufsize -= (bufsize % TS_SIZE);
|
bufsize -= (bufsize % TS_SIZE);
|
||||||
isyslog("creating SAT>IP device %d (CardIndex=%d)", deviceIndexM, CardIndex());
|
info("Creating device CardIndex=%d DeviceNumber=%d [device %u]", CardIndex(), DeviceNumber(), deviceIndexM);
|
||||||
tsBufferM = new cRingBufferLinear(bufsize + 1, TS_SIZE, false,
|
tsBufferM = new cRingBufferLinear(bufsize + 1, TS_SIZE, false,
|
||||||
*cString::sprintf("SAT>IP TS %d", deviceIndexM));
|
*cString::sprintf("SATIP#%d TS", deviceIndexM));
|
||||||
if (tsBufferM) {
|
if (tsBufferM) {
|
||||||
tsBufferM->SetTimeouts(100, 100);
|
tsBufferM->SetTimeouts(10, 10);
|
||||||
tsBufferM->SetIoThrottle();
|
tsBufferM->SetIoThrottle();
|
||||||
pTunerM = new cSatipTuner(*this, tsBufferM->Free());
|
pTunerM = new cSatipTuner(*this, tsBufferM->Free());
|
||||||
}
|
}
|
||||||
@@ -40,7 +41,7 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
|
|||||||
|
|
||||||
cSatipDevice::~cSatipDevice()
|
cSatipDevice::~cSatipDevice()
|
||||||
{
|
{
|
||||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug1("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
// Stop section handler
|
// Stop section handler
|
||||||
StopSectionHandler();
|
StopSectionHandler();
|
||||||
DELETE_POINTER(pSectionFilterHandlerM);
|
DELETE_POINTER(pSectionFilterHandlerM);
|
||||||
@@ -50,7 +51,7 @@ cSatipDevice::~cSatipDevice()
|
|||||||
|
|
||||||
bool cSatipDevice::Initialize(unsigned int deviceCountP)
|
bool cSatipDevice::Initialize(unsigned int deviceCountP)
|
||||||
{
|
{
|
||||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceCountP);
|
debug1("%s (%u)", __PRETTY_FUNCTION__, deviceCountP);
|
||||||
if (deviceCountP > SATIP_MAX_DEVICES)
|
if (deviceCountP > SATIP_MAX_DEVICES)
|
||||||
deviceCountP = SATIP_MAX_DEVICES;
|
deviceCountP = SATIP_MAX_DEVICES;
|
||||||
for (unsigned int i = 0; i < deviceCountP; ++i)
|
for (unsigned int i = 0; i < deviceCountP; ++i)
|
||||||
@@ -62,7 +63,7 @@ bool cSatipDevice::Initialize(unsigned int deviceCountP)
|
|||||||
|
|
||||||
void cSatipDevice::Shutdown(void)
|
void cSatipDevice::Shutdown(void)
|
||||||
{
|
{
|
||||||
debug("cSatipDevice::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
for (int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
for (int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
||||||
if (SatipDevicesS[i])
|
if (SatipDevicesS[i])
|
||||||
SatipDevicesS[i]->CloseDvr();
|
SatipDevicesS[i]->CloseDvr();
|
||||||
@@ -72,7 +73,7 @@ void cSatipDevice::Shutdown(void)
|
|||||||
unsigned int cSatipDevice::Count(void)
|
unsigned int cSatipDevice::Count(void)
|
||||||
{
|
{
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
debug("cSatipDevice::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
for (unsigned int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
for (unsigned int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
||||||
if (SatipDevicesS[i] != NULL)
|
if (SatipDevicesS[i] != NULL)
|
||||||
count++;
|
count++;
|
||||||
@@ -82,19 +83,51 @@ unsigned int cSatipDevice::Count(void)
|
|||||||
|
|
||||||
cSatipDevice *cSatipDevice::GetSatipDevice(int cardIndexP)
|
cSatipDevice *cSatipDevice::GetSatipDevice(int cardIndexP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%d)", __FUNCTION__, cardIndexP);
|
debug16("%s (%d)", __PRETTY_FUNCTION__, cardIndexP);
|
||||||
for (unsigned int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
for (unsigned int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
||||||
if (SatipDevicesS[i] && (SatipDevicesS[i]->CardIndex() == cardIndexP)) {
|
if (SatipDevicesS[i] && (SatipDevicesS[i]->CardIndex() == cardIndexP)) {
|
||||||
//debug("cSatipDevice::%s(%d): found!", __FUNCTION__, cardIndexP);
|
debug16("%s (%d): Found!", __PRETTY_FUNCTION__, cardIndexP);
|
||||||
return SatipDevicesS[i];
|
return SatipDevicesS[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cString cSatipDevice::GetSatipStatus(void)
|
||||||
|
{
|
||||||
|
cString info = "";
|
||||||
|
for (int i = 0; i < cDevice::NumDevices(); i++) {
|
||||||
|
const cDevice *device = cDevice::GetDevice(i);
|
||||||
|
if (device && strstr(device->DeviceType(), "SAT>IP")) {
|
||||||
|
int timers = 0;
|
||||||
|
bool live = (device == cDevice::ActualDevice());
|
||||||
|
bool lock = device->HasLock();
|
||||||
|
const cChannel *channel = device->GetCurrentlyTunedTransponder();
|
||||||
|
for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
|
||||||
|
if (timer->Recording()) {
|
||||||
|
cRecordControl *control = cRecordControls::GetRecordControl(timer);
|
||||||
|
if (control && control->Device() == device)
|
||||||
|
timers++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info = cString::sprintf("%sDevice: %s\n", *info, *device->DeviceName());
|
||||||
|
if (lock)
|
||||||
|
info = cString::sprintf("%sCardIndex: %d HasLock: yes Strength: %d Quality: %d%s\n", *info, device->CardIndex(), device->SignalStrength(), device->SignalQuality(), live ? " Live: yes" : "");
|
||||||
|
else
|
||||||
|
info = cString::sprintf("%sCardIndex: %d HasLock: no\n", *info, device->CardIndex());
|
||||||
|
if (channel && channel->Number() > 0)
|
||||||
|
info = cString::sprintf("%sTransponder: %d Channel: %s\n", *info, (channel && channel->Number() > 0) ? channel->Transponder() : 0, (channel && channel->Number() > 0) ? channel->Name() : "---");
|
||||||
|
if (timers)
|
||||||
|
info = cString::sprintf("%sRecording: %d timer%s\n", *info, timers, (timers > 1) ? "s" : "");
|
||||||
|
info = cString::sprintf("%s\n", *info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isempty(*info) ? cString(tr("SAT>IP information not available!")) : info;
|
||||||
|
}
|
||||||
|
|
||||||
cString cSatipDevice::GetGeneralInformation(void)
|
cString cSatipDevice::GetGeneralInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s",
|
return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s",
|
||||||
deviceIndexM, CardIndex(),
|
deviceIndexM, CardIndex(),
|
||||||
pTunerM ? *pTunerM->GetInformation() : "",
|
pTunerM ? *pTunerM->GetInformation() : "",
|
||||||
@@ -106,13 +139,13 @@ cString cSatipDevice::GetGeneralInformation(void)
|
|||||||
|
|
||||||
cString cSatipDevice::GetPidsInformation(void)
|
cString cSatipDevice::GetPidsInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return GetPidStatistic();
|
return GetPidStatistic();
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipDevice::GetFiltersInformation(void)
|
cString cSatipDevice::GetFiltersInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return cString::sprintf("Active section filters:\n%s", pSectionFilterHandlerM ? *pSectionFilterHandlerM->GetInformation() : "");
|
return cString::sprintf("Active section filters:\n%s", pSectionFilterHandlerM ? *pSectionFilterHandlerM->GetInformation() : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,50 +181,64 @@ cString cSatipDevice::GetInformation(unsigned int pageP)
|
|||||||
|
|
||||||
bool cSatipDevice::Ready(void)
|
bool cSatipDevice::Ready(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return ((cSatipDiscover::GetInstance()->GetServerCount() > 0) || (createdM.Elapsed() > eReadyTimeoutMs));
|
return ((cSatipDiscover::GetInstance()->GetServerCount() > 0) || (createdM.Elapsed() > eReadyTimeoutMs));
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipDevice::DeviceType(void) const
|
cString cSatipDevice::DeviceType(void) const
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return "SAT>IP";
|
return "SAT>IP";
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipDevice::DeviceName(void) const
|
cString cSatipDevice::DeviceName(void) const
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return deviceNameM;
|
return deviceNameM;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipDevice::AvoidRecording(void) const
|
bool cSatipDevice::AvoidRecording(void) const
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return SatipConfig.IsOperatingModeLow();
|
return SatipConfig.IsOperatingModeLow();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cSatipDevice::SignalStrength(void) const
|
int cSatipDevice::SignalStrength(void) const
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return (pTunerM ? pTunerM->SignalStrength() : -1);
|
return (pTunerM ? pTunerM->SignalStrength() : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cSatipDevice::SignalQuality(void) const
|
int cSatipDevice::SignalQuality(void) const
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return (pTunerM ? pTunerM->SignalQuality() : -1);
|
return (pTunerM ? pTunerM->SignalQuality() : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipDevice::ProvidesSource(int sourceP) const
|
bool cSatipDevice::ProvidesSource(int sourceP) const
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
cSource *s = Sources.Get(sourceP);
|
||||||
return (!SatipConfig.IsOperatingModeOff() && !!cSatipDiscover::GetInstance()->GetServer(sourceP));
|
debug9("%s (%c) desc='%s' [device %u]", __PRETTY_FUNCTION__, cSource::ToChar(sourceP), s ? s->Description() : "", deviceIndexM);
|
||||||
|
// source descriptions starting with '0' are disabled
|
||||||
|
if (s && s->Description() && (*(s->Description()) == '0'))
|
||||||
|
return false;
|
||||||
|
if (!SatipConfig.IsOperatingModeOff() && !!cSatipDiscover::GetInstance()->GetServer(sourceP)) {
|
||||||
|
int numDisabledSourcesM = SatipConfig.GetDisabledSourcesCount();
|
||||||
|
for (int i = 0; i < numDisabledSourcesM; ++i) {
|
||||||
|
if (sourceP == SatipConfig.GetDisabledSources(i))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipDevice::ProvidesTransponder(const cChannel *channelP) const
|
bool cSatipDevice::ProvidesTransponder(const cChannel *channelP) const
|
||||||
{
|
{
|
||||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug9("%s (%d) transponder=%d source=%c [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, channelP ? channelP->Transponder() : -1, channelP ? cSource::ToChar(channelP->Source()) : '?', deviceIndexM);
|
||||||
return (ProvidesSource(channelP->Source()));
|
if (!ProvidesSource(channelP->Source()))
|
||||||
|
return false;
|
||||||
|
return DeviceHooksProvidesTransponder(channelP);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool *needsDetachReceiversP) const
|
bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool *needsDetachReceiversP) const
|
||||||
@@ -200,7 +247,7 @@ bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool
|
|||||||
bool hasPriority = (priorityP == IDLEPRIORITY) || (priorityP > this->Priority());
|
bool hasPriority = (priorityP == IDLEPRIORITY) || (priorityP > this->Priority());
|
||||||
bool needsDetachReceivers = false;
|
bool needsDetachReceivers = false;
|
||||||
|
|
||||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug9("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, priorityP, !!needsDetachReceiversP, deviceIndexM);
|
||||||
|
|
||||||
if (channelP && ProvidesTransponder(channelP)) {
|
if (channelP && ProvidesTransponder(channelP)) {
|
||||||
result = hasPriority;
|
result = hasPriority;
|
||||||
@@ -272,31 +319,37 @@ bool cSatipDevice::MaySwitchTransponder(const cChannel *channelP) const
|
|||||||
|
|
||||||
bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
|
bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
|
||||||
{
|
{
|
||||||
|
debug9("%s (%d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, liveViewP, deviceIndexM);
|
||||||
if (channelP) {
|
if (channelP) {
|
||||||
cDvbTransponderParameters dtp(channelP->Parameters());
|
cDvbTransponderParameters dtp(channelP->Parameters());
|
||||||
cString params = GetTransponderUrlParameters(channelP);
|
cString params = GetTransponderUrlParameters(channelP);
|
||||||
if (isempty(params)) {
|
if (isempty(params)) {
|
||||||
error("Unrecognized SAT>IP channel parameters: %s", channelP->Parameters());
|
error("Unrecognized channel parameters: %s [device %u]", channelP->Parameters(), deviceIndexM);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cString address;
|
cString address;
|
||||||
cSatipServer *server = cSatipDiscover::GetInstance()->GetServer(channelP->Source(), dtp.System());
|
cSatipServer *server = cSatipDiscover::GetInstance()->GetServer(channelP->Source(), channelP->Transponder(), dtp.System());
|
||||||
if (!server) {
|
if (!server) {
|
||||||
debug("cSatipDevice::%s(%u): no suitable server found", __FUNCTION__, deviceIndexM);
|
debug9("%s No suitable server found [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
cSatipDiscover::GetInstance()->SetTransponder(server, channelP->Transponder());
|
||||||
if (pTunerM && pTunerM->SetSource(server, *params, deviceIndexM)) {
|
if (pTunerM && pTunerM->SetSource(server, *params, deviceIndexM)) {
|
||||||
deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server));
|
|
||||||
channelM = *channelP;
|
channelM = *channelP;
|
||||||
|
deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (pTunerM) {
|
||||||
|
pTunerM->SetSource(NULL, NULL, deviceIndexM);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
|
bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u): pid=%d type=%d on=%d", __FUNCTION__, deviceIndexM, handleP->pid, typeP, onP);
|
debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP->pid, typeP, onP, deviceIndexM);
|
||||||
if (pTunerM && handleP && handleP->pid >= 0) {
|
if (pTunerM && handleP && handleP->pid >= 0) {
|
||||||
if (onP)
|
if (onP)
|
||||||
return pTunerM->SetPid(handleP->pid, typeP, true);
|
return pTunerM->SetPid(handleP->pid, typeP, true);
|
||||||
@@ -308,7 +361,7 @@ bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
|
|||||||
|
|
||||||
int cSatipDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP)
|
int cSatipDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u): pid=%d tid=%d mask=%d", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
|
debug12("%s (%d, %02X, %02X) [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, deviceIndexM);
|
||||||
if (pSectionFilterHandlerM) {
|
if (pSectionFilterHandlerM) {
|
||||||
int handle = pSectionFilterHandlerM->Open(pidP, tidP, maskP);
|
int handle = pSectionFilterHandlerM->Open(pidP, tidP, maskP);
|
||||||
if (pTunerM && (handle >= 0))
|
if (pTunerM && (handle >= 0))
|
||||||
@@ -320,17 +373,18 @@ int cSatipDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP)
|
|||||||
|
|
||||||
void cSatipDevice::CloseFilter(int handleP)
|
void cSatipDevice::CloseFilter(int handleP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u): handle=%d", __FUNCTION__, deviceIndexM, handleP);
|
|
||||||
if (pSectionFilterHandlerM) {
|
if (pSectionFilterHandlerM) {
|
||||||
|
int pid = pSectionFilterHandlerM->GetPid(handleP);
|
||||||
|
debug12("%s (%d) [device %u]", __PRETTY_FUNCTION__, pid, deviceIndexM);
|
||||||
if (pTunerM)
|
if (pTunerM)
|
||||||
pTunerM->SetPid(pSectionFilterHandlerM->GetPid(handleP), ptOther, false);
|
pTunerM->SetPid(pid, ptOther, false);
|
||||||
pSectionFilterHandlerM->Close(handleP);
|
pSectionFilterHandlerM->Close(handleP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipDevice::OpenDvr(void)
|
bool cSatipDevice::OpenDvr(void)
|
||||||
{
|
{
|
||||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug9("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
isPacketDeliveredM = false;
|
isPacketDeliveredM = false;
|
||||||
tsBufferM->Clear();
|
tsBufferM->Clear();
|
||||||
if (pTunerM)
|
if (pTunerM)
|
||||||
@@ -341,7 +395,7 @@ bool cSatipDevice::OpenDvr(void)
|
|||||||
|
|
||||||
void cSatipDevice::CloseDvr(void)
|
void cSatipDevice::CloseDvr(void)
|
||||||
{
|
{
|
||||||
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug9("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
if (pTunerM)
|
if (pTunerM)
|
||||||
pTunerM->Close();
|
pTunerM->Close();
|
||||||
isOpenDvrM = false;
|
isOpenDvrM = false;
|
||||||
@@ -349,21 +403,21 @@ void cSatipDevice::CloseDvr(void)
|
|||||||
|
|
||||||
bool cSatipDevice::HasLock(int timeoutMsP) const
|
bool cSatipDevice::HasLock(int timeoutMsP) const
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u): timeoutMs=%d", __FUNCTION__, deviceIndexM, timeoutMsP);
|
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, timeoutMsP, deviceIndexM);
|
||||||
return (pTunerM && pTunerM->HasLock());
|
return (pTunerM && pTunerM->HasLock());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipDevice::HasInternalCam(void)
|
bool cSatipDevice::HasInternalCam(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
return false;
|
return SatipConfig.GetCIExtension();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipDevice::WriteData(uchar *bufferP, int lengthP)
|
void cSatipDevice::WriteData(uchar *bufferP, int lengthP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
// Fill up TS buffer
|
// Fill up TS buffer
|
||||||
if (tsBufferM) {
|
if (isOpenDvrM && tsBufferM) {
|
||||||
int len = tsBufferM->Put(bufferP, lengthP);
|
int len = tsBufferM->Put(bufferP, lengthP);
|
||||||
if (len != lengthP)
|
if (len != lengthP)
|
||||||
tsBufferM->ReportOverflow(lengthP - len);
|
tsBufferM->ReportOverflow(lengthP - len);
|
||||||
@@ -373,23 +427,44 @@ void cSatipDevice::WriteData(uchar *bufferP, int lengthP)
|
|||||||
pSectionFilterHandlerM->Write(bufferP, lengthP);
|
pSectionFilterHandlerM->Write(bufferP, lengthP);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cSatipDevice::CheckData(void)
|
|
||||||
{
|
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
|
||||||
if (tsBufferM)
|
|
||||||
return (unsigned int)tsBufferM->Free();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cSatipDevice::GetId(void)
|
int cSatipDevice::GetId(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
|
||||||
return deviceIndexM;
|
return deviceIndexM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cSatipDevice::GetPmtPid(void)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cSatipDevice::GetCISlot(void)
|
||||||
|
{
|
||||||
|
int slot = 0;
|
||||||
|
int ca = 0;
|
||||||
|
for (const int *id = channelM.Caids(); *id; ++id) {
|
||||||
|
if (checkCASystem(SatipConfig.GetCICAM(0), *id)) {
|
||||||
|
ca = *id;
|
||||||
|
slot = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (checkCASystem(SatipConfig.GetCICAM(1), *id)) {
|
||||||
|
ca = *id;
|
||||||
|
slot = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug11("%s slot=%d ca=%X name=%s [device %u]", __PRETTY_FUNCTION__, slot, ca, channelM.Name(), deviceIndexM);
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
uchar *cSatipDevice::GetData(int *availableP)
|
uchar *cSatipDevice::GetData(int *availableP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
if (isOpenDvrM && tsBufferM) {
|
if (isOpenDvrM && tsBufferM) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
if (isPacketDeliveredM)
|
if (isPacketDeliveredM)
|
||||||
@@ -420,7 +495,7 @@ uchar *cSatipDevice::GetData(int *availableP)
|
|||||||
|
|
||||||
void cSatipDevice::SkipData(int countP)
|
void cSatipDevice::SkipData(int countP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
tsBufferM->Del(countP);
|
tsBufferM->Del(countP);
|
||||||
isPacketDeliveredM = false;
|
isPacketDeliveredM = false;
|
||||||
// Update buffer statistics
|
// Update buffer statistics
|
||||||
@@ -429,7 +504,7 @@ void cSatipDevice::SkipData(int countP)
|
|||||||
|
|
||||||
bool cSatipDevice::GetTSPacket(uchar *&dataP)
|
bool cSatipDevice::GetTSPacket(uchar *&dataP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
if (tsBufferM) {
|
if (tsBufferM) {
|
||||||
#if defined(APIVERSNUM) && APIVERSNUM >= 20104
|
#if defined(APIVERSNUM) && APIVERSNUM >= 20104
|
||||||
if (cCamSlot *cs = CamSlot()) {
|
if (cCamSlot *cs = CamSlot()) {
|
||||||
@@ -447,8 +522,6 @@ bool cSatipDevice::GetTSPacket(uchar *&dataP)
|
|||||||
dataP = GetData();
|
dataP = GetData();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Reduce cpu load by preventing busylooping
|
|
||||||
cCondWait::SleepMs(10);
|
|
||||||
dataP = NULL;
|
dataP = NULL;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
4
device.h
4
device.h
@@ -23,6 +23,7 @@ public:
|
|||||||
static void Shutdown(void);
|
static void Shutdown(void);
|
||||||
static unsigned int Count(void);
|
static unsigned int Count(void);
|
||||||
static cSatipDevice *GetSatipDevice(int CardIndex);
|
static cSatipDevice *GetSatipDevice(int CardIndex);
|
||||||
|
static cString GetSatipStatus(void);
|
||||||
|
|
||||||
// private parts
|
// private parts
|
||||||
private:
|
private:
|
||||||
@@ -106,8 +107,9 @@ public:
|
|||||||
// for internal device interface
|
// for internal device interface
|
||||||
public:
|
public:
|
||||||
virtual void WriteData(u_char *bufferP, int lengthP);
|
virtual void WriteData(u_char *bufferP, int lengthP);
|
||||||
virtual unsigned int CheckData(void);
|
|
||||||
virtual int GetId(void);
|
virtual int GetId(void);
|
||||||
|
virtual int GetPmtPid(void);
|
||||||
|
virtual int GetCISlot(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __SATIP_DEVICE_H
|
#endif // __SATIP_DEVICE_H
|
||||||
|
@@ -13,8 +13,9 @@ public:
|
|||||||
cSatipDeviceIf() {}
|
cSatipDeviceIf() {}
|
||||||
virtual ~cSatipDeviceIf() {}
|
virtual ~cSatipDeviceIf() {}
|
||||||
virtual void WriteData(u_char *bufferP, int lengthP) = 0;
|
virtual void WriteData(u_char *bufferP, int lengthP) = 0;
|
||||||
virtual unsigned int CheckData(void) = 0;
|
|
||||||
virtual int GetId(void) = 0;
|
virtual int GetId(void) = 0;
|
||||||
|
virtual int GetPmtPid(void) = 0;
|
||||||
|
virtual int GetCISlot(void) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cSatipDeviceIf(const cSatipDeviceIf&);
|
cSatipDeviceIf(const cSatipDeviceIf&);
|
||||||
|
312
discover.c
312
discover.c
@@ -13,18 +13,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
#include "discover.h"
|
#include "discover.h"
|
||||||
|
|
||||||
cSatipDiscover *cSatipDiscover::instanceS = NULL;
|
cSatipDiscover *cSatipDiscover::instanceS = NULL;
|
||||||
|
|
||||||
const char *cSatipDiscover::bcastAddressS = "239.255.255.250";
|
|
||||||
const char *cSatipDiscover::bcastMessageS = "M-SEARCH * HTTP/1.1\r\n" \
|
|
||||||
"HOST: 239.255.255.250:1900\r\n" \
|
|
||||||
"MAN: \"ssdp:discover\"\r\n" \
|
|
||||||
"ST: urn:ses-com:device:SatIPServer:1\r\n" \
|
|
||||||
"MX: 2\r\n\r\n";
|
|
||||||
|
|
||||||
cSatipDiscover *cSatipDiscover::GetInstance(void)
|
cSatipDiscover *cSatipDiscover::GetInstance(void)
|
||||||
{
|
{
|
||||||
if (!instanceS)
|
if (!instanceS)
|
||||||
@@ -32,17 +26,23 @@ cSatipDiscover *cSatipDiscover::GetInstance(void)
|
|||||||
return instanceS;
|
return instanceS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipDiscover::Initialize(void)
|
bool cSatipDiscover::Initialize(cSatipDiscoverServers *serversP)
|
||||||
{
|
{
|
||||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
if (instanceS)
|
if (instanceS) {
|
||||||
instanceS->Activate();
|
if (serversP) {
|
||||||
|
for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s))
|
||||||
|
instanceS->AddServer(s->IpAddress(), s->Model(), s->Description());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
instanceS->Activate();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipDiscover::Destroy(void)
|
void cSatipDiscover::Destroy(void)
|
||||||
{
|
{
|
||||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
if (instanceS)
|
if (instanceS)
|
||||||
instanceS->Deactivate();
|
instanceS->Deactivate();
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, vo
|
|||||||
{
|
{
|
||||||
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
|
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
|
||||||
size_t len = sizeP * nmembP;
|
size_t len = sizeP * nmembP;
|
||||||
//debug("cSatipDiscover::%s(%zu)", __FUNCTION__, len);
|
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
|
||||||
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
CURLcode res = CURLE_OK;
|
CURLcode res = CURLE_OK;
|
||||||
@@ -82,37 +82,64 @@ size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, vo
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr);
|
SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr);
|
||||||
obj->AddServer(addr, desc, model);
|
obj->AddServer(addr, model, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP)
|
||||||
|
{
|
||||||
|
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(userPtrP);
|
||||||
|
|
||||||
|
if (obj) {
|
||||||
|
switch (typeP) {
|
||||||
|
case CURLINFO_TEXT:
|
||||||
|
debug2("%s HTTP INFO %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
case CURLINFO_HEADER_IN:
|
||||||
|
debug2("%s HTTP HEAD <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
case CURLINFO_HEADER_OUT:
|
||||||
|
debug2("%s HTTP HEAD >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
case CURLINFO_DATA_IN:
|
||||||
|
debug2("%s HTTP DATA <<< %.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
case CURLINFO_DATA_OUT:
|
||||||
|
debug2("%s HTTP DATA >>>\n%.*s", __PRETTY_FUNCTION__, (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
cSatipDiscover::cSatipDiscover()
|
cSatipDiscover::cSatipDiscover()
|
||||||
: cThread("SAT>IP discover"),
|
: cThread("SATIP discover"),
|
||||||
mutexM(),
|
mutexM(),
|
||||||
|
msearchM(*this),
|
||||||
|
probeUrlListM(),
|
||||||
handleM(curl_easy_init()),
|
handleM(curl_easy_init()),
|
||||||
socketM(new cSatipSocket()),
|
|
||||||
sleepM(),
|
sleepM(),
|
||||||
probeIntervalM(0),
|
probeIntervalM(0),
|
||||||
serversM(new cSatipServers())
|
serversM()
|
||||||
{
|
{
|
||||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Start the thread
|
|
||||||
Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipDiscover::~cSatipDiscover()
|
cSatipDiscover::~cSatipDiscover()
|
||||||
{
|
{
|
||||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
Deactivate();
|
Deactivate();
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
// Free allocated memory
|
// Free allocated memory
|
||||||
DELETENULL(socketM);
|
|
||||||
DELETENULL(serversM);
|
|
||||||
if (handleM)
|
if (handleM)
|
||||||
curl_easy_cleanup(handleM);
|
curl_easy_cleanup(handleM);
|
||||||
handleM = NULL;
|
handleM = NULL;
|
||||||
|
probeUrlListM.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipDiscover::Activate(void)
|
void cSatipDiscover::Activate(void)
|
||||||
@@ -123,7 +150,7 @@ void cSatipDiscover::Activate(void)
|
|||||||
|
|
||||||
void cSatipDiscover::Deactivate(void)
|
void cSatipDiscover::Deactivate(void)
|
||||||
{
|
{
|
||||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
sleepM.Signal();
|
sleepM.Signal();
|
||||||
if (Running())
|
if (Running())
|
||||||
@@ -132,131 +159,103 @@ void cSatipDiscover::Deactivate(void)
|
|||||||
|
|
||||||
void cSatipDiscover::Action(void)
|
void cSatipDiscover::Action(void)
|
||||||
{
|
{
|
||||||
debug("cSatipDiscover::%s(): entering", __FUNCTION__);
|
debug1("%s Entering", __PRETTY_FUNCTION__);
|
||||||
|
probeIntervalM.Set(eProbeIntervalMs);
|
||||||
|
msearchM.Probe();
|
||||||
// Do the thread loop
|
// Do the thread loop
|
||||||
while (Running()) {
|
while (Running()) {
|
||||||
|
cStringList tmp;
|
||||||
|
|
||||||
if (probeIntervalM.TimedOut()) {
|
if (probeIntervalM.TimedOut()) {
|
||||||
probeIntervalM.Set(eProbeIntervalMs);
|
probeIntervalM.Set(eProbeIntervalMs);
|
||||||
Probe();
|
msearchM.Probe();
|
||||||
Janitor();
|
mutexM.Lock();
|
||||||
|
serversM.Cleanup(eProbeIntervalMs * 2);
|
||||||
|
mutexM.Unlock();
|
||||||
|
}
|
||||||
|
mutexM.Lock();
|
||||||
|
if (probeUrlListM.Size()) {
|
||||||
|
for (int i = 0; i < probeUrlListM.Size(); ++i)
|
||||||
|
tmp.Insert(strdup(probeUrlListM.At(i)));
|
||||||
|
probeUrlListM.Clear();
|
||||||
|
}
|
||||||
|
mutexM.Unlock();
|
||||||
|
if (tmp.Size()) {
|
||||||
|
for (int i = 0; i < tmp.Size(); ++i)
|
||||||
|
Fetch(tmp.At(i));
|
||||||
|
tmp.Clear();
|
||||||
}
|
}
|
||||||
// to avoid busy loop and reduce cpu load
|
// to avoid busy loop and reduce cpu load
|
||||||
sleepM.Wait(10);
|
sleepM.Wait(eSleepTimeoutMs);
|
||||||
}
|
}
|
||||||
debug("cSatipDiscover::%s(): exiting", __FUNCTION__);
|
debug1("%s Exiting", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipDiscover::Janitor(void)
|
void cSatipDiscover::Fetch(const char *urlP)
|
||||||
{
|
{
|
||||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug1("%s (%s)", __PRETTY_FUNCTION__, urlP);
|
||||||
cMutexLock MutexLock(&mutexM);
|
if (handleM && !isempty(urlP)) {
|
||||||
if (serversM)
|
long rc = 0;
|
||||||
serversM->Cleanup(eProbeIntervalMs * 2);
|
CURLcode res = CURLE_OK;
|
||||||
}
|
|
||||||
|
|
||||||
void cSatipDiscover::Probe(void)
|
// Verbose output
|
||||||
{
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
|
||||||
debug("cSatipDiscover::%s()", __FUNCTION__);
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback);
|
||||||
if (socketM && socketM->Open(eDiscoveryPort)) {
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this);
|
||||||
cTimeMs timeout(eProbeTimeoutMs);
|
|
||||||
socketM->Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
|
// Set callback
|
||||||
while (Running() && !timeout.TimedOut()) {
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback);
|
||||||
Read();
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
|
||||||
// to avoid busy loop and reduce cpu load
|
|
||||||
sleepM.Wait(100);
|
// No progress meter and no signaling
|
||||||
}
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
|
||||||
socketM->Close();
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
|
||||||
|
|
||||||
|
// Set timeouts
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||||
|
|
||||||
|
// Set user-agent
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
|
||||||
|
|
||||||
|
// Set URL
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, urlP);
|
||||||
|
|
||||||
|
// Fetch the data
|
||||||
|
SATIP_CURL_EASY_PERFORM(handleM);
|
||||||
|
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
||||||
|
if (rc != 200)
|
||||||
|
error("Discovery detected invalid status code: %ld", rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipDiscover::Read(void)
|
void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char * descP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug1("%s (%s, %s, %s)", __PRETTY_FUNCTION__, addrP, modelP, descP);
|
||||||
if (socketM) {
|
cMutexLock MutexLock(&mutexM);
|
||||||
unsigned char *buf = MALLOC(unsigned char, eProbeBufferSize + 1);
|
if (SatipConfig.GetUseSingleModelServers()) {
|
||||||
if (buf) {
|
int n = 0;
|
||||||
memset(buf, 0, eProbeBufferSize + 1);
|
char *s, *p = strdup(modelP);
|
||||||
int len = socketM->Read(buf, eProbeBufferSize);
|
char *r = strtok_r(p, ",", &s);
|
||||||
if (len > 0) {
|
while (r) {
|
||||||
//debug("cSatipDiscover::%s(): len=%d", __FUNCTION__, len);
|
r = skipspace(r);
|
||||||
bool status = false, valid = false;
|
cString desc = cString::sprintf("%s #%d", !isempty(descP) ? descP : "MyBrokenHardware", n++);
|
||||||
char *s, *p = reinterpret_cast<char *>(buf), *location = NULL;
|
cSatipServer *tmp = new cSatipServer(addrP, r, desc);
|
||||||
char *r = strtok_r(p, "\r\n", &s);
|
if (!serversM.Update(tmp)) {
|
||||||
while (r) {
|
info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
|
||||||
//debug("cSatipDiscover::%s(): %s", __FUNCTION__, r);
|
serversM.Add(tmp);
|
||||||
// Check the status code
|
|
||||||
// HTTP/1.1 200 OK
|
|
||||||
if (!status && startswith(r, "HTTP/1.1 200 OK")) {
|
|
||||||
status = true;
|
|
||||||
}
|
|
||||||
if (status) {
|
|
||||||
// Check the location data
|
|
||||||
// LOCATION: http://192.168.0.115:8888/octonet.xml
|
|
||||||
if (startswith(r, "LOCATION:")) {
|
|
||||||
location = compactspace(r + 9);
|
|
||||||
debug("cSatipDiscover::%s(): location='%s'", __FUNCTION__, location);
|
|
||||||
}
|
|
||||||
// Check the source type
|
|
||||||
// ST: urn:ses-com:device:SatIPServer:1
|
|
||||||
else if (startswith(r, "ST:")) {
|
|
||||||
char *st = compactspace(r + 3);
|
|
||||||
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
|
|
||||||
valid = true;
|
|
||||||
debug("cSatipDiscover::%s(): st='%s'", __FUNCTION__, st);
|
|
||||||
}
|
|
||||||
// Check whether all the required data is found
|
|
||||||
if (valid && !isempty(location))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
r = strtok_r(NULL, "\r\n", &s);
|
|
||||||
}
|
|
||||||
if (handleM && valid && !isempty(location)) {
|
|
||||||
long rc = 0;
|
|
||||||
CURLcode res = CURLE_OK;
|
|
||||||
#ifdef DEBUG
|
|
||||||
// Verbose output
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
|
|
||||||
#endif
|
|
||||||
// Set callback
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
|
|
||||||
|
|
||||||
// No progress meter and no signaling
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
|
|
||||||
|
|
||||||
// Set timeouts
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
|
|
||||||
|
|
||||||
// Set user-agent
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
|
|
||||||
|
|
||||||
// Set URL
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, location);
|
|
||||||
|
|
||||||
// Fetch the data
|
|
||||||
SATIP_CURL_EASY_PERFORM(handleM);
|
|
||||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
|
||||||
if (rc != 200)
|
|
||||||
error("Discovery detected invalid status code: %ld", rc);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
DELETENULL(tmp);
|
||||||
|
r = strtok_r(NULL, ",", &s);
|
||||||
}
|
}
|
||||||
free(buf);
|
FREE_POINTER(p);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
cSatipServer *tmp = new cSatipServer(addrP, modelP, descP);
|
||||||
void cSatipDiscover::AddServer(const char *addrP, const char *descP, const char * modelP)
|
if (!serversM.Update(tmp)) {
|
||||||
{
|
info("Adding server '%s|%s|%s'", tmp->Address(), tmp->Model(), tmp->Description());
|
||||||
debug("cSatipDiscover::%s(%s, %s, %s)", __FUNCTION__, addrP, descP, modelP);
|
serversM.Add(tmp);
|
||||||
cMutexLock MutexLock(&mutexM);
|
|
||||||
if (serversM) {
|
|
||||||
cSatipServer *tmp = new cSatipServer(addrP, descP, modelP);
|
|
||||||
// Validate against existing servers
|
|
||||||
if (!serversM->Update(tmp)) {
|
|
||||||
info("Adding device %s (%s %s)", tmp->Description(), tmp->Address(), tmp->Model());
|
|
||||||
serversM->Add(tmp);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DELETENULL(tmp);
|
DELETENULL(tmp);
|
||||||
@@ -265,57 +264,72 @@ void cSatipDiscover::AddServer(const char *addrP, const char *descP, const char
|
|||||||
|
|
||||||
int cSatipDiscover::GetServerCount(void)
|
int cSatipDiscover::GetServerCount(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
return serversM ? serversM->Count() : -1;
|
return serversM.Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipServer *cSatipDiscover::GetServer(int sourceP, int systemP)
|
cSatipServer *cSatipDiscover::GetServer(int sourceP, int transponderP, int systemP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s(%d, %d)", __FUNCTION__, sourceP, systemP);
|
debug16("%s (%d, %d, %d)", __PRETTY_FUNCTION__, sourceP, transponderP, systemP);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
return serversM ? serversM->Find(sourceP, systemP) : NULL;
|
return serversM.Find(sourceP, transponderP, systemP);
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipServer *cSatipDiscover::GetServer(cSatipServer *serverP)
|
cSatipServer *cSatipDiscover::GetServer(cSatipServer *serverP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
return serversM ? serversM->Find(serverP) : NULL;
|
return serversM.Find(serverP);
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipServers *cSatipDiscover::GetServers(void)
|
cSatipServers *cSatipDiscover::GetServers(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
return serversM;
|
return &serversM;
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipDiscover::GetServerString(cSatipServer *serverP)
|
cString cSatipDiscover::GetServerString(cSatipServer *serverP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s(%d)", __FUNCTION__, modelP);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
return serversM ? serversM->GetString(serverP) : "";
|
return serversM.GetString(serverP);
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipDiscover::GetServerList(void)
|
cString cSatipDiscover::GetServerList(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s(%d)", __FUNCTION__, modelP);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
return serversM ? serversM->List() : "";
|
return serversM.List();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipDiscover::SetTransponder(cSatipServer *serverP, int transponderP)
|
||||||
|
{
|
||||||
|
debug16("%s (, %d)", __PRETTY_FUNCTION__, transponderP);
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
serversM.SetTransponder(serverP, transponderP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipDiscover::UseServer(cSatipServer *serverP, bool onOffP)
|
void cSatipDiscover::UseServer(cSatipServer *serverP, bool onOffP)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s(%d)", __FUNCTION__, modelP);
|
debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
if (serversM)
|
serversM.Use(serverP, onOffP);
|
||||||
serversM->Use(serverP, onOffP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cSatipDiscover::NumProvidedSystems(void)
|
int cSatipDiscover::NumProvidedSystems(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipDiscover::%s(%d)", __FUNCTION__, modelP);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
return serversM ? serversM->NumProvidedSystems() : 0;
|
return serversM.NumProvidedSystems();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipDiscover::SetUrl(const char *urlP)
|
||||||
|
{
|
||||||
|
debug16("%s (%s)", __PRETTY_FUNCTION__, urlP);
|
||||||
|
mutexM.Lock();
|
||||||
|
probeUrlListM.Insert(strdup(urlP));
|
||||||
|
mutexM.Unlock();
|
||||||
|
sleepM.Signal();
|
||||||
}
|
}
|
||||||
|
48
discover.h
48
discover.h
@@ -13,34 +13,51 @@
|
|||||||
#include <vdr/thread.h>
|
#include <vdr/thread.h>
|
||||||
#include <vdr/tools.h>
|
#include <vdr/tools.h>
|
||||||
|
|
||||||
|
#include "discoverif.h"
|
||||||
|
#include "msearch.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
class cSatipDiscover : public cThread {
|
class cSatipDiscoverServer : public cListObject {
|
||||||
|
private:
|
||||||
|
cString ipAddressM;
|
||||||
|
cString descriptionM;
|
||||||
|
cString modelM;
|
||||||
|
public:
|
||||||
|
cSatipDiscoverServer(const char *ipAddressP, const char *modelP, const char *descriptionP)
|
||||||
|
{
|
||||||
|
ipAddressM = ipAddressP; modelM = modelP; descriptionM = descriptionP;
|
||||||
|
}
|
||||||
|
const char *IpAddress(void) { return *ipAddressM; }
|
||||||
|
const char *Model(void) { return *modelM; }
|
||||||
|
const char *Description(void) { return *descriptionM; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class cSatipDiscoverServers : public cList<cSatipDiscoverServer> {
|
||||||
|
};
|
||||||
|
|
||||||
|
class cSatipDiscover : public cThread, public cSatipDiscoverIf {
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
|
eSleepTimeoutMs = 500, // in milliseconds
|
||||||
eConnectTimeoutMs = 1500, // in milliseconds
|
eConnectTimeoutMs = 1500, // in milliseconds
|
||||||
eDiscoveryPort = 1900,
|
|
||||||
eProbeBufferSize = 1024, // in bytes
|
|
||||||
eProbeTimeoutMs = 2000, // in milliseconds
|
eProbeTimeoutMs = 2000, // in milliseconds
|
||||||
eProbeIntervalMs = 60000 // in milliseconds
|
eProbeIntervalMs = 60000 // in milliseconds
|
||||||
};
|
};
|
||||||
static cSatipDiscover *instanceS;
|
static cSatipDiscover *instanceS;
|
||||||
static const char *bcastAddressS;
|
|
||||||
static const char *bcastMessageS;
|
|
||||||
static size_t WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
static 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;
|
cMutex mutexM;
|
||||||
|
cSatipMsearch msearchM;
|
||||||
|
cStringList probeUrlListM;
|
||||||
CURL *handleM;
|
CURL *handleM;
|
||||||
cSatipSocket *socketM;
|
|
||||||
cCondWait sleepM;
|
cCondWait sleepM;
|
||||||
cTimeMs probeIntervalM;
|
cTimeMs probeIntervalM;
|
||||||
cSatipServers *serversM;
|
cSatipServers serversM;
|
||||||
void Activate(void);
|
void Activate(void);
|
||||||
void Deactivate(void);
|
void Deactivate(void);
|
||||||
void Janitor(void);
|
void AddServer(const char *addrP, const char *modelP, const char *descP);
|
||||||
void Probe(void);
|
void Fetch(const char *urlP);
|
||||||
void Read(void);
|
|
||||||
void AddServer(const char *addrP, const char *descP, const char *modelP);
|
|
||||||
// constructor
|
// constructor
|
||||||
cSatipDiscover();
|
cSatipDiscover();
|
||||||
// to prevent copy constructor and assignment
|
// to prevent copy constructor and assignment
|
||||||
@@ -52,18 +69,23 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static cSatipDiscover *GetInstance(void);
|
static cSatipDiscover *GetInstance(void);
|
||||||
static bool Initialize(void);
|
static bool Initialize(cSatipDiscoverServers *serversP);
|
||||||
static void Destroy(void);
|
static void Destroy(void);
|
||||||
virtual ~cSatipDiscover();
|
virtual ~cSatipDiscover();
|
||||||
void TriggerScan(void) { probeIntervalM.Set(0); }
|
void TriggerScan(void) { probeIntervalM.Set(0); }
|
||||||
int GetServerCount(void);
|
int GetServerCount(void);
|
||||||
cSatipServer *GetServer(int sourceP, int systemP = -1);
|
cSatipServer *GetServer(int sourceP, int transponderP = 0, int systemP = -1);
|
||||||
cSatipServer *GetServer(cSatipServer *serverP);
|
cSatipServer *GetServer(cSatipServer *serverP);
|
||||||
cSatipServers *GetServers(void);
|
cSatipServers *GetServers(void);
|
||||||
cString GetServerString(cSatipServer *serverP);
|
cString GetServerString(cSatipServer *serverP);
|
||||||
|
void SetTransponder(cSatipServer *serverP, int transponderP);
|
||||||
void UseServer(cSatipServer *serverP, bool onOffP);
|
void UseServer(cSatipServer *serverP, bool onOffP);
|
||||||
cString GetServerList(void);
|
cString GetServerList(void);
|
||||||
int NumProvidedSystems(void);
|
int NumProvidedSystems(void);
|
||||||
|
|
||||||
|
// for internal discover interface
|
||||||
|
public:
|
||||||
|
virtual void SetUrl(const char *urlP);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __SATIP_DISCOVER_H
|
#endif // __SATIP_DISCOVER_H
|
||||||
|
22
discoverif.h
Normal file
22
discoverif.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* discoverif.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_DISCOVERIF_H
|
||||||
|
#define __SATIP_DISCOVERIF_H
|
||||||
|
|
||||||
|
class cSatipDiscoverIf {
|
||||||
|
public:
|
||||||
|
cSatipDiscoverIf() {}
|
||||||
|
virtual ~cSatipDiscoverIf() {}
|
||||||
|
virtual void SetUrl(const char *urlP) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
cSatipDiscoverIf(const cSatipDiscoverIf&);
|
||||||
|
cSatipDiscoverIf& operator=(const cSatipDiscoverIf&);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SATIP_DISCOVERIF_H
|
49
log.h
Normal file
49
log.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* log.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_LOG_H
|
||||||
|
#define __SATIP_LOG_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#define error(x...) esyslog("SATIP-ERROR: " x)
|
||||||
|
#define info(x...) isyslog("SATIP: " x)
|
||||||
|
// 0x0001: Generic call stack
|
||||||
|
#define debug1(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug1) ? dsyslog("SATIP1: " x) : void() )
|
||||||
|
// 0x0002: CURL data flow
|
||||||
|
#define debug2(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug2) ? dsyslog("SATIP2: " x) : void() )
|
||||||
|
// 0x0004: Data parsing
|
||||||
|
#define debug3(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug3) ? dsyslog("SATIP3: " x) : void() )
|
||||||
|
// 0x0008: Tuner state machine
|
||||||
|
#define debug4(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug4) ? dsyslog("SATIP4: " x) : void() )
|
||||||
|
// 0x0010: RTSP responses
|
||||||
|
#define debug5(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug5) ? dsyslog("SATIP5: " x) : void() )
|
||||||
|
// 0x0020: RTP throughput performance
|
||||||
|
#define debug6(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug6) ? dsyslog("SATIP6: " x) : void() )
|
||||||
|
// 0x0040: RTP packet internals
|
||||||
|
#define debug7(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug7) ? dsyslog("SATIP7: " x) : void() )
|
||||||
|
// 0x0080: Section filtering
|
||||||
|
#define debug8(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug8) ? dsyslog("SATIP8: " x) : void() )
|
||||||
|
// 0x0100: Channel switching
|
||||||
|
#define debug9(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug9) ? dsyslog("SATIP9: " x) : void() )
|
||||||
|
// 0x0200: RTCP packets
|
||||||
|
#define debug10(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug10) ? dsyslog("SATIP10: " x) : void() )
|
||||||
|
// 0x0400: CI
|
||||||
|
#define debug11(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug11) ? dsyslog("SATIP11: " x) : void() )
|
||||||
|
// 0x0800: Discovery
|
||||||
|
#define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() )
|
||||||
|
// 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() )
|
||||||
|
// 0x4000: TBD
|
||||||
|
#define debug15(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug15) ? dsyslog("SATIP15: " x) : void() )
|
||||||
|
// 0x8000; Extra call stack
|
||||||
|
#define debug16(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug16) ? dsyslog("SATIP16: " x) : void() )
|
||||||
|
|
||||||
|
#endif // __SATIP_LOG_H
|
||||||
|
|
104
msearch.c
Normal file
104
msearch.c
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* msearch.c: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "discover.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "poller.h"
|
||||||
|
#include "msearch.h"
|
||||||
|
|
||||||
|
const char *cSatipMsearch::bcastAddressS = "239.255.255.250";
|
||||||
|
const char *cSatipMsearch::bcastMessageS = "M-SEARCH * HTTP/1.1\r\n" \
|
||||||
|
"HOST: 239.255.255.250:1900\r\n" \
|
||||||
|
"MAN: \"ssdp:discover\"\r\n" \
|
||||||
|
"ST: urn:ses-com:device:SatIPServer:1\r\n" \
|
||||||
|
"MX: 2\r\n\r\n";
|
||||||
|
|
||||||
|
cSatipMsearch::cSatipMsearch(cSatipDiscoverIf &discoverP)
|
||||||
|
: discoverM(discoverP),
|
||||||
|
bufferLenM(eProbeBufferSize),
|
||||||
|
bufferM(MALLOC(unsigned char, bufferLenM)),
|
||||||
|
registeredM(false)
|
||||||
|
{
|
||||||
|
if (bufferM)
|
||||||
|
memset(bufferM, 0, bufferLenM);
|
||||||
|
else
|
||||||
|
error("Cannot create Msearch buffer!");
|
||||||
|
if (!Open(eDiscoveryPort))
|
||||||
|
error("Cannot open Msearch port!");
|
||||||
|
}
|
||||||
|
|
||||||
|
cSatipMsearch::~cSatipMsearch()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipMsearch::Probe(void)
|
||||||
|
{
|
||||||
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
|
if (!registeredM) {
|
||||||
|
cSatipPoller::GetInstance()->Register(*this);
|
||||||
|
registeredM = true;
|
||||||
|
}
|
||||||
|
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
|
||||||
|
}
|
||||||
|
|
||||||
|
int cSatipMsearch::GetFd(void)
|
||||||
|
{
|
||||||
|
return Fd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipMsearch::Process(void)
|
||||||
|
{
|
||||||
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
|
if (bufferM) {
|
||||||
|
int length;
|
||||||
|
while ((length = Read(bufferM, bufferLenM)) > 0) {
|
||||||
|
bufferM[min(length, int(bufferLenM - 1))] = 0;
|
||||||
|
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) {
|
||||||
|
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"))
|
||||||
|
status = true;
|
||||||
|
if (status) {
|
||||||
|
// Check the location data
|
||||||
|
// LOCATION: http://192.168.0.115:8888/octonet.xml
|
||||||
|
if (startswith(r, "LOCATION:")) {
|
||||||
|
location = compactspace(r + 9);
|
||||||
|
debug1("%s location='%s'", __PRETTY_FUNCTION__, location);
|
||||||
|
}
|
||||||
|
// Check the source type
|
||||||
|
// ST: urn:ses-com:device:SatIPServer:1
|
||||||
|
else if (startswith(r, "ST:")) {
|
||||||
|
char *st = compactspace(r + 3);
|
||||||
|
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
|
||||||
|
valid = true;
|
||||||
|
debug1("%s st='%s'", __PRETTY_FUNCTION__, st);
|
||||||
|
}
|
||||||
|
// Check whether all the required data is found
|
||||||
|
if (valid && !isempty(location)) {
|
||||||
|
discoverM.SetUrl(location);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r = strtok_r(NULL, "\r\n", &s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
error("Error %d reading in %s", errno, *ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cString cSatipMsearch::ToString(void) const
|
||||||
|
{
|
||||||
|
return "MSearch";
|
||||||
|
}
|
40
msearch.h
Normal file
40
msearch.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* msearch.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_MSEARCH_H_
|
||||||
|
#define __SATIP_MSEARCH_H_
|
||||||
|
|
||||||
|
#include "discoverif.h"
|
||||||
|
#include "socket.h"
|
||||||
|
#include "pollerif.h"
|
||||||
|
|
||||||
|
class cSatipMsearch : public cSatipSocket, public cSatipPollerIf {
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
eProbeBufferSize = 1024, // in bytes
|
||||||
|
eDiscoveryPort = 1900,
|
||||||
|
};
|
||||||
|
static const char *bcastAddressS;
|
||||||
|
static const char *bcastMessageS;
|
||||||
|
cSatipDiscoverIf &discoverM;
|
||||||
|
unsigned int bufferLenM;
|
||||||
|
unsigned char *bufferM;
|
||||||
|
bool registeredM;
|
||||||
|
|
||||||
|
public:
|
||||||
|
cSatipMsearch(cSatipDiscoverIf &discoverP);
|
||||||
|
virtual ~cSatipMsearch();
|
||||||
|
void Probe(void);
|
||||||
|
|
||||||
|
// for internal poller interface
|
||||||
|
public:
|
||||||
|
virtual int GetFd(void);
|
||||||
|
virtual void Process(void);
|
||||||
|
virtual cString ToString(void) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __SATIP_MSEARCH_H_ */
|
57
param.c
57
param.c
@@ -24,24 +24,24 @@ static const tSatipParameterMap SatipBandwidthValues[] = {
|
|||||||
{ 8000000, "&bw=8" },
|
{ 8000000, "&bw=8" },
|
||||||
{ 10000000, "&bw=10" },
|
{ 10000000, "&bw=10" },
|
||||||
{ 1712000, "&bw=1.712" },
|
{ 1712000, "&bw=1.712" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipPilotValues[] = {
|
static const tSatipParameterMap SatipPilotValues[] = {
|
||||||
{ PILOT_OFF, "&plts=off" },
|
{ PILOT_OFF, "&plts=off" },
|
||||||
{ PILOT_ON, "&plts=on" },
|
{ PILOT_ON, "&plts=on" },
|
||||||
{ PILOT_AUTO, "" },
|
{ PILOT_AUTO, "" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipSisoMisoValues[] = {
|
static const tSatipParameterMap SatipSisoMisoValues[] = {
|
||||||
{ 0, "&sm=0" },
|
{ 0, "&sm=0" },
|
||||||
{ 1, "&sm=1" },
|
{ 1, "&sm=1" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipCodeRateValues[] = {
|
static const tSatipParameterMap SatipCodeRateValues[] = {
|
||||||
{ FEC_NONE, "" },
|
{ FEC_NONE, "" },
|
||||||
{ FEC_1_2, "&fec=12" },
|
{ FEC_1_2, "&fec=12" },
|
||||||
{ FEC_2_3, "&fec=23" },
|
{ FEC_2_3, "&fec=23" },
|
||||||
{ FEC_3_4, "&fec=34" },
|
{ FEC_3_4, "&fec=34" },
|
||||||
@@ -52,8 +52,8 @@ static const tSatipParameterMap SatipCodeRateValues[] = {
|
|||||||
{ FEC_7_8, "&fec=78" },
|
{ FEC_7_8, "&fec=78" },
|
||||||
{ FEC_8_9, "&fec=89" },
|
{ FEC_8_9, "&fec=89" },
|
||||||
{ FEC_9_10, "&fec=910" },
|
{ FEC_9_10, "&fec=910" },
|
||||||
{ FEC_AUTO, "" },
|
{ FEC_AUTO, "" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipModulationValues[] = {
|
static const tSatipParameterMap SatipModulationValues[] = {
|
||||||
@@ -63,26 +63,26 @@ static const tSatipParameterMap SatipModulationValues[] = {
|
|||||||
{ QAM_64, "&mtype=64qam" },
|
{ QAM_64, "&mtype=64qam" },
|
||||||
{ QAM_128, "&mtype=128qam" },
|
{ QAM_128, "&mtype=128qam" },
|
||||||
{ QAM_256, "&mtype=256qam" },
|
{ QAM_256, "&mtype=256qam" },
|
||||||
{ QAM_AUTO, "" },
|
{ QAM_AUTO, "" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipSystemValuesSat[] = {
|
static const tSatipParameterMap SatipSystemValuesSat[] = {
|
||||||
{ 0, "&msys=dvbs" },
|
{ 0, "&msys=dvbs" },
|
||||||
{ 1, "&msys=dvbs2" },
|
{ 1, "&msys=dvbs2" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipSystemValuesTerrestrial[] = {
|
static const tSatipParameterMap SatipSystemValuesTerrestrial[] = {
|
||||||
{ 0, "&msys=dvbt" },
|
{ 0, "&msys=dvbt" },
|
||||||
{ 1, "&msys=dvbt2" },
|
{ 1, "&msys=dvbt2" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipSystemValuesCable[] = {
|
static const tSatipParameterMap SatipSystemValuesCable[] = {
|
||||||
{ 0, "&msys=dvbc" },
|
{ 0, "&msys=dvbc" },
|
||||||
{ 1, "&msys=dvbc2" },
|
{ 1, "&msys=dvbc2" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipTransmissionValues[] = {
|
static const tSatipParameterMap SatipTransmissionValues[] = {
|
||||||
@@ -92,8 +92,8 @@ static const tSatipParameterMap SatipTransmissionValues[] = {
|
|||||||
{ TRANSMISSION_MODE_8K, "&tmode=8k" },
|
{ TRANSMISSION_MODE_8K, "&tmode=8k" },
|
||||||
{ TRANSMISSION_MODE_16K, "&tmode=16k" },
|
{ TRANSMISSION_MODE_16K, "&tmode=16k" },
|
||||||
{ TRANSMISSION_MODE_32K, "&tmode=32k" },
|
{ TRANSMISSION_MODE_32K, "&tmode=32k" },
|
||||||
{ TRANSMISSION_MODE_AUTO, "" },
|
{ TRANSMISSION_MODE_AUTO, "" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipGuardValues[] = {
|
static const tSatipParameterMap SatipGuardValues[] = {
|
||||||
@@ -104,16 +104,23 @@ static const tSatipParameterMap SatipGuardValues[] = {
|
|||||||
{ GUARD_INTERVAL_1_128, "&gi=1128" },
|
{ GUARD_INTERVAL_1_128, "&gi=1128" },
|
||||||
{ GUARD_INTERVAL_19_128, "&gi=19128" },
|
{ GUARD_INTERVAL_19_128, "&gi=19128" },
|
||||||
{ GUARD_INTERVAL_19_256, "&gi=19256" },
|
{ GUARD_INTERVAL_19_256, "&gi=19256" },
|
||||||
{ GUARD_INTERVAL_AUTO, "" },
|
{ GUARD_INTERVAL_AUTO, "" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const tSatipParameterMap SatipRollOffValues[] = {
|
static const tSatipParameterMap SatipRollOffValues[] = {
|
||||||
{ ROLLOFF_AUTO, "" },
|
{ ROLLOFF_AUTO, "" },
|
||||||
{ ROLLOFF_20, "&ro=0.20" },
|
{ ROLLOFF_20, "&ro=0.20" },
|
||||||
{ ROLLOFF_25, "&ro=0.25" },
|
{ ROLLOFF_25, "&ro=0.25" },
|
||||||
{ ROLLOFF_35, "&ro=0.35" },
|
{ ROLLOFF_35, "&ro=0.35" },
|
||||||
{ -1, NULL }
|
{ -1, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const tSatipParameterMap SatipInversionValues[] = {
|
||||||
|
{ INVERSION_AUTO, "" },
|
||||||
|
{ INVERSION_OFF, "&specinv=0" },
|
||||||
|
{ INVERSION_ON, "&specinv=1" },
|
||||||
|
{ -1, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int SatipUserIndex(int valueP, const tSatipParameterMap *mapP)
|
static int SatipUserIndex(int valueP, const tSatipParameterMap *mapP)
|
||||||
@@ -138,6 +145,8 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
|
|||||||
if (channelP) {
|
if (channelP) {
|
||||||
char buffer[255];
|
char buffer[255];
|
||||||
cDvbTransponderParameters dtp(channelP->Parameters());
|
cDvbTransponderParameters dtp(channelP->Parameters());
|
||||||
|
int DataSlice = 0;
|
||||||
|
int C2TuningFrequencyType = 0;
|
||||||
#if defined(APIVERSNUM) && APIVERSNUM < 20106
|
#if defined(APIVERSNUM) && APIVERSNUM < 20106
|
||||||
int Pilot = PILOT_AUTO;
|
int Pilot = PILOT_AUTO;
|
||||||
int T2SystemId = 0;
|
int T2SystemId = 0;
|
||||||
@@ -160,22 +169,30 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
|
|||||||
#define STBUFLEFT (sizeof(buffer) - (q - buffer))
|
#define STBUFLEFT (sizeof(buffer) - (q - buffer))
|
||||||
q += snprintf(q, STBUFLEFT, "freq=%s", *dtoa(freq, "%lg"));
|
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, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1);
|
||||||
ST("CS *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
|
ST(" S *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
|
||||||
|
ST("C 1") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
|
||||||
ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization()));
|
ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization()));
|
||||||
ST("C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId());
|
ST("C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId());
|
||||||
ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", T2SystemId);
|
ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", T2SystemId);
|
||||||
|
ST("C 2") q += snprintf(q, STBUFLEFT, "&c2tft=%d", C2TuningFrequencyType);
|
||||||
|
ST("C 2") q += snprintf(q, STBUFLEFT, "&ds=%d", DataSlice);
|
||||||
|
ST("C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues);
|
||||||
ST(" T2") q += PrintUrlString(q, STBUFLEFT, SisoMiso, SatipSisoMisoValues);
|
ST(" T2") q += PrintUrlString(q, STBUFLEFT, SisoMiso, SatipSisoMisoValues);
|
||||||
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues);
|
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(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(), SatipGuardValues);
|
||||||
ST("CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(), SatipCodeRateValues);
|
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, Pilot, SatipPilotValues);
|
||||||
ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
||||||
ST("C T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
||||||
|
ST("C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
|
||||||
ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues);
|
ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues);
|
||||||
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesSat);
|
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesSat);
|
||||||
ST("C *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesCable);
|
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.System(), SatipSystemValuesTerrestrial);
|
||||||
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues);
|
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues);
|
||||||
|
if ((channelP->Rid() % 100) > 0)
|
||||||
|
q += snprintf(q, STBUFLEFT, "&fe=%d", channelP->Rid() % 100);
|
||||||
#undef ST
|
#undef ST
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
80
po/ca_ES.po
80
po/ca_ES.po
@@ -1,14 +1,14 @@
|
|||||||
# VDR plugin language source file.
|
# VDR plugin language source file.
|
||||||
# Copyright (C) 2007-2014 Rolf Ahrenberg
|
# Copyright (C) 2007-2015 Rolf Ahrenberg
|
||||||
# This file is distributed under the same license as the satip package.
|
# This file is distributed under the same license as the satip package.
|
||||||
# Gabriel Bonich, 2014
|
# Gabriel Bonich, 2014-2015
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: vdr-satip 0.3.3\n"
|
"Project-Id-Version: vdr-satip 1.0.2\n"
|
||||||
"Report-Msgid-Bugs-To: <see README>\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
|
"POT-Creation-Date: 2015-01-18 01:18+0200\n"
|
||||||
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
|
"PO-Revision-Date: 2015-01-18 01:18+0200\n"
|
||||||
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
|
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
|
||||||
"Language-Team: Catalan <vdr@linuxtv.org>\n"
|
"Language-Team: Catalan <vdr@linuxtv.org>\n"
|
||||||
"Language: ca\n"
|
"Language: ca\n"
|
||||||
@@ -31,11 +31,14 @@ msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
|||||||
msgid "TDT (0x70)"
|
msgid "TDT (0x70)"
|
||||||
msgstr "TDT (0x70)"
|
msgstr "TDT (0x70)"
|
||||||
|
|
||||||
|
msgid "SAT>IP information not available!"
|
||||||
|
msgstr "SAT>IP Informació no disponible!"
|
||||||
|
|
||||||
msgid "SAT>IP Devices"
|
msgid "SAT>IP Devices"
|
||||||
msgstr "SAT>IP Dispositius"
|
msgstr "SAT>IP Dispositius"
|
||||||
|
|
||||||
msgid "SAT>IP Device"
|
msgid "SAT>IP Server"
|
||||||
msgstr "SAT>IP Dispositiu"
|
msgstr "SAT>IP Server"
|
||||||
|
|
||||||
msgid "Address"
|
msgid "Address"
|
||||||
msgstr "Adressa"
|
msgstr "Adressa"
|
||||||
@@ -46,9 +49,15 @@ msgstr "Model"
|
|||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripció"
|
msgstr "Descripció"
|
||||||
|
|
||||||
|
msgid "CI extension"
|
||||||
|
msgstr "Extensió CI"
|
||||||
|
|
||||||
msgid "Creation date"
|
msgid "Creation date"
|
||||||
msgstr "Creació de data"
|
msgstr "Creació de data"
|
||||||
|
|
||||||
|
msgid "SAT>IP Device Status"
|
||||||
|
msgstr "SAT>IP Estat Dispositiu"
|
||||||
|
|
||||||
msgid "SAT>IP Information"
|
msgid "SAT>IP Information"
|
||||||
msgstr "SAT>IP Informació"
|
msgstr "SAT>IP Informació"
|
||||||
|
|
||||||
@@ -64,9 +73,6 @@ msgstr "Filtres"
|
|||||||
msgid "Bits/bytes"
|
msgid "Bits/bytes"
|
||||||
msgstr "Bits/Bytes"
|
msgstr "Bits/Bytes"
|
||||||
|
|
||||||
msgid "SAT>IP information not available!"
|
|
||||||
msgstr "SAT>IP Informació no disponible!"
|
|
||||||
|
|
||||||
msgid "off"
|
msgid "off"
|
||||||
msgstr "Apagat"
|
msgstr "Apagat"
|
||||||
|
|
||||||
@@ -79,6 +85,9 @@ msgstr "Normal"
|
|||||||
msgid "high"
|
msgid "high"
|
||||||
msgstr "Alt"
|
msgstr "Alt"
|
||||||
|
|
||||||
|
msgid "Button$Devices"
|
||||||
|
msgstr "Dispositius"
|
||||||
|
|
||||||
msgid "Operating mode"
|
msgid "Operating mode"
|
||||||
msgstr "Mode de operació"
|
msgstr "Mode de operació"
|
||||||
|
|
||||||
@@ -90,13 +99,37 @@ msgid ""
|
|||||||
"normal - devices are working within normal parameters\n"
|
"normal - devices are working within normal parameters\n"
|
||||||
"high - devices are working at the highest priority"
|
"high - devices are working at the highest priority"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Defineig la manera de operar els Disposituis SAT>IP:\n"
|
"Defineig la manera de operar els Dispositius SAT>IP:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Apagat - Dispositius desactivats\n"
|
"Apagat - Dispositius desactivats\n"
|
||||||
"Baix - Dispositius treballan a baixa prioritat\n"
|
"Baix - Dispositius treballan a baixa prioritat\n"
|
||||||
"Normal - Dispositius treballan en parametres normals\n"
|
"Normal - Dispositius treballan en parametres normals\n"
|
||||||
"Alta - Dispositius treballan a prioritat Alta"
|
"Alta - Dispositius treballan a prioritat Alta"
|
||||||
|
|
||||||
|
msgid "Enable CI extension"
|
||||||
|
msgstr "Habilita la extenció 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 ""
|
||||||
|
"Definir si s'utilitzarà una extensió de CI.\n"
|
||||||
|
"\n"
|
||||||
|
"Aquesta configuració permet utilitzar CI/CAM integrat que es troba en alguns equips SAT>IP (ex. 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 ""
|
||||||
|
"Definir quin tipus de CAM vols per a la ranura CI.\n"
|
||||||
|
"\n"
|
||||||
|
"L'opció '---' permet l'equip SAT>IP fer la selecció automàtica."
|
||||||
|
|
||||||
msgid "Enable EPG scanning"
|
msgid "Enable EPG scanning"
|
||||||
msgstr "Activa Escanneig EPG"
|
msgstr "Activa Escanneig EPG"
|
||||||
|
|
||||||
@@ -109,16 +142,31 @@ msgstr ""
|
|||||||
"\n"
|
"\n"
|
||||||
"Aquesta configuració desactiva la funcionalitat d'escaneig EIT automàtica per a tots els dispositius SAT>IP."
|
"Aquesta configuració desactiva la funcionalitat d'escaneig EIT automàtica per a tots els dispositius SAT>IP."
|
||||||
|
|
||||||
msgid "Disabled filters"
|
msgid "Disabled sources"
|
||||||
msgstr "Desactiva filtres"
|
msgstr "Desactiva entrades"
|
||||||
|
|
||||||
msgid "none"
|
msgid "none"
|
||||||
msgstr "no"
|
msgstr "no"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define number of sources to be disabled.\n"
|
||||||
|
"\n"
|
||||||
|
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
|
||||||
|
msgstr ""
|
||||||
|
"Definir nombre de entrades que es desactiven.\n"
|
||||||
|
"\n"
|
||||||
|
"SAT>IP els servidors podrien no tenir totes les posicions dels satèl·lits disponibles i aquestes entrades poden ser la llista negra."
|
||||||
|
|
||||||
|
msgid "Define a source to be blacklisted."
|
||||||
|
msgstr "Definir una entrada a la llista negra"
|
||||||
|
|
||||||
|
msgid "Disabled filters"
|
||||||
|
msgstr "Desactiva filtres"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Define number of section filters to be disabled.\n"
|
"Define number of section filters to be disabled.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Defineix el numero de filtres de secció que seran deshabilitats.\n"
|
"Defineix el numero de filtres de secció que seran deshabilitats.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -130,8 +178,8 @@ msgstr "Filtra"
|
|||||||
msgid "Define an ill-behaving filter to be blacklisted."
|
msgid "Define an ill-behaving filter to be blacklisted."
|
||||||
msgstr "Definir un filtre mal comportar a la llista negra."
|
msgstr "Definir un filtre mal comportar a la llista negra."
|
||||||
|
|
||||||
msgid "Active SAT>IP devices:"
|
msgid "Active SAT>IP servers:"
|
||||||
msgstr "Dispositius SAT>IP actius:"
|
msgstr "Activa SAT>IP servers:"
|
||||||
|
|
||||||
msgid "Help"
|
msgid "Help"
|
||||||
msgstr "Ajuda"
|
msgstr "Ajuda"
|
||||||
|
80
po/de_DE.po
80
po/de_DE.po
@@ -1,14 +1,14 @@
|
|||||||
# VDR plugin language source file.
|
# VDR plugin language source file.
|
||||||
# Copyright (C) 2007-2014 Rolf Ahrenberg
|
# Copyright (C) 2007-2015 Rolf Ahrenberg
|
||||||
# This file is distributed under the same license as the satip package.
|
# This file is distributed under the same license as the satip package.
|
||||||
# Frank Neumann, 2014
|
# Frank Neumann, 2014-2015
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: vdr-satip 0.3.3\n"
|
"Project-Id-Version: vdr-satip 1.0.2\n"
|
||||||
"Report-Msgid-Bugs-To: <see README>\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
|
"POT-Creation-Date: 2015-01-18 01:18+0200\n"
|
||||||
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
|
"PO-Revision-Date: 2015-01-18 01:18+0200\n"
|
||||||
"Last-Translator: Frank Neumann <fnu@yavdr.org>\n"
|
"Last-Translator: Frank Neumann <fnu@yavdr.org>\n"
|
||||||
"Language-Team: German <vdr@linuxtv.org>\n"
|
"Language-Team: German <vdr@linuxtv.org>\n"
|
||||||
"Language: de\n"
|
"Language: de\n"
|
||||||
@@ -31,11 +31,14 @@ msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
|||||||
msgid "TDT (0x70)"
|
msgid "TDT (0x70)"
|
||||||
msgstr "TDT (0x70)"
|
msgstr "TDT (0x70)"
|
||||||
|
|
||||||
|
msgid "SAT>IP information not available!"
|
||||||
|
msgstr "Keine SAT>IP Informationen verfügbar!"
|
||||||
|
|
||||||
msgid "SAT>IP Devices"
|
msgid "SAT>IP Devices"
|
||||||
msgstr "SAT>IP Geräte"
|
msgstr "SAT>IP Geräte"
|
||||||
|
|
||||||
msgid "SAT>IP Device"
|
msgid "SAT>IP Server"
|
||||||
msgstr "SAT>IP Gerät"
|
msgstr "SAT>IP Server"
|
||||||
|
|
||||||
msgid "Address"
|
msgid "Address"
|
||||||
msgstr "Adresse"
|
msgstr "Adresse"
|
||||||
@@ -46,9 +49,15 @@ msgstr "Modell"
|
|||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Beschreibung"
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
|
msgid "CI extension"
|
||||||
|
msgstr "CI Erweiterung"
|
||||||
|
|
||||||
msgid "Creation date"
|
msgid "Creation date"
|
||||||
msgstr "Zeitpunkt der Erstellung"
|
msgstr "Zeitpunkt der Erstellung"
|
||||||
|
|
||||||
|
msgid "SAT>IP Device Status"
|
||||||
|
msgstr "SAT>IP Geräte Status"
|
||||||
|
|
||||||
msgid "SAT>IP Information"
|
msgid "SAT>IP Information"
|
||||||
msgstr "SAT>IP Informationen"
|
msgstr "SAT>IP Informationen"
|
||||||
|
|
||||||
@@ -64,9 +73,6 @@ msgstr "Filter"
|
|||||||
msgid "Bits/bytes"
|
msgid "Bits/bytes"
|
||||||
msgstr "Bits/Bytes"
|
msgstr "Bits/Bytes"
|
||||||
|
|
||||||
msgid "SAT>IP information not available!"
|
|
||||||
msgstr "Keine SAT>IP Informationen verfügbar!"
|
|
||||||
|
|
||||||
msgid "off"
|
msgid "off"
|
||||||
msgstr "aus"
|
msgstr "aus"
|
||||||
|
|
||||||
@@ -79,6 +85,9 @@ msgstr "normal"
|
|||||||
msgid "high"
|
msgid "high"
|
||||||
msgstr "hoch"
|
msgstr "hoch"
|
||||||
|
|
||||||
|
msgid "Button$Devices"
|
||||||
|
msgstr "Geräte"
|
||||||
|
|
||||||
msgid "Operating mode"
|
msgid "Operating mode"
|
||||||
msgstr "Betriebsmodus"
|
msgstr "Betriebsmodus"
|
||||||
|
|
||||||
@@ -97,6 +106,30 @@ msgstr ""
|
|||||||
"normal - Geräte arbeiten innerhalb der gewöhnlichen Parameter\n"
|
"normal - Geräte arbeiten innerhalb der gewöhnlichen Parameter\n"
|
||||||
"hoch - Geräte arbeiten mit höchste Priorität"
|
"hoch - Geräte arbeiten mit höchste Priorität"
|
||||||
|
|
||||||
|
msgid "Enable CI extension"
|
||||||
|
msgstr "Aktiviere CI Erweiterung"
|
||||||
|
|
||||||
|
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 ""
|
||||||
|
"Legt fest ob eine CI Erweiterung genutzt werden soll.\n"
|
||||||
|
"\n"
|
||||||
|
"Diese Einstellung aktiviert die Nutzung des integrierten CI/CAM einiger SAT>IP Geräte (z.B. 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 ""
|
||||||
|
"Bestimmt welcher CI Einschub für ein CAM genutzt werden soll.\n"
|
||||||
|
"\n"
|
||||||
|
"Die Option '---' überlässt der SAT>IP Hardware die automatische Auswahl."
|
||||||
|
|
||||||
msgid "Enable EPG scanning"
|
msgid "Enable EPG scanning"
|
||||||
msgstr "Aktiviere EPG Aktualisierung"
|
msgstr "Aktiviere EPG Aktualisierung"
|
||||||
|
|
||||||
@@ -105,20 +138,35 @@ msgid ""
|
|||||||
"\n"
|
"\n"
|
||||||
"This setting disables the automatic EIT scanning functionality for all SAT>IP devices."
|
"This setting disables the automatic EIT scanning functionality for all SAT>IP devices."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Definiert ob EPG im Hintergrund aktualisiert werden soll oder nicht.\n"
|
"Legt fest ob EPG im Hintergrund aktualisiert werden soll oder nicht.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Diese Einstellung schaltet die automatische EIT Aktualisierung für alle SAT>IP Geräte."
|
"Diese Einstellung schaltet die automatische EIT Aktualisierung für alle SAT>IP Geräte."
|
||||||
|
|
||||||
msgid "Disabled filters"
|
msgid "Disabled sources"
|
||||||
msgstr "Deaktivierte Filter"
|
msgstr "Deaktivierte Quellen"
|
||||||
|
|
||||||
msgid "none"
|
msgid "none"
|
||||||
msgstr "keine"
|
msgstr "keine"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define number of sources to be disabled.\n"
|
||||||
|
"\n"
|
||||||
|
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
|
||||||
|
msgstr ""
|
||||||
|
"Legt die Anzahl der deaktivierten Quellen fest.\n"
|
||||||
|
"\n"
|
||||||
|
"Für einige SAT>IP server sind nicht alle Satellitenpositionen verfügbar, nicht verfügbare Quellen können hier ausgeblendet werden"
|
||||||
|
|
||||||
|
msgid "Define a source to be blacklisted."
|
||||||
|
msgstr "Bestimme eine Quelle, die ausgeblendet wird"
|
||||||
|
|
||||||
|
msgid "Disabled filters"
|
||||||
|
msgstr "Deaktivierte Filter"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Define number of section filters to be disabled.\n"
|
"Define number of section filters to be disabled.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\n"
|
"Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -130,8 +178,8 @@ msgstr "Filter"
|
|||||||
msgid "Define an ill-behaving filter to be blacklisted."
|
msgid "Define an ill-behaving filter to be blacklisted."
|
||||||
msgstr "Bestimme einen fehlerhaften Filter der ausgeblendet werden soll."
|
msgstr "Bestimme einen fehlerhaften Filter der ausgeblendet werden soll."
|
||||||
|
|
||||||
msgid "Active SAT>IP devices:"
|
msgid "Active SAT>IP servers:"
|
||||||
msgstr "Aktive SAT>IP Geräte:"
|
msgstr "Aktive SAT>IP Server:"
|
||||||
|
|
||||||
msgid "Help"
|
msgid "Help"
|
||||||
msgstr "Hilfe"
|
msgstr "Hilfe"
|
||||||
|
78
po/es_ES.po
78
po/es_ES.po
@@ -1,14 +1,14 @@
|
|||||||
# VDR plugin language source file.
|
# VDR plugin language source file.
|
||||||
# Copyright (C) 2007-2014 Rolf Ahrenberg
|
# Copyright (C) 2007-2015 Rolf Ahrenberg
|
||||||
# This file is distributed under the same license as the satip package.
|
# This file is distributed under the same license as the satip package.
|
||||||
# Gabriel Bonich, 2014
|
# Gabriel Bonich, 2014-2015
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: vdr-satip 0.3.3\n"
|
"Project-Id-Version: vdr-satip 1.0.2\n"
|
||||||
"Report-Msgid-Bugs-To: <see README>\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
|
"POT-Creation-Date: 2015-01-18 01:18+0200\n"
|
||||||
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
|
"PO-Revision-Date: 2015-01-18 01:18+0200\n"
|
||||||
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
|
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
|
||||||
"Language-Team: Spanish <vdr@linuxtv.org>\n"
|
"Language-Team: Spanish <vdr@linuxtv.org>\n"
|
||||||
"Language: es\n"
|
"Language: es\n"
|
||||||
@@ -31,11 +31,14 @@ msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
|||||||
msgid "TDT (0x70)"
|
msgid "TDT (0x70)"
|
||||||
msgstr "TDT (0x70)"
|
msgstr "TDT (0x70)"
|
||||||
|
|
||||||
|
msgid "SAT>IP information not available!"
|
||||||
|
msgstr "SAT>IP Información no disponible!"
|
||||||
|
|
||||||
msgid "SAT>IP Devices"
|
msgid "SAT>IP Devices"
|
||||||
msgstr "SAT>IP Dispositivos"
|
msgstr "SAT>IP Dispositivos"
|
||||||
|
|
||||||
msgid "SAT>IP Device"
|
msgid "SAT>IP Server"
|
||||||
msgstr "SAT>IP Dispositivo"
|
msgstr "SAT>IP Server"
|
||||||
|
|
||||||
msgid "Address"
|
msgid "Address"
|
||||||
msgstr "Dirección"
|
msgstr "Dirección"
|
||||||
@@ -46,9 +49,15 @@ msgstr "Modelo"
|
|||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Descripción"
|
msgstr "Descripción"
|
||||||
|
|
||||||
|
msgid "CI extension"
|
||||||
|
msgstr "Extensión CI"
|
||||||
|
|
||||||
msgid "Creation date"
|
msgid "Creation date"
|
||||||
msgstr "Fecha creación"
|
msgstr "Fecha creación"
|
||||||
|
|
||||||
|
msgid "SAT>IP Device Status"
|
||||||
|
msgstr "SAT>IP Estado del Dispositivo"
|
||||||
|
|
||||||
msgid "SAT>IP Information"
|
msgid "SAT>IP Information"
|
||||||
msgstr "SAT>IP Información"
|
msgstr "SAT>IP Información"
|
||||||
|
|
||||||
@@ -64,9 +73,6 @@ msgstr "Filtros"
|
|||||||
msgid "Bits/bytes"
|
msgid "Bits/bytes"
|
||||||
msgstr "Bits/Bytes"
|
msgstr "Bits/Bytes"
|
||||||
|
|
||||||
msgid "SAT>IP information not available!"
|
|
||||||
msgstr "SAT>IP Información no disponible!"
|
|
||||||
|
|
||||||
msgid "off"
|
msgid "off"
|
||||||
msgstr "Apagado"
|
msgstr "Apagado"
|
||||||
|
|
||||||
@@ -79,6 +85,9 @@ msgstr "Normal"
|
|||||||
msgid "high"
|
msgid "high"
|
||||||
msgstr "Alto"
|
msgstr "Alto"
|
||||||
|
|
||||||
|
msgid "Button$Devices"
|
||||||
|
msgstr "Dispositivos"
|
||||||
|
|
||||||
msgid "Operating mode"
|
msgid "Operating mode"
|
||||||
msgstr "Modo de operación"
|
msgstr "Modo de operación"
|
||||||
|
|
||||||
@@ -97,6 +106,30 @@ msgstr ""
|
|||||||
"Normal - Dispositivos trabajando con prioridad Normal\n"
|
"Normal - Dispositivos trabajando con prioridad Normal\n"
|
||||||
"Alta - Dispositivos trabajando con prioridad Alta"
|
"Alta - Dispositivos trabajando con prioridad Alta"
|
||||||
|
|
||||||
|
msgid "Enable CI extension"
|
||||||
|
msgstr "Habilitar extensión 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 ""
|
||||||
|
"Definir si se utilizará una extensión de CI.\n"
|
||||||
|
"\n"
|
||||||
|
"Esto permite la configuración CI/CAM integrado que se encuentra en algunos equipos SAT>IP (ej. 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 ""
|
||||||
|
"Definir el tipo de CAM para la ranura CI.\n"
|
||||||
|
"\n"
|
||||||
|
"La opción '---' permite al equipo SAT>IP hacer la selección automática."
|
||||||
|
|
||||||
msgid "Enable EPG scanning"
|
msgid "Enable EPG scanning"
|
||||||
msgstr "Activa Escaneo EPG"
|
msgstr "Activa Escaneo EPG"
|
||||||
|
|
||||||
@@ -109,16 +142,31 @@ msgstr ""
|
|||||||
"\n"
|
"\n"
|
||||||
"Esta configuración desactiva la funcionalidad del escaneo EIT automática para todos los Dispositivos SAT>IP."
|
"Esta configuración desactiva la funcionalidad del escaneo EIT automática para todos los Dispositivos SAT>IP."
|
||||||
|
|
||||||
msgid "Disabled filters"
|
msgid "Disabled sources"
|
||||||
msgstr "Desactiva filtros"
|
msgstr "Desactiva fuentes"
|
||||||
|
|
||||||
msgid "none"
|
msgid "none"
|
||||||
msgstr "no"
|
msgstr "no"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define number of sources to be disabled.\n"
|
||||||
|
"\n"
|
||||||
|
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
|
||||||
|
msgstr ""
|
||||||
|
"Definir número de fuentes desactivadas.\n"
|
||||||
|
"\n"
|
||||||
|
"SAT>IP servidores que no tenga todas las posiciones de los satélites disponibles y estas se ponen en la lista negra."
|
||||||
|
|
||||||
|
msgid "Define a source to be blacklisted."
|
||||||
|
msgstr "Define fuentes de la lista negra"
|
||||||
|
|
||||||
|
msgid "Disabled filters"
|
||||||
|
msgstr "Desactiva filtros"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Define number of section filters to be disabled.\n"
|
"Define number of section filters to be disabled.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Define el numero de filtros de sección que seran deshabilitados.\n"
|
"Define el numero de filtros de sección que seran deshabilitados.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -130,8 +178,8 @@ msgstr "Filtra"
|
|||||||
msgid "Define an ill-behaving filter to be blacklisted."
|
msgid "Define an ill-behaving filter to be blacklisted."
|
||||||
msgstr "Define un filtro para poner en la lista negra."
|
msgstr "Define un filtro para poner en la lista negra."
|
||||||
|
|
||||||
msgid "Active SAT>IP devices:"
|
msgid "Active SAT>IP servers:"
|
||||||
msgstr "Dispositivos SAT>IP activos:"
|
msgstr "Activa SAT>IP servers:"
|
||||||
|
|
||||||
msgid "Help"
|
msgid "Help"
|
||||||
msgstr "Ayuda"
|
msgstr "Ayuda"
|
||||||
|
78
po/fi_FI.po
78
po/fi_FI.po
@@ -1,14 +1,14 @@
|
|||||||
# VDR plugin language source file.
|
# VDR plugin language source file.
|
||||||
# Copyright (C) 2007-2014 Rolf Ahrenberg
|
# Copyright (C) 2007-2015 Rolf Ahrenberg
|
||||||
# This file is distributed under the same license as the satip package.
|
# This file is distributed under the same license as the satip package.
|
||||||
# Rolf Ahrenberg, 2014
|
# Rolf Ahrenberg, 2015
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: vdr-satip 0.3.3\n"
|
"Project-Id-Version: vdr-satip 1.0.2\n"
|
||||||
"Report-Msgid-Bugs-To: <see README>\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
|
"POT-Creation-Date: 2015-01-18 01:18+0200\n"
|
||||||
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
|
"PO-Revision-Date: 2015-01-18 01:18+0200\n"
|
||||||
"Last-Translator: Rolf Ahrenberg\n"
|
"Last-Translator: Rolf Ahrenberg\n"
|
||||||
"Language-Team: Finnish <vdr@linuxtv.org>\n"
|
"Language-Team: Finnish <vdr@linuxtv.org>\n"
|
||||||
"Language: fi\n"
|
"Language: fi\n"
|
||||||
@@ -31,11 +31,14 @@ msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
|
|||||||
msgid "TDT (0x70)"
|
msgid "TDT (0x70)"
|
||||||
msgstr "TDT (0x70)"
|
msgstr "TDT (0x70)"
|
||||||
|
|
||||||
|
msgid "SAT>IP information not available!"
|
||||||
|
msgstr "SAT>IP-tietoja ei saatavilla!"
|
||||||
|
|
||||||
msgid "SAT>IP Devices"
|
msgid "SAT>IP Devices"
|
||||||
msgstr "SAT>IP-laitteet"
|
msgstr "SAT>IP-laitteet"
|
||||||
|
|
||||||
msgid "SAT>IP Device"
|
msgid "SAT>IP Server"
|
||||||
msgstr "SAT>IP-laite"
|
msgstr "SAT>IP-palvelin"
|
||||||
|
|
||||||
msgid "Address"
|
msgid "Address"
|
||||||
msgstr "Osoite"
|
msgstr "Osoite"
|
||||||
@@ -46,9 +49,15 @@ msgstr "Malli"
|
|||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Kuvaus"
|
msgstr "Kuvaus"
|
||||||
|
|
||||||
|
msgid "CI extension"
|
||||||
|
msgstr "CI-laajennos"
|
||||||
|
|
||||||
msgid "Creation date"
|
msgid "Creation date"
|
||||||
msgstr "Luontiajankohta"
|
msgstr "Luontiajankohta"
|
||||||
|
|
||||||
|
msgid "SAT>IP Device Status"
|
||||||
|
msgstr "SAT>IP-laitteiden tiedot"
|
||||||
|
|
||||||
msgid "SAT>IP Information"
|
msgid "SAT>IP Information"
|
||||||
msgstr "SAT>IP-tiedot"
|
msgstr "SAT>IP-tiedot"
|
||||||
|
|
||||||
@@ -64,9 +73,6 @@ msgstr "Suodattimet"
|
|||||||
msgid "Bits/bytes"
|
msgid "Bits/bytes"
|
||||||
msgstr "Bitit/tavut"
|
msgstr "Bitit/tavut"
|
||||||
|
|
||||||
msgid "SAT>IP information not available!"
|
|
||||||
msgstr "SAT>IP-tietoja ei saatavilla!"
|
|
||||||
|
|
||||||
msgid "off"
|
msgid "off"
|
||||||
msgstr "ei käytössä"
|
msgstr "ei käytössä"
|
||||||
|
|
||||||
@@ -79,6 +85,9 @@ msgstr "normaali"
|
|||||||
msgid "high"
|
msgid "high"
|
||||||
msgstr "korkea"
|
msgstr "korkea"
|
||||||
|
|
||||||
|
msgid "Button$Devices"
|
||||||
|
msgstr "Laitteet"
|
||||||
|
|
||||||
msgid "Operating mode"
|
msgid "Operating mode"
|
||||||
msgstr "Laitteiden toimintatapa"
|
msgstr "Laitteiden toimintatapa"
|
||||||
|
|
||||||
@@ -96,6 +105,30 @@ msgstr ""
|
|||||||
"normaali - laitteet toimivat normaalilla prioriteetilla\n"
|
"normaali - laitteet toimivat normaalilla prioriteetilla\n"
|
||||||
"korkea - laitteet toimivat korkealla prioriteetilla"
|
"korkea - laitteet toimivat korkealla prioriteetilla"
|
||||||
|
|
||||||
|
msgid "Enable CI extension"
|
||||||
|
msgstr "Käytä CI-laajennosta"
|
||||||
|
|
||||||
|
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 ""
|
||||||
|
"Määrittele CI-laajennoksen käyttöönotto\n"
|
||||||
|
"\n"
|
||||||
|
"Tällä asetuksella saadaan otettua käyttöön SAT>IP-laitteiden sisäinen CI-paikka (esim. 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 ""
|
||||||
|
"Määrittele haluttu CAM-tyyppi CI-paikalle.\n"
|
||||||
|
"\n"
|
||||||
|
"Vaihtoehto '---' antaa SAT>IP-laitteen valita automaattisesti käytetyn CI-paikan."
|
||||||
|
|
||||||
msgid "Enable EPG scanning"
|
msgid "Enable EPG scanning"
|
||||||
msgstr "Käytä ohjelmaoppaan taustapäivitystä"
|
msgstr "Käytä ohjelmaoppaan taustapäivitystä"
|
||||||
|
|
||||||
@@ -108,16 +141,31 @@ msgstr ""
|
|||||||
"\n"
|
"\n"
|
||||||
"Tällä asetuksella saadaan otettua automaattinen EIT-datan päivitys pois päältä kaikilta SAT>IP-laitteilta."
|
"Tällä asetuksella saadaan otettua automaattinen EIT-datan päivitys pois päältä kaikilta SAT>IP-laitteilta."
|
||||||
|
|
||||||
msgid "Disabled filters"
|
msgid "Disabled sources"
|
||||||
msgstr "Käytöstä poistetut suodattimet"
|
msgstr "Käytöstä poistetut lähteet"
|
||||||
|
|
||||||
msgid "none"
|
msgid "none"
|
||||||
msgstr "tyhjä"
|
msgstr "tyhjä"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Define number of sources to be disabled.\n"
|
||||||
|
"\n"
|
||||||
|
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
|
||||||
|
msgstr ""
|
||||||
|
"Määrittele käytöstä poistettavien lähteiden lukumäärä.\n"
|
||||||
|
"\n"
|
||||||
|
"SAT>IP-palvelimilla ei välttämättä ole kaikkia ohjelmalähteitä tarjolla."
|
||||||
|
|
||||||
|
msgid "Define a source to be blacklisted."
|
||||||
|
msgstr "Määrittele käytöstä"
|
||||||
|
|
||||||
|
msgid "Disabled filters"
|
||||||
|
msgstr "Käytöstä poistetut suodattimet"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Define number of section filters to be disabled.\n"
|
"Define number of section filters to be disabled.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
|
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Määrittele käytöstä poistettavien suodattimien lukumäärä sektioille.\n"
|
"Määrittele käytöstä poistettavien suodattimien lukumäärä sektioille.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -129,8 +177,8 @@ msgstr "Suodatin"
|
|||||||
msgid "Define an ill-behaving filter to be blacklisted."
|
msgid "Define an ill-behaving filter to be blacklisted."
|
||||||
msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle."
|
msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle."
|
||||||
|
|
||||||
msgid "Active SAT>IP devices:"
|
msgid "Active SAT>IP servers:"
|
||||||
msgstr "Aktiiviset SAT>IP-laitteet:"
|
msgstr "Aktiiviset SAT>IP-palvelimet:"
|
||||||
|
|
||||||
msgid "Help"
|
msgid "Help"
|
||||||
msgstr "Opaste"
|
msgstr "Opaste"
|
||||||
|
122
poller.c
Normal file
122
poller.c
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* poller.c: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "poller.h"
|
||||||
|
|
||||||
|
cSatipPoller *cSatipPoller::instanceS = NULL;
|
||||||
|
|
||||||
|
cSatipPoller *cSatipPoller::GetInstance(void)
|
||||||
|
{
|
||||||
|
if (!instanceS)
|
||||||
|
instanceS = new cSatipPoller();
|
||||||
|
return instanceS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipPoller::Initialize(void)
|
||||||
|
{
|
||||||
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
|
if (instanceS)
|
||||||
|
instanceS->Activate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipPoller::Destroy(void)
|
||||||
|
{
|
||||||
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
|
if (instanceS)
|
||||||
|
instanceS->Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
cSatipPoller::cSatipPoller()
|
||||||
|
: cThread("SATIP poller"),
|
||||||
|
mutexM(),
|
||||||
|
fdM(epoll_create(eMaxFileDescriptors))
|
||||||
|
{
|
||||||
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
cSatipPoller::~cSatipPoller()
|
||||||
|
{
|
||||||
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
|
Deactivate();
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
close(fdM);
|
||||||
|
// Free allocated memory
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipPoller::Activate(void)
|
||||||
|
{
|
||||||
|
// Start the thread
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipPoller::Deactivate(void)
|
||||||
|
{
|
||||||
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
if (Running())
|
||||||
|
Cancel(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipPoller::Action(void)
|
||||||
|
{
|
||||||
|
debug1("%s Entering", __PRETTY_FUNCTION__);
|
||||||
|
struct epoll_event events[eMaxFileDescriptors];
|
||||||
|
uint64_t maxElapsed = 0;
|
||||||
|
// Increase priority
|
||||||
|
SetPriority(-1);
|
||||||
|
// Do the thread loop
|
||||||
|
while (Running()) {
|
||||||
|
int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, -1);
|
||||||
|
ERROR_IF_FUNC((nfds == -1), "epoll_wait() failed", break, ;);
|
||||||
|
for (int i = 0; i < nfds; ++i) {
|
||||||
|
cSatipPollerIf* poll = reinterpret_cast<cSatipPollerIf *>(events[i].data.ptr);
|
||||||
|
if (poll) {
|
||||||
|
uint64_t elapsed;
|
||||||
|
cTimeMs processing(0);
|
||||||
|
poll->Process();
|
||||||
|
elapsed = processing.Elapsed();
|
||||||
|
if (elapsed > maxElapsed) {
|
||||||
|
maxElapsed = elapsed;
|
||||||
|
debug1("%s Processing %s took %" PRIu64 " ms", __PRETTY_FUNCTION__, *(poll->ToString()), maxElapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug1("%s Exiting", __PRETTY_FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipPoller::Register(cSatipPollerIf &pollerP)
|
||||||
|
{
|
||||||
|
debug1("%s fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd());
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
|
||||||
|
struct epoll_event ev;
|
||||||
|
ev.events = EPOLLIN | EPOLLET;
|
||||||
|
ev.data.ptr = &pollerP;
|
||||||
|
ERROR_IF_RET(epoll_ctl(fdM, EPOLL_CTL_ADD, pollerP.GetFd(), &ev) == -1, "epoll_ctl(EPOLL_CTL_ADD) failed", return false);
|
||||||
|
debug1("%s Added interface fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipPoller::Unregister(cSatipPollerIf &pollerP)
|
||||||
|
{
|
||||||
|
debug1("%s fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd());
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
ERROR_IF_RET((epoll_ctl(fdM, EPOLL_CTL_DEL, pollerP.GetFd(), NULL) == -1), "epoll_ctl(EPOLL_CTL_DEL) failed", return false);
|
||||||
|
debug1("%s Removed interface fd=%d", __PRETTY_FUNCTION__, pollerP.GetFd());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
44
poller.h
Normal file
44
poller.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* poller.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_POLLER_H
|
||||||
|
#define __SATIP_POLLER_H
|
||||||
|
|
||||||
|
#include <vdr/thread.h>
|
||||||
|
#include <vdr/tools.h>
|
||||||
|
|
||||||
|
#include "pollerif.h"
|
||||||
|
|
||||||
|
class cSatipPoller : public cThread {
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
eMaxFileDescriptors = SATIP_MAX_DEVICES * 2, // Data + Application
|
||||||
|
};
|
||||||
|
static cSatipPoller *instanceS;
|
||||||
|
cMutex mutexM;
|
||||||
|
int fdM;
|
||||||
|
void Activate(void);
|
||||||
|
void Deactivate(void);
|
||||||
|
// constructor
|
||||||
|
cSatipPoller();
|
||||||
|
// to prevent copy constructor and assignment
|
||||||
|
cSatipPoller(const cSatipPoller&);
|
||||||
|
cSatipPoller& operator=(const cSatipPoller&);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void Action(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static cSatipPoller *GetInstance(void);
|
||||||
|
static bool Initialize(void);
|
||||||
|
static void Destroy(void);
|
||||||
|
virtual ~cSatipPoller();
|
||||||
|
bool Register(cSatipPollerIf &pollerP);
|
||||||
|
bool Unregister(cSatipPollerIf &pollerP);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SATIP_POLLER_H
|
24
pollerif.h
Normal file
24
pollerif.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* pollerif.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_POLLERIF_H
|
||||||
|
#define __SATIP_POLLERIF_H
|
||||||
|
|
||||||
|
class cSatipPollerIf {
|
||||||
|
public:
|
||||||
|
cSatipPollerIf() {}
|
||||||
|
virtual ~cSatipPollerIf() {}
|
||||||
|
virtual int GetFd(void) = 0;
|
||||||
|
virtual void Process(void) = 0;
|
||||||
|
virtual cString ToString(void) const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
cSatipPollerIf(const cSatipPollerIf&);
|
||||||
|
cSatipPollerIf& operator=(const cSatipPollerIf&);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SATIP_POLLERIF_H
|
100
rtcp.c
Normal file
100
rtcp.c
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* rtcp.c: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "rtcp.h"
|
||||||
|
|
||||||
|
cSatipRtcp::cSatipRtcp(cSatipTunerIf &tunerP)
|
||||||
|
: tunerM(tunerP),
|
||||||
|
bufferLenM(eApplicationMaxSizeB),
|
||||||
|
bufferM(MALLOC(unsigned char, bufferLenM))
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
if (bufferM)
|
||||||
|
memset(bufferM, 0, bufferLenM);
|
||||||
|
else
|
||||||
|
error("Cannot create RTCP buffer! [device %d]", tunerM.GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
cSatipRtcp::~cSatipRtcp()
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
DELETE_POINTER(bufferM);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cSatipRtcp::GetFd(void)
|
||||||
|
{
|
||||||
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
return Fd();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cSatipRtcp::GetApplicationOffset(int *lengthP)
|
||||||
|
{
|
||||||
|
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, *lengthP, tunerM.GetId());
|
||||||
|
if (!lengthP)
|
||||||
|
return -1;
|
||||||
|
int offset = 0;
|
||||||
|
int total = *lengthP;
|
||||||
|
while (total > 0) {
|
||||||
|
// Version
|
||||||
|
unsigned int v = (bufferM[offset] >> 6) & 0x03;
|
||||||
|
// Padding
|
||||||
|
//unsigned int p = (bufferM[offset] >> 5) & 0x01;
|
||||||
|
// Subtype
|
||||||
|
//unsigned int st = bufferM[offset] & 0x1F;
|
||||||
|
// Payload type
|
||||||
|
unsigned int pt = bufferM[offset + 1] & 0xFF;
|
||||||
|
// Length
|
||||||
|
unsigned int length = ((bufferM[offset + 2] & 0xFF) << 8) | (bufferM[offset + 3] & 0xFF);
|
||||||
|
// Convert it to bytes
|
||||||
|
length = (length + 1) * 4;
|
||||||
|
// V=2, APP = 204
|
||||||
|
if ((v == 2) && (pt == 204)) {
|
||||||
|
// SSCR/CSCR
|
||||||
|
//unsigned int ssrc = ((bufferM[offset + 4] & 0xFF) << 24) | ((bufferM[offset + 5] & 0xFF) << 16) |
|
||||||
|
// ((bufferM[offset + 6] & 0xFF) << 8) | (bufferM[offset + 7] & 0xFF);
|
||||||
|
// Name
|
||||||
|
if ((bufferM[offset + 8] == 'S') && (bufferM[offset + 9] == 'E') &&
|
||||||
|
(bufferM[offset + 10] == 'S') && (bufferM[offset + 11] == '1')) {
|
||||||
|
// Identifier
|
||||||
|
//unsigned int id = ((bufferM[offset + 12] & 0xFF) << 8) | (bufferM[offset + 13] & 0xFF);
|
||||||
|
// String length
|
||||||
|
int string_length = ((bufferM[offset + 14] & 0xFF) << 8) | (bufferM[offset + 15] & 0xFF);
|
||||||
|
if (string_length > 0) {
|
||||||
|
*lengthP = string_length;
|
||||||
|
return (offset + 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += length;
|
||||||
|
total -= length;
|
||||||
|
}
|
||||||
|
*lengthP = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipRtcp::Process(void)
|
||||||
|
{
|
||||||
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
if (bufferM) {
|
||||||
|
int length;
|
||||||
|
while ((length = Read(bufferM, bufferLenM)) > 0) {
|
||||||
|
int offset = GetApplicationOffset(&length);
|
||||||
|
if (offset >= 0)
|
||||||
|
tunerM.ProcessApplicationData(bufferM + offset, length);
|
||||||
|
}
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
error("Error %d reading in %s", errno, *ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cString cSatipRtcp::ToString(void) const
|
||||||
|
{
|
||||||
|
return cString::sprintf("RTCP [device %d]", tunerM.GetId());
|
||||||
|
}
|
36
rtcp.h
Normal file
36
rtcp.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* rtcp.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_RTCP_H_
|
||||||
|
#define __SATIP_RTCP_H_
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
#include "tunerif.h"
|
||||||
|
#include "pollerif.h"
|
||||||
|
|
||||||
|
class cSatipRtcp : public cSatipSocket, public cSatipPollerIf {
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
eApplicationMaxSizeB = 1500,
|
||||||
|
};
|
||||||
|
cSatipTunerIf &tunerM;
|
||||||
|
unsigned int bufferLenM;
|
||||||
|
unsigned char *bufferM;
|
||||||
|
int GetApplicationOffset(int *lengthP);
|
||||||
|
|
||||||
|
public:
|
||||||
|
cSatipRtcp(cSatipTunerIf &tunerP);
|
||||||
|
virtual ~cSatipRtcp();
|
||||||
|
|
||||||
|
// for internal poller interface
|
||||||
|
public:
|
||||||
|
virtual int GetFd(void);
|
||||||
|
virtual void Process(void);
|
||||||
|
virtual cString ToString(void) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __SATIP_RTCP_H_ */
|
151
rtp.c
Normal file
151
rtp.c
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* rtp.c: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "rtp.h"
|
||||||
|
|
||||||
|
cSatipRtp::cSatipRtp(cSatipTunerIf &tunerP)
|
||||||
|
: tunerM(tunerP),
|
||||||
|
bufferLenM(eRtpPacketReadCount * eMaxUdpPacketSizeB),
|
||||||
|
bufferM(MALLOC(unsigned char, bufferLenM)),
|
||||||
|
lastErrorReportM(0),
|
||||||
|
packetErrorsM(0),
|
||||||
|
sequenceNumberM(-1)
|
||||||
|
{
|
||||||
|
debug1("%s () [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
if (!bufferM)
|
||||||
|
error("Cannot create RTP buffer! [device %d]", tunerM.GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
cSatipRtp::~cSatipRtp()
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
DELETE_POINTER(bufferM);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cSatipRtp::GetFd(void)
|
||||||
|
{
|
||||||
|
return Fd();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipRtp::Close(void)
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
|
||||||
|
cSatipSocket::Close();
|
||||||
|
|
||||||
|
sequenceNumberM = -1;
|
||||||
|
if (packetErrorsM) {
|
||||||
|
info("Detected %d RTP packet errors [device %d]", packetErrorsM, tunerM.GetId());
|
||||||
|
packetErrorsM = 0;
|
||||||
|
lastErrorReportM = time(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cSatipRtp::GetHeaderLength(unsigned char *bufferP, unsigned int lengthP)
|
||||||
|
{
|
||||||
|
debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, tunerM.GetId());
|
||||||
|
unsigned int headerlen = 0;
|
||||||
|
|
||||||
|
if (lengthP > 0) {
|
||||||
|
if (bufferP[0] == TS_SYNC_BYTE)
|
||||||
|
return headerlen;
|
||||||
|
else if (lengthP > 3) {
|
||||||
|
// http://tools.ietf.org/html/rfc3550
|
||||||
|
// http://tools.ietf.org/html/rfc2250
|
||||||
|
// Version
|
||||||
|
unsigned int v = (bufferP[0] >> 6) & 0x03;
|
||||||
|
// Extension bit
|
||||||
|
unsigned int x = (bufferP[0] >> 4) & 0x01;
|
||||||
|
// CSCR count
|
||||||
|
unsigned int cc = bufferP[0] & 0x0F;
|
||||||
|
// Payload type: MPEG2 TS = 33
|
||||||
|
unsigned int pt = bufferP[1] & 0x7F;
|
||||||
|
if (pt != 33)
|
||||||
|
debug7("%s (%d) Received invalid RTP payload type %d - v=%d [device %d]",
|
||||||
|
__PRETTY_FUNCTION__, lengthP, pt, v, tunerM.GetId());
|
||||||
|
// Sequence number
|
||||||
|
int seq = ((bufferP[2] & 0xFF) << 8) | (bufferP[3] & 0xFF);
|
||||||
|
if ((((sequenceNumberM + 1) % 0xFFFF) == 0) && (seq == 0xFFFF))
|
||||||
|
sequenceNumberM = -1;
|
||||||
|
else if ((sequenceNumberM >= 0) && (((sequenceNumberM + 1) % 0xFFFF) != seq)) {
|
||||||
|
packetErrorsM++;
|
||||||
|
if (time(NULL) - lastErrorReportM > eReportIntervalS) {
|
||||||
|
info("Detected %d RTP packet errors [device %d]", packetErrorsM, tunerM.GetId());
|
||||||
|
packetErrorsM = 0;
|
||||||
|
lastErrorReportM = time(NULL);
|
||||||
|
}
|
||||||
|
sequenceNumberM = seq;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sequenceNumberM = seq;
|
||||||
|
// Header length
|
||||||
|
headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
|
||||||
|
// Check if extension
|
||||||
|
if (x) {
|
||||||
|
// Extension header length
|
||||||
|
unsigned int ehl = (((bufferP[headerlen + 2] & 0xFF) << 8) | (bufferP[headerlen + 3] & 0xFF));
|
||||||
|
// Update header length
|
||||||
|
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
// Check for empty payload
|
||||||
|
if (lengthP == headerlen) {
|
||||||
|
debug7("%s (%d) Received empty RTP packet #%d [device %d]", __PRETTY_FUNCTION__, lengthP, seq, tunerM.GetId());
|
||||||
|
headerlen = -1;
|
||||||
|
}
|
||||||
|
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
||||||
|
else if ((v != 2) || (((lengthP - headerlen) % TS_SIZE) != 0) || (bufferP[headerlen] != TS_SYNC_BYTE)) {
|
||||||
|
debug7("%s (%d) Received incorrect RTP packet #%d v=%d len=%d sync=0x%02X [device %d]", __PRETTY_FUNCTION__,
|
||||||
|
lengthP, seq, v, headerlen, bufferP[headerlen], tunerM.GetId());
|
||||||
|
headerlen = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
debug7("%s (%d) Received RTP packet #%d v=%d len=%d sync=0x%02X [device %d]", __PRETTY_FUNCTION__,
|
||||||
|
lengthP, seq, v, headerlen, bufferP[headerlen], tunerM.GetId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return headerlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipRtp::Process(void)
|
||||||
|
{
|
||||||
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
if (bufferM) {
|
||||||
|
unsigned int lenMsg[eRtpPacketReadCount];
|
||||||
|
uint64_t elapsed;
|
||||||
|
int count = 0;
|
||||||
|
cTimeMs processing(0);
|
||||||
|
|
||||||
|
do {
|
||||||
|
count = ReadMulti(bufferM, lenMsg, eRtpPacketReadCount, eMaxUdpPacketSizeB);
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
unsigned char *p = &bufferM[i * eMaxUdpPacketSizeB];
|
||||||
|
int headerlen = GetHeaderLength(p, lenMsg[i]);
|
||||||
|
if ((headerlen >= 0) && (headerlen < (int)lenMsg[i]))
|
||||||
|
tunerM.ProcessVideoData(p + headerlen, lenMsg[i] - headerlen);
|
||||||
|
}
|
||||||
|
} while (count >= eRtpPacketReadCount);
|
||||||
|
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
error("Error %d reading in %s [device %d]", errno, *ToString(), tunerM.GetId());
|
||||||
|
|
||||||
|
elapsed = processing.Elapsed();
|
||||||
|
if (elapsed > 1)
|
||||||
|
debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, count, elapsed, tunerM.GetId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cString cSatipRtp::ToString(void) const
|
||||||
|
{
|
||||||
|
return cString::sprintf("RTP [device %d]", tunerM.GetId());
|
||||||
|
}
|
42
rtp.h
Normal file
42
rtp.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* rtp.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_RTP_H_
|
||||||
|
#define __SATIP_RTP_H_
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
#include "tunerif.h"
|
||||||
|
#include "pollerif.h"
|
||||||
|
|
||||||
|
class cSatipRtp : public cSatipSocket, public cSatipPollerIf {
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
eRtpPacketReadCount = 50,
|
||||||
|
eMaxUdpPacketSizeB = TS_SIZE * 7 + 12,
|
||||||
|
eReportIntervalS = 300 // in seconds
|
||||||
|
};
|
||||||
|
cSatipTunerIf &tunerM;
|
||||||
|
unsigned int bufferLenM;
|
||||||
|
unsigned char *bufferM;
|
||||||
|
time_t lastErrorReportM;
|
||||||
|
int packetErrorsM;
|
||||||
|
int sequenceNumberM;
|
||||||
|
int GetHeaderLength(unsigned char *bufferP, unsigned int lengthP);
|
||||||
|
|
||||||
|
public:
|
||||||
|
cSatipRtp(cSatipTunerIf &tunerP);
|
||||||
|
virtual ~cSatipRtp();
|
||||||
|
virtual void Close(void);
|
||||||
|
|
||||||
|
// for internal poller interface
|
||||||
|
public:
|
||||||
|
virtual int GetFd(void);
|
||||||
|
virtual void Process(void);
|
||||||
|
virtual cString ToString(void) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __SATIP_RTP_H_ */
|
335
rtsp.c
Normal file
335
rtsp.c
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
* rtsp.c: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "rtsp.h"
|
||||||
|
|
||||||
|
cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP)
|
||||||
|
: tunerM(tunerP),
|
||||||
|
modeM(cmUnicast),
|
||||||
|
handleM(NULL),
|
||||||
|
headerListM(NULL)
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
cSatipRtsp::~cSatipRtsp()
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cSatipRtsp::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||||
|
{
|
||||||
|
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP);
|
||||||
|
size_t len = sizeP * nmembP;
|
||||||
|
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
|
||||||
|
|
||||||
|
char *s, *p = (char *)ptrP;
|
||||||
|
char *r = strtok_r(p, "\r\n", &s);
|
||||||
|
|
||||||
|
while (obj && r) {
|
||||||
|
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, len, r);
|
||||||
|
r = skipspace(r);
|
||||||
|
if (strstr(r, "com.ses.streamID")) {
|
||||||
|
int streamid = -1;
|
||||||
|
if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1)
|
||||||
|
obj->tunerM.SetStreamId(streamid);
|
||||||
|
}
|
||||||
|
else if (strstr(r, "Session:")) {
|
||||||
|
int timeout = -1;
|
||||||
|
char *session = NULL;
|
||||||
|
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
|
||||||
|
obj->tunerM.SetSessionTimeout(skipspace(session), timeout * 1000);
|
||||||
|
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
|
||||||
|
obj->tunerM.SetSessionTimeout(skipspace(session), -1);
|
||||||
|
FREE_POINTER(session);
|
||||||
|
}
|
||||||
|
r = strtok_r(NULL, "\r\n", &s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cSatipRtsp::WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
||||||
|
{
|
||||||
|
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP);
|
||||||
|
size_t len = sizeP * nmembP;
|
||||||
|
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
|
||||||
|
|
||||||
|
if (obj && (len > 0))
|
||||||
|
obj->tunerM.ProcessApplicationData((u_char*)ptrP, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP)
|
||||||
|
{
|
||||||
|
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(userPtrP);
|
||||||
|
|
||||||
|
if (obj) {
|
||||||
|
switch (typeP) {
|
||||||
|
case CURLINFO_TEXT:
|
||||||
|
debug2("%s [device %d] RTSP INFO %.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
case CURLINFO_HEADER_IN:
|
||||||
|
debug2("%s [device %d] RTSP HEAD <<< %.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
case CURLINFO_HEADER_OUT:
|
||||||
|
debug2("%s [device %d] RTSP HEAD >>>\n%.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
case CURLINFO_DATA_IN:
|
||||||
|
debug2("%s [device %d] RTSP DATA <<< %.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
case CURLINFO_DATA_OUT:
|
||||||
|
debug2("%s [device %d] RTSP DATA >>>\n%.*s", __PRETTY_FUNCTION__, obj->tunerM.GetId(), (int)sizeP, dataP);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cString cSatipRtsp::RtspUnescapeString(const char *strP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId());
|
||||||
|
if (handleM) {
|
||||||
|
char *p = curl_easy_unescape(handleM, strP, 0, NULL);
|
||||||
|
cString s = p;
|
||||||
|
curl_free(p);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cString(strP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipRtsp::Create(void)
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
if (!handleM)
|
||||||
|
handleM = curl_easy_init();
|
||||||
|
|
||||||
|
if (handleM) {
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
|
||||||
|
// Verbose output
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipRtsp::DebugCallback);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this);
|
||||||
|
|
||||||
|
// No progress meter and no signaling
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
|
||||||
|
|
||||||
|
// Set timeouts
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
|
||||||
|
|
||||||
|
// Set user-agent
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, tunerM.GetId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipRtsp::Destroy(void)
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
if (handleM) {
|
||||||
|
// Cleanup curl stuff
|
||||||
|
if (headerListM) {
|
||||||
|
curl_slist_free_all(headerListM);
|
||||||
|
headerListM = NULL;
|
||||||
|
}
|
||||||
|
curl_easy_cleanup(handleM);
|
||||||
|
handleM = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipRtsp::Reset(void)
|
||||||
|
{
|
||||||
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
Destroy();
|
||||||
|
Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipRtsp::Options(const char *uriP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (handleM && !isempty(uriP)) {
|
||||||
|
long rc = 0;
|
||||||
|
cTimeMs processing(0);
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, uriP);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
|
||||||
|
SATIP_CURL_EASY_PERFORM(handleM);
|
||||||
|
|
||||||
|
result = ValidateLatestResponse(&rc);
|
||||||
|
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, tunerM.GetId());
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (handleM && !isempty(uriP)) {
|
||||||
|
cString transport;
|
||||||
|
long rc = 0;
|
||||||
|
cTimeMs processing(0);
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
|
||||||
|
switch (modeM) {
|
||||||
|
case cmMulticast:
|
||||||
|
// RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl>
|
||||||
|
transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case cmUnicast:
|
||||||
|
// RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port>
|
||||||
|
transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup media stream
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_TRANSPORT, *transport);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
|
||||||
|
// Set header callback for catching the session and timeout
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipRtsp::HeaderCallback);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
|
||||||
|
SATIP_CURL_EASY_PERFORM(handleM);
|
||||||
|
// Session id is now known - disable header parsing
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL);
|
||||||
|
|
||||||
|
result = ValidateLatestResponse(&rc);
|
||||||
|
debug5("%s (%s, %d, %d) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, rc, processing.Elapsed(), tunerM.GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipRtsp::SetSession(const char *sessionP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, sessionP, tunerM.GetId());
|
||||||
|
if (handleM) {
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
|
||||||
|
debug1("%s: session id quirk enabled [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, sessionP);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipRtsp::Describe(const char *uriP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (handleM && !isempty(uriP)) {
|
||||||
|
long rc = 0;
|
||||||
|
cTimeMs processing(0);
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::WriteCallback);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
|
||||||
|
SATIP_CURL_EASY_PERFORM(handleM);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
|
||||||
|
|
||||||
|
result = ValidateLatestResponse(&rc);
|
||||||
|
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipRtsp::Play(const char *uriP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (handleM && !isempty(uriP)) {
|
||||||
|
long rc = 0;
|
||||||
|
cTimeMs processing(0);
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
|
||||||
|
SATIP_CURL_EASY_PERFORM(handleM);
|
||||||
|
|
||||||
|
result = ValidateLatestResponse(&rc);
|
||||||
|
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipRtsp::Teardown(const char *uriP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (handleM && !isempty(uriP)) {
|
||||||
|
long rc = 0;
|
||||||
|
cTimeMs processing(0);
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
|
||||||
|
SATIP_CURL_EASY_PERFORM(handleM);
|
||||||
|
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_CLIENT_CSEQ, 1L);
|
||||||
|
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL);
|
||||||
|
|
||||||
|
result = ValidateLatestResponse(&rc);
|
||||||
|
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipRtsp::ValidateLatestResponse(long *rcP)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (handleM) {
|
||||||
|
long rc = 0;
|
||||||
|
CURLcode res = CURLE_OK;
|
||||||
|
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
||||||
|
if (rc == 200)
|
||||||
|
result = true;
|
||||||
|
else if (rc != 0) {
|
||||||
|
char *url = NULL;
|
||||||
|
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
|
||||||
|
error("Detected invalid status code %ld: %s [device %d]", rc, url, tunerM.GetId());
|
||||||
|
}
|
||||||
|
if (rcP)
|
||||||
|
*rcP = rc;
|
||||||
|
}
|
||||||
|
debug1("%s result=%s [device %d]", __PRETTY_FUNCTION__, result ? "ok" : "failed", tunerM.GetId());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
58
rtsp.h
Normal file
58
rtsp.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* rtsp.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_RTSP_H
|
||||||
|
#define __SATIP_RTSP_H
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <curl/easy.h>
|
||||||
|
|
||||||
|
#ifndef CURLOPT_RTSPHEADER
|
||||||
|
#error "libcurl is missing required RTSP support"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tunerif.h"
|
||||||
|
|
||||||
|
class cSatipRtsp {
|
||||||
|
private:
|
||||||
|
static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
||||||
|
static size_t WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
||||||
|
static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
eConnectTimeoutMs = 1500, // in milliseconds
|
||||||
|
};
|
||||||
|
enum eCommunicationMode { cmUnicast, cmMulticast };
|
||||||
|
|
||||||
|
cSatipTunerIf &tunerM;
|
||||||
|
eCommunicationMode modeM;
|
||||||
|
CURL *handleM;
|
||||||
|
struct curl_slist *headerListM;
|
||||||
|
|
||||||
|
void Create(void);
|
||||||
|
void Destroy(void);
|
||||||
|
bool ValidateLatestResponse(long *rcP);
|
||||||
|
|
||||||
|
// to prevent copy constructor and assignment
|
||||||
|
cSatipRtsp(const cSatipRtsp&);
|
||||||
|
cSatipRtsp& operator=(const cSatipRtsp&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
cSatipRtsp(cSatipTunerIf &tunerP);
|
||||||
|
virtual ~cSatipRtsp();
|
||||||
|
|
||||||
|
cString RtspUnescapeString(const char *strP);
|
||||||
|
void Reset(void);
|
||||||
|
bool Options(const char *uriP);
|
||||||
|
bool Setup(const char *uriP, int rtpPortP, int rtcpPortP);
|
||||||
|
bool SetSession(const char *sessionP);
|
||||||
|
bool Describe(const char *uriP);
|
||||||
|
bool Play(const char *uriP);
|
||||||
|
bool Teardown(const char *uriP);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SATIP_RTSP_H
|
215
satip.c
215
satip.c
@@ -11,6 +11,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "discover.h"
|
#include "discover.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "poller.h"
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
|
|
||||||
#if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM < 0x072400
|
#if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM < 0x072400
|
||||||
@@ -25,13 +27,16 @@
|
|||||||
#define GITVERSION ""
|
#define GITVERSION ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char VERSION[] = "0.3.3" GITVERSION;
|
const char VERSION[] = "1.0.2" GITVERSION;
|
||||||
static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
|
static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
|
||||||
|
|
||||||
class cPluginSatip : public cPlugin {
|
class cPluginSatip : public cPlugin {
|
||||||
private:
|
private:
|
||||||
unsigned int deviceCountM;
|
unsigned int deviceCountM;
|
||||||
cSatipDiscover *discoverM;
|
cSatipDiscoverServers *serversM;
|
||||||
|
void ParseServer(const char *paramP);
|
||||||
|
int ParseCicams(const char *valueP, int *cicamsP);
|
||||||
|
int ParseSources(const char *valueP, int *sourcesP);
|
||||||
int ParseFilters(const char *valueP, int *filtersP);
|
int ParseFilters(const char *valueP, int *filtersP);
|
||||||
public:
|
public:
|
||||||
cPluginSatip(void);
|
cPluginSatip(void);
|
||||||
@@ -58,9 +63,9 @@ public:
|
|||||||
|
|
||||||
cPluginSatip::cPluginSatip(void)
|
cPluginSatip::cPluginSatip(void)
|
||||||
: deviceCountM(1),
|
: deviceCountM(1),
|
||||||
discoverM(NULL)
|
serversM(NULL)
|
||||||
{
|
{
|
||||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
// Initialize any member variables here.
|
// Initialize any member variables here.
|
||||||
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
|
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
|
||||||
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
|
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
|
||||||
@@ -68,53 +73,78 @@ cPluginSatip::cPluginSatip(void)
|
|||||||
|
|
||||||
cPluginSatip::~cPluginSatip()
|
cPluginSatip::~cPluginSatip()
|
||||||
{
|
{
|
||||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
// Clean up after yourself!
|
// Clean up after yourself!
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *cPluginSatip::CommandLineHelp(void)
|
const char *cPluginSatip::CommandLineHelp(void)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Return a string that describes all known command line options.
|
// Return a string that describes all known command line options.
|
||||||
return " -d <num>, --devices=<number> number of devices to be created\n";
|
return " -d <num>, --devices=<number> set number of devices to be created\n"
|
||||||
|
" -t <mode>, --trace=<mode> set the tracing mode\n"
|
||||||
|
" -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>|<model2>|<desc2>\n"
|
||||||
|
" define hard-coded SAT>IP server(s)"
|
||||||
|
" -S, --single set the single model server mode on\n"
|
||||||
|
" -n, --noquirks disable all the server quirks\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cPluginSatip::ProcessArgs(int argc, char *argv[])
|
bool cPluginSatip::ProcessArgs(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Implement command line argument processing here if applicable.
|
// Implement command line argument processing here if applicable.
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
{ "devices", required_argument, NULL, 'd' },
|
{ "devices", required_argument, NULL, 'd' },
|
||||||
{ NULL, no_argument, NULL, 0 }
|
{ "trace", required_argument, NULL, 't' },
|
||||||
|
{ "server", required_argument, NULL, 's' },
|
||||||
|
{ "single", no_argument, NULL, 'S' },
|
||||||
|
{ "noquirks", no_argument, NULL, 'n' },
|
||||||
|
{ NULL, no_argument, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cString server;
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) {
|
while ((c = getopt_long(argc, argv, "d:t:s:Sn", long_options, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'd':
|
case 'd':
|
||||||
deviceCountM = atoi(optarg);
|
deviceCountM = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
SatipConfig.SetTraceMode(strtol(optarg, NULL, 0));
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
server = optarg;
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
SatipConfig.SetUseSingleModelServers(true);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
SatipConfig.SetDisableServerQuirks(true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// this must be done after all parameters are parsed
|
||||||
|
if (!isempty(*server))
|
||||||
|
ParseServer(*server);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cPluginSatip::Initialize(void)
|
bool cPluginSatip::Initialize(void)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Initialize any background activities the plugin shall perform.
|
// Initialize any background activities the plugin shall perform.
|
||||||
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
|
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
|
||||||
error("Unable to initialize CURL");
|
error("Unable to initialize CURL");
|
||||||
SatipConfig.SetConfigDirectory(cPlugin::ResourceDirectory(PLUGIN_NAME_I18N));
|
cSatipPoller::GetInstance()->Initialize();
|
||||||
cSatipDiscover::GetInstance()->Initialize();
|
cSatipDiscover::GetInstance()->Initialize(serversM);
|
||||||
return cSatipDevice::Initialize(deviceCountM);
|
return cSatipDevice::Initialize(deviceCountM);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cPluginSatip::Start(void)
|
bool cPluginSatip::Start(void)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Start any background activities the plugin shall perform.
|
// Start any background activities the plugin shall perform.
|
||||||
curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
|
curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
|
||||||
cString info = cString::sprintf("Using CURL %s", data->version);
|
cString info = cString::sprintf("Using CURL %s", data->version);
|
||||||
@@ -129,63 +159,142 @@ bool cPluginSatip::Start(void)
|
|||||||
|
|
||||||
void cPluginSatip::Stop(void)
|
void cPluginSatip::Stop(void)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Stop any background activities the plugin is performing.
|
// Stop any background activities the plugin is performing.
|
||||||
cSatipDevice::Shutdown();
|
cSatipDevice::Shutdown();
|
||||||
cSatipDiscover::GetInstance()->Destroy();
|
cSatipDiscover::GetInstance()->Destroy();
|
||||||
|
cSatipPoller::GetInstance()->Destroy();
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cPluginSatip::Housekeeping(void)
|
void cPluginSatip::Housekeeping(void)
|
||||||
{
|
{
|
||||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
// Perform any cleanup or other regular tasks.
|
// Perform any cleanup or other regular tasks.
|
||||||
}
|
}
|
||||||
|
|
||||||
void cPluginSatip::MainThreadHook(void)
|
void cPluginSatip::MainThreadHook(void)
|
||||||
{
|
{
|
||||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
// Perform actions in the context of the main program thread.
|
// Perform actions in the context of the main program thread.
|
||||||
// WARNING: Use with great care - see PLUGINS.html!
|
// WARNING: Use with great care - see PLUGINS.html!
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cPluginSatip::Active(void)
|
cString cPluginSatip::Active(void)
|
||||||
{
|
{
|
||||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
// Return a message string if shutdown should be postponed
|
// Return a message string if shutdown should be postponed
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t cPluginSatip::WakeupTime(void)
|
time_t cPluginSatip::WakeupTime(void)
|
||||||
{
|
{
|
||||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
// Return custom wakeup time for shutdown script
|
// Return custom wakeup time for shutdown script
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cOsdObject *cPluginSatip::MainMenuAction(void)
|
cOsdObject *cPluginSatip::MainMenuAction(void)
|
||||||
{
|
{
|
||||||
//debug("cPluginSatip::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
// Perform the action when selected from the main VDR menu.
|
// Perform the action when selected from the main VDR menu.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cMenuSetupPage *cPluginSatip::SetupMenu(void)
|
cMenuSetupPage *cPluginSatip::SetupMenu(void)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Return a setup menu in case the plugin supports one.
|
// Return a setup menu in case the plugin supports one.
|
||||||
return new cSatipPluginSetup();
|
return new cSatipPluginSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cPluginSatip::ParseServer(const char *paramP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s)", __PRETTY_FUNCTION__, paramP);
|
||||||
|
int n = 0;
|
||||||
|
char *s, *p = strdup(paramP);
|
||||||
|
char *r = strtok_r(p, ";", &s);
|
||||||
|
while (r) {
|
||||||
|
r = skipspace(r);
|
||||||
|
debug3("%s server[%d]=%s", __PRETTY_FUNCTION__, n, r);
|
||||||
|
cString serverAddr, serverModel, serverDescription;
|
||||||
|
int n2 = 0;
|
||||||
|
char *s2, *p2 = r;
|
||||||
|
char *r2 = strtok_r(p2, "|", &s2);
|
||||||
|
while (r2) {
|
||||||
|
debug3("%s param[%d]=%s", __PRETTY_FUNCTION__, n2, r2);
|
||||||
|
switch (n2++) {
|
||||||
|
case 0:
|
||||||
|
serverAddr = r2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
serverModel = r2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
serverDescription = r2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r2 = strtok_r(NULL, "|", &s2);
|
||||||
|
}
|
||||||
|
if (*serverAddr && *serverModel && *serverDescription) {
|
||||||
|
debug1("%s ipaddr=%s model=%s desc=%s", __PRETTY_FUNCTION__, *serverAddr, *serverModel, *serverDescription);
|
||||||
|
if (!serversM)
|
||||||
|
serversM = new cSatipDiscoverServers();
|
||||||
|
serversM->Add(new cSatipDiscoverServer(*serverAddr, *serverModel, *serverDescription));
|
||||||
|
}
|
||||||
|
++n;
|
||||||
|
r = strtok_r(NULL, ";", &s);
|
||||||
|
}
|
||||||
|
FREE_POINTER(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPluginSatip::ParseCicams(const char *valueP, int *cicamsP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP);
|
||||||
|
int n = 0;
|
||||||
|
char *s, *p = strdup(valueP);
|
||||||
|
char *r = strtok_r(p, " ", &s);
|
||||||
|
while (r) {
|
||||||
|
r = skipspace(r);
|
||||||
|
debug3("%s cicams[%d]=%s", __PRETTY_FUNCTION__, n, r);
|
||||||
|
if (n < MAX_CICAM_COUNT) {
|
||||||
|
cicamsP[n++] = atoi(r);
|
||||||
|
}
|
||||||
|
r = strtok_r(NULL, " ", &s);
|
||||||
|
}
|
||||||
|
FREE_POINTER(p);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPluginSatip::ParseSources(const char *valueP, int *sourcesP)
|
||||||
|
{
|
||||||
|
debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP);
|
||||||
|
int n = 0;
|
||||||
|
char *s, *p = strdup(valueP);
|
||||||
|
char *r = strtok_r(p, " ", &s);
|
||||||
|
while (r) {
|
||||||
|
r = skipspace(r);
|
||||||
|
debug3("%s sources[%d]=%s", __PRETTY_FUNCTION__, n, r);
|
||||||
|
if (n < MAX_DISABLED_SOURCES_COUNT) {
|
||||||
|
sourcesP[n++] = cSource::FromString(r);
|
||||||
|
}
|
||||||
|
r = strtok_r(NULL, " ", &s);
|
||||||
|
}
|
||||||
|
FREE_POINTER(p);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
int cPluginSatip::ParseFilters(const char *valueP, int *filtersP)
|
int cPluginSatip::ParseFilters(const char *valueP, int *filtersP)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s(%s)", __FUNCTION__, valueP);
|
debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP);
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (valueP && *valueP && (n < SECTION_FILTER_TABLE_SIZE)) {
|
while (valueP && *valueP && (n < SECTION_FILTER_TABLE_SIZE)) {
|
||||||
strn0cpy(buffer, valueP, sizeof(buffer));
|
strn0cpy(buffer, valueP, sizeof(buffer));
|
||||||
int i = atoi(buffer);
|
int i = atoi(buffer);
|
||||||
//debug("cPluginSatip::%s(): filters[%d]=%d", __FUNCTION__, n, i);
|
debug3("%s filters[%d]=%d", __PRETTY_FUNCTION__, n, i);
|
||||||
if (i >= 0)
|
if (i >= 0)
|
||||||
filtersP[n++] = i;
|
filtersP[n++] = i;
|
||||||
if ((valueP = strchr(valueP, ' ')) != NULL)
|
if ((valueP = strchr(valueP, ' ')) != NULL)
|
||||||
@@ -196,15 +305,33 @@ int cPluginSatip::ParseFilters(const char *valueP, int *filtersP)
|
|||||||
|
|
||||||
bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
|
bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Parse your own setup parameters and store their values.
|
// Parse your own setup parameters and store their values.
|
||||||
if (!strcasecmp(nameP, "OperatingMode"))
|
if (!strcasecmp(nameP, "OperatingMode"))
|
||||||
SatipConfig.SetOperatingMode(atoi(valueP));
|
SatipConfig.SetOperatingMode(atoi(valueP));
|
||||||
|
else if (!strcasecmp(nameP, "EnableCIExtension"))
|
||||||
|
SatipConfig.SetCIExtension(atoi(valueP));
|
||||||
|
else if (!strcasecmp(nameP, "CICAM")) {
|
||||||
|
int Cicams[MAX_CICAM_COUNT];
|
||||||
|
for (unsigned int i = 0; i < ELEMENTS(Cicams); ++i)
|
||||||
|
Cicams[i] = 0;
|
||||||
|
unsigned int CicamsCount = ParseCicams(valueP, Cicams);
|
||||||
|
for (unsigned int i = 0; i < CicamsCount; ++i)
|
||||||
|
SatipConfig.SetCICAM(i, Cicams[i]);
|
||||||
|
}
|
||||||
else if (!strcasecmp(nameP, "EnableEITScan"))
|
else if (!strcasecmp(nameP, "EnableEITScan"))
|
||||||
SatipConfig.SetEITScan(atoi(valueP));
|
SatipConfig.SetEITScan(atoi(valueP));
|
||||||
|
else if (!strcasecmp(nameP, "DisabledSources")) {
|
||||||
|
int DisabledSources[MAX_DISABLED_SOURCES_COUNT];
|
||||||
|
for (unsigned int i = 0; i < ELEMENTS(DisabledSources); ++i)
|
||||||
|
DisabledSources[i] = cSource::stNone;
|
||||||
|
unsigned int DisabledSourcesCount = ParseSources(valueP, DisabledSources);
|
||||||
|
for (unsigned int i = 0; i < DisabledSourcesCount; ++i)
|
||||||
|
SatipConfig.SetDisabledSources(i, DisabledSources[i]);
|
||||||
|
}
|
||||||
else if (!strcasecmp(nameP, "DisabledFilters")) {
|
else if (!strcasecmp(nameP, "DisabledFilters")) {
|
||||||
int DisabledFilters[SECTION_FILTER_TABLE_SIZE];
|
int DisabledFilters[SECTION_FILTER_TABLE_SIZE];
|
||||||
for (unsigned int i = 0; i < ARRAY_SIZE(DisabledFilters); ++i)
|
for (unsigned int i = 0; i < ELEMENTS(DisabledFilters); ++i)
|
||||||
DisabledFilters[i] = -1;
|
DisabledFilters[i] = -1;
|
||||||
unsigned int DisabledFiltersCount = ParseFilters(valueP, DisabledFilters);
|
unsigned int DisabledFiltersCount = ParseFilters(valueP, DisabledFilters);
|
||||||
for (unsigned int i = 0; i < DisabledFiltersCount; ++i)
|
for (unsigned int i = 0; i < DisabledFiltersCount; ++i)
|
||||||
@@ -217,13 +344,13 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP)
|
|||||||
|
|
||||||
bool cPluginSatip::Service(const char *idP, void *dataP)
|
bool cPluginSatip::Service(const char *idP, void *dataP)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char **cPluginSatip::SVDRPHelpPages(void)
|
const char **cPluginSatip::SVDRPHelpPages(void)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
static const char *HelpPages[] = {
|
static const char *HelpPages[] = {
|
||||||
"INFO [ <page> ] [ <card index> ]\n"
|
"INFO [ <page> ] [ <card index> ]\n"
|
||||||
" Prints SAT>IP device information and statistics.\n"
|
" Prints SAT>IP device information and statistics.\n"
|
||||||
@@ -233,10 +360,16 @@ const char **cPluginSatip::SVDRPHelpPages(void)
|
|||||||
" Toggles between bit or byte information mode.\n",
|
" Toggles between bit or byte information mode.\n",
|
||||||
"LIST\n"
|
"LIST\n"
|
||||||
" Lists active SAT>IP servers.\n",
|
" Lists active SAT>IP servers.\n",
|
||||||
|
"SCAN\n"
|
||||||
|
" Scans active SAT>IP servers.\n",
|
||||||
|
"STAT\n"
|
||||||
|
" Lists status information of SAT>IP devices.\n",
|
||||||
"CONT\n"
|
"CONT\n"
|
||||||
" Shows SAT>IP device count.\n",
|
" Shows SAT>IP device count.\n",
|
||||||
"OPER\n"
|
"OPER\n"
|
||||||
" Toggles operating mode of SAT>IP devices.\n",
|
" Toggles operating mode of SAT>IP devices.\n",
|
||||||
|
"TRAC [ <mode> ]\n"
|
||||||
|
" Gets and/or sets used tracing mode.\n",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
return HelpPages;
|
return HelpPages;
|
||||||
@@ -244,7 +377,7 @@ const char **cPluginSatip::SVDRPHelpPages(void)
|
|||||||
|
|
||||||
cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, int &replyCodeP)
|
cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, int &replyCodeP)
|
||||||
{
|
{
|
||||||
debug("cPluginSatip::%s(%s, %s)", __FUNCTION__, commandP, optionP);
|
debug1("%s (%s, %s,)", __PRETTY_FUNCTION__, commandP, optionP);
|
||||||
if (strcasecmp(commandP, "INFO") == 0) {
|
if (strcasecmp(commandP, "INFO") == 0) {
|
||||||
int index = cDevice::ActualDevice()->CardIndex();
|
int index = cDevice::ActualDevice()->CardIndex();
|
||||||
int page = SATIP_DEVICE_INFO_ALL;
|
int page = SATIP_DEVICE_INFO_ALL;
|
||||||
@@ -271,13 +404,13 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
replyCodeP = 550; // Requested action not taken
|
replyCodeP = 550; // Requested action not taken
|
||||||
return cString("SAT>IP information not available!");
|
return cString("SATIP information not available!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcasecmp(commandP, "MODE") == 0) {
|
else if (strcasecmp(commandP, "MODE") == 0) {
|
||||||
unsigned int mode = !SatipConfig.GetUseBytes();
|
unsigned int mode = !SatipConfig.GetUseBytes();
|
||||||
SatipConfig.SetUseBytes(mode);
|
SatipConfig.SetUseBytes(mode);
|
||||||
return cString::sprintf("SAT>IP information mode: %s\n", mode ? "bytes" : "bits");
|
return cString::sprintf("SATIP information mode: %s\n", mode ? "bytes" : "bits");
|
||||||
}
|
}
|
||||||
else if (strcasecmp(commandP, "LIST") == 0) {
|
else if (strcasecmp(commandP, "LIST") == 0) {
|
||||||
cString list = cSatipDiscover::GetInstance()->GetServerList();
|
cString list = cSatipDiscover::GetInstance()->GetServerList();
|
||||||
@@ -286,11 +419,18 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
replyCodeP = 550; // Requested action not taken
|
replyCodeP = 550; // Requested action not taken
|
||||||
return cString("No SAT>IP devices detected!");
|
return cString("No SATIP servers detected!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (strcasecmp(commandP, "SCAN") == 0) {
|
||||||
|
cSatipDiscover::GetInstance()->TriggerScan();
|
||||||
|
return cString("SATIP server scan requested");
|
||||||
|
}
|
||||||
|
else if (strcasecmp(commandP, "STAT") == 0) {
|
||||||
|
return cSatipDevice::GetSatipStatus();
|
||||||
|
}
|
||||||
else if (strcasecmp(commandP, "CONT") == 0) {
|
else if (strcasecmp(commandP, "CONT") == 0) {
|
||||||
return cString::sprintf("SAT>IP device count: %u", cSatipDevice::Count());
|
return cString::sprintf("SATIP device count: %u", cSatipDevice::Count());
|
||||||
}
|
}
|
||||||
else if (strcasecmp(commandP, "OPER") == 0) {
|
else if (strcasecmp(commandP, "OPER") == 0) {
|
||||||
cString mode;
|
cString mode;
|
||||||
@@ -312,7 +452,12 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in
|
|||||||
mode = "unknown";
|
mode = "unknown";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return cString::sprintf("SAT>IP operating mode: %s\n", *mode);
|
return cString::sprintf("SATIP operating mode: %s\n", *mode);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(commandP, "TRAC") == 0) {
|
||||||
|
if (optionP && *optionP)
|
||||||
|
SatipConfig.SetTraceMode(strtol(optionP, NULL, 0));
|
||||||
|
return cString::sprintf("SATIP tracing mode: 0x%04X\n", SatipConfig.GetTraceMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
#include "sectionfilter.h"
|
#include "sectionfilter.h"
|
||||||
|
|
||||||
cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP)
|
cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP)
|
||||||
@@ -20,7 +21,7 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
|
|||||||
ringBufferM(new cRingBufferFrame(eDmxMaxSectionCount * eDmxMaxSectionSize)),
|
ringBufferM(new cRingBufferFrame(eDmxMaxSectionCount * eDmxMaxSectionSize)),
|
||||||
deviceIndexM(deviceIndexP)
|
deviceIndexM(deviceIndexP)
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionFilter::%s(%d, %d)", __FUNCTION__, deviceIndexM, pidM);
|
debug16("%s (%d, %d, %d, %d) [device %d]", __PRETTY_FUNCTION__, deviceIndexM, pidM, tidP, maskP, deviceIndexM);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(secBufBaseM, 0, sizeof(secBufBaseM));
|
memset(secBufBaseM, 0, sizeof(secBufBaseM));
|
||||||
@@ -37,10 +38,10 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
|
|||||||
for (i = 0; i < eDmxMaxFilterSize; ++i)
|
for (i = 0; i < eDmxMaxFilterSize; ++i)
|
||||||
filterValueM[i] ^= 0xFF;
|
filterValueM[i] ^= 0xFF;
|
||||||
|
|
||||||
uint8_t mask, mode, doneq = 0;
|
uint8_t doneq = 0;
|
||||||
for (i = 0; i < eDmxMaxFilterSize; ++i) {
|
for (i = 0; i < eDmxMaxFilterSize; ++i) {
|
||||||
mode = filterModeM[i];
|
uint8_t mode = filterModeM[i];
|
||||||
mask = filterMaskM[i];
|
uint8_t mask = filterMaskM[i];
|
||||||
maskAndModeM[i] = (uint8_t)(mask & mode);
|
maskAndModeM[i] = (uint8_t)(mask & mode);
|
||||||
maskAndNotModeM[i] = (uint8_t)(mask & ~mode);
|
maskAndNotModeM[i] = (uint8_t)(mask & ~mode);
|
||||||
doneq |= maskAndNotModeM[i];
|
doneq |= maskAndNotModeM[i];
|
||||||
@@ -61,7 +62,7 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
|
|||||||
|
|
||||||
cSatipSectionFilter::~cSatipSectionFilter()
|
cSatipSectionFilter::~cSatipSectionFilter()
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionFilter::%s(%d, %d)", __FUNCTION__, deviceIndexM, pidM);
|
debug16("%s pid=%d [device %d]", __PRETTY_FUNCTION__, pidM, deviceIndexM);
|
||||||
int tmp = socketM[1];
|
int tmp = socketM[1];
|
||||||
socketM[1] = -1;
|
socketM[1] = -1;
|
||||||
if (tmp >= 0)
|
if (tmp >= 0)
|
||||||
@@ -117,7 +118,7 @@ inline int cSatipSectionFilter::Feed(void)
|
|||||||
|
|
||||||
int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
|
int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
|
||||||
{
|
{
|
||||||
uint16_t limit, seclen, n;
|
uint16_t limit, n;
|
||||||
|
|
||||||
if (tsFeedpM >= eDmxMaxSectionFeedSize)
|
if (tsFeedpM >= eDmxMaxSectionFeedSize)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -139,7 +140,7 @@ int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
|
|||||||
secBufM = secBufBaseM + secBufpM;
|
secBufM = secBufBaseM + secBufpM;
|
||||||
|
|
||||||
for (n = 0; secBufpM + 2 < limit; ++n) {
|
for (n = 0; secBufpM + 2 < limit; ++n) {
|
||||||
seclen = GetLength(secBufM);
|
uint16_t seclen = GetLength(secBufM);
|
||||||
if ((seclen <= 0) || (seclen > eDmxMaxSectionSize) || ((seclen + secBufpM) > limit))
|
if ((seclen <= 0) || (seclen > eDmxMaxSectionSize) || ((seclen + secBufpM) > limit))
|
||||||
return 0;
|
return 0;
|
||||||
secLenM = seclen;
|
secLenM = seclen;
|
||||||
@@ -231,12 +232,12 @@ bool cSatipSectionFilter::Send(void)
|
|||||||
|
|
||||||
|
|
||||||
cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP)
|
cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP)
|
||||||
: cThread("SAT>IP section handler"),
|
: cThread(cString::sprintf("SATIP#%d section handler", deviceIndexP)),
|
||||||
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SAT>IP SECTION HANDLER %d", deviceIndexP))),
|
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SATIP %d section handler", deviceIndexP))),
|
||||||
mutexM(),
|
mutexM(),
|
||||||
deviceIndexM(deviceIndexP)
|
deviceIndexM(deviceIndexP)
|
||||||
{
|
{
|
||||||
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
|
debug1("%s (%d, %d) [device %d]", __PRETTY_FUNCTION__, deviceIndexM, bufferLenP, deviceIndexM);
|
||||||
|
|
||||||
// Initialize filter pointers
|
// Initialize filter pointers
|
||||||
memset(filtersM, 0, sizeof(filtersM));
|
memset(filtersM, 0, sizeof(filtersM));
|
||||||
@@ -247,14 +248,14 @@ cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigne
|
|||||||
ringBufferM->SetIoThrottle();
|
ringBufferM->SetIoThrottle();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
error("Failed to allocate buffer for section filter handler (device=%d): ", deviceIndexM);
|
error("Failed to allocate buffer for section filter handler [device=%d]", deviceIndexM);
|
||||||
|
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
|
cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
|
||||||
{
|
{
|
||||||
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
// Stop thread
|
// Stop thread
|
||||||
if (Running())
|
if (Running())
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
@@ -268,7 +269,7 @@ cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
|
|||||||
|
|
||||||
void cSatipSectionFilterHandler::Action(void)
|
void cSatipSectionFilterHandler::Action(void)
|
||||||
{
|
{
|
||||||
debug("cSatipSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM);
|
debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
// Do the thread loop
|
// Do the thread loop
|
||||||
while (Running()) {
|
while (Running()) {
|
||||||
@@ -299,7 +300,7 @@ void cSatipSectionFilterHandler::Action(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ringBufferM->Del(len);
|
ringBufferM->Del(len);
|
||||||
debug("cSatipSectionFilterHandler::%s(%d): Skipped %d bytes to sync on TS packet", __FUNCTION__, deviceIndexM, len);
|
debug1("%s Skipped %d bytes to sync on TS packet [device %d]", __PRETTY_FUNCTION__, len, deviceIndexM);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Process TS packet through all filters
|
// Process TS packet through all filters
|
||||||
@@ -315,12 +316,12 @@ void cSatipSectionFilterHandler::Action(void)
|
|||||||
}
|
}
|
||||||
cCondWait::SleepMs(10); // to avoid busy loop and reduce cpu load
|
cCondWait::SleepMs(10); // to avoid busy loop and reduce cpu load
|
||||||
}
|
}
|
||||||
debug("cSatipSectionFilterHandler::%s(%d): exiting", __FUNCTION__, deviceIndexM);
|
debug1("%s Exiting [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipSectionFilterHandler::GetInformation(void)
|
cString cSatipSectionFilterHandler::GetInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
|
||||||
// loop through active section filters
|
// loop through active section filters
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
cString s = "";
|
cString s = "";
|
||||||
@@ -339,9 +340,9 @@ cString cSatipSectionFilterHandler::GetInformation(void)
|
|||||||
|
|
||||||
bool cSatipSectionFilterHandler::Delete(unsigned int indexP)
|
bool cSatipSectionFilterHandler::Delete(unsigned int indexP)
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d): index=%d", __FUNCTION__, deviceIndexM, indexP);
|
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);
|
||||||
if ((indexP < eMaxSecFilterCount) && filtersM[indexP]) {
|
if ((indexP < eMaxSecFilterCount) && filtersM[indexP]) {
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d): found %d", __FUNCTION__, deviceIndexM, indexP);
|
debug8("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM);
|
||||||
cSatipSectionFilter *tmp = filtersM[indexP];
|
cSatipSectionFilter *tmp = filtersM[indexP];
|
||||||
filtersM[indexP] = NULL;
|
filtersM[indexP] = NULL;
|
||||||
delete tmp;
|
delete tmp;
|
||||||
@@ -352,7 +353,7 @@ bool cSatipSectionFilterHandler::Delete(unsigned int indexP)
|
|||||||
|
|
||||||
bool cSatipSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const
|
bool cSatipSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d): pid=%d tid=%02X mask=%02X", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
|
debug16("%s (%d, %02X, %02X) [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, deviceIndexM);
|
||||||
// loop through section filter table
|
// loop through section filter table
|
||||||
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
||||||
int index = SatipConfig.GetDisabledFilters(i);
|
int index = SatipConfig.GetDisabledFilters(i);
|
||||||
@@ -360,7 +361,7 @@ bool cSatipSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char
|
|||||||
if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) &&
|
if ((index >= 0) && (index < SECTION_FILTER_TABLE_SIZE) &&
|
||||||
(section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) &&
|
(section_filter_table[index].pid == pidP) && (section_filter_table[index].tid == tidP) &&
|
||||||
(section_filter_table[index].mask == maskP)) {
|
(section_filter_table[index].mask == maskP)) {
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d): found %s", __FUNCTION__, deviceIndexM, section_filter_table[index].description);
|
debug8("%s Found %s [device %d]", __PRETTY_FUNCTION__, section_filter_table[index].description, deviceIndexM);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,7 +370,6 @@ bool cSatipSectionFilterHandler::IsBlackListed(u_short pidP, u_char tidP, u_char
|
|||||||
|
|
||||||
int cSatipSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
|
int cSatipSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
|
||||||
{
|
{
|
||||||
// Lock
|
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
// Blacklist check, refuse certain filters
|
// Blacklist check, refuse certain filters
|
||||||
if (IsBlackListed(pidP, tidP, maskP))
|
if (IsBlackListed(pidP, tidP, maskP))
|
||||||
@@ -378,7 +378,7 @@ int cSatipSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
|
|||||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||||
if (!filtersM[i]) {
|
if (!filtersM[i]) {
|
||||||
filtersM[i] = new cSatipSectionFilter(deviceIndexM, pidP, tidP, maskP);
|
filtersM[i] = new cSatipSectionFilter(deviceIndexM, pidP, tidP, maskP);
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d): pid=%d tid=%02X mask=%02X handle=%d index=%u", __FUNCTION__, deviceIndexM, pidP, tidP, maskP, filtersM[i]->GetFd(), i);
|
debug16("%s (%d, %02X, %02X) handle=%d index=%u [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, filtersM[i]->GetFd(), i, deviceIndexM);
|
||||||
return filtersM[i]->GetFd();
|
return filtersM[i]->GetFd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,12 +388,11 @@ int cSatipSectionFilterHandler::Open(u_short pidP, u_char tidP, u_char maskP)
|
|||||||
|
|
||||||
void cSatipSectionFilterHandler::Close(int handleP)
|
void cSatipSectionFilterHandler::Close(int handleP)
|
||||||
{
|
{
|
||||||
// Lock
|
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
// Search the filter for deletion
|
// Search the filter for deletion
|
||||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||||
if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
|
if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d): pid=%d handle=%d index=%u", __FUNCTION__, deviceIndexM, filtersM[i]->GetPid(), filtersM[i]->GetFd(), i);
|
debug8("%s (%d) pid=%d index=%u [device %d]", __PRETTY_FUNCTION__, handleP, filtersM[i]->GetPid(), i, deviceIndexM);
|
||||||
Delete(i);
|
Delete(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -402,12 +401,11 @@ void cSatipSectionFilterHandler::Close(int handleP)
|
|||||||
|
|
||||||
int cSatipSectionFilterHandler::GetPid(int handleP)
|
int cSatipSectionFilterHandler::GetPid(int handleP)
|
||||||
{
|
{
|
||||||
// Lock
|
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
// Search the filter for data
|
// Search the filter for data
|
||||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||||
if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
|
if (filtersM[i] && (handleP == filtersM[i]->GetFd())) {
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d): pid=%d handle=%d index=%u", __FUNCTION__, deviceIndexM, filtersM[i]->GetPid(), filtersM[i]->GetFd(), i);
|
debug8("%s (%d) pid=%d index=%u [device %d]", __PRETTY_FUNCTION__, handleP, filtersM[i]->GetPid(), i, deviceIndexM);
|
||||||
return filtersM[i]->GetPid();
|
return filtersM[i]->GetPid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -416,7 +414,7 @@ int cSatipSectionFilterHandler::GetPid(int handleP)
|
|||||||
|
|
||||||
void cSatipSectionFilterHandler::Write(uchar *bufferP, int lengthP)
|
void cSatipSectionFilterHandler::Write(uchar *bufferP, int lengthP)
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionFilterHandler::%s(%d): length=%d", __FUNCTION__, deviceIndexM, lengthP);
|
debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIndexM);
|
||||||
// Fill up the buffer
|
// Fill up the buffer
|
||||||
if (ringBufferM) {
|
if (ringBufferM) {
|
||||||
int len = ringBufferM->Put(bufferP, lengthP);
|
int len = ringBufferM->Put(bufferP, lengthP);
|
||||||
|
118
server.c
118
server.c
@@ -7,62 +7,78 @@
|
|||||||
|
|
||||||
#include <vdr/sources.h>
|
#include <vdr/sources.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "log.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
// --- cSatipServer -----------------------------------------------------------
|
// --- cSatipServer -----------------------------------------------------------
|
||||||
|
|
||||||
cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const char *modelP)
|
cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char *descriptionP)
|
||||||
: addressM(addressP),
|
: addressM((addressP && *addressP) ? addressP : "0.0.0.0"),
|
||||||
descriptionM(descriptionP),
|
modelM((modelP && *modelP) ? modelP : "DVBS-1"),
|
||||||
modelM(modelP),
|
descriptionM(!isempty(descriptionP) ? descriptionP : "MyBrokenHardware"),
|
||||||
modelTypeM(eSatipModelTypeNone),
|
modelTypeM(eSatipModelTypeNone),
|
||||||
quirkM(eSatipQuirkNone),
|
quirkM(eSatipQuirkNone),
|
||||||
useCountM(0),
|
useCountM(0),
|
||||||
|
transponderM(0),
|
||||||
createdM(time(NULL)),
|
createdM(time(NULL)),
|
||||||
lastSeenM(0)
|
lastSeenM(0)
|
||||||
{
|
{
|
||||||
memset(modelCountM, 0, sizeof(modelCountM));
|
memset(modelCountM, 0, sizeof(modelCountM));
|
||||||
if (isempty(*modelM))
|
if (!SatipConfig.GetDisableServerQuirks()) {
|
||||||
modelM = "DVBS-1";
|
debug3("%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM);
|
||||||
// These devices contain a session id bug:
|
// These devices contain a session id bug:
|
||||||
// Inverto Airscreen Server IDL 400 ?
|
// Inverto Airscreen Server IDL 400 ?
|
||||||
// Telestar Digibit R1 ?
|
// Elgato EyeTV Netstream 4Sat ?
|
||||||
// Elgato EyeTV Netstream 4Sat ?
|
if (strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
|
||||||
if (!isempty(*descriptionM) &&
|
strstr(*descriptionM, "DIGIBIT") || // Telestar Digibit R1
|
||||||
(strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
|
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
|
||||||
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
|
)
|
||||||
))
|
quirkM |= eSatipQuirkSessionId;
|
||||||
quirkM |= eSatipQuirkSessionId;
|
// These devices contain a play (add/delpids) parameter bug:
|
||||||
|
if (strstr(*descriptionM, "fritzdvbc")) // Fritz!WLAN Repeater DVB-C
|
||||||
|
quirkM |= eSatipQuirkPlayPids;
|
||||||
|
// These devices contain a frontend locking bug:
|
||||||
|
if (strstr(*descriptionM, "fritzdvbc")) // Fritz!WLAN Repeater DVB-C
|
||||||
|
quirkM |= eSatipQuirkForceLock;
|
||||||
|
if (quirkM != eSatipQuirkNone)
|
||||||
|
info("Malfunctioning '%s' server detected! Please, fix the firmware.", *descriptionM);
|
||||||
|
}
|
||||||
|
// These devices support the X_PMT protocol extension
|
||||||
|
if (strstr(*descriptionM, "OctopusNet")) // Digital Devices OctopusNet
|
||||||
|
quirkM |= eSatipQuirkUseXCI;
|
||||||
char *s, *p = strdup(*modelM);
|
char *s, *p = strdup(*modelM);
|
||||||
char *r = strtok_r(p, ",", &s);
|
char *r = strtok_r(p, ",", &s);
|
||||||
while (r) {
|
while (r) {
|
||||||
if (strstr(r, "DVBS2")) {
|
if (strstr(r, "DVBS2-")) {
|
||||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBS2;
|
modelTypeM |= eSatipModelTypeDVBS2;
|
||||||
if (char *c = strstr(r, "-"))
|
if (char *c = strstr(r, "-"))
|
||||||
modelCountM[eSatipModuleDVBS2] = atoi(++c);
|
modelCountM[eSatipModuleDVBS2] = atoi(++c);
|
||||||
else
|
|
||||||
modelCountM[eSatipModuleDVBS2] = 1;
|
|
||||||
}
|
}
|
||||||
if (strstr(r, "DVBT2")) {
|
else if (strstr(r, "DVBT2-")) {
|
||||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBT | cSatipServer::eSatipModelTypeDVBT2;
|
modelTypeM |= eSatipModelTypeDVBT2;
|
||||||
if (char *c = strstr(r, "-"))
|
if (char *c = strstr(r, "-"))
|
||||||
modelCountM[eSatipModuleDVBT2] = atoi(++c);
|
modelCountM[eSatipModuleDVBT2] = atoi(++c);
|
||||||
else
|
modelTypeM |= eSatipModelTypeDVBT;
|
||||||
modelCountM[eSatipModuleDVBT2] = 1;
|
modelCountM[eSatipModuleDVBT] = modelCountM[eSatipModuleDVBT2];
|
||||||
// Add model quirks here
|
|
||||||
if (!isempty(*descriptionM) && strstr(*descriptionM, "OctopusNet"))
|
|
||||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBC;
|
|
||||||
}
|
}
|
||||||
if (strstr(r, "DVBT")) {
|
else if (strstr(r, "DVBT-")) {
|
||||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBT;
|
modelTypeM |= eSatipModelTypeDVBT;
|
||||||
if (char *c = strstr(r, "-"))
|
if (char *c = strstr(r, "-"))
|
||||||
modelCountM[eSatipModuleDVBT] = atoi(++c);
|
modelCountM[eSatipModuleDVBT] = atoi(++c);
|
||||||
else
|
}
|
||||||
modelCountM[eSatipModuleDVBT] = 1;
|
else if (strstr(r, "DVBC2-")) {
|
||||||
// Add model quirks here
|
modelTypeM |= eSatipModelTypeDVBC2;
|
||||||
if (!isempty(*descriptionM) && strstr(*descriptionM, "OctopusNet"))
|
if (char *c = strstr(r, "-"))
|
||||||
modelTypeM |= cSatipServer::eSatipModelTypeDVBC;
|
modelCountM[eSatipModuleDVBC2] = atoi(++c);
|
||||||
|
modelTypeM |= eSatipModelTypeDVBC;
|
||||||
|
modelCountM[eSatipModuleDVBC] = modelCountM[eSatipModuleDVBC2];
|
||||||
|
}
|
||||||
|
else if (strstr(r, "DVBC-")) {
|
||||||
|
modelTypeM |= eSatipModelTypeDVBC;
|
||||||
|
if (char *c = strstr(r, "-"))
|
||||||
|
modelCountM[eSatipModuleDVBC] = atoi(++c);
|
||||||
}
|
}
|
||||||
r = strtok_r(NULL, ",", &s);
|
r = strtok_r(NULL, ",", &s);
|
||||||
}
|
}
|
||||||
@@ -76,7 +92,13 @@ cSatipServer::~cSatipServer()
|
|||||||
int cSatipServer::Compare(const cListObject &listObjectP) const
|
int cSatipServer::Compare(const cListObject &listObjectP) const
|
||||||
{
|
{
|
||||||
const cSatipServer *s = (const cSatipServer *)&listObjectP;
|
const cSatipServer *s = (const cSatipServer *)&listObjectP;
|
||||||
return strcasecmp(*addressM, *s->addressM);
|
int result = strcasecmp(*addressM, *s->addressM);
|
||||||
|
if (!result) {
|
||||||
|
result = strcasecmp(*modelM, *s->modelM);
|
||||||
|
if (!result)
|
||||||
|
result = strcasecmp(*descriptionM, *s->descriptionM);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipServer::Use(bool onOffP)
|
void cSatipServer::Use(bool onOffP)
|
||||||
@@ -98,7 +120,7 @@ cSatipServer *cSatipServers::Find(cSatipServer *serverP)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipServer *cSatipServers::Find(int sourceP, int systemP)
|
cSatipServer *cSatipServers::Find(int sourceP, int transponderP, int systemP)
|
||||||
{
|
{
|
||||||
cSatipServer *result = NULL;
|
cSatipServer *result = NULL;
|
||||||
int model = 0;
|
int model = 0;
|
||||||
@@ -112,6 +134,10 @@ cSatipServer *cSatipServers::Find(int sourceP, int systemP)
|
|||||||
}
|
}
|
||||||
else if (cSource::IsType(sourceP, 'C'))
|
else if (cSource::IsType(sourceP, 'C'))
|
||||||
model |= cSatipServer::eSatipModelTypeDVBC;
|
model |= cSatipServer::eSatipModelTypeDVBC;
|
||||||
|
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||||
|
if (s->Match(model) && s->Used() && (s->Transponder() == transponderP))
|
||||||
|
return s;
|
||||||
|
}
|
||||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||||
if (s->Match(model)) {
|
if (s->Match(model)) {
|
||||||
result = s;
|
result = s;
|
||||||
@@ -123,6 +149,16 @@ cSatipServer *cSatipServers::Find(int sourceP, int systemP)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cSatipServers::SetTransponder(cSatipServer *serverP, int transponderP)
|
||||||
|
{
|
||||||
|
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||||
|
if (s == serverP) {
|
||||||
|
s->SetTransponder(transponderP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cSatipServer *cSatipServers::Update(cSatipServer *serverP)
|
cSatipServer *cSatipServers::Update(cSatipServer *serverP)
|
||||||
{
|
{
|
||||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||||
@@ -148,7 +184,7 @@ void cSatipServers::Cleanup(uint64_t intervalMsP)
|
|||||||
{
|
{
|
||||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||||
if (!intervalMsP || (s->LastSeen() > intervalMsP)) {
|
if (!intervalMsP || (s->LastSeen() > intervalMsP)) {
|
||||||
info("Removing device %s (%s %s)", s->Description(), s->Address(), s->Model());
|
info("Removing server %s (%s %s)", s->Description(), s->Address(), s->Model());
|
||||||
Del(s);
|
Del(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,10 +214,14 @@ int cSatipServers::NumProvidedSystems(void)
|
|||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (cSatipServer *s = First(); s; s = Next(s)) {
|
for (cSatipServer *s = First(); s; s = Next(s)) {
|
||||||
// DVB-S*: qpsk, 8psk
|
// DVB-S2: qpsk, 8psk, 16apsk, 32apsk
|
||||||
count += s->Satellite() * 4;
|
count += s->Satellite() * 4;
|
||||||
// DVB-T*: qpsk, qam16, qam64, qam256
|
// DVB-T2: qpsk, qam16, qam64, qam256
|
||||||
count += (s->Terrestrial2() ? s->Terrestrial2() : s->Terrestrial()) * 4;
|
// DVB-T: qpsk, qam16, qam64
|
||||||
|
count += s->Terrestrial2() ? s->Terrestrial2() * 4 : s->Terrestrial() * 3;
|
||||||
|
// DVB-C2: qam16, qam32, qam64, qam128, qam256
|
||||||
|
// DVB-C: qam64, qam128, qam256
|
||||||
|
count += s->Cable2() ? s->Cable2() * 5 : s->Cable() * 3;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
25
server.h
25
server.h
@@ -16,15 +16,18 @@ private:
|
|||||||
eSatipModuleDVBS2 = 0,
|
eSatipModuleDVBS2 = 0,
|
||||||
eSatipModuleDVBT,
|
eSatipModuleDVBT,
|
||||||
eSatipModuleDVBT2,
|
eSatipModuleDVBT2,
|
||||||
|
eSatipModuleDVBC,
|
||||||
|
eSatipModuleDVBC2,
|
||||||
eSatipModuleCount
|
eSatipModuleCount
|
||||||
};
|
};
|
||||||
cString addressM;
|
cString addressM;
|
||||||
cString descriptionM;
|
|
||||||
cString modelM;
|
cString modelM;
|
||||||
|
cString descriptionM;
|
||||||
int modelCountM[eSatipModuleCount];
|
int modelCountM[eSatipModuleCount];
|
||||||
int modelTypeM;
|
int modelTypeM;
|
||||||
int quirkM;
|
int quirkM;
|
||||||
int useCountM;
|
int useCountM;
|
||||||
|
int transponderM;
|
||||||
time_t createdM;
|
time_t createdM;
|
||||||
cTimeMs lastSeenM;
|
cTimeMs lastSeenM;
|
||||||
|
|
||||||
@@ -32,6 +35,9 @@ public:
|
|||||||
enum eSatipQuirk {
|
enum eSatipQuirk {
|
||||||
eSatipQuirkNone = 0x00,
|
eSatipQuirkNone = 0x00,
|
||||||
eSatipQuirkSessionId = 0x01,
|
eSatipQuirkSessionId = 0x01,
|
||||||
|
eSatipQuirkPlayPids = 0x02,
|
||||||
|
eSatipQuirkForceLock = 0x04,
|
||||||
|
eSatipQuirkUseXCI = 0x08,
|
||||||
eSatipQuirkMask = 0x0F
|
eSatipQuirkMask = 0x0F
|
||||||
};
|
};
|
||||||
enum eSatipModelType {
|
enum eSatipModelType {
|
||||||
@@ -40,20 +46,24 @@ public:
|
|||||||
eSatipModelTypeDVBT = 0x02,
|
eSatipModelTypeDVBT = 0x02,
|
||||||
eSatipModelTypeDVBT2 = 0x04,
|
eSatipModelTypeDVBT2 = 0x04,
|
||||||
eSatipModelTypeDVBC = 0x08,
|
eSatipModelTypeDVBC = 0x08,
|
||||||
eSatipModelTypeMask = 0x0F
|
eSatipModelTypeDVBC2 = 0x10,
|
||||||
|
eSatipModelTypeMask = 0xFF
|
||||||
};
|
};
|
||||||
cSatipServer(const char *addressP, const char *descriptionP, const char *modelP);
|
cSatipServer(const char *addressP, const char *modelP, const char *descriptionP);
|
||||||
virtual ~cSatipServer();
|
virtual ~cSatipServer();
|
||||||
virtual int Compare(const cListObject &listObjectP) const;
|
virtual int Compare(const cListObject &listObjectP) const;
|
||||||
void Use(bool onOffP);
|
void Use(bool onOffP);
|
||||||
|
void SetTransponder(const int transponderP) { transponderM = transponderP; }
|
||||||
|
int Transponder(void) { return transponderM; }
|
||||||
bool Used(void) { return !!useCountM; }
|
bool Used(void) { return !!useCountM; }
|
||||||
const char *Description() { return *descriptionM; }
|
|
||||||
const char *Address() { return *addressM; }
|
const char *Address() { return *addressM; }
|
||||||
const char *Model(void) { return modelM; }
|
const char *Model(void) { return *modelM; }
|
||||||
|
const char *Description() { return *descriptionM; }
|
||||||
bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); }
|
bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); }
|
||||||
int ModelType(void) { return modelTypeM; }
|
int ModelType(void) { return modelTypeM; }
|
||||||
bool Match(int modelP) { return ((modelP & eSatipModelTypeMask) & modelTypeM); }
|
bool Match(int modelP) { return ((modelP & eSatipModelTypeMask) & modelTypeM); }
|
||||||
int Cable() { return Match(eSatipModelTypeDVBC) ? (Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : modelCountM[eSatipModuleDVBT]) : 0; } // an ugly hack
|
int Cable() { return Match(eSatipModelTypeDVBC) ? modelCountM[eSatipModuleDVBC] : 0; }
|
||||||
|
int Cable2() { return Match(eSatipModelTypeDVBC2) ? modelCountM[eSatipModuleDVBC2] : 0; }
|
||||||
int Satellite() { return Match(eSatipModelTypeDVBS2) ? modelCountM[eSatipModuleDVBS2] : 0; }
|
int Satellite() { return Match(eSatipModelTypeDVBS2) ? modelCountM[eSatipModuleDVBS2] : 0; }
|
||||||
int Terrestrial() { return Match(eSatipModelTypeDVBT) ? modelCountM[eSatipModuleDVBT] : 0; }
|
int Terrestrial() { return Match(eSatipModelTypeDVBT) ? modelCountM[eSatipModuleDVBT] : 0; }
|
||||||
int Terrestrial2() { return Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : 0; }
|
int Terrestrial2() { return Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : 0; }
|
||||||
@@ -67,7 +77,8 @@ public:
|
|||||||
class cSatipServers : public cList<cSatipServer> {
|
class cSatipServers : public cList<cSatipServer> {
|
||||||
public:
|
public:
|
||||||
cSatipServer *Find(cSatipServer *serverP);
|
cSatipServer *Find(cSatipServer *serverP);
|
||||||
cSatipServer *Find(int sourceP, int systemP);
|
cSatipServer *Find(int sourceP, int transponderP, int systemP);
|
||||||
|
void SetTransponder(cSatipServer *serverP, int transponderP);
|
||||||
cSatipServer *Update(cSatipServer *serverP);
|
cSatipServer *Update(cSatipServer *serverP);
|
||||||
void Use(cSatipServer *serverP, bool onOffP);
|
void Use(cSatipServer *serverP, bool onOffP);
|
||||||
void Cleanup(uint64_t intervalMsP = 0);
|
void Cleanup(uint64_t intervalMsP = 0);
|
||||||
|
262
setup.c
262
setup.c
@@ -12,8 +12,75 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "discover.h"
|
#include "discover.h"
|
||||||
|
#include "log.h"
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
|
|
||||||
|
// --- cSatipEditSrcItem ------------------------------------------------------
|
||||||
|
// This class is a 99% copy of cMenuEditSrcItem() taken from VDR's menu.c
|
||||||
|
|
||||||
|
class cSatipEditSrcItem : public cMenuEditIntItem {
|
||||||
|
private:
|
||||||
|
const cSource *source;
|
||||||
|
protected:
|
||||||
|
virtual void Set(void);
|
||||||
|
public:
|
||||||
|
cSatipEditSrcItem(const char *Name, int *Value);
|
||||||
|
eOSState ProcessKey(eKeys Key);
|
||||||
|
};
|
||||||
|
|
||||||
|
cSatipEditSrcItem::cSatipEditSrcItem(const char *Name, int *Value)
|
||||||
|
:cMenuEditIntItem(Name, Value, 0)
|
||||||
|
{
|
||||||
|
source = Sources.Get(*Value);
|
||||||
|
if (!source)
|
||||||
|
source = Sources.First();
|
||||||
|
Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipEditSrcItem::Set(void)
|
||||||
|
{
|
||||||
|
if (source)
|
||||||
|
SetValue(cString::sprintf("%s - %s", *cSource::ToString(source->Code()), source->Description()));
|
||||||
|
else
|
||||||
|
cMenuEditIntItem::Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
eOSState cSatipEditSrcItem::ProcessKey(eKeys Key)
|
||||||
|
{
|
||||||
|
eOSState state = cMenuEditItem::ProcessKey(Key);
|
||||||
|
|
||||||
|
if (state == osUnknown) {
|
||||||
|
bool IsRepeat = Key & k_Repeat;
|
||||||
|
Key = NORMALKEY(Key);
|
||||||
|
if (Key == kLeft) { // TODO might want to increase the delta if repeated quickly?
|
||||||
|
if (source) {
|
||||||
|
if (source->Prev())
|
||||||
|
source = (cSource *)source->Prev();
|
||||||
|
else if (!IsRepeat)
|
||||||
|
source = Sources.Last();
|
||||||
|
*value = source->Code();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Key == kRight) {
|
||||||
|
if (source) {
|
||||||
|
if (source->Next())
|
||||||
|
source = (cSource *)source->Next();
|
||||||
|
else if (!IsRepeat)
|
||||||
|
source = Sources.First();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
source = Sources.First();
|
||||||
|
if (source)
|
||||||
|
*value = source->Code();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return state; // we don't call cMenuEditIntItem::ProcessKey(Key) here since we don't accept numerical input
|
||||||
|
Set();
|
||||||
|
state = osContinue;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
// --- cSatipServerInfo -------------------------------------------------------
|
// --- cSatipServerInfo -------------------------------------------------------
|
||||||
|
|
||||||
class cSatipServerInfo : public cOsdMenu
|
class cSatipServerInfo : public cOsdMenu
|
||||||
@@ -22,6 +89,7 @@ private:
|
|||||||
cString addressM;
|
cString addressM;
|
||||||
cString modelM;
|
cString modelM;
|
||||||
cString descriptionM;
|
cString descriptionM;
|
||||||
|
cString ciExtensionM;
|
||||||
uint64_t createdM;
|
uint64_t createdM;
|
||||||
void Setup(void);
|
void Setup(void);
|
||||||
|
|
||||||
@@ -32,10 +100,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP)
|
cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP)
|
||||||
: cOsdMenu(tr("SAT>IP Device"), 20),
|
: cOsdMenu(tr("SAT>IP Server"), 20),
|
||||||
addressM(serverP ? serverP->Address() : "---"),
|
addressM(serverP ? serverP->Address() : "---"),
|
||||||
modelM(serverP ? serverP->Model() : "---"),
|
modelM(serverP ? serverP->Model() : "---"),
|
||||||
descriptionM(serverP ? serverP->Description() : "---"),
|
descriptionM(serverP ? serverP->Description() : "---"),
|
||||||
|
ciExtensionM(serverP && serverP->Quirk(cSatipServer::eSatipQuirkUseXCI) ? trVDR("yes") : trVDR("no")),
|
||||||
createdM(serverP ? serverP->Created() : 0)
|
createdM(serverP ? serverP->Created() : 0)
|
||||||
{
|
{
|
||||||
SetMenuCategory(mcSetupPlugins);
|
SetMenuCategory(mcSetupPlugins);
|
||||||
@@ -52,6 +121,7 @@ void cSatipServerInfo::Setup(void)
|
|||||||
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Address"), *addressM), osUnknown, false));
|
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("Model"), *modelM), osUnknown, false));
|
||||||
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Description"), *descriptionM), osUnknown, false));
|
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Description"), *descriptionM), osUnknown, false));
|
||||||
|
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("CI extension"), *ciExtensionM), osUnknown, false));
|
||||||
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Creation date"), *DayDateTime(createdM)), osUnknown, false));
|
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Creation date"), *DayDateTime(createdM)), osUnknown, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +164,71 @@ void cSatipServerItem::SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, b
|
|||||||
displayMenuP->SetItem(Text(), indexP, currentP, selectableP);
|
displayMenuP->SetItem(Text(), indexP, currentP, selectableP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- cSatipMenuDeviceStatus -------------------------------------------------
|
||||||
|
|
||||||
|
class cSatipMenuDeviceStatus : public cOsdMenu
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
eInfoTimeoutMs = 15000
|
||||||
|
};
|
||||||
|
cString textM;
|
||||||
|
cTimeMs timeoutM;
|
||||||
|
void UpdateInfo();
|
||||||
|
|
||||||
|
public:
|
||||||
|
cSatipMenuDeviceStatus();
|
||||||
|
virtual ~cSatipMenuDeviceStatus();
|
||||||
|
virtual void Display(void);
|
||||||
|
virtual eOSState ProcessKey(eKeys keyP);
|
||||||
|
};
|
||||||
|
|
||||||
|
cSatipMenuDeviceStatus::cSatipMenuDeviceStatus()
|
||||||
|
: cOsdMenu(tr("SAT>IP Device Status")),
|
||||||
|
textM(""),
|
||||||
|
timeoutM()
|
||||||
|
{
|
||||||
|
SetMenuCategory(mcText);
|
||||||
|
timeoutM.Set(eInfoTimeoutMs);
|
||||||
|
UpdateInfo();
|
||||||
|
SetHelp(NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
cSatipMenuDeviceStatus::~cSatipMenuDeviceStatus()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipMenuDeviceStatus::UpdateInfo()
|
||||||
|
{
|
||||||
|
textM = cSatipDevice::GetSatipStatus();
|
||||||
|
Display();
|
||||||
|
timeoutM.Set(eInfoTimeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipMenuDeviceStatus::Display(void)
|
||||||
|
{
|
||||||
|
cOsdMenu::Display();
|
||||||
|
DisplayMenu()->SetText(textM, true);
|
||||||
|
if (*textM)
|
||||||
|
cStatus::MsgOsdTextItem(textM);
|
||||||
|
}
|
||||||
|
|
||||||
|
eOSState cSatipMenuDeviceStatus::ProcessKey(eKeys keyP)
|
||||||
|
{
|
||||||
|
eOSState state = cOsdMenu::ProcessKey(keyP);
|
||||||
|
|
||||||
|
if (state == osUnknown) {
|
||||||
|
switch (keyP) {
|
||||||
|
case kOk: state = osBack; break;
|
||||||
|
default: if (timeoutM.TimedOut())
|
||||||
|
UpdateInfo();
|
||||||
|
state = osContinue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
// --- cSatipMenuInfo ---------------------------------------------------------
|
// --- cSatipMenuInfo ---------------------------------------------------------
|
||||||
|
|
||||||
class cSatipMenuInfo : public cOsdMenu
|
class cSatipMenuInfo : public cOsdMenu
|
||||||
@@ -197,14 +332,24 @@ eOSState cSatipMenuInfo::ProcessKey(eKeys keyP)
|
|||||||
cSatipPluginSetup::cSatipPluginSetup()
|
cSatipPluginSetup::cSatipPluginSetup()
|
||||||
: deviceCountM(0),
|
: deviceCountM(0),
|
||||||
operatingModeM(SatipConfig.GetOperatingMode()),
|
operatingModeM(SatipConfig.GetOperatingMode()),
|
||||||
|
ciExtensionM(SatipConfig.GetCIExtension()),
|
||||||
eitScanM(SatipConfig.GetEITScan()),
|
eitScanM(SatipConfig.GetEITScan()),
|
||||||
|
numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()),
|
||||||
numDisabledFiltersM(SatipConfig.GetDisabledFiltersCount())
|
numDisabledFiltersM(SatipConfig.GetDisabledFiltersCount())
|
||||||
{
|
{
|
||||||
debug("cSatipPluginSetup::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
operatingModeTextsM[cSatipConfig::eOperatingModeOff] = tr("off");
|
operatingModeTextsM[cSatipConfig::eOperatingModeOff] = tr("off");
|
||||||
operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low");
|
operatingModeTextsM[cSatipConfig::eOperatingModeLow] = tr("low");
|
||||||
operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal");
|
operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal");
|
||||||
operatingModeTextsM[cSatipConfig::eOperatingModeHigh] = tr("high");
|
operatingModeTextsM[cSatipConfig::eOperatingModeHigh] = tr("high");
|
||||||
|
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)
|
||||||
|
cicamTextsM[i] = ca_systems_table[i].description;
|
||||||
|
if (numDisabledSourcesM > MAX_DISABLED_SOURCES_COUNT)
|
||||||
|
numDisabledSourcesM = MAX_DISABLED_SOURCES_COUNT;
|
||||||
|
for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i)
|
||||||
|
disabledSourcesM[i] = SatipConfig.GetDisabledSources(i);
|
||||||
if (numDisabledFiltersM > SECTION_FILTER_TABLE_SIZE)
|
if (numDisabledFiltersM > SECTION_FILTER_TABLE_SIZE)
|
||||||
numDisabledFiltersM = SECTION_FILTER_TABLE_SIZE;
|
numDisabledFiltersM = SECTION_FILTER_TABLE_SIZE;
|
||||||
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
||||||
@@ -213,7 +358,7 @@ cSatipPluginSetup::cSatipPluginSetup()
|
|||||||
}
|
}
|
||||||
SetMenuCategory(mcSetupPlugins);
|
SetMenuCategory(mcSetupPlugins);
|
||||||
Setup();
|
Setup();
|
||||||
SetHelp(trVDR("Button$Scan"), NULL, NULL, trVDR("Button$Info"));
|
SetHelp(trVDR("Button$Scan"), NULL, tr("Button$Devices"), trVDR("Button$Info"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipPluginSetup::Setup(void)
|
void cSatipPluginSetup::Setup(void)
|
||||||
@@ -227,18 +372,34 @@ void cSatipPluginSetup::Setup(void)
|
|||||||
helpM.Append(tr("Define the used operating mode for all SAT>IP devices:\n\noff - devices are disabled\nlow - devices are working at the lowest priority\nnormal - devices are working within normal parameters\nhigh - devices are working at the highest priority"));
|
helpM.Append(tr("Define the used operating mode for all SAT>IP devices:\n\noff - devices are disabled\nlow - devices are working at the lowest priority\nnormal - devices are working within normal parameters\nhigh - devices are working at the highest priority"));
|
||||||
|
|
||||||
if (operatingModeM) {
|
if (operatingModeM) {
|
||||||
|
Add(new cMenuEditBoolItem(tr("Enable CI extension"), &ciExtensionM));
|
||||||
|
helpM.Append(tr("Define whether a CI extension shall be used.\n\nThis setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)."));
|
||||||
|
|
||||||
|
for (unsigned int i = 0; ciExtensionM && i < ELEMENTS(cicamsM); ++i) {
|
||||||
|
Add(new cMenuEditStraItem(*cString::sprintf(" %s #%d", tr("CI/CAM"), i + 1), &cicamsM[i], ELEMENTS(cicamTextsM), cicamTextsM));
|
||||||
|
helpM.Append(tr("Define a desired CAM type for the CI slot.\n\nThe '---' option lets SAT>IP hardware do the auto-selection."));
|
||||||
|
}
|
||||||
|
|
||||||
Add(new cMenuEditBoolItem(tr("Enable EPG scanning"), &eitScanM));
|
Add(new cMenuEditBoolItem(tr("Enable EPG scanning"), &eitScanM));
|
||||||
helpM.Append(tr("Define whether the EPG background scanning shall be used.\n\nThis setting disables the automatic EIT scanning functionality for all SAT>IP devices."));
|
helpM.Append(tr("Define whether the EPG background scanning shall be used.\n\nThis setting disables the automatic EIT scanning functionality for all SAT>IP devices."));
|
||||||
|
|
||||||
|
Add(new cMenuEditIntItem(tr("Disabled sources"), &numDisabledSourcesM, 0, MAX_DISABLED_SOURCES_COUNT, tr("none")));
|
||||||
|
helpM.Append(tr("Define number of sources to be disabled.\n\nSAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."));
|
||||||
|
|
||||||
|
for (int i = 0; i < numDisabledSourcesM; ++i) {
|
||||||
|
Add(new cSatipEditSrcItem(*cString::sprintf(" %s %d", trVDR("Source"), i + 1), &disabledSourcesM[i]));
|
||||||
|
helpM.Append(tr("Define a source to be blacklisted."));
|
||||||
|
}
|
||||||
|
|
||||||
Add(new cMenuEditIntItem(tr("Disabled filters"), &numDisabledFiltersM, 0, SECTION_FILTER_TABLE_SIZE, tr("none")));
|
Add(new cMenuEditIntItem(tr("Disabled filters"), &numDisabledFiltersM, 0, SECTION_FILTER_TABLE_SIZE, tr("none")));
|
||||||
helpM.Append(tr("Define number of section filters to be disabled.\n\nCertain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."));
|
helpM.Append(tr("Define number of section filters to be disabled.\n\nCertain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."));
|
||||||
|
|
||||||
for (int i = 0; i < numDisabledFiltersM; ++i) {
|
for (int i = 0; i < numDisabledFiltersM; ++i) {
|
||||||
Add(new cMenuEditStraItem(*cString::sprintf(" %s %d", tr("Filter"), i + 1), &disabledFilterIndexesM[i], SECTION_FILTER_TABLE_SIZE, disabledFilterNamesM));
|
Add(new cMenuEditStraItem(*cString::sprintf(" %s %d", tr("Filter"), i + 1), &disabledFilterIndexesM[i], SECTION_FILTER_TABLE_SIZE, disabledFilterNamesM));
|
||||||
helpM.Append(tr("Define an ill-behaving filter to be blacklisted."));
|
helpM.Append(tr("Define an ill-behaving filter to be blacklisted."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Add(new cOsdItem(tr("Active SAT>IP devices:"), osUnknown, false));
|
Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false));
|
||||||
helpM.Append("");
|
helpM.Append("");
|
||||||
|
|
||||||
cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers();
|
cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers();
|
||||||
@@ -254,7 +415,7 @@ void cSatipPluginSetup::Setup(void)
|
|||||||
|
|
||||||
eOSState cSatipPluginSetup::DeviceScan(void)
|
eOSState cSatipPluginSetup::DeviceScan(void)
|
||||||
{
|
{
|
||||||
debug("cSatipPluginSetup::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
cSatipDiscover::GetInstance()->TriggerScan();
|
cSatipDiscover::GetInstance()->TriggerScan();
|
||||||
|
|
||||||
return osContinue;
|
return osContinue;
|
||||||
@@ -262,7 +423,7 @@ eOSState cSatipPluginSetup::DeviceScan(void)
|
|||||||
|
|
||||||
eOSState cSatipPluginSetup::DeviceInfo(void)
|
eOSState cSatipPluginSetup::DeviceInfo(void)
|
||||||
{
|
{
|
||||||
debug("cSatipPluginSetup::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
if (HasSubMenu() || Count() == 0)
|
if (HasSubMenu() || Count() == 0)
|
||||||
return osContinue;
|
return osContinue;
|
||||||
|
|
||||||
@@ -273,9 +434,18 @@ eOSState cSatipPluginSetup::DeviceInfo(void)
|
|||||||
return osContinue;
|
return osContinue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eOSState cSatipPluginSetup::ShowDeviceStatus(void)
|
||||||
|
{
|
||||||
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
|
if (HasSubMenu() || Count() == 0)
|
||||||
|
return osContinue;
|
||||||
|
|
||||||
|
return AddSubMenu(new cSatipMenuDeviceStatus());
|
||||||
|
}
|
||||||
|
|
||||||
eOSState cSatipPluginSetup::ShowInfo(void)
|
eOSState cSatipPluginSetup::ShowInfo(void)
|
||||||
{
|
{
|
||||||
debug("cSatipPluginSetup::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
if (HasSubMenu() || Count() == 0)
|
if (HasSubMenu() || Count() == 0)
|
||||||
return osContinue;
|
return osContinue;
|
||||||
|
|
||||||
@@ -286,6 +456,8 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
|
|||||||
{
|
{
|
||||||
bool hadSubMenu = HasSubMenu();
|
bool hadSubMenu = HasSubMenu();
|
||||||
int oldOperatingMode = operatingModeM;
|
int oldOperatingMode = operatingModeM;
|
||||||
|
int oldCiExtension = ciExtensionM;
|
||||||
|
int oldNumDisabledSources = numDisabledSourcesM;
|
||||||
int oldNumDisabledFilters = numDisabledFiltersM;
|
int oldNumDisabledFilters = numDisabledFiltersM;
|
||||||
eOSState state = cMenuSetupPage::ProcessKey(keyP);
|
eOSState state = cMenuSetupPage::ProcessKey(keyP);
|
||||||
|
|
||||||
@@ -296,18 +468,21 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
|
|||||||
|
|
||||||
if (state == osUnknown) {
|
if (state == osUnknown) {
|
||||||
switch (keyP) {
|
switch (keyP) {
|
||||||
case kRed: return DeviceScan();
|
case kRed: return DeviceScan();
|
||||||
case kBlue: return ShowInfo();
|
case kYellow: return ShowDeviceStatus();
|
||||||
case kInfo: if (Current() < helpM.Size())
|
case kBlue: return ShowInfo();
|
||||||
return AddSubMenu(new cMenuText(cString::sprintf("%s - %s '%s'", tr("Help"), trVDR("Plugin"), PLUGIN_NAME_I18N), helpM[Current()]));
|
case kInfo: if (Current() < helpM.Size())
|
||||||
default: state = osContinue; break;
|
return AddSubMenu(new cMenuText(cString::sprintf("%s - %s '%s'", tr("Help"), trVDR("Plugin"), PLUGIN_NAME_I18N), helpM[Current()]));
|
||||||
|
default: state = osContinue; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((keyP == kNone) && (cSatipDiscover::GetInstance()->GetServers()->Count() != deviceCountM))
|
if ((keyP == kNone) && (cSatipDiscover::GetInstance()->GetServers()->Count() != deviceCountM))
|
||||||
Setup();
|
Setup();
|
||||||
|
|
||||||
if ((keyP != kNone) && ((numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode))) {
|
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))
|
while ((numDisabledFiltersM < oldNumDisabledFilters) && (oldNumDisabledFilters > 0))
|
||||||
disabledFilterIndexesM[--oldNumDisabledFilters] = -1;
|
disabledFilterIndexesM[--oldNumDisabledFilters] = -1;
|
||||||
Setup();
|
Setup();
|
||||||
@@ -316,34 +491,71 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cSatipPluginSetup::StoreCicams(const char *nameP, int *cicamsP)
|
||||||
|
{
|
||||||
|
cString buffer = "";
|
||||||
|
int n = 0;
|
||||||
|
for (int i = 0; i < MAX_CICAM_COUNT; ++i) {
|
||||||
|
if (cicamsP[i] < 0)
|
||||||
|
break;
|
||||||
|
if (n++ > 0)
|
||||||
|
buffer = cString::sprintf("%s %d", *buffer, cicamsP[i]);
|
||||||
|
else
|
||||||
|
buffer = cString::sprintf("%d", cicamsP[i]);
|
||||||
|
}
|
||||||
|
debug3("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer);
|
||||||
|
SetupStore(nameP, *buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cSatipPluginSetup::StoreSources(const char *nameP, int *sourcesP)
|
||||||
|
{
|
||||||
|
cString buffer = "";
|
||||||
|
int n = 0;
|
||||||
|
for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i) {
|
||||||
|
if (sourcesP[i] == cSource::stNone)
|
||||||
|
break;
|
||||||
|
if (n++ > 0)
|
||||||
|
buffer = cString::sprintf("%s %s", *buffer, *cSource::ToString(sourcesP[i]));
|
||||||
|
else
|
||||||
|
buffer = cString::sprintf("%s", *cSource::ToString(sourcesP[i]));
|
||||||
|
}
|
||||||
|
debug3("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer);
|
||||||
|
SetupStore(nameP, *buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void cSatipPluginSetup::StoreFilters(const char *nameP, int *valuesP)
|
void cSatipPluginSetup::StoreFilters(const char *nameP, int *valuesP)
|
||||||
{
|
{
|
||||||
char buffer[SECTION_FILTER_TABLE_SIZE * 4];
|
cString buffer = "";
|
||||||
char *q = buffer;
|
int n = 0;
|
||||||
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i) {
|
||||||
char s[3];
|
|
||||||
if (valuesP[i] < 0)
|
if (valuesP[i] < 0)
|
||||||
break;
|
break;
|
||||||
if (q > buffer)
|
if (n++ > 0)
|
||||||
*q++ = ' ';
|
buffer = cString::sprintf("%s %d", *buffer, valuesP[i]);
|
||||||
snprintf(s, sizeof(s), "%d", valuesP[i]);
|
else
|
||||||
strncpy(q, s, strlen(s));
|
buffer = cString::sprintf("%d", valuesP[i]);
|
||||||
q += strlen(s);
|
|
||||||
}
|
}
|
||||||
*q = 0;
|
debug3("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer);
|
||||||
debug("cSatipPluginSetup::%s(%s, %s)", __FUNCTION__, nameP, buffer);
|
SetupStore(nameP, *buffer);
|
||||||
SetupStore(nameP, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipPluginSetup::Store(void)
|
void cSatipPluginSetup::Store(void)
|
||||||
{
|
{
|
||||||
// Store values into setup.conf
|
// Store values into setup.conf
|
||||||
SetupStore("OperatingMode", operatingModeM);
|
SetupStore("OperatingMode", operatingModeM);
|
||||||
|
SetupStore("EnableCIExtension", ciExtensionM);
|
||||||
SetupStore("EnableEITScan", eitScanM);
|
SetupStore("EnableEITScan", eitScanM);
|
||||||
|
StoreCicams("CICAM", cicamsM);
|
||||||
|
StoreSources("DisabledSources", disabledSourcesM);
|
||||||
StoreFilters("DisabledFilters", disabledFilterIndexesM);
|
StoreFilters("DisabledFilters", disabledFilterIndexesM);
|
||||||
// Update global config
|
// Update global config
|
||||||
SatipConfig.SetOperatingMode(operatingModeM);
|
SatipConfig.SetOperatingMode(operatingModeM);
|
||||||
|
SatipConfig.SetCIExtension(ciExtensionM);
|
||||||
SatipConfig.SetEITScan(eitScanM);
|
SatipConfig.SetEITScan(eitScanM);
|
||||||
|
for (int i = 0; i < MAX_CICAM_COUNT; ++i)
|
||||||
|
SatipConfig.SetCICAM(i, cicamsM[i]);
|
||||||
|
for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i)
|
||||||
|
SatipConfig.SetDisabledSources(i, disabledSourcesM[i]);
|
||||||
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i)
|
for (int i = 0; i < SECTION_FILTER_TABLE_SIZE; ++i)
|
||||||
SatipConfig.SetDisabledFilters(i, disabledFilterIndexesM[i]);
|
SatipConfig.SetDisabledFilters(i, disabledFilterIndexesM[i]);
|
||||||
}
|
}
|
||||||
|
8
setup.h
8
setup.h
@@ -18,7 +18,12 @@ private:
|
|||||||
int deviceCountM;
|
int deviceCountM;
|
||||||
int operatingModeM;
|
int operatingModeM;
|
||||||
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];
|
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];
|
||||||
|
int ciExtensionM;
|
||||||
|
int cicamsM[MAX_CICAM_COUNT];
|
||||||
|
const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE];
|
||||||
int eitScanM;
|
int eitScanM;
|
||||||
|
int numDisabledSourcesM;
|
||||||
|
int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT];
|
||||||
int numDisabledFiltersM;
|
int numDisabledFiltersM;
|
||||||
int disabledFilterIndexesM[SECTION_FILTER_TABLE_SIZE];
|
int disabledFilterIndexesM[SECTION_FILTER_TABLE_SIZE];
|
||||||
const char *disabledFilterNamesM[SECTION_FILTER_TABLE_SIZE];
|
const char *disabledFilterNamesM[SECTION_FILTER_TABLE_SIZE];
|
||||||
@@ -26,8 +31,11 @@ private:
|
|||||||
|
|
||||||
eOSState DeviceScan(void);
|
eOSState DeviceScan(void);
|
||||||
eOSState DeviceInfo(void);
|
eOSState DeviceInfo(void);
|
||||||
|
eOSState ShowDeviceStatus(void);
|
||||||
eOSState ShowInfo(void);
|
eOSState ShowInfo(void);
|
||||||
void Setup(void);
|
void Setup(void);
|
||||||
|
void StoreCicams(const char *nameP, int *cicamsP);
|
||||||
|
void StoreSources(const char *nameP, int *sourcesP);
|
||||||
void StoreFilters(const char *nameP, int *valuesP);
|
void StoreFilters(const char *nameP, int *valuesP);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
164
socket.c
164
socket.c
@@ -16,29 +16,26 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
cSatipSocket::cSatipSocket()
|
cSatipSocket::cSatipSocket()
|
||||||
: socketPortM(0),
|
: socketPortM(0),
|
||||||
socketDescM(-1),
|
socketDescM(-1)
|
||||||
lastErrorReportM(0),
|
|
||||||
packetErrorsM(0),
|
|
||||||
sequenceNumberM(-1)
|
|
||||||
{
|
{
|
||||||
debug("cSatipSocket::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipSocket::~cSatipSocket()
|
cSatipSocket::~cSatipSocket()
|
||||||
{
|
{
|
||||||
debug("cSatipSocket::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
// Close the socket
|
// Close the socket
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipSocket::Open(const int portP)
|
bool cSatipSocket::Open(const int portP)
|
||||||
{
|
{
|
||||||
debug("cSatipSocket::%s(%d)", __FUNCTION__, portP);
|
|
||||||
// Bind to the socket if it is not active already
|
// Bind to the socket if it is not active already
|
||||||
if (socketDescM < 0) {
|
if (socketDescM < 0) {
|
||||||
socklen_t len = sizeof(sockAddrM);
|
socklen_t len = sizeof(sockAddrM);
|
||||||
@@ -64,30 +61,25 @@ bool cSatipSocket::Open(const int portP)
|
|||||||
"getsockname()", Close(), return false);
|
"getsockname()", Close(), return false);
|
||||||
socketPortM = ntohs(sockAddrM.sin_port);
|
socketPortM = ntohs(sockAddrM.sin_port);
|
||||||
}
|
}
|
||||||
|
debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipSocket::Close(void)
|
void cSatipSocket::Close(void)
|
||||||
{
|
{
|
||||||
debug("cSatipSocket::%s()", __FUNCTION__);
|
debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM);
|
||||||
// Check if socket exists
|
// Check if socket exists
|
||||||
if (socketDescM >= 0) {
|
if (socketDescM >= 0) {
|
||||||
close(socketDescM);
|
close(socketDescM);
|
||||||
socketDescM = -1;
|
socketDescM = -1;
|
||||||
socketPortM = 0;
|
socketPortM = 0;
|
||||||
sequenceNumberM = -1;
|
|
||||||
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
memset(&sockAddrM, 0, sizeof(sockAddrM));
|
||||||
}
|
}
|
||||||
if (packetErrorsM) {
|
|
||||||
info("detected %d RTP packet errors", packetErrorsM);
|
|
||||||
packetErrorsM = 0;
|
|
||||||
lastErrorReportM = time(NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipSocket::Flush(void)
|
bool cSatipSocket::Flush(void)
|
||||||
{
|
{
|
||||||
debug("cSatipSocket::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
if (socketDescM < 0) {
|
if (socketDescM < 0) {
|
||||||
const unsigned int len = 65535;
|
const unsigned int len = 65535;
|
||||||
unsigned char *buf = MALLOC(unsigned char, len);
|
unsigned char *buf = MALLOC(unsigned char, len);
|
||||||
@@ -106,10 +98,10 @@ bool cSatipSocket::Flush(void)
|
|||||||
|
|
||||||
int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||||
{
|
{
|
||||||
//debug("cSatipSocket::%s()", __FUNCTION__);
|
debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP);
|
||||||
// Error out if socket not initialized
|
// Error out if socket not initialized
|
||||||
if (socketDescM <= 0) {
|
if (socketDescM <= 0) {
|
||||||
error("Invalid socket in cSatipUdpSocket::%s()", __FUNCTION__);
|
error("%s Invalid socket", __PRETTY_FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int len = 0;
|
int len = 0;
|
||||||
@@ -128,7 +120,7 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
|||||||
msgh.msg_controllen = sizeof(cbuf);
|
msgh.msg_controllen = sizeof(cbuf);
|
||||||
msgh.msg_name = &sockAddrM;
|
msgh.msg_name = &sockAddrM;
|
||||||
msgh.msg_namelen = addrlen;
|
msgh.msg_namelen = addrlen;
|
||||||
msgh.msg_iov = &iov;
|
msgh.msg_iov = &iov;
|
||||||
msgh.msg_iovlen = 1;
|
msgh.msg_iovlen = 1;
|
||||||
msgh.msg_flags = 0;
|
msgh.msg_flags = 0;
|
||||||
|
|
||||||
@@ -141,110 +133,56 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cSatipSocket::ReadVideo(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP)
|
||||||
{
|
{
|
||||||
//debug("cSatipSocket::%s()", __FUNCTION__);
|
debug16("%s (, , %d, %d)", __PRETTY_FUNCTION__, elementCountP, elementBufferSizeP);
|
||||||
int len = Read(bufferAddrP, bufferLenP);
|
#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,12)
|
||||||
if (len > 0) {
|
// Error out if socket not initialized
|
||||||
if (bufferAddrP[0] == TS_SYNC_BYTE)
|
if (socketDescM <= 0) {
|
||||||
return len;
|
error("%s Invalid socket", __PRETTY_FUNCTION__);
|
||||||
else if (len > 3) {
|
return -1;
|
||||||
// http://tools.ietf.org/html/rfc3550
|
|
||||||
// http://tools.ietf.org/html/rfc2250
|
|
||||||
// Version
|
|
||||||
unsigned int v = (bufferAddrP[0] >> 6) & 0x03;
|
|
||||||
// Extension bit
|
|
||||||
unsigned int x = (bufferAddrP[0] >> 4) & 0x01;
|
|
||||||
// CSCR count
|
|
||||||
unsigned int cc = bufferAddrP[0] & 0x0F;
|
|
||||||
// Payload type: MPEG2 TS = 33
|
|
||||||
//unsigned int pt = bufferAddrP[1] & 0x7F;
|
|
||||||
// Sequence number
|
|
||||||
int seq = ((bufferAddrP[2] & 0xFF) << 8) | (bufferAddrP[3] & 0xFF);
|
|
||||||
if ((((sequenceNumberM + 1) % 0xFFFF) == 0) && (seq == 0xFFFF))
|
|
||||||
sequenceNumberM = -1;
|
|
||||||
else if ((sequenceNumberM >= 0) && (((sequenceNumberM + 1) % 0xFFFF) != seq)) {
|
|
||||||
packetErrorsM++;
|
|
||||||
if (time(NULL) - lastErrorReportM > eReportIntervalS) {
|
|
||||||
info("detected %d RTP packet errors", packetErrorsM);
|
|
||||||
packetErrorsM = 0;
|
|
||||||
lastErrorReportM = time(NULL);
|
|
||||||
}
|
|
||||||
sequenceNumberM = seq;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sequenceNumberM = seq;
|
|
||||||
// Header lenght
|
|
||||||
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
|
|
||||||
// Check if extension
|
|
||||||
if (x) {
|
|
||||||
// Extension header length
|
|
||||||
unsigned int ehl = (((bufferAddrP[headerlen + 2] & 0xFF) << 8) |
|
|
||||||
(bufferAddrP[headerlen + 3] & 0xFF));
|
|
||||||
// Update header length
|
|
||||||
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
|
||||||
if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) &&
|
|
||||||
(bufferAddrP[headerlen] == TS_SYNC_BYTE)) {
|
|
||||||
// Set argument point to payload in read buffer
|
|
||||||
memmove(bufferAddrP, &bufferAddrP[headerlen], (len - headerlen));
|
|
||||||
return (len - headerlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
// Initialize iov and msgh structures
|
||||||
|
struct mmsghdr mmsgh[elementCountP];
|
||||||
|
struct iovec iov[elementCountP];
|
||||||
|
memset(mmsgh, 0, sizeof(mmsgh[0]) * elementCountP);
|
||||||
|
for (unsigned int i = 0; i < elementCountP; ++i) {
|
||||||
|
iov[i].iov_base = bufferAddrP + i * elementBufferSizeP;
|
||||||
|
iov[i].iov_len = elementBufferSizeP;
|
||||||
|
mmsgh[i].msg_hdr.msg_iov = &iov[i];
|
||||||
|
mmsgh[i].msg_hdr.msg_iovlen = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read data from socket as a set
|
||||||
|
int count = -1;
|
||||||
|
if (socketDescM && bufferAddrP && elementRecvSizeP && (elementCountP > 0) && (elementBufferSizeP > 0))
|
||||||
|
count = (int)recvmmsg(socketDescM, mmsgh, elementCountP, MSG_DONTWAIT, NULL);
|
||||||
|
ERROR_IF_RET(count < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmmsg()", return -1);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
elementRecvSizeP[i] = mmsgh[i].msg_len;
|
||||||
|
#else
|
||||||
|
int count = 0;
|
||||||
|
while (count < (int)elementCountP) {
|
||||||
|
int len = Read(bufferAddrP + count * elementBufferSizeP, elementBufferSizeP);
|
||||||
|
if (len < 0)
|
||||||
|
return -1;
|
||||||
|
else if (len == 0)
|
||||||
|
break;
|
||||||
|
elementRecvSizeP[count++] = len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
debug16("%s Received %d packets size[0]=%d", __PRETTY_FUNCTION__, count, elementRecvSizeP[0]);
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cSatipSocket::ReadApplication(unsigned char *bufferAddrP, unsigned int bufferLenP)
|
|
||||||
{
|
|
||||||
//debug("cSatipSocket::%s()", __FUNCTION__);
|
|
||||||
int len = Read(bufferAddrP, bufferLenP);
|
|
||||||
int offset = 0;
|
|
||||||
while (len > 0) {
|
|
||||||
// Version
|
|
||||||
unsigned int v = (bufferAddrP[offset] >> 6) & 0x03;
|
|
||||||
// Padding
|
|
||||||
//unsigned int p = (bufferAddrP[offset] >> 5) & 0x01;
|
|
||||||
// Subtype
|
|
||||||
//unsigned int st = bufferAddrP[offset] & 0x1F;
|
|
||||||
// Payload type
|
|
||||||
unsigned int pt = bufferAddrP[offset + 1] & 0xFF;
|
|
||||||
// Lenght
|
|
||||||
unsigned int length = ((bufferAddrP[offset + 2] & 0xFF) << 8) | (bufferAddrP[offset + 3] & 0xFF);
|
|
||||||
// Convert it to bytes
|
|
||||||
length = (length + 1) * 4;
|
|
||||||
// V=2, APP = 204
|
|
||||||
if ((v == 2) && (pt == 204)) {
|
|
||||||
// SSCR/CSCR
|
|
||||||
//unsigned int ssrc = ((bufferAddrP[offset + 4] & 0xFF) << 24) | ((bufferAddrP[offset + 5] & 0xFF) << 16) |
|
|
||||||
// ((bufferAddrP[offset + 6] & 0xFF) << 8) | (bufferAddrP[offset + 7] & 0xFF);
|
|
||||||
// Name
|
|
||||||
if ((bufferAddrP[offset + 8] == 'S') && (bufferAddrP[offset + 9] == 'E') &&
|
|
||||||
(bufferAddrP[offset + 10] == 'S') && (bufferAddrP[offset + 11] == '1')) {
|
|
||||||
// Identifier
|
|
||||||
//unsigned int id = ((bufferAddrP[offset + 12] & 0xFF) << 8) | (bufferAddrP[offset + 13] & 0xFF);
|
|
||||||
// String length
|
|
||||||
int string_length = ((bufferAddrP[offset + 14] & 0xFF) << 8) | (bufferAddrP[offset + 15] & 0xFF);
|
|
||||||
if (string_length > 0) {
|
|
||||||
// Set argument point to payload in read buffer
|
|
||||||
memmove(bufferAddrP, &bufferAddrP[offset + 16], string_length);
|
|
||||||
return string_length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset += length;
|
|
||||||
len -= length;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cSatipSocket::Write(const char *addrP, const unsigned char *bufferAddrP, unsigned int bufferLenP)
|
bool cSatipSocket::Write(const char *addrP, const unsigned char *bufferAddrP, unsigned int bufferLenP)
|
||||||
{
|
{
|
||||||
debug("cSatipSocket::%s(%s)", __FUNCTION__, addrP);
|
debug1("%s (%s, , %d)", __PRETTY_FUNCTION__, addrP, bufferLenP);
|
||||||
// Error out if socket not initialized
|
// Error out if socket not initialized
|
||||||
if (socketDescM <= 0) {
|
if (socketDescM <= 0) {
|
||||||
error("cSatipSocket::%s(): Invalid socket", __FUNCTION__);
|
error("%s Invalid socket", __PRETTY_FUNCTION__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
struct sockaddr_in sockAddr;
|
struct sockaddr_in sockAddr;
|
||||||
|
14
socket.h
14
socket.h
@@ -12,27 +12,21 @@
|
|||||||
|
|
||||||
class cSatipSocket {
|
class cSatipSocket {
|
||||||
private:
|
private:
|
||||||
enum {
|
|
||||||
eReportIntervalS = 300 // in seconds
|
|
||||||
};
|
|
||||||
int socketPortM;
|
int socketPortM;
|
||||||
int socketDescM;
|
int socketDescM;
|
||||||
struct sockaddr_in sockAddrM;
|
struct sockaddr_in sockAddrM;
|
||||||
time_t lastErrorReportM;
|
|
||||||
int packetErrorsM;
|
|
||||||
int sequenceNumberM;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cSatipSocket();
|
cSatipSocket();
|
||||||
~cSatipSocket();
|
virtual ~cSatipSocket();
|
||||||
bool Open(const int portP = 0);
|
bool Open(const int portP = 0);
|
||||||
void Close(void);
|
virtual void Close(void);
|
||||||
|
int Fd(void) { return socketDescM; }
|
||||||
int Port(void) { return socketPortM; }
|
int Port(void) { return socketPortM; }
|
||||||
bool IsOpen(void) { return (socketDescM >= 0); }
|
bool IsOpen(void) { return (socketDescM >= 0); }
|
||||||
bool Flush(void);
|
bool Flush(void);
|
||||||
int Read(unsigned char *bufferAddrP, unsigned int bufferLenP);
|
int Read(unsigned char *bufferAddrP, unsigned int bufferLenP);
|
||||||
int ReadVideo(unsigned char *bufferAddrP, unsigned int bufferLenP);
|
int ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP);
|
||||||
int ReadApplication(unsigned char *bufferAddrP, unsigned int bufferLenP);
|
|
||||||
bool Write(const char *addrP, const unsigned char *bufferAddrP, unsigned int bufferLenP);
|
bool Write(const char *addrP, const unsigned char *bufferAddrP, unsigned int bufferLenP);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
41
statistics.c
41
statistics.c
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "statistics.h"
|
#include "statistics.h"
|
||||||
|
#include "log.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
// Section statistics class
|
// Section statistics class
|
||||||
@@ -18,17 +19,17 @@ cSatipSectionStatistics::cSatipSectionStatistics()
|
|||||||
timerM(),
|
timerM(),
|
||||||
mutexM()
|
mutexM()
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionStatistics::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipSectionStatistics::~cSatipSectionStatistics()
|
cSatipSectionStatistics::~cSatipSectionStatistics()
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionStatistics::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipSectionStatistics::GetSectionStatistic()
|
cString cSatipSectionStatistics::GetSectionStatistic()
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionStatistics::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
||||||
timerM.Set();
|
timerM.Set();
|
||||||
@@ -44,7 +45,7 @@ cString cSatipSectionStatistics::GetSectionStatistic()
|
|||||||
|
|
||||||
void cSatipSectionStatistics::AddSectionStatistic(long bytesP, long callsP)
|
void cSatipSectionStatistics::AddSectionStatistic(long bytesP, long callsP)
|
||||||
{
|
{
|
||||||
//debug("cSatipSectionStatistics::%s(%ld, %ld)", __FUNCTION__, bytesP, callsP);
|
debug16("%s (%ld, %ld)", __PRETTY_FUNCTION__, bytesP, callsP);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
filteredDataM += bytesP;
|
filteredDataM += bytesP;
|
||||||
numberOfCallsM += callsP;
|
numberOfCallsM += callsP;
|
||||||
@@ -57,7 +58,7 @@ cSatipPidStatistics::cSatipPidStatistics()
|
|||||||
: timerM(),
|
: timerM(),
|
||||||
mutexM()
|
mutexM()
|
||||||
{
|
{
|
||||||
debug("cSatipPidStatistics::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
||||||
for (int i = 0; i < numberOfElements; ++i) {
|
for (int i = 0; i < numberOfElements; ++i) {
|
||||||
mostActivePidsM[i].pid = -1;
|
mostActivePidsM[i].pid = -1;
|
||||||
@@ -67,12 +68,12 @@ cSatipPidStatistics::cSatipPidStatistics()
|
|||||||
|
|
||||||
cSatipPidStatistics::~cSatipPidStatistics()
|
cSatipPidStatistics::~cSatipPidStatistics()
|
||||||
{
|
{
|
||||||
debug("cSatipPidStatistics::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipPidStatistics::GetPidStatistic()
|
cString cSatipPidStatistics::GetPidStatistic()
|
||||||
{
|
{
|
||||||
//debug("cSatipPidStatistics::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
||||||
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
||||||
@@ -97,7 +98,7 @@ cString cSatipPidStatistics::GetPidStatistic()
|
|||||||
|
|
||||||
int cSatipPidStatistics::SortPids(const void* data1P, const void* data2P)
|
int cSatipPidStatistics::SortPids(const void* data1P, const void* data2P)
|
||||||
{
|
{
|
||||||
//debug("cSatipPidStatistics::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
const pidStruct *comp1 = reinterpret_cast<const pidStruct*>(data1P);
|
const pidStruct *comp1 = reinterpret_cast<const pidStruct*>(data1P);
|
||||||
const pidStruct *comp2 = reinterpret_cast<const pidStruct*>(data2P);
|
const pidStruct *comp2 = reinterpret_cast<const pidStruct*>(data2P);
|
||||||
if (comp1->dataAmount > comp2->dataAmount)
|
if (comp1->dataAmount > comp2->dataAmount)
|
||||||
@@ -109,7 +110,7 @@ int cSatipPidStatistics::SortPids(const void* data1P, const void* data2P)
|
|||||||
|
|
||||||
void cSatipPidStatistics::AddPidStatistic(int pidP, long payloadP)
|
void cSatipPidStatistics::AddPidStatistic(int pidP, long payloadP)
|
||||||
{
|
{
|
||||||
//debug("cSatipPidStatistics::%s(%ld, %ld)", __FUNCTION__, pidP, payloadP);
|
debug16("%s (%d, %ld)", __PRETTY_FUNCTION__, pidP, payloadP);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
const int numberOfElements = sizeof(mostActivePidsM) / sizeof(pidStruct);
|
||||||
// If our statistic already is in the array, update it and quit
|
// If our statistic already is in the array, update it and quit
|
||||||
@@ -139,31 +140,33 @@ cSatipTunerStatistics::cSatipTunerStatistics()
|
|||||||
timerM(),
|
timerM(),
|
||||||
mutexM()
|
mutexM()
|
||||||
{
|
{
|
||||||
debug("cSatipTunerStatistics::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipTunerStatistics::~cSatipTunerStatistics()
|
cSatipTunerStatistics::~cSatipTunerStatistics()
|
||||||
{
|
{
|
||||||
debug("cSatipTunerStatistics::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipTunerStatistics::GetTunerStatistic()
|
cString cSatipTunerStatistics::GetTunerStatistic()
|
||||||
{
|
{
|
||||||
//debug("cSatipTunerStatistics::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
mutexM.Lock();
|
||||||
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
||||||
timerM.Set();
|
timerM.Set();
|
||||||
long bitrate = elapsed ? (long)(1000.0L * dataBytesM / KILOBYTE(1) / elapsed) : 0L;
|
long bitrate = elapsed ? (long)(1000.0L * dataBytesM / KILOBYTE(1) / elapsed) : 0L;
|
||||||
|
dataBytesM = 0;
|
||||||
|
mutexM.Unlock();
|
||||||
|
|
||||||
if (!SatipConfig.GetUseBytes())
|
if (!SatipConfig.GetUseBytes())
|
||||||
bitrate *= 8;
|
bitrate *= 8;
|
||||||
cString s = cString::sprintf("%ld k%s/s", bitrate, SatipConfig.GetUseBytes() ? "B" : "bit");
|
cString s = cString::sprintf("%ld k%s/s", bitrate, SatipConfig.GetUseBytes() ? "B" : "bit");
|
||||||
dataBytesM = 0;
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipTunerStatistics::AddTunerStatistic(long bytesP)
|
void cSatipTunerStatistics::AddTunerStatistic(long bytesP)
|
||||||
{
|
{
|
||||||
//debug("cSatipTunerStatistics::%s(%ld)", __FUNCTION__, bytesP);
|
debug16("%s (%ld)", __PRETTY_FUNCTION__, bytesP);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
dataBytesM += bytesP;
|
dataBytesM += bytesP;
|
||||||
}
|
}
|
||||||
@@ -177,17 +180,17 @@ cSatipBufferStatistics::cSatipBufferStatistics()
|
|||||||
timerM(),
|
timerM(),
|
||||||
mutexM()
|
mutexM()
|
||||||
{
|
{
|
||||||
debug("cSatipBufferStatistics::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipBufferStatistics::~cSatipBufferStatistics()
|
cSatipBufferStatistics::~cSatipBufferStatistics()
|
||||||
{
|
{
|
||||||
debug("cSatipBufferStatistics::%s()", __FUNCTION__);
|
debug1("%s", __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipBufferStatistics::GetBufferStatistic()
|
cString cSatipBufferStatistics::GetBufferStatistic()
|
||||||
{
|
{
|
||||||
//debug("cSatipBufferStatistics::%s()", __FUNCTION__);
|
debug16("%s", __PRETTY_FUNCTION__);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
uint64_t elapsed = timerM.Elapsed(); /* in milliseconds */
|
||||||
timerM.Set();
|
timerM.Set();
|
||||||
@@ -211,7 +214,7 @@ cString cSatipBufferStatistics::GetBufferStatistic()
|
|||||||
|
|
||||||
void cSatipBufferStatistics::AddBufferStatistic(long bytesP, long usedP)
|
void cSatipBufferStatistics::AddBufferStatistic(long bytesP, long usedP)
|
||||||
{
|
{
|
||||||
//debug("cSatipBufferStatistics::%s(%ld, %ld)", __FUNCTION__, bytesP, usedP);
|
debug16("%s (%ld, %ld)", __PRETTY_FUNCTION__, bytesP, usedP);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
dataBytesM += bytesP;
|
dataBytesM += bytesP;
|
||||||
if (usedP > usedSpaceM)
|
if (usedP > usedSpaceM)
|
||||||
|
717
tuner.c
717
tuner.c
@@ -5,257 +5,213 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define __STDC_FORMAT_MACROS // Required for format specifiers
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "discover.h"
|
#include "discover.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "poller.h"
|
||||||
#include "tuner.h"
|
#include "tuner.h"
|
||||||
|
|
||||||
cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
|
cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
|
||||||
: cThread("SAT>IP tuner"),
|
: cThread(cString::sprintf("SATIP#%d tuner", deviceP.GetId())),
|
||||||
sleepM(),
|
sleepM(),
|
||||||
deviceM(&deviceP),
|
deviceM(&deviceP),
|
||||||
packetBufferLenM(packetLenP),
|
deviceIdM(deviceP.GetId()),
|
||||||
rtpSocketM(new cSatipSocket()),
|
rtspM(*this),
|
||||||
rtcpSocketM(new cSatipSocket()),
|
rtpM(*this),
|
||||||
|
rtcpM(*this),
|
||||||
streamAddrM(""),
|
streamAddrM(""),
|
||||||
streamParamM(""),
|
streamParamM(""),
|
||||||
currentServerM(NULL),
|
currentServerM(NULL),
|
||||||
nextServerM(NULL),
|
nextServerM(NULL),
|
||||||
mutexM(),
|
mutexM(),
|
||||||
handleM(NULL),
|
reConnectM(),
|
||||||
headerListM(NULL),
|
|
||||||
keepAliveM(),
|
keepAliveM(),
|
||||||
|
statusUpdateM(),
|
||||||
pidUpdateCacheM(),
|
pidUpdateCacheM(),
|
||||||
sessionM(""),
|
sessionM(""),
|
||||||
|
currentStateM(tsIdle),
|
||||||
|
internalStateM(),
|
||||||
|
externalStateM(),
|
||||||
timeoutM(eMinKeepAliveIntervalMs),
|
timeoutM(eMinKeepAliveIntervalMs),
|
||||||
openedM(false),
|
|
||||||
tunedM(false),
|
|
||||||
hasLockM(false),
|
hasLockM(false),
|
||||||
signalStrengthM(-1),
|
signalStrengthM(-1),
|
||||||
signalQualityM(-1),
|
signalQualityM(-1),
|
||||||
streamIdM(-1),
|
streamIdM(-1),
|
||||||
|
pmtPidM(-1),
|
||||||
addPidsM(),
|
addPidsM(),
|
||||||
delPidsM(),
|
delPidsM(),
|
||||||
pidsM()
|
pidsM()
|
||||||
{
|
{
|
||||||
debug("cSatipTuner::%s(%d) [device %d]", __FUNCTION__, packetBufferLenM, deviceM->GetId());
|
debug1("%s (, %d) [device %d]", __PRETTY_FUNCTION__, packetLenP, deviceIdM);
|
||||||
// Allocate packet buffer
|
|
||||||
packetBufferM = MALLOC(unsigned char, packetBufferLenM);
|
// Open sockets
|
||||||
if (packetBufferM)
|
int i = 100;
|
||||||
memset(packetBufferM, 0, packetBufferLenM);
|
while (i-- > 0) {
|
||||||
else
|
if (rtpM.Open(0) && rtcpM.Open(rtpM.Port() + 1))
|
||||||
error("MALLOC() failed for packet buffer [device %d]", deviceM->GetId());
|
break;
|
||||||
|
rtpM.Close();
|
||||||
|
rtcpM.Close();
|
||||||
|
}
|
||||||
|
if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) {
|
||||||
|
error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM);
|
||||||
|
}
|
||||||
|
// Must be done after socket initialization!
|
||||||
|
cSatipPoller::GetInstance()->Register(rtpM);
|
||||||
|
cSatipPoller::GetInstance()->Register(rtcpM);
|
||||||
|
|
||||||
// Start thread
|
// Start thread
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
cSatipTuner::~cSatipTuner()
|
cSatipTuner::~cSatipTuner()
|
||||||
{
|
{
|
||||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
|
|
||||||
// Stop thread
|
// Stop thread
|
||||||
sleepM.Signal();
|
sleepM.Signal();
|
||||||
if (Running())
|
if (Running())
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
Close();
|
Close();
|
||||||
// Free allocated memory
|
currentStateM = tsIdle;
|
||||||
free(packetBufferM);
|
internalStateM.Clear();
|
||||||
DELETENULL(rtcpSocketM);
|
externalStateM.Clear();
|
||||||
DELETENULL(rtpSocketM);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t cSatipTuner::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP)
|
// Close the listening sockets
|
||||||
{
|
cSatipPoller::GetInstance()->Unregister(rtcpM);
|
||||||
cSatipTuner *obj = reinterpret_cast<cSatipTuner *>(dataP);
|
cSatipPoller::GetInstance()->Unregister(rtpM);
|
||||||
size_t len = sizeP * nmembP;
|
rtcpM.Close();
|
||||||
//debug("cSatipTuner::%s(%zu)", __FUNCTION__, len);
|
rtpM.Close();
|
||||||
|
|
||||||
char *s, *p = (char *)ptrP;
|
|
||||||
char *r = strtok_r(p, "\r\n", &s);
|
|
||||||
|
|
||||||
while (obj && r) {
|
|
||||||
//debug("cSatipTuner::%s(%zu): %s", __FUNCTION__, len, r);
|
|
||||||
r = skipspace(r);
|
|
||||||
if (strstr(r, "com.ses.streamID")) {
|
|
||||||
int streamid = -1;
|
|
||||||
if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1)
|
|
||||||
obj->SetStreamId(streamid);
|
|
||||||
}
|
|
||||||
else if (strstr(r, "Session:")) {
|
|
||||||
int timeout = -1;
|
|
||||||
char *session = NULL;
|
|
||||||
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
|
|
||||||
obj->SetSessionTimeout(skipspace(session), timeout * 1000);
|
|
||||||
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
|
|
||||||
obj->SetSessionTimeout(skipspace(session));
|
|
||||||
FREE_POINTER(session);
|
|
||||||
}
|
|
||||||
r = strtok_r(NULL, "\r\n", &s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipTuner::Action(void)
|
void cSatipTuner::Action(void)
|
||||||
{
|
{
|
||||||
debug("cSatipTuner::%s(): entering [device %d]", __FUNCTION__, deviceM->GetId());
|
debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
cTimeMs timeout(eReConnectTimeoutMs);
|
reConnectM.Set(eConnectTimeoutMs);
|
||||||
// Increase priority
|
|
||||||
SetPriority(-1);
|
|
||||||
// Do the thread loop
|
// Do the thread loop
|
||||||
while (packetBufferM && Running()) {
|
while (Running()) {
|
||||||
int length = -1;
|
UpdateCurrentState();
|
||||||
unsigned int size = min(deviceM->CheckData(), packetBufferLenM);
|
switch (currentStateM) {
|
||||||
if (tunedM && (size > 0)) {
|
case tsIdle:
|
||||||
// Update pids
|
debug4("%s: tsIdle [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
UpdatePids();
|
break;
|
||||||
// Remember the heart beat
|
case tsRelease:
|
||||||
KeepAlive();
|
debug4("%s: tsRelease [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
// Read reception statistics
|
Disconnect();
|
||||||
if (rtcpSocketM && rtcpSocketM->IsOpen()) {
|
RequestState(tsIdle, smInternal);
|
||||||
unsigned char buf[1450];
|
break;
|
||||||
memset(buf, 0, sizeof(buf));
|
case tsSet:
|
||||||
if (rtcpSocketM->ReadApplication(buf, sizeof(buf)) > 0) {
|
debug4("%s: tsSet [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
ParseReceptionParameters((const char *)buf);
|
if (Connect()) {
|
||||||
timeout.Set(eReConnectTimeoutMs);
|
RequestState(tsTuned, smInternal);
|
||||||
}
|
UpdatePids(true);
|
||||||
}
|
}
|
||||||
// Read data
|
else
|
||||||
if (rtpSocketM && rtpSocketM->IsOpen())
|
Disconnect();
|
||||||
length = rtpSocketM->ReadVideo(packetBufferM, size);
|
break;
|
||||||
}
|
case tsTuned:
|
||||||
if (length > 0) {
|
debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
AddTunerStatistic(length);
|
reConnectM.Set(eConnectTimeoutMs);
|
||||||
deviceM->WriteData(packetBufferM, length);
|
// Read reception statistics via DESCRIBE and RTCP
|
||||||
timeout.Set(eReConnectTimeoutMs);
|
if (hasLockM || ReadReceptionStatus()) {
|
||||||
}
|
// Quirk for devices without valid reception data
|
||||||
else {
|
if (currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkForceLock)) {
|
||||||
// Reconnect if necessary
|
hasLockM = true;
|
||||||
if (openedM && timeout.TimedOut()) {
|
signalStrengthM = eDefaultSignalStrength;
|
||||||
Disconnect();
|
signalQualityM = eDefaultSignalQuality;
|
||||||
Connect();
|
}
|
||||||
timeout.Set(eReConnectTimeoutMs);
|
if (hasLockM)
|
||||||
}
|
RequestState(tsLocked, smInternal);
|
||||||
sleepM.Wait(10); // to avoid busy loop and reduce cpu load
|
}
|
||||||
}
|
break;
|
||||||
|
case tsLocked:
|
||||||
|
debug4("%s: tsLocked [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
|
if (!UpdatePids()) {
|
||||||
|
error("Pid update failed - retuning [device %d]", deviceIdM);
|
||||||
|
RequestState(tsSet, smInternal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!KeepAlive()) {
|
||||||
|
error("Keep-alive failed - retuning [device %d]", deviceIdM);
|
||||||
|
RequestState(tsSet, smInternal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (reConnectM.TimedOut()) {
|
||||||
|
error("Connection timeout - retuning [device %d]", deviceIdM);
|
||||||
|
RequestState(tsSet, smInternal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown tuner status %d [device %d]", currentStateM, deviceIdM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!StateRequested())
|
||||||
|
sleepM.Wait(eSleepTimeoutMs); // to avoid busy loop and reduce cpu load
|
||||||
}
|
}
|
||||||
debug("cSatipTuner::%s(): exiting [device %d]", __FUNCTION__, deviceM->GetId());
|
debug1("%s Exiting [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipTuner::Open(void)
|
bool cSatipTuner::Open(void)
|
||||||
{
|
{
|
||||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
cMutexLock MutexLock(&mutexM);
|
||||||
if (Connect()) {
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
openedM = true;
|
|
||||||
return true;
|
RequestState(tsSet, smExternal);
|
||||||
}
|
|
||||||
return false;
|
// return always true
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipTuner::Close(void)
|
bool cSatipTuner::Close(void)
|
||||||
{
|
{
|
||||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
cMutexLock MutexLock(&mutexM);
|
||||||
openedM = false;
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
Disconnect();
|
|
||||||
|
RequestState(tsRelease, smExternal);
|
||||||
|
|
||||||
|
// return always true
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipTuner::Connect(void)
|
bool cSatipTuner::Connect(void)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
|
|
||||||
// Initialize the curl session
|
|
||||||
if (!handleM)
|
|
||||||
handleM = curl_easy_init();
|
|
||||||
|
|
||||||
if (handleM && !isempty(*streamAddrM)) {
|
|
||||||
cString uri, control, transport, range;
|
|
||||||
CURLcode res = CURLE_OK;
|
|
||||||
|
|
||||||
|
if (!isempty(*streamAddrM)) {
|
||||||
|
cString connectionUri = cString::sprintf("rtsp://%s/", *streamAddrM);
|
||||||
// Just retune
|
// Just retune
|
||||||
if (tunedM && (streamIdM >= 0)) {
|
if (streamIdM >= 0) {
|
||||||
debug("cSatipTuner::%s(): retune [device %d]", __FUNCTION__, deviceM->GetId());
|
cString uri = cString::sprintf("%sstream=%d?%s", *connectionUri, streamIdM, *streamParamM);
|
||||||
keepAliveM.Set(0);
|
debug1("%s Retuning [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
KeepAlive();
|
if (rtspM.Play(*uri)) {
|
||||||
// Flush any old content
|
keepAliveM.Set(timeoutM);
|
||||||
if (rtpSocketM)
|
return true;
|
||||||
rtpSocketM->Flush();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
// Verbose output
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// No progress meter and no signaling
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
|
|
||||||
|
|
||||||
// Set timeouts
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
|
|
||||||
|
|
||||||
// Set user-agent
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, deviceM->GetId()));
|
|
||||||
|
|
||||||
// Set URL
|
|
||||||
char *p = curl_easy_unescape(handleM, *streamAddrM, 0, NULL);
|
|
||||||
streamAddrM = p;
|
|
||||||
curl_free(p);
|
|
||||||
uri = cString::sprintf("rtsp://%s/", *streamAddrM);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, *uri);
|
|
||||||
|
|
||||||
// Open sockets
|
|
||||||
int i = 100;
|
|
||||||
while (i-- > 0) {
|
|
||||||
if (rtpSocketM->Open() && rtcpSocketM->Open(rtpSocketM->Port() + 1))
|
|
||||||
break;
|
|
||||||
rtpSocketM->Close();
|
|
||||||
rtcpSocketM->Close();
|
|
||||||
}
|
}
|
||||||
if ((rtpSocketM->Port() <= 0) || (rtcpSocketM->Port() <= 0)) {
|
|
||||||
error("Cannot open required RTP/RTCP ports [device %d]", deviceM->GetId());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
else if (rtspM.Options(*connectionUri)) {
|
||||||
// Request server options
|
cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM);
|
||||||
keepAliveM.Set(timeoutM);
|
// Flush any old content
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
|
rtpM.Flush();
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
|
rtcpM.Flush();
|
||||||
SATIP_CURL_EASY_PERFORM(handleM);
|
if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port())) {
|
||||||
if (!ValidateLatestResponse())
|
keepAliveM.Set(timeoutM);
|
||||||
return false;
|
if (nextServerM) {
|
||||||
|
cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
|
||||||
// Setup media stream: "&pids=all" for the whole mux
|
currentServerM = nextServerM;
|
||||||
uri = cString::sprintf("rtsp://%s/?%s", *streamAddrM, *streamParamM);
|
nextServerM = NULL;
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
|
}
|
||||||
transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpSocketM->Port(), rtcpSocketM->Port());
|
return true;
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_TRANSPORT, *transport);
|
}
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
|
|
||||||
// Set header callback for catching the session and timeout
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipTuner::HeaderCallback);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
|
|
||||||
SATIP_CURL_EASY_PERFORM(handleM);
|
|
||||||
// Session id is now known - disable header parsing
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL);
|
|
||||||
if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0")) {
|
|
||||||
debug("cSatipTuner::%s(): session id quirk [device %d]", __FUNCTION__, deviceM->GetId());
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, SkipZeroes(*sessionM));
|
|
||||||
}
|
}
|
||||||
if (!ValidateLatestResponse())
|
else
|
||||||
return false;
|
rtspM.Reset();
|
||||||
|
streamIdM = -1;
|
||||||
// Start playing
|
error("Connect failed [device %d]", deviceIdM);
|
||||||
tunedM = true;
|
|
||||||
UpdatePids(true);
|
|
||||||
if (nextServerM) {
|
|
||||||
cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
|
|
||||||
currentServerM = nextServerM;
|
|
||||||
nextServerM = NULL;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -264,34 +220,16 @@ bool cSatipTuner::Connect(void)
|
|||||||
bool cSatipTuner::Disconnect(void)
|
bool cSatipTuner::Disconnect(void)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
|
|
||||||
// Terminate curl session
|
if (!isempty(*streamAddrM) && (streamIdM >= 0)) {
|
||||||
if (handleM) {
|
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||||
// Teardown rtsp session
|
rtspM.Teardown(*uri);
|
||||||
if (!isempty(*streamAddrM) && streamIdM >= 0) {
|
// some devices requires a teardown for TCP connection also
|
||||||
CURLcode res = CURLE_OK;
|
rtspM.Reset();
|
||||||
|
streamIdM = -1;
|
||||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN);
|
|
||||||
SATIP_CURL_EASY_PERFORM(handleM);
|
|
||||||
ValidateLatestResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup curl stuff
|
|
||||||
if (headerListM) {
|
|
||||||
curl_slist_free_all(headerListM);
|
|
||||||
headerListM = NULL;
|
|
||||||
}
|
|
||||||
curl_easy_cleanup(handleM);
|
|
||||||
handleM = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the listening sockets
|
|
||||||
rtpSocketM->Close();
|
|
||||||
rtcpSocketM->Close();
|
|
||||||
|
|
||||||
// Reset signal parameters
|
// Reset signal parameters
|
||||||
hasLockM = false;
|
hasLockM = false;
|
||||||
signalStrengthM = -1;
|
signalStrengthM = -1;
|
||||||
@@ -299,39 +237,50 @@ bool cSatipTuner::Disconnect(void)
|
|||||||
|
|
||||||
if (currentServerM)
|
if (currentServerM)
|
||||||
cSatipDiscover::GetInstance()->UseServer(currentServerM, false);
|
cSatipDiscover::GetInstance()->UseServer(currentServerM, false);
|
||||||
tunedM = false;
|
statusUpdateM.Set(0);
|
||||||
timeoutM = eMinKeepAliveIntervalMs;
|
timeoutM = eMinKeepAliveIntervalMs;
|
||||||
|
pmtPidM = -1;
|
||||||
addPidsM.Clear();
|
addPidsM.Clear();
|
||||||
delPidsM.Clear();
|
delPidsM.Clear();
|
||||||
|
|
||||||
|
// return always true
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipTuner::ValidateLatestResponse(void)
|
void cSatipTuner::ProcessVideoData(u_char *bufferP, int lengthP)
|
||||||
{
|
{
|
||||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM);
|
||||||
if (handleM) {
|
if (lengthP > 0) {
|
||||||
long rc = 0;
|
uint64_t elapsed;
|
||||||
CURLcode res = CURLE_OK;
|
cTimeMs processing(0);
|
||||||
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
|
|
||||||
if (rc == 200)
|
|
||||||
return true;
|
|
||||||
else if (rc != 0)
|
|
||||||
error("Tuner detected invalid status code %ld [device %d]", rc, deviceM->GetId());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
AddTunerStatistic(lengthP);
|
||||||
|
elapsed = processing.Elapsed();
|
||||||
|
if (elapsed > 1)
|
||||||
|
debug6("%s AddTunerStatistic() took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, elapsed, deviceIdM);
|
||||||
|
|
||||||
|
processing.Set(0);
|
||||||
|
deviceM->WriteData(bufferP, lengthP);
|
||||||
|
elapsed = processing.Elapsed();
|
||||||
|
if (elapsed > 1)
|
||||||
|
debug6("%s WriteData() took %" PRIu64 " ms [device %d]", __FUNCTION__, elapsed, deviceIdM);
|
||||||
|
}
|
||||||
|
reConnectM.Set(eConnectTimeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipTuner::ParseReceptionParameters(const char *paramP)
|
void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP)
|
||||||
{
|
{
|
||||||
//debug("cSatipTuner::%s(%s) [device %d]", __FUNCTION__, paramP, deviceM->GetId());
|
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM);
|
||||||
// DVB-S2:
|
// DVB-S2:
|
||||||
// ver=<major>.<minor>;src=<srcID>;tuner=<feID>,<level>,<lock>,<quality>,<frequency>,<polarisation>,<system>,<type>,<pilots>,<roll_off>,<symbol_rate>,<fec_inner>;pids=<pid0>,...,<pidn>
|
// ver=<major>.<minor>;src=<srcID>;tuner=<feID>,<level>,<lock>,<quality>,<frequency>,<polarisation>,<system>,<type>,<pilots>,<roll_off>,<symbol_rate>,<fec_inner>;pids=<pid0>,...,<pidn>
|
||||||
// DVB-T2:
|
// DVB-T2:
|
||||||
// ver=1.1;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<tmode>,<mtype>,<gi>,<fec>,<plp>,<t2id>,<sm>;pids=<pid0>,...,<pidn>
|
// ver=1.1;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<tmode>,<mtype>,<gi>,<fec>,<plp>,<t2id>,<sm>;pids=<pid0>,...,<pidn>
|
||||||
if (!isempty(paramP)) {
|
// DVB-C2:
|
||||||
char *s = strdup(paramP);
|
// ver=1.2;tuner=<feID>,<level>,<lock>,<quality>,<freq>,<bw>,<msys>,<mtype>,<sr>,<c2tft>,<ds>,<plp>,<specinv>;pids=<pid0>,...,<pidn>
|
||||||
|
if (lengthP > 0) {
|
||||||
|
char s[lengthP];
|
||||||
|
memcpy(s, (char *)bufferP, lengthP);
|
||||||
|
debug10("%s (%s) [device %d]", __PRETTY_FUNCTION__, s, deviceIdM);
|
||||||
char *c = strstr(s, ";tuner=");
|
char *c = strstr(s, ";tuner=");
|
||||||
if (c) {
|
if (c) {
|
||||||
int value;
|
int value;
|
||||||
@@ -343,7 +292,7 @@ void cSatipTuner::ParseReceptionParameters(const char *paramP)
|
|||||||
// -65dBm corresponds to 32
|
// -65dBm corresponds to 32
|
||||||
// No signal corresponds to 0
|
// No signal corresponds to 0
|
||||||
c = strstr(c, ",");
|
c = strstr(c, ",");
|
||||||
value = atoi(++c);
|
value = min(atoi(++c), 255);
|
||||||
// Scale value to 0-100
|
// Scale value to 0-100
|
||||||
signalStrengthM = (value >= 0) ? (value * 100 / 255) : -1;
|
signalStrengthM = (value >= 0) ? (value * 100 / 255) : -1;
|
||||||
|
|
||||||
@@ -352,7 +301,7 @@ void cSatipTuner::ParseReceptionParameters(const char *paramP)
|
|||||||
// "0" the frontend is not locked
|
// "0" the frontend is not locked
|
||||||
// "1" the frontend is locked
|
// "1" the frontend is locked
|
||||||
c = strstr(c, ",");
|
c = strstr(c, ",");
|
||||||
hasLockM = atoi(++c);
|
hasLockM = !!atoi(++c);
|
||||||
|
|
||||||
// quality:
|
// quality:
|
||||||
// Numerical value between 0 and 15
|
// Numerical value between 0 and 15
|
||||||
@@ -361,188 +310,280 @@ void cSatipTuner::ParseReceptionParameters(const char *paramP)
|
|||||||
// -a BER lower than 2x10-4 after Viterbi for DVB-S
|
// -a BER lower than 2x10-4 after Viterbi for DVB-S
|
||||||
// -a PER lower than 10-7 for DVB-S2
|
// -a PER lower than 10-7 for DVB-S2
|
||||||
c = strstr(c, ",");
|
c = strstr(c, ",");
|
||||||
value = atoi(++c);
|
value = min(atoi(++c), 15);
|
||||||
// Scale value to 0-100
|
// Scale value to 0-100
|
||||||
signalQualityM = (hasLockM && (value >= 0)) ? (value * 100 / 15) : 0;
|
signalQualityM = (hasLockM && (value >= 0)) ? (value * 100 / 15) : 0;
|
||||||
}
|
}
|
||||||
free(s);
|
|
||||||
}
|
}
|
||||||
|
reConnectM.Set(eConnectTimeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipTuner::SetStreamId(int streamIdP)
|
void cSatipTuner::SetStreamId(int streamIdP)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
debug("cSatipTuner::%s(%d) [device %d]", __FUNCTION__, streamIdP, deviceM->GetId());
|
debug1("%s (%d) [device %d]", __PRETTY_FUNCTION__, streamIdP, deviceIdM);
|
||||||
streamIdM = streamIdP;
|
streamIdM = streamIdP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
|
void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
debug("cSatipTuner::%s(%s, %d) [device %d]", __FUNCTION__, sessionP, timeoutP, deviceM->GetId());
|
debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, sessionP, timeoutP, deviceIdM);
|
||||||
sessionM = sessionP;
|
sessionM = sessionP;
|
||||||
|
if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0"))
|
||||||
|
rtspM.SetSession(SkipZeroes(*sessionM));
|
||||||
timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
|
timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cSatipTuner::GetId(void)
|
||||||
|
{
|
||||||
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
|
return deviceIdM;
|
||||||
|
}
|
||||||
|
|
||||||
bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const int indexP)
|
bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const int indexP)
|
||||||
{
|
{
|
||||||
debug("cSatipTuner::%s(%s, %d) [device %d]", __FUNCTION__, parameterP, indexP, deviceM->GetId());
|
debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, parameterP, indexP, deviceIdM);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
nextServerM = cSatipDiscover::GetInstance()->GetServer(serverP);
|
if (serverP) {
|
||||||
if (nextServerM && !isempty(nextServerM->Address()) && !isempty(parameterP)) {
|
nextServerM = cSatipDiscover::GetInstance()->GetServer(serverP);
|
||||||
// Update stream address and parameter
|
if (nextServerM && !isempty(nextServerM->Address()) && !isempty(parameterP)) {
|
||||||
streamAddrM = nextServerM->Address();
|
// Update stream address and parameter
|
||||||
streamParamM = parameterP;
|
streamAddrM = rtspM.RtspUnescapeString(nextServerM->Address());
|
||||||
// Reconnect
|
streamParamM = rtspM.RtspUnescapeString(parameterP);
|
||||||
Connect();
|
// Reconnect
|
||||||
|
RequestState(tsSet, smExternal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
streamAddrM = "";
|
||||||
|
streamParamM = "";
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipTuner::SetPid(int pidP, int typeP, bool onP)
|
bool cSatipTuner::SetPid(int pidP, int typeP, bool onP)
|
||||||
{
|
{
|
||||||
//debug("cSatipTuner::%s(%d, %d, %d) [device %d]", __FUNCTION__, pidP, typeP, onP, deviceM->GetId());
|
debug16("%s (%d, %d, %d) [device %d]", __PRETTY_FUNCTION__, pidP, typeP, onP, deviceIdM);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
bool found = false;
|
|
||||||
for (int i = 0; i < pidsM.Size(); ++i) {
|
|
||||||
if (pidsM[i] == pidP) {
|
|
||||||
found = true;
|
|
||||||
if (!onP)
|
|
||||||
pidsM.Remove(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (onP && !found)
|
|
||||||
pidsM.Append(pidP);
|
|
||||||
// Generate deltas
|
|
||||||
found = false;
|
|
||||||
if (onP) {
|
if (onP) {
|
||||||
for (int i = 0; i < addPidsM.Size(); ++i) {
|
pidsM.AddPid(pidP);
|
||||||
if (addPidsM[i] == pidP) {
|
addPidsM.AddPid(pidP);
|
||||||
found = true;
|
delPidsM.RemovePid(pidP);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
addPidsM.Append(pidP);
|
|
||||||
for (int i = 0; i < delPidsM.Size(); ++i) {
|
|
||||||
if (delPidsM[i] == pidP) {
|
|
||||||
delPidsM.Remove(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int i = 0; i < delPidsM.Size(); ++i) {
|
pidsM.RemovePid(pidP);
|
||||||
if (delPidsM[i] == pidP) {
|
delPidsM.AddPid(pidP);
|
||||||
found = true;
|
addPidsM.RemovePid(pidP);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
delPidsM.Append(pidP);
|
|
||||||
for (int i = 0; i < addPidsM.Size(); ++i) {
|
|
||||||
if (addPidsM[i] == pidP) {
|
|
||||||
addPidsM.Remove(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pidUpdateCacheM.Set(ePidUpdateIntervalMs);
|
debug12("%s (%d, %d, %d) pids=%s [device %d]", __PRETTY_FUNCTION__, pidP, typeP, onP, *pidsM.ListPids(), deviceIdM);
|
||||||
|
sleepM.Signal();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipTuner::UpdatePids(bool forceP)
|
bool cSatipTuner::UpdatePids(bool forceP)
|
||||||
{
|
{
|
||||||
|
debug16("%s (%d) tunerState=%s [device %d]", __PRETTY_FUNCTION__, forceP, TunerStateString(currentStateM), deviceIdM);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) &&
|
if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) &&
|
||||||
tunedM && handleM && !isempty(*streamAddrM) && (streamIdM > 0)) {
|
!isempty(*streamAddrM) && (streamIdM > 0)) {
|
||||||
CURLcode res = CURLE_OK;
|
|
||||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||||
if (forceP) {
|
bool useci = (SatipConfig.GetCIExtension() && !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkUseXCI)));
|
||||||
if (pidsM.Size()) {
|
bool usedummy = !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkPlayPids));
|
||||||
uri = cString::sprintf("%s?pids=", *uri);
|
if (forceP || usedummy) {
|
||||||
for (int i = 0; i < pidsM.Size(); ++i)
|
if (pidsM.Size())
|
||||||
uri = cString::sprintf("%s%d%s", *uri, pidsM[i], (i == (pidsM.Size() - 1)) ? "" : ",");
|
uri = cString::sprintf("%s?pids=%s", *uri, *pidsM.ListPids());
|
||||||
}
|
if (usedummy && (pidsM.Size() == 1) && (pidsM[0] < 0x20))
|
||||||
|
uri = cString::sprintf("%s,%d", *uri, eDummyPid);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (addPidsM.Size()) {
|
if (addPidsM.Size())
|
||||||
uri = cString::sprintf("%s?addpids=", *uri);
|
uri = cString::sprintf("%s?addpids=%s", *uri, *addPidsM.ListPids());
|
||||||
for (int i = 0; i < addPidsM.Size(); ++i)
|
if (delPidsM.Size())
|
||||||
uri = cString::sprintf("%s%d%s", *uri, addPidsM[i], (i == (addPidsM.Size() - 1)) ? "" : ",");
|
uri = cString::sprintf("%s%sdelpids=%s", *uri, addPidsM.Size() ? "&" : "?", *delPidsM.ListPids());
|
||||||
}
|
|
||||||
if (delPidsM.Size()) {
|
|
||||||
uri = cString::sprintf("%s%sdelpids=", *uri, addPidsM.Size() ? "&" : "?");
|
|
||||||
for (int i = 0; i < delPidsM.Size(); ++i)
|
|
||||||
uri = cString::sprintf("%s%d%s", *uri, delPidsM[i], (i == (delPidsM.Size() - 1)) ? "" : ",");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//debug("cSatipTuner::%s(): %s [device %d]", __FUNCTION__, *uri, deviceM->GetId());
|
if (useci) {
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
|
// CI extension parameters:
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
|
// - x_pmt : specifies the PMT of the service you want the CI to decode
|
||||||
SATIP_CURL_EASY_PERFORM(handleM);
|
// - x_ci : specfies which CI slot (1..n) to use
|
||||||
if (ValidateLatestResponse()) {
|
// value 0 releases the CI slot
|
||||||
addPidsM.Clear();
|
// CI slot released automatically if the stream is released,
|
||||||
delPidsM.Clear();
|
// but not when used retuning to another channel
|
||||||
|
int pid = deviceM->GetPmtPid();
|
||||||
|
if ((pid > 0) && (pid != pmtPidM)) {
|
||||||
|
int slot = deviceM->GetCISlot();
|
||||||
|
uri = cString::sprintf("%s&x_pmt=%d", *uri, pid);
|
||||||
|
if (slot > 0)
|
||||||
|
uri = cString::sprintf("%s&x_ci=%d", *uri, slot);
|
||||||
|
}
|
||||||
|
pmtPidM = pid;
|
||||||
}
|
}
|
||||||
else
|
pidUpdateCacheM.Set(ePidUpdateIntervalMs);
|
||||||
Disconnect();
|
if (!rtspM.Play(*uri))
|
||||||
|
return false;
|
||||||
|
addPidsM.Clear();
|
||||||
|
delPidsM.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipTuner::KeepAlive(bool forceP)
|
||||||
|
{
|
||||||
|
debug16("%s (%d) tunerState=%s [device %d]", __PRETTY_FUNCTION__, forceP, TunerStateString(currentStateM), deviceIdM);
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
if (keepAliveM.TimedOut()) {
|
||||||
|
keepAliveM.Set(timeoutM);
|
||||||
|
forceP = true;
|
||||||
|
}
|
||||||
|
if (forceP && !isempty(*streamAddrM)) {
|
||||||
|
cString uri = cString::sprintf("rtsp://%s/", *streamAddrM);
|
||||||
|
if (!rtspM.Options(*uri))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipTuner::ReadReceptionStatus(bool forceP)
|
||||||
|
{
|
||||||
|
debug16("%s (%d) tunerState=%s [device %d]", __PRETTY_FUNCTION__, forceP, TunerStateString(currentStateM), deviceIdM);
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
if (statusUpdateM.TimedOut()) {
|
||||||
|
statusUpdateM.Set(eStatusUpdateTimeoutMs);
|
||||||
|
forceP = true;
|
||||||
|
}
|
||||||
|
if (forceP && !isempty(*streamAddrM) && (streamIdM > 0)) {
|
||||||
|
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
||||||
|
if (rtspM.Describe(*uri))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipTuner::KeepAlive(void)
|
void cSatipTuner::UpdateCurrentState(void)
|
||||||
{
|
{
|
||||||
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
cMutexLock MutexLock(&mutexM);
|
cMutexLock MutexLock(&mutexM);
|
||||||
if (tunedM && handleM && keepAliveM.TimedOut()) {
|
eTunerState state = currentStateM;
|
||||||
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
|
||||||
CURLcode res = CURLE_OK;
|
|
||||||
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
|
|
||||||
|
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
|
if (internalStateM.Size()) {
|
||||||
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
|
state = internalStateM.At(0);
|
||||||
SATIP_CURL_EASY_PERFORM(handleM);
|
internalStateM.Remove(0);
|
||||||
if (ValidateLatestResponse())
|
}
|
||||||
keepAliveM.Set(timeoutM);
|
else if (externalStateM.Size()) {
|
||||||
else
|
state = externalStateM.At(0);
|
||||||
Disconnect();
|
externalStateM.Remove(0);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (currentStateM != state) {
|
||||||
|
debug1("%s: Switching from %s to %s [device %d]", __PRETTY_FUNCTION__, TunerStateString(currentStateM), TunerStateString(state), deviceIdM);
|
||||||
|
currentStateM = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipTuner::StateRequested(void)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
debug16("%s current=%s internal=%d external=%d [device %d]", __PRETTY_FUNCTION__, TunerStateString(currentStateM), internalStateM.Size(), externalStateM.Size(), deviceIdM);
|
||||||
|
|
||||||
|
return (internalStateM.Size() || externalStateM.Size());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cSatipTuner::RequestState(eTunerState stateP, eStateMode modeP)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutexM);
|
||||||
|
debug1("%s (%s, %s) current=%s internal=%d external=%d [device %d]", __PRETTY_FUNCTION__, TunerStateString(stateP), StateModeString(modeP), TunerStateString(currentStateM), internalStateM.Size(), externalStateM.Size(), deviceIdM);
|
||||||
|
|
||||||
|
if (modeP == smExternal)
|
||||||
|
externalStateM.Append(stateP);
|
||||||
|
else if (modeP == smInternal) {
|
||||||
|
eTunerState state = internalStateM.Size() ? internalStateM.At(internalStateM.Size() - 1) : currentStateM;
|
||||||
|
|
||||||
|
// validate legal state changes
|
||||||
|
switch (state) {
|
||||||
|
case tsIdle:
|
||||||
|
if (stateP == tsRelease)
|
||||||
|
return false;
|
||||||
|
case tsRelease:
|
||||||
|
case tsSet:
|
||||||
|
case tsLocked:
|
||||||
|
case tsTuned:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
internalStateM.Append(stateP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cSatipTuner::StateModeString(eStateMode modeP)
|
||||||
|
{
|
||||||
|
switch (modeP) {
|
||||||
|
case smInternal:
|
||||||
|
return "smInternal";
|
||||||
|
case smExternal:
|
||||||
|
return "smExternal";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "---";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cSatipTuner::TunerStateString(eTunerState stateP)
|
||||||
|
{
|
||||||
|
switch (stateP) {
|
||||||
|
case tsIdle:
|
||||||
|
return "tsIdle";
|
||||||
|
case tsRelease:
|
||||||
|
return "tsRelease";
|
||||||
|
case tsSet:
|
||||||
|
return "tsSet";
|
||||||
|
case tsLocked:
|
||||||
|
return "tsLocked";
|
||||||
|
case tsTuned:
|
||||||
|
return "tsTuned";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "---";
|
||||||
}
|
}
|
||||||
|
|
||||||
int cSatipTuner::SignalStrength(void)
|
int cSatipTuner::SignalStrength(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
return signalStrengthM;
|
return signalStrengthM;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cSatipTuner::SignalQuality(void)
|
int cSatipTuner::SignalQuality(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
return signalQualityM;
|
return signalQualityM;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSatipTuner::HasLock(void)
|
bool cSatipTuner::HasLock(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
return tunedM && hasLockM;
|
return (currentStateM >= tsTuned) && hasLockM;
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipTuner::GetSignalStatus(void)
|
cString cSatipTuner::GetSignalStatus(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
return cString::sprintf("lock=%d strength=%d quality=%d", HasLock(), SignalStrength(), SignalQuality());
|
return cString::sprintf("lock=%d strength=%d quality=%d", HasLock(), SignalStrength(), SignalQuality());
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cSatipTuner::GetInformation(void)
|
cString cSatipTuner::GetInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
|
debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM);
|
||||||
return tunedM ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed";
|
return (currentStateM >= tsTuned) ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed";
|
||||||
}
|
}
|
||||||
|
132
tuner.h
132
tuner.h
@@ -8,69 +8,129 @@
|
|||||||
#ifndef __SATIP_TUNER_H
|
#ifndef __SATIP_TUNER_H
|
||||||
#define __SATIP_TUNER_H
|
#define __SATIP_TUNER_H
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <vdr/config.h> // APIVERSNUM
|
||||||
#include <curl/easy.h>
|
|
||||||
|
|
||||||
#ifndef CURLOPT_RTSPHEADER
|
|
||||||
#error "libcurl is missing required RTSP support"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <vdr/thread.h>
|
#include <vdr/thread.h>
|
||||||
#include <vdr/tools.h>
|
#include <vdr/tools.h>
|
||||||
|
|
||||||
#include "deviceif.h"
|
#include "deviceif.h"
|
||||||
|
#include "rtp.h"
|
||||||
|
#include "rtcp.h"
|
||||||
|
#include "rtsp.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "statistics.h"
|
#include "statistics.h"
|
||||||
#include "socket.h"
|
|
||||||
|
|
||||||
class cSatipTuner : public cThread, public cSatipTunerStatistics {
|
class cSatipPid : public cVector<int> {
|
||||||
|
private:
|
||||||
|
static int PidCompare(const void *aPidP, const void *bPidP)
|
||||||
|
{
|
||||||
|
return (*(int*)aPidP - *(int*)bPidP);
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
Sort(PidCompare);
|
||||||
|
}
|
||||||
|
void AddPid(int pidP)
|
||||||
|
{
|
||||||
|
if (AppendUnique(pidP))
|
||||||
|
Sort(PidCompare);
|
||||||
|
}
|
||||||
|
cString ListPids(void)
|
||||||
|
{
|
||||||
|
cString list = "";
|
||||||
|
if (Size()) {
|
||||||
|
for (int i = 0; i < Size(); ++i)
|
||||||
|
list = cString::sprintf("%s%d,", *list, At(i));
|
||||||
|
list = list.Truncate(-1);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class cSatipTuner : public cThread, public cSatipTunerStatistics, public cSatipTunerIf
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
eConnectTimeoutMs = 1500, // in milliseconds
|
eDummyPid = 100,
|
||||||
|
eDefaultSignalStrength = 15,
|
||||||
|
eDefaultSignalQuality = 224,
|
||||||
|
eSleepTimeoutMs = 250, // in milliseconds
|
||||||
|
eStatusUpdateTimeoutMs = 1000, // in milliseconds
|
||||||
ePidUpdateIntervalMs = 250, // in milliseconds
|
ePidUpdateIntervalMs = 250, // in milliseconds
|
||||||
eReConnectTimeoutMs = 5000, // in milliseconds
|
eConnectTimeoutMs = 5000, // in milliseconds
|
||||||
eMinKeepAliveIntervalMs = 30000 // in milliseconds
|
eMinKeepAliveIntervalMs = 30000 // in milliseconds
|
||||||
};
|
};
|
||||||
|
enum eTunerState { tsIdle, tsRelease, tsSet, tsTuned, tsLocked };
|
||||||
static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
|
enum eStateMode { smInternal, smExternal };
|
||||||
|
|
||||||
cCondWait sleepM;
|
cCondWait sleepM;
|
||||||
cSatipDeviceIf* deviceM;
|
cSatipDeviceIf* deviceM;
|
||||||
unsigned char* packetBufferM;
|
int deviceIdM;
|
||||||
unsigned int packetBufferLenM;
|
cSatipRtsp rtspM;
|
||||||
cSatipSocket *rtpSocketM;
|
cSatipRtp rtpM;
|
||||||
cSatipSocket *rtcpSocketM;
|
cSatipRtcp rtcpM;
|
||||||
cString streamAddrM;
|
cString streamAddrM;
|
||||||
cString streamParamM;
|
cString streamParamM;
|
||||||
cSatipServer *currentServerM;
|
cSatipServer *currentServerM;
|
||||||
cSatipServer *nextServerM;
|
cSatipServer *nextServerM;
|
||||||
cMutex mutexM;
|
cMutex mutexM;
|
||||||
CURL *handleM;
|
cTimeMs reConnectM;
|
||||||
struct curl_slist *headerListM;
|
|
||||||
cTimeMs keepAliveM;
|
cTimeMs keepAliveM;
|
||||||
cTimeMs signalInfoCacheM;
|
cTimeMs statusUpdateM;
|
||||||
cTimeMs pidUpdateCacheM;
|
cTimeMs pidUpdateCacheM;
|
||||||
cString sessionM;
|
cString sessionM;
|
||||||
|
eTunerState currentStateM;
|
||||||
|
cVector<eTunerState> internalStateM;
|
||||||
|
cVector<eTunerState> externalStateM;
|
||||||
int timeoutM;
|
int timeoutM;
|
||||||
bool openedM;
|
|
||||||
bool tunedM;
|
|
||||||
bool hasLockM;
|
bool hasLockM;
|
||||||
int signalStrengthM;
|
int signalStrengthM;
|
||||||
int signalQualityM;
|
int signalQualityM;
|
||||||
int streamIdM;
|
int streamIdM;
|
||||||
cVector<int> addPidsM;
|
int pmtPidM;
|
||||||
cVector<int> delPidsM;
|
cSatipPid addPidsM;
|
||||||
cVector<int> pidsM;
|
cSatipPid delPidsM;
|
||||||
|
cSatipPid pidsM;
|
||||||
|
|
||||||
bool Connect(void);
|
bool Connect(void);
|
||||||
bool Disconnect(void);
|
bool Disconnect(void);
|
||||||
bool ValidateLatestResponse(void);
|
bool KeepAlive(bool forceP = false);
|
||||||
void ParseReceptionParameters(const char *paramP);
|
bool ReadReceptionStatus(bool forceP = false);
|
||||||
void SetStreamId(int streamIdP);
|
|
||||||
void SetSessionTimeout(const char *sessionP, int timeoutP = 0);
|
|
||||||
bool KeepAlive(void);
|
|
||||||
bool UpdateSignalInfoCache(void);
|
|
||||||
bool UpdatePids(bool forceP = false);
|
bool UpdatePids(bool forceP = false);
|
||||||
|
void UpdateCurrentState(void);
|
||||||
|
bool StateRequested(void);
|
||||||
|
bool RequestState(eTunerState stateP, eStateMode modeP);
|
||||||
|
const char *StateModeString(eStateMode modeP);
|
||||||
|
const char *TunerStateString(eTunerState stateP);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Action(void);
|
virtual void Action(void);
|
||||||
@@ -78,7 +138,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP);
|
cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP);
|
||||||
virtual ~cSatipTuner();
|
virtual ~cSatipTuner();
|
||||||
bool IsTuned(void) const { return tunedM; }
|
bool IsTuned(void) const { return (currentStateM >= tsTuned); }
|
||||||
bool SetSource(cSatipServer *serverP, const char *parameterP, const int indexP);
|
bool SetSource(cSatipServer *serverP, const char *parameterP, const int indexP);
|
||||||
bool SetPid(int pidP, int typeP, bool onP);
|
bool SetPid(int pidP, int typeP, bool onP);
|
||||||
bool Open(void);
|
bool Open(void);
|
||||||
@@ -88,6 +148,14 @@ public:
|
|||||||
bool HasLock(void);
|
bool HasLock(void);
|
||||||
cString GetSignalStatus(void);
|
cString GetSignalStatus(void);
|
||||||
cString GetInformation(void);
|
cString GetInformation(void);
|
||||||
|
|
||||||
|
// for internal tuner interface
|
||||||
|
public:
|
||||||
|
virtual void ProcessVideoData(u_char *bufferP, int lengthP);
|
||||||
|
virtual void ProcessApplicationData(u_char *bufferP, int lengthP);
|
||||||
|
virtual void SetStreamId(int streamIdP);
|
||||||
|
virtual void SetSessionTimeout(const char *sessionP, int timeoutP);
|
||||||
|
virtual int GetId(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __SATIP_TUNER_H
|
#endif // __SATIP_TUNER_H
|
||||||
|
26
tunerif.h
Normal file
26
tunerif.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* tunerif.h: SAT>IP plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SATIP_TUNERIF_H
|
||||||
|
#define __SATIP_TUNERIF_H
|
||||||
|
|
||||||
|
class cSatipTunerIf {
|
||||||
|
public:
|
||||||
|
cSatipTunerIf() {}
|
||||||
|
virtual ~cSatipTunerIf() {}
|
||||||
|
virtual void ProcessVideoData(u_char *bufferP, int lengthP) = 0;
|
||||||
|
virtual void ProcessApplicationData(u_char *bufferP, int lengthP) = 0;
|
||||||
|
virtual void SetStreamId(int streamIdP) = 0;
|
||||||
|
virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0;
|
||||||
|
virtual int GetId(void) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
cSatipTunerIf(const cSatipTunerIf&);
|
||||||
|
cSatipTunerIf& operator=(const cSatipTunerIf&);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SATIP_TUNERIF_H
|
Reference in New Issue
Block a user