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

Compare commits

..

304 Commits

Author SHA1 Message Date
Martin
02a842f95a
More fixes from Firefly (#84)
* fix missing retune resulting in black screen

(cherry picked from commit 0f20f764bce549f7866ab19a91d0850397de21ea)

* avoid empty and therefore useless requests to SATIP server

(cherry picked from commit 275afb68bc6a8a7fdc91600c8869815008c94d6d)

Co-authored-by: FireFly <christoph1.haubrich@arcor.de>
2023-01-05 15:43:33 +02:00
Manuel Reimer
a76ff4c25a
Several fixes for Sat-IP (#82)
* Apply vdr-satip_transfer-mode_fix.diff

Author: FireFly
VDR-Portal thread: https://www.vdr-portal.de/forum/index.php?thread/135143-satip-plugin-patches/&postID=1350960#post1350960
Patch URL: https://www.vdr-portal.de/index.php?attachment/46673-vdr-satip-transfer-mode-fix-diff/

* Apply satip_retune_fix.diff

Author: FireFly
VDR-Portal thread: https://www.vdr-portal.de/forum/index.php?thread/135143-satip-plugin-patches/&postID=1350960#post1350960
Patch URL: https://www.vdr-portal.de/index.php?attachment/46674-satip-retune-fix-diff/

* Apply satip_secfilter_fix.diff

Author: FireFly
VDR-Portal thread: https://www.vdr-portal.de/forum/index.php?thread/135143-satip-plugin-patches/&postID=1350960#post1350960
Patch URL: https://www.vdr-portal.de/index.php?attachment/46675-satip-secfilter-fix-diff/
2022-10-25 19:58:29 +03:00
Mihai Renea
64554ad0cc
SAT>IP client: UPnP header field names are case insensitive (#83)
Co-authored-by: Mihai Renea <m.renea@avm.de>
2022-10-25 19:55:50 +03:00
Rolf Ahrenberg
0a216f1cf9 Update HISTORY 2021-05-30 19:54:39 +03:00
Rolf Ahrenberg
02296fa8d7 Update README 2021-05-29 17:47:45 +03:00
Rolf Ahrenberg
417d4ed8fc Fix keepalive interval 2021-05-26 22:11:54 +03:00
Rolf Ahrenberg
1ad0a81d16 Update web links 2021-03-13 19:53:15 +02:00
Rolf Ahrenberg
27122747a7 Update detectsatip for Python3 2021-03-13 19:28:17 +02:00
Winfried Koehler
ba0b04ba12
HasLock(): add timeout feature (#71) 2021-03-02 21:50:43 +02:00
Rolf Ahrenberg
55362a2db6 Always retune without lock 2021-02-28 22:43:42 +02:00
Rolf Ahrenberg
0115ba1725 Use quirk to TEARDOWN before PLAY to avoid possible glitches 2021-02-28 20:36:21 +02:00
Winfried Koehler
43b60b1566
Add DeviceHooksProvidesEIT() from vdr-2.4.3+ (#68) 2021-01-31 13:41:04 +02:00
maazl
df81905821
Fix rofafor#65 RTSP streams not disconnected on error (#66)
Fix for #65 RTSP streams not disconnected on error
2020-12-28 21:01:12 +02:00
Rolf Ahrenberg
cc19cff5e9
Merge pull request #64 from madmartin/translation
Fix / extend german translation de_DE.
2020-12-27 19:44:12 +02:00
Martin Dummer
63d3c4370b Fix / extend german translation de_DE. 2020-09-26 12:50:55 +02:00
Rolf Ahrenberg
a7625c028c Make Inverto IDL-400s detection more common. 2020-02-18 19:06:53 +02:00
Rolf Ahrenberg
17c36fa9d2 Added quirks for Inverto IDL-400s. 2020-02-18 17:55:22 +02:00
Rolf Ahrenberg
826dea4ba8 Fixed a channel switching logic bug (Thanks to REELcoder). 2020-01-03 23:02:52 +02:00
Rolf Ahrenberg
a3fa5865f3 Add a preliminary ATSC support. 2020-01-03 22:05:18 +02:00
Rolf Ahrenberg
19e3057f34 Added an option to enable/disable frontend reuse. 2019-10-27 19:29:37 +02:00
Rolf Ahrenberg
b697e435d4 Fix URL parameter creation. 2019-02-09 00:01:13 +02:00
Rolf Ahrenberg
66d7aae89d Add a workaround for detecting Panasonic devices. 2019-01-06 16:18:45 +02:00
Rolf Ahrenberg
a4051bf88c Removed quirks from FRITZ!Box 6490 Cable due to new firmware. 2018-10-21 20:42:15 +03:00
Rolf Ahrenberg
98ecd22a27 Fix RTP over TCP with a nasty hack. 2018-10-21 20:22:37 +03:00
Rolf Ahrenberg
8130a4b4e5 Fix RTCP over TCP. 2018-10-21 13:35:48 +03:00
Rolf Ahrenberg
5254bb7ca2
Merge pull request #53 from mjanser/fix-uri-generation
Fix URI for x_pmt
2018-10-21 12:30:54 +03:00
Rolf Ahrenberg
6c74c10cbb Add an upper limit for pid validity according to the SAT>IP specification. 2018-10-21 12:25:15 +03:00
Martin Janser
6e6cd42c84 Fix URI for x_pmt if it's the only parameter
Fixes #52
2018-10-18 01:35:31 +02:00
Rolf Ahrenberg
299296bbb1 Updated for vdr-2.4.0. 2018-04-15 22:42:21 +03:00
Rolf Ahrenberg
43373b6951 Silence "misleading-indentation" warning. 2018-03-14 23:22:24 +02:00
Rolf Ahrenberg
0a15717245 Remove speed limit. 2018-02-13 17:22:25 +02:00
Rolf Ahrenberg
82cf5488a7 Avoid closing RTP/RTCP ports. 2018-02-06 22:54:36 +02:00
Rolf Ahrenberg
8dc4844db8 Fixed transport media change for RTCP. 2018-02-06 22:35:48 +02:00
Rolf Ahrenberg
e008ee04b2 Strip off the constructor delegation after all to broaden compiler compability. 2017-11-19 15:29:07 +02:00
Stefan Rehm
8be58070ad Added command line parameter to make the RTP receive bufferr size configurable. 2017-11-19 15:28:52 +02:00
Rolf Ahrenberg
72c3247dc2 Serialize channel switching to prevent device allocation failures. 2017-11-18 12:20:45 +02:00
Rolf Ahrenberg
dbe67a2242 Merge pull request #45 from pipelka/sectionfilter-poll-fix
Ignore handlers without any data.
2017-10-04 19:56:00 +03:00
Alexander Pipelka
f4454b0f0d Ignore handlers without any data. 2017-10-04 18:42:37 +02:00
Rolf Ahrenberg
0a9bb96dd4 Cleanup section filter code. 2017-10-01 22:34:18 +03:00
Rolf Ahrenberg
3cc63dadac Merge pull request #44 from pipelka/sectionfilter-send
Added transfer timeout for sectionfilter data.
2017-10-01 22:32:48 +03:00
Alexander Pipelka
46a197d8f8 Moved send loop one level down. 2017-09-28 10:29:41 +02:00
Alexander Pipelka
ece52576dd Changed include header. 2017-09-26 18:23:34 +02:00
Alexander Pipelka
5159508f2d Use error() to display error messages. 2017-09-25 20:48:20 +02:00
Alexander Pipelka
c4c2ba8d14 Defined section filter send timeout. 2017-09-25 20:37:57 +02:00
Alexander Pipelka
e90926d5f6 Minor coding-style fix. 2017-09-25 20:34:38 +02:00
Alexander Pipelka
27e86dd3ea Removed dead sleep code (comment) in cSatipSectionFilterHandler::Action(). 2017-09-25 20:32:51 +02:00
Alexander Pipelka
7e6b722747 Added transfer timeout for sectionfilter data. 2017-09-25 13:04:11 +02:00
Rolf Ahrenberg
97097f74af Merge pull request #43 from pipelka/sectionfilter-mem-leak
Fixed memory leak in cSatipSectionFilter
2017-09-24 23:24:42 +03:00
Alexander Pipelka
1de063ca38 Fixed memory leak in cSatipSectionFilter. 2017-09-24 22:23:08 +02:00
Rolf Ahrenberg
bf5b058725 Update HISTORY. 2017-08-15 09:22:39 +03:00
Rolf Ahrenberg
470fee436f Merge pull request #40 from CvH/gcc7
Fix GCC7 compiling
2017-08-14 19:07:52 +03:00
Sascha Kuehndel (InuSasha)
c10372bb4f fix gcc7 compiling 2017-08-14 17:17:47 +02:00
Rolf Ahrenberg
1984ec662c Fix info messages. 2017-07-31 16:18:45 +03:00
Rolf Ahrenberg
537c0ad000 Refactor the server detection script. 2017-07-31 16:18:02 +03:00
Rolf Ahrenberg
732e28d0f0 Add a server detection script. 2017-07-22 13:39:16 +03:00
Rolf Ahrenberg
3a9dc9a634 Add support for interface binding via a defined source address. 2017-07-22 13:38:54 +03:00
Rolf Ahrenberg
438f5c9254 Update quirks for FRITZ!WLAN Repeater DVB-C and FRITZ!Box 6490 Cable devices. 2017-07-18 14:13:24 +03:00
Rolf Ahrenberg
5e524a969e Update HISTORY. 2017-06-25 14:21:41 +03:00
Rolf Ahrenberg
8b1d8de468 Adapt VDR's Makefile style again. 2017-06-04 23:01:25 +03:00
Rolf Ahrenberg
12b5dac447 Adapt VDR's new Makefile style. 2017-05-25 15:11:25 +03:00
Rolf Ahrenberg
40943b8bd2 Add support for cDevice::SignalStats(). 2017-05-25 14:51:51 +03:00
Rolf Ahrenberg
e092d085b8 Merge pull request #36 from kavanu/master
Added support for Kathrein ExIP 414/E.
2017-05-17 19:03:10 +03:00
kavanu
1158141d35 added name of "KATHREIN SatIP Server" 2017-05-17 09:43:51 +02:00
Rolf Ahrenberg
c6145e1ed9 Adapt decryption for vdr-2.3.4 (Thanks to Klaus Schmidinger). 2017-04-17 22:10:29 +03:00
Rolf Ahrenberg
c5da1074f3 Merge pull request #35 from tmn505/polish_language
Add polish language
2017-02-28 21:52:35 +02:00
Tomasz Maciej Nowak
69795ec82a Add polish language 2017-02-28 16:36:50 +01:00
Rolf Ahrenberg
3cf32a64eb Remove non-compatible RTP-over-TCP devices. 2017-02-25 14:03:49 +02:00
Frank Neumann
3fd4928d75 Update Catalan and Espanol translations. 2017-02-11 19:32:18 +02:00
Rolf Ahrenberg
941a13b794 Add musl-libc compatibility. 2017-01-05 17:27:13 +02:00
Rolf Ahrenberg
20e9dc99f9 Updated HISTORY. 2016-12-18 17:25:24 +02:00
Rolf Ahrenberg
d26658a22e Prefer section pids. 2016-12-16 08:17:41 +02:00
Rolf Ahrenberg
a5d57e9390 Add a preliminary RTP-over-TCP support. 2016-12-15 23:47:30 +02:00
Frank Neumann
af64cb3011 Update German translations. 2016-12-15 08:10:48 +02:00
Rolf Ahrenberg
48862f99d3 Add a preliminary multicast support. 2016-12-14 00:37:36 +02:00
Rolf Ahrenberg
6ed729c153 Add a new ForcePilot quirk. 2016-11-10 16:47:30 +02:00
Rolf Ahrenberg
0fc044a316 Update README. 2016-11-10 16:47:10 +02:00
Rolf Ahrenberg
94b7f1132f Add command-line support for setting server quirks. 2016-10-09 18:53:40 +03:00
Rolf Ahrenberg
e7c9b04ad2 Add preliminary support for DVBViewer CI. 2016-09-11 13:08:20 +03:00
Rolf Ahrenberg
9c91e01a87 Handle Out-of-Range responses as a normal operation. 2016-09-09 19:59:12 +03:00
Rolf Ahrenberg
7a84ba78c8 Check source validity also in server assign (Thanks to Patrick Boettcher). 2016-07-31 12:00:55 +03:00
Rolf Ahrenberg
c2fe2b748d Add support for source filtering. 2016-07-30 13:42:44 +03:00
Rolf Ahrenberg
13a6b5938f Fix command-line examples to match defined quirks. 2016-07-23 17:37:07 +03:00
Rolf Ahrenberg
5db9f93a11 Fix active device check. 2016-06-23 15:36:51 +03:00
Rolf Ahrenberg
cede4743cb Add support for activating/deactivating server on-the-fly. 2016-06-22 22:49:04 +03:00
Rolf Ahrenberg
4e9b6f11eb Add support for RTP-over-TCP. 2016-06-21 23:02:46 +03:00
Rolf Ahrenberg
4b1892d754 Change EINTR handling in poller. 2016-06-05 14:19:46 +03:00
Rolf Ahrenberg
473e016152 Use 2MB ringbuffer per device. 2016-05-12 23:46:27 +03:00
Rolf Ahrenberg
793aab17d7 Set SO_REUSEPORT only if it's defined. 2016-05-07 21:43:49 +03:00
Rolf Ahrenberg
8222d05f5d Re-enable to reuse address for msearch protocol. 2016-04-11 23:02:12 +03:00
Rolf Ahrenberg
9d7c745fe1 Reset device name when the device is idling. 2016-03-19 20:33:00 +02:00
Rolf Ahrenberg
c8a5245b6c Fix statistics output a bit more. 2016-02-28 18:23:31 +02:00
Rolf Ahrenberg
ff459f426e Fix statistics output. 2016-02-28 15:32:28 +02:00
Rolf Ahrenberg
4c216d81c8 Added support for X-SATIP-RTSP-Port header. 2016-02-27 17:28:13 +02:00
Rolf Ahrenberg
23e2b4d54d Merge pull request #18 from e-tobi/master
C++11 requires a mandatory space when concatenating string literals
2016-01-30 21:43:42 +02:00
Rolf Ahrenberg
954e1be6b3 Add a missing device name update. 2016-01-30 21:41:10 +02:00
Tobias Grimm
e46340f5f3 C++11 requires a mandatory space when concatenating string literals 2016-01-23 18:38:44 +01:00
Rolf Ahrenberg
d5e9b1050e Merge pull request #16 from chriszero/master
Make it possible to specify the rtp and rtcp ports
2016-01-08 20:22:51 +02:00
chriszero
6e9b5fc414 Make it possible to specify the rtp and rtcp ports
this makes it possible to use the satip through a
NAT (e.g. a docker bridged network)
2016-01-07 21:09:39 +01:00
Rolf Ahrenberg
6e9b43b0d8 Reorder also terrestrial and cable query parameters as introduced in the satip specification 1.2.2, although the ordering shouldn't matter according to it. 2015-12-05 20:23:32 +02:00
Rolf Ahrenberg
97aba6db0f Merge pull request #14 from e-tobi/master
Reorderd the transponder URL parameter in a way the Panasonic CXW804 …
2015-12-05 20:13:50 +02:00
Tobias Grimm
660c48a9f4 Reorderd the transponder URL parameter in a way the Panasonic CXW804 expects them
(src/freq/pol/ro/msys/mtype/plts/sr/fec)

This only applies to DVB-S. DVB-C and DVB-T might need further tweaking.
It's actually a bug of the Panasonic TV to expect the transponder parameters in
a specific order in the query string, but for now this seems to be the most
pragmatic workaround.
2015-12-05 17:11:44 +01:00
Rolf Ahrenberg
67b6c9f4f7 Removed support for older version than vdr-2.3.1. 2015-09-18 18:58:07 +03:00
Rolf Ahrenberg
37a0572a64 Updated HISTORY. 2015-09-18 18:49:44 +03:00
Rolf Ahrenberg
613c0aed7c Added a force lock quirk for Schwaiger MS41IP. 2015-09-18 18:31:53 +03:00
Rolf Ahrenberg
c3ad29eb27 Updated for vdr-2.3.1 (Thanks to Klaus Schmidinger). 2015-08-20 19:12:21 +03:00
Rolf Ahrenberg
e90b8651e6 Silenced some cppcheck warnings. 2015-08-16 01:38:03 +03:00
Rolf Ahrenberg
0f370aa36a Added a tuning timeout for better recovery. 2015-08-16 01:10:52 +03:00
Rolf Ahrenberg
49e2dd1fc1 Reset the RTSP connection after any failed connect. 2015-06-04 18:51:09 +03:00
Rolf Ahrenberg
ba0b808ec4 Enabled the X_PMT extension for minisatip servers. 2015-05-26 21:18:05 +03:00
Rolf Ahrenberg
4e2535a7e2 Added a double check for the idle release. 2015-05-23 15:28:37 +03:00
Rolf Ahrenberg
6384b8694e Added a timeout for releasing idling devices. 2015-05-22 22:43:08 +03:00
Rolf Ahrenberg
6c4c8a10b7 Set the default device count to two. 2015-04-26 12:49:40 +03:00
Rolf Ahrenberg
8b43cdc634 Added initial support for detaching and attaching SAT>IP servers. 2015-04-12 21:25:41 +03:00
Rolf Ahrenberg
fe010ab72c Added a more flexible OPER command in the SVDRP interface. 2015-04-09 21:36:13 +03:00
Rolf Ahrenberg
7bdc152f76 Prepared for a release. 2015-04-03 20:37:29 +03:00
Rolf Ahrenberg
bd6774ba28 Relaxed the server cleanup timeout. 2015-03-26 00:28:17 +02:00
Rolf Ahrenberg
fbf7977853 Added a memory guard for cSatipMemoryBuffer(). 2015-03-26 00:23:55 +02:00
Rolf Ahrenberg
19a6a4a5ee Simplified GetTransponderUrlParameters(). 2015-03-22 23:44:15 +02:00
Rolf Ahrenberg
7b683dba8d Implemented cSatipMemoryBuffer(). 2015-03-22 20:06:47 +02:00
Rolf Ahrenberg
942d3a936e Fixed CURL buffer size for discovery. 2015-03-22 17:33:08 +02:00
Rolf Ahrenberg
748ea15d1d Updated against SAT>IP protocol specification version 1.2.2. 2015-03-22 16:47:02 +02:00
Rolf Ahrenberg
1d75da403a Simplified GetTransponderUrlParameters(). 2015-03-22 16:33:48 +02:00
Rolf Ahrenberg
4d8263e8fd Improved RTSP error checking. 2015-03-18 22:59:38 +02:00
Rolf Ahrenberg
7019b719a5 Fixed a memory leak in TinyXML implementation (Thanks to Oliver Endriss). 2015-03-18 20:55:10 +02:00
Rolf Ahrenberg
39249ca2d5 Fixed generic error macros. 2015-03-08 15:53:54 +02:00
Rolf Ahrenberg
68e0d1474e Got rid of SATIP_DEBUG. 2015-03-07 17:50:48 +02:00
Rolf Ahrenberg
ad5c221e44 Fixed wrong indenting. 2015-03-04 19:43:01 +02:00
Rolf Ahrenberg
826e53e8ea Fixed the discovery tracing level. 2015-03-03 19:09:51 +02:00
Rolf Ahrenberg
f4dd02a9aa Robustify the server discovery. 2015-03-02 20:08:21 +02:00
Rolf Ahrenberg
8184a785b7 Updated README. 2015-02-20 21:15:55 +02:00
Rolf Ahrenberg
1b4094696a Updated HISTORY. 2015-02-20 20:53:20 +02:00
Rolf Ahrenberg
4139e87f4a Disable socket flushing. 2015-02-20 20:51:31 +02:00
Rolf Ahrenberg
7196c9403b Updated the APIVERSNUM requirement. 2015-02-20 20:47:58 +02:00
Rolf Ahrenberg
e1c896c1a6 Added a missing linefeed. 2015-02-17 21:16:30 +02:00
Rolf Ahrenberg
6b63ad145f Fixed the frontend assignment. 2015-02-16 19:42:18 +02:00
Rolf Ahrenberg
84dfc6701e Refactored the frontend attaching/detaching signaling. 2015-02-16 17:59:27 +02:00
Rolf Ahrenberg
653d9d659b Updated README. 2015-02-16 16:49:51 +02:00
Rolf Ahrenberg
26cd34f965 Updated version to 2.2.0. 2015-02-08 22:41:01 +02:00
Rolf Ahrenberg
df258d127f Reverted the force locking quirk for Triax TSS 400. 2015-01-27 21:31:39 +02:00
Rolf Ahrenberg
3e4b1c0383 Updated the server info message to show used quirks. 2015-01-27 17:19:06 +02:00
Rolf Ahrenberg
73ed299ed9 Fixed to nag about any malfunctioning firmware only once. 2015-01-26 00:24:07 +02:00
Rolf Ahrenberg
37e151b3e3 Added the force locking quirk for Triax TSS 400. 2015-01-25 23:47:56 +02:00
Rolf Ahrenberg
b1aad3fb80 Updated the version number. 2015-01-24 17:21:04 +02:00
Rolf Ahrenberg
a87dfc43f7 Refactored the frontend handling. 2015-01-24 17:16:09 +02:00
Rolf Ahrenberg
26be862d89 Refactored some errno handling. 2015-01-24 16:20:13 +02:00
Rolf Ahrenberg
ab2a47e3e7 Got rid of scan-build warnings. 2015-01-22 21:37:33 +02:00
Rolf Ahrenberg
3d1efe7a80 Fixed freeing some memory. 2015-01-21 22:40:24 +02:00
Rolf Ahrenberg
c9898bfbfd Added support for showing the frontend id. 2015-01-20 00:35:46 +02:00
Rolf Ahrenberg
46bfc805e6 Removed SATIP_XCI. 2015-01-18 15:08:57 +02:00
Rolf Ahrenberg
30925337cb Updated Spanish and Catalan translations (Thanks to Gabriel Bonich). 2015-01-18 00:13:29 +02:00
Rolf Ahrenberg
63e47ad24a Reworded the README. 2015-01-17 20:02:18 +02:00
Rolf Ahrenberg
14123e160f Fixed the server parsing multiple times. 2015-01-17 19:42:21 +02:00
Rolf Ahrenberg
278d0478cf Added a command-line option to disable all the SAT>IP server quirks. 2015-01-17 17:29:21 +02:00
Rolf Ahrenberg
9989c36eee Delayed the server parameter parsing. 2015-01-17 16:47:19 +02:00
Rolf Ahrenberg
d2064f0c04 Added an option to disable sources via sources.conf. 2015-01-17 01:39:32 +02:00
Rolf Ahrenberg
714d3ed902 Increased the max number of disabled sources. 2015-01-17 00:45:30 +02:00
Rolf Ahrenberg
b466d6836e Added NULL checks for cSatipServer parameters. 2015-01-17 00:00:59 +02:00
Rolf Ahrenberg
184ddf2a53 Fixed a wrong parameter type. 2015-01-16 00:08:48 +02:00
Rolf Ahrenberg
65a2158051 Fixed some whitespaces. 2015-01-15 23:38:02 +02:00
Rolf Ahrenberg
e833ca6fdd Added a separate trace mode for pids. 2015-01-15 20:03:35 +02:00
Rolf Ahrenberg
c9abfddf11 Changed SATIP_USE_SINGLE_MODEL_SERVERS_ONLY into a command-line switch. 2015-01-15 19:27:02 +02:00
Rolf Ahrenberg
fb7a7fe3a2 Fixed parsing of the setup values. 2015-01-15 00:12:55 +02:00
Rolf Ahrenberg
3b9269e9de Added a separate trace mode for server discovery. 2015-01-14 22:59:56 +02:00
Rolf Ahrenberg
09e6c272cd Refactored cSatipPid for upcoming API changes. 2015-01-14 20:51:16 +02:00
Rolf Ahrenberg
266aadb999 Modified the model detection a bit more readable. 2015-01-14 20:34:12 +02:00
Rolf Ahrenberg
aed5a7820a Fixed 'length' typos. 2015-01-14 17:58:13 +02:00
Rolf Ahrenberg
bcb11b6257 Added a compile-time option to split any mixed model server into several single ones. 2015-01-13 21:45:14 +02:00
Rolf Ahrenberg
21261f8042 Clamp signal quality and level values. 2015-01-12 23:58:30 +02:00
Rolf Ahrenberg
2f11ad7a98 Added server parameter exanples. 2015-01-12 23:51:38 +02:00
Rolf Ahrenberg
83a0233780 Updated German translation (Thanks to Frank Neumann). 2015-01-12 13:09:09 +02:00
Rolf Ahrenberg
6f3715eb8b Merge pull request #5 from CvH/patch-1
Fixed a typo in firmware version.
2015-01-12 09:22:43 +02:00
CvH
92991cd144 fixed typo at fw version 2015-01-11 22:52:40 +01:00
Rolf Ahrenberg
304addbc00 Added missing CI/CAM translations. 2015-01-11 23:49:12 +02:00
Rolf Ahrenberg
26ff10ce1e Added configurable CI slots. 2015-01-11 16:34:32 +02:00
Rolf Ahrenberg
e654b3bbd2 Updated version number. 2015-01-11 16:33:42 +02:00
Rolf Ahrenberg
acea8748a4 Added SATIP_XCI variable for enabling CI support. 2015-01-10 18:30:07 +02:00
Rolf Ahrenberg
755f1049bb Reduced tuner sleep timeout to get better performance for pid updates. 2015-01-10 14:14:30 +02:00
Rolf Ahrenberg
2f6315280f Tweaked setting the pid update cache timer. 2015-01-09 19:56:43 +02:00
Rolf Ahrenberg
695dd53bfc Added initial support for x_ci parameter. 2015-01-09 16:38:02 +02:00
Rolf Ahrenberg
5fef77518e Changed the PMT debugging into a separate trace mode. 2015-01-09 02:06:20 +02:00
Rolf Ahrenberg
791767f02b Documented CI extension parameters. 2015-01-07 17:45:48 +02:00
Rolf Ahrenberg
0d52649dbd Added the missing translation item. 2015-01-06 21:41:52 +02:00
Rolf Ahrenberg
0c03c1b8d4 Added a CI extension item into the device info menu. 2015-01-06 19:46:56 +02:00
Rolf Ahrenberg
db59aa9c29 Added support for Digital Devices CI extension. 2015-01-06 15:53:31 +02:00
Rolf Ahrenberg
0fd559ce79 Added a fallback for older glibc libraries. 2015-01-05 20:24:45 +02:00
Rolf Ahrenberg
e10ce57210 Removed the unnecessary config directory definition. 2015-01-05 20:15:04 +02:00
Rolf Ahrenberg
c7f4b265d5 Fixed the server teardown. 2015-01-05 20:12:15 +02:00
Rolf Ahrenberg
35c0f25c38 Updated the command-line help and README. 2015-01-05 20:09:45 +02:00
Rolf Ahrenberg
dadd26f980 Removed an unnecessary wait. 2014-12-22 21:19:24 +02:00
Rolf Ahrenberg
5c5f21631f Added transponder information into the device info menu. 2014-12-22 20:16:28 +02:00
Rolf Ahrenberg
29eaf994f8 Added a multicast mode for the RTSP setup. 2014-12-21 16:31:38 +02:00
Rolf Ahrenberg
f884b23f7c Renamed logging to tracing. 2014-12-21 16:11:05 +02:00
Rolf Ahrenberg
1bc2dc01fd Updated HISTORY. 2014-12-20 18:58:15 +02:00
Rolf Ahrenberg
eba49c979f Removed the special logging mode for a debug build. 2014-12-20 18:50:34 +02:00
Rolf Ahrenberg
3475c179d1 Added an info message for malfunctioning devices with quirks. 2014-12-20 18:47:02 +02:00
Rolf Ahrenberg
4cb25ce93c Fixed CURLOPT_URL. 2014-12-20 18:46:00 +02:00
Rolf Ahrenberg
c5499ce1da Prepare for a release. 2014-12-19 20:08:27 +02:00
Rolf Ahrenberg
fa226b0d2f Removed DVB-C model quirks from OctopusNet. The firmware version 1.0.40 looks correct. 2014-12-18 00:27:13 +02:00
Rolf Ahrenberg
4b714196f3 Added a SCAN command into the SVDRP interface. 2014-12-18 00:25:01 +02:00
Rolf Ahrenberg
9cace319a3 Reformatted some info messages. 2014-12-16 23:09:31 +02:00
Rolf Ahrenberg
01d2afcfc2 Fixed reconnection. 2014-12-16 23:09:14 +02:00
Rolf Ahrenberg
8ea561a021 Fixed the default logging mode in a DEBUG build. 2014-12-16 22:00:22 +02:00
Rolf Ahrenberg
d23578cea9 Fixed a race condition while updating pids. 2014-12-14 22:09:18 +02:00
Rolf Ahrenberg
629c4ff378 Renamed threads and ringbuffers. 2014-12-14 21:39:13 +02:00
Rolf Ahrenberg
2d997b3fdd Added RTCP packet logging. 2014-12-14 19:22:52 +02:00
Rolf Ahrenberg
7f9d016b52 Deduplicated pid listings. 2014-12-14 17:54:37 +02:00
Rolf Ahrenberg
778f3bd84a Preliminary documentation for used logging modes. 2014-12-14 17:45:55 +02:00
nafets227
382e1dedef Performance enhancement via recvmmsg().
Use recvmmsg() in order to read multiple packets with one system call.
This improves performance, especially in have loaded areas when catching up
a log of queued packets.

Original patch tweaked and optimized by Rolf Ahrenberg.
2014-12-14 15:39:18 +02:00
Rolf Ahrenberg
fecbd3cbd4 Added better logging for channel changes. 2014-12-14 01:56:21 +02:00
nafets227
7c1aa732b4 Improved RTP data logging.
Original patch tweaked ad optimized by Rolf Ahrenberg.
2014-12-12 21:38:11 +02:00
Rolf Ahrenberg
395390fb32 Added a device hook support for ProvidesTransponder(). 2014-12-09 21:56:32 +02:00
nafets227
913cdbef66 Logging improvements.
Logging of RTSP command summaries on debug 5
Logging for Performance/Locking on debug 6

Original patch tweaked and optimized by Rolf Ahrenberg.
2014-12-09 00:27:19 +02:00
Rolf Ahrenberg
60a2b1fecf Fixed the LOGG SVDRP command output. 2014-12-08 21:37:17 +02:00
Rolf Ahrenberg
b9d89b8c1d Added more debugging macros. 2014-12-08 21:23:23 +02:00
Rolf Ahrenberg
d0ffc3e1a5 Enabled CURL debug callbacks always. 2014-12-07 23:14:02 +02:00
Rolf Ahrenberg
46db1dea11 Reworked the RTSP debug callback to adapt dynamically any logging mode changes during SETUP. 2014-12-07 22:04:39 +02:00
Rolf Ahrenberg
dd320af7f2 Fixed the session id quirk. 2014-12-07 21:58:06 +02:00
Rolf Ahrenberg
d6ffffd932 Fixed the tuning status. 2014-12-07 18:12:08 +02:00
Rolf Ahrenberg
7f9060a4cb Reformatted debug messages. 2014-12-07 17:27:53 +02:00
Rolf Ahrenberg
097a607389 Renamed some "SAT>IP" texts into a simpler "SATIP". 2014-12-07 16:19:23 +02:00
Rolf Ahrenberg
45b3166729 Simplified the logging interface. 2014-12-07 16:10:12 +02:00
Rolf Ahrenberg
38f815d439 Added new debugging modes. 2014-12-06 17:10:02 +02:00
Rolf Ahrenberg
23dce9e205 Changed logging to to use SATIP instead of SAT>IP. 2014-12-06 00:37:55 +02:00
Rolf Ahrenberg
796a047401 Renamed logging level to the actual mask. 2014-12-06 00:06:24 +02:00
Rolf Ahrenberg
b62a25597b Reworked header dependencies. 2014-12-05 23:14:40 +02:00
Rolf Ahrenberg
81f6af3bdf Reformat debug messages. 2014-12-05 23:02:57 +02:00
Rolf Ahrenberg
9a40a8eeec Fixed compilation under g++-4.7. 2014-12-04 21:44:44 +02:00
Rolf Ahrenberg
0668fb7a15 Added a new extra() macro. 2014-12-03 22:57:04 +02:00
Rolf Ahrenberg
735e7487d3 Added a preliminary support for dynamic logging level. 2014-12-03 19:57:23 +02:00
Rolf Ahrenberg
d48fe3bced Fixed OPTIONS url and enabled retuning. 2014-12-03 01:42:33 +02:00
Rolf Ahrenberg
98437ce57e Fixed retuning. 2014-12-02 23:19:24 +02:00
Rolf Ahrenberg
f6ab251294 Removed unnecessary this declarations. 2014-12-01 21:50:02 +02:00
Rolf Ahrenberg
0fe1722dee Increased TS buffer size to one megabyte to avoid overrun errors on my RPi. 2014-12-01 20:26:19 +02:00
Rolf Ahrenberg
9b88c0d55f Decreased TS buffer timeouts to 10ms. 2014-12-01 18:12:12 +02:00
Rolf Ahrenberg
e6e185cbd7 Changed int to uint64_t. 2014-11-30 01:00:20 +02:00
nafets227
561ca26098 Reduced locking scope for a performance improvement.
Reduced the time that cSatipTunerStatistics() is locked.
This is important for poller thread as every lock in cSatipTunerStatistics()
leads to the poller thread waiting in SatipTuner::ProcessVideoData().
2014-11-30 00:54:05 +02:00
nafets227
4600a2a070 Performance improvement by avoiding locks in cSatipTuner::ProcessApplicationData().
Don't use malloc, but put variable on stack (=local char array).
This avoids a possible lock with other threads, because malloc uses global
storage and needs a lock then.

Tests eliminated the long lasting processing of RTCP packaged in poller
Thread.
2014-11-29 21:24:29 +02:00
Rolf Ahrenberg
52f54d2177 Prepare for a release. 2014-11-29 17:03:07 +02:00
Rolf Ahrenberg
8415075de9 Added preliminary tuner state queues. 2014-11-29 17:00:31 +02:00
Rolf Ahrenberg
eea0aa33bd Added cSatipDiscoverIf(). 2014-11-29 15:37:21 +02:00
Rolf Ahrenberg
cdb2e0e3b4 Added logging of maximum processing time in cPoller(). 2014-11-29 14:51:27 +02:00
nafets227
e0727516ce Bugfix: Don't block in cTunerIf()::Process(Video|Application)Data() methods.
The original patch is polished and tweaked by Rolf Ahrenberg.
2014-11-29 14:26:59 +02:00
nafets227
fde3198997 Bugfix: Reading from sockets.
In cSatipRtp::Process() und cSatipRtcp::Process() we need to read until no more data is
available, not just once.

The original patch is polished and tweaked by Rolf Ahrenberg.
2014-11-27 23:13:51 +02:00
nafets227
c966d28d13 Bugfix: Write data to tsbuffer only if DvrOpen has been called. This avoids Buffer Overflow when not recording or viewing live. 2014-11-26 23:51:49 +02:00
Rolf Ahrenberg
6d68ef3e49 Simplified poller interface. 2014-11-25 22:04:34 +02:00
Rolf Ahrenberg
1642f59980 Get rid of CheckData() as we are receiving only live streams. 2014-11-23 19:28:29 +02:00
nafets227
80abbddae7 Corrected log Macros.
If used like the code below, it would produce a compile error as
in the 'if' path there would be two semicolons:

if (anything)
   debug(...);
else
   doanything();
2014-11-23 17:59:32 +02:00
Rolf Ahrenberg
8bd4a1a67d Fixed teardown. 2014-11-23 00:13:15 +02:00
Rolf Ahrenberg
3a16e57f87 Get rid of OPTIONS while retuning. 2014-11-22 23:17:32 +02:00
Rolf Ahrenberg
1244397365 Updated debug messages. 2014-11-22 21:55:58 +02:00
Rolf Ahrenberg
1f528cf7e1 Fixed tuner shutdown. 2014-11-22 21:33:31 +02:00
Rolf Ahrenberg
5d697c36dc Fixed reading reception status. 2014-11-22 20:06:56 +02:00
Rolf Ahrenberg
005fa59dd6 Tweaked tuning. 2014-11-22 17:04:32 +02:00
Rolf Ahrenberg
6d64a8b0a7 Fixed keep-alive and retuning. 2014-11-22 15:01:37 +02:00
Rolf Ahrenberg
4e2e6d0b9b Fixed OPTIONS syntax. 2014-11-22 12:26:50 +02:00
Rolf Ahrenberg
ade52d5a22 Cleaned up debug messages. 2014-11-21 23:56:03 +02:00
Rolf Ahrenberg
524b21e042 Updated against SAT>IP protocol specification version 1.2.1. 2014-11-20 22:39:19 +02:00
Rolf Ahrenberg
0896df33e6 Merge pull request #3 from rofafor/poller
Refactored poller implementation.
2014-11-19 22:17:48 +02:00
Rolf Ahrenberg
111a1ff16d Merge branch 'master' into poller
Conflicts:
	tuner.c
	tuner.h
2014-11-19 22:10:54 +02:00
Rolf Ahrenberg
8d198178bb Updated version number. 2014-11-19 21:16:51 +02:00
Rolf Ahrenberg
ec596a02b8 Tweaked tuner state machine. 2014-11-19 21:05:18 +02:00
Rolf Ahrenberg
8ec972d4ee Factored tuner state machine a bit more robust. 2014-11-17 22:59:01 +02:00
Rolf Ahrenberg
54f8b4f0a6 Get rid of pointers. 2014-11-17 22:33:38 +02:00
Rolf Ahrenberg
f5015bcfba Refactored device discovery. 2014-11-17 22:28:11 +02:00
Rolf Ahrenberg
443dd9706a Get rid of a magic number. 2014-11-16 21:42:24 +02:00
Rolf Ahrenberg
2dcf3bbd6a Get rid of pointers. 2014-11-16 17:03:40 +02:00
Rolf Ahrenberg
12d61d37cf Renamed Action() to Process(). 2014-11-16 17:03:35 +02:00
Rolf Ahrenberg
a94d25b635 Get rid of pointers. 2014-11-16 16:39:20 +02:00
Rolf Ahrenberg
6b2090e9ad Moved tuner statistics back to cSatipTuner. 2014-11-16 16:30:45 +02:00
Rolf Ahrenberg
5c051d919b Fixed tuner reconnection issues. 2014-11-16 15:38:23 +02:00
Rolf Ahrenberg
02bf42b006 Fixed buffer handling in cSatipTuner::ParseReceptionParameters(). 2014-11-16 15:00:08 +02:00
nafets227
adddf3e4e7 Moved ReadVideo/Application() from cSatipSocket into cSatipRtp/cStatipRtcp classes and get rid of unnecessary memcpy.
The original patch is polished and tweaked by Rolf Ahrenberg.
2014-11-16 14:56:59 +02:00
Rolf Ahrenberg
3a742f1f14 Fixed cSatipTuner::Disconnect(). 2014-11-15 22:59:40 +02:00
Rolf Ahrenberg
82fe5c59c8 Fixed cSatipTuner::Disconnect(). 2014-11-15 22:58:52 +02:00
Rolf Ahrenberg
304f1d4af6 Fixed cSatipTuner::Connect(). 2014-11-15 22:16:38 +02:00
Rolf Ahrenberg
4a9a36a9c2 Tweaked error messages. 2014-11-15 22:15:47 +02:00
Rolf Ahrenberg
daa2f903c8 Fixed cSatipTuner::Connect(). 2014-11-15 22:05:46 +02:00
Rolf Ahrenberg
d36597954a Tweaked error messages. 2014-11-15 21:58:38 +02:00
Rolf Ahrenberg
0bf841555b Implemented a preliminary state machine for tuner. 2014-11-15 20:44:42 +02:00
Rolf Ahrenberg
0431806f24 Implemented a preliminary state machine for tuner. 2014-11-15 20:29:12 +02:00
Nafets227
ede0294943 Refactored polling.
The original patch is polished and tweaked by Rolf Ahrenberg.
2014-11-15 02:12:35 +02:00
Rolf Ahrenberg
e05801b464 Refactored epoll() to use only one thread. 2014-11-11 21:10:44 +02:00
Rolf Ahrenberg
e51650cd0a Updated HISTORY. 2014-11-11 00:38:03 +02:00
Rolf Ahrenberg
45d0227d2b Tweaked internals and log messages to match SVDRP interface. 2014-11-11 00:05:03 +02:00
Rolf Ahrenberg
7110cee7a9 Added STAT command into SVDRP interface. 2014-11-10 23:46:45 +02:00
Rolf Ahrenberg
a9109d750c Some minor tweaks. 2014-11-10 23:31:30 +02:00
Rolf Ahrenberg
ac4ab867d9 Switched to epoll(). 2014-11-10 23:05:26 +02:00
Rolf Ahrenberg
2f723e0f66 Added cSatipRtsp(). 2014-11-09 16:42:14 +02:00
Rolf Ahrenberg
72a5ad34fb Added cSatipPid(). 2014-11-09 12:48:45 +02:00
Rolf Ahrenberg
123fc5f96b Added support for CURL debug callback. 2014-11-09 02:25:47 +02:00
Rolf Ahrenberg
cf930286c2 Updated German translation (Thanks to Stefan Schallenberg). 2014-11-08 20:01:59 +02:00
Rolf Ahrenberg
2308fc4a65 Fixed EIT scan (Thanks to Stefan Schallenberg). 2014-11-08 20:01:47 +02:00
Rolf Ahrenberg
04e7648c01 Added support for SAT>IP frontend selection via Radio ID. 2014-11-04 23:20:10 +02:00
Rolf Ahrenberg
18ca0beaa7 Added support for defining multiple SAT>IP servers via the command-line switch. 2014-11-04 22:32:12 +02:00
Rolf Ahrenberg
aeb8f24474 Added support for Telestar Digibit R1 (Thanks to Dirk Wagner). 2014-11-04 21:02:30 +02:00
Rolf Ahrenberg
bde88d78b1 Added a command-line switch for manually defining a SAT>IP server. 2014-11-03 23:57:08 +02:00
Rolf Ahrenberg
30e8040f99 Decreased the default buffer size. 2014-11-03 21:57:16 +02:00
Rolf Ahrenberg
5795bb58af Fixed SetChannelDevice() with NULL channel and EOL in ReadApplication(). 2014-11-03 21:55:54 +02:00
Rolf Ahrenberg
d81f700194 Added a new device status menu. 2014-11-03 21:55:28 +02:00
Rolf Ahrenberg
0de0be5ae4 Added a preliminary support for Fritz!WLAN Repeater DVB-C (Thanks to Christian Wick). 2014-11-03 21:54:19 +02:00
Rolf Ahrenberg
92b2c63f0d Fixed server reuse for active transponders. 2014-11-01 16:31:44 +02:00
Rolf Ahrenberg
c4d82eac36 Added support for blacklisted sources. 2014-10-31 22:17:52 +02:00
Rolf Ahrenberg
3630a9f78a Added a quirk to avoid addpids/delpids in PLAY commands. 2014-10-31 18:18:33 +02:00
Rolf Ahrenberg
c8497e1fce Fixed the cable only device detection. 2014-10-30 22:10:09 +02:00
47 changed files with 5884 additions and 1349 deletions

3
.gitignore vendored
View File

@ -4,3 +4,6 @@
*~ *~
po/*.pot po/*.pot
po/*.mo po/*.mo
.settings
.cproject
.project

163
HISTORY
View File

@ -64,3 +64,166 @@ 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).
===================================
VDR Plugin 'satip' Revision History
===================================
2015-02-19: Version 2.2.0
- Updated for vdr-2.2.0.
- Fixed memory deallocation errors.
- Cleaned up all scan-build warnings.
- Refactored the frontend handling.
2015-04-04: Version 2.2.1
- Improved RTSP error checking.
- Got rid of SATIP_DEBUG.
- Robustify the server discovery.
- Fixed a memory leak in TinyXML implementation
(Thanks to Oliver Endriss).
- Updated against SAT>IP protocol specification
version 1.2.2.
2015-04-26: Version 2.2.2
- Added a more flexible OPER command in the SVDRP
interface.
- Added new ATTA and DETA SVDRP commands.
- Set the default device count to two.
2015-09-18: Version 2.2.3
- Added a timeout for releasing idling devices.
- Reset the RTSP connection after any failed connect.
- Added tweaks for minisatip and Schwaiger MS41IP.
- Updated for vdr-2.3.1 (Thanks to Klaus Schmidinger).
2016-12-18: Version 2.2.4
- Updated German translation (Thanks to Frank Neumann).
- Fixed Panasonic CXW804 support (Thanks to Tobias Grimm).
- Fixed C++11 support (Thanks to Tobias Grimm).
- Fixed server assigment with source validation (Thanks to Patrick Boettcher).
- Added configurable RTP/RTCP ports (Thanks to chriszero).
- Added support for X-SATIP-RTSP-Port header.
- Added multicast and RTP-over-TCP support.
- Added support for activating/deactivating server on-the-fly.
- Extended command-line parameters for setting server quirks.
2017-08-15: Version 2.2.5
- Added Polish translation (Thanks to Tomasz Nowak).
- Updated Catalan and Spanish translations (Thanks to Gabriel Bonich).
- Added support for KATHREIN SatIP Server (Thanks to kavanu).
- Added support for FRITZ!Box 6490 Cable (Thanks to 9000h).
- Updated FRITZ!WLAN Repeater DVB-C detection for the latest firmware (Thanks to 9000h).
- Added GCC7 compatibility (Thanks to Sascha Kuehndel).
===================================
VDR Plugin 'satip' Revision History
===================================
2016-12-18: Version 2.3.0
- Updated for vdr-2.3.1.
- Updated German translation (Thanks to Frank Neumann).
- Fixed Panasonic CXW804 support (Thanks to Tobias Grimm).
- Fixed C++11 support (Thanks to Tobias Grimm).
- Fixed server assigment with source validation (Thanks to Patrick Boettcher).
- Added configurable RTP/RTCP ports (Thanks to chriszero).
- Added support for X-SATIP-RTSP-Port header.
- Added multicast and RTP-over-TCP support.
- Added support for activating/deactivating server on-the-fly.
- Extended command-line parameters for setting server quirks.
2017-08-15: Version 2.3.1
- Updated for vdr-2.3.7 (Thanks to Klaus Schmidinger).
- Added Polish translation (Thanks to Tomasz Nowak).
- Updated Catalan and Spanish translations (Thanks to Gabriel Bonich).
- Added support for KATHREIN SatIP Server (Thanks to kavanu).
- Added support for FRITZ!Box 6490 Cable (Thanks to 9000h).
- Updated FRITZ!WLAN Repeater DVB-C detection for the latest firmware (Thanks to 9000h).
- Added GCC7 compatibility (Thanks to Sascha Kuehndel).
===================================
VDR Plugin 'satip' Revision History
===================================
2018-04-15: Version 2.4.0
- Updated for vdr-2.4.0.
- Removed speed limit.
- Fixed transport media changes.
- Fixed memory leak in cSatipSectionFilter (Thanks to Alexander Pipelka).
- Added more robust section filter handling (Thanks to Alexander Pipelka).
- Added a command line parameter for the RTP receive buffer size (Thanks to Stefan Rehm).
2021-06-01: Version 2.4.1
- Added an option to enable/disable frontend reuse.
- Added a preliminary ATSC support.
- Fixed a channel switching logic bug (Thanks to REELcoder).
- Added a workaround for detecting Panasonic devices.
- Removed quirks from FRITZ!Box 6490 Cable due to new firmware.
- Fixed RTP over TCP.
- Fixed URL parameter creation (Thanks to Martin Janser).
- Added an option to enable/disable frontend reuse.
- Added a preliminary ATSC support.
- Fixed a channel switching logic bug (Thanks to REELcoder).
- Added quirks for Inverto IDL-400s.
- Updated German translation (Thanks to Martin Dummer).
- Added a quirk for always teardown before play (Thanks to maazl).
- Updated for vdr-2.4.3 (Thanks to <Winfried Koehler).
- Added timeout for HasLock (Thanks to Winfried Koehler).
- Updated detectsatip script for Python 3.
- Fixed keepalive interval.

View File

@ -2,18 +2,10 @@
# Makefile for SAT>IP plugin # Makefile for SAT>IP plugin
# #
# Debugging on/off
#SATIP_DEBUG = 1
# Use TinyXML instead of PugiXML # Use TinyXML instead of PugiXML
#SATIP_USE_TINYXML = 1 #SATIP_USE_TINYXML = 1
# Strip debug symbols? Set eg. to /bin/true if not
STRIP = strip
# The official name of this plugin. # The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin. # This name will be used in the '-P...' option of VDR to load the plugin.
# By default the main source file also carries this name. # By default the main source file also carries this name.
@ -40,6 +32,7 @@ TMPDIR ?= /tmp
export CFLAGS = $(call PKGCFG,cflags) export CFLAGS = $(call PKGCFG,cflags)
export CXXFLAGS = $(call PKGCFG,cxxflags) export CXXFLAGS = $(call PKGCFG,cxxflags)
STRIP ?= /bin/true
### The version number of VDR's plugin API: ### The version number of VDR's plugin API:
@ -75,10 +68,6 @@ else
LIBS += -lpugixml LIBS += -lpugixml
endif endif
ifdef SATIP_DEBUG
DEFINES += -DDEBUG
endif
ifneq ($(strip $(GITTAG)),) ifneq ($(strip $(GITTAG)),)
DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"' DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"'
endif endif
@ -88,8 +77,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:
@ -98,14 +88,15 @@ all: $(SOFILE) i18n
### Implicit rules: ### Implicit rules:
%.o: %.c %.o: %.c
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< @echo CC $@
$(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies: ### Dependencies:
MAKEDEP = $(CXX) -MM -MG MAKEDEP = $(CXX) -MM -MG
DEPFILE = .dependencies DEPFILE = .dependencies
$(DEPFILE): Makefile $(DEPFILE): Makefile
@$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ $(Q)$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
-include $(DEPFILE) -include $(DEPFILE)
@ -118,17 +109,21 @@ I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLU
I18Npot = $(PODIR)/$(PLUGIN).pot I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po %.mo: %.po
msgfmt -c -o $@ $< @echo MO $@
$(Q)msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c) $(I18Npot): $(wildcard *.c)
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^` @echo GT $@
$(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
%.po: $(I18Npot) %.po: $(I18Npot)
msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $< @echo PO $@
$(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@ @touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo $(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
install -D -m644 $< $@ @echo IN $@
$(Q)install -D -m644 $< $@
.PHONY: i18n .PHONY: i18n
i18n: $(I18Nmo) $(I18Npot) i18n: $(I18Nmo) $(I18Npot)
@ -138,13 +133,13 @@ install-i18n: $(I18Nmsgs)
### Targets: ### Targets:
$(SOFILE): $(OBJS) $(SOFILE): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@ @echo LD $@
ifndef SATIP_DEBUG $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
@$(STRIP) $@ $(Q)$(STRIP) $@
endif
install-lib: $(SOFILE) install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) @echo IN $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
$(Q)install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
install-conf: install-conf:
@mkdir -p $(DESTDIR)$(CFGDIR)/plugins/$(PLUGIN) @mkdir -p $(DESTDIR)$(CFGDIR)/plugins/$(PLUGIN)
@ -165,4 +160,4 @@ clean:
.PHONY: cppcheck .PHONY: cppcheck
cppcheck: cppcheck:
@cppcheck --language=c++ --enable=all -v -f $(OBJS:%.o=%.c) $(Q)cppcheck --language=c++ --enable=all -v -f $(OBJS:%.o=%.c)

169
README
View File

@ -3,9 +3,9 @@ This is an SAT>IP plugin for the Video Disk Recorder (VDR).
Written by: Rolf Ahrenberg Written by: Rolf Ahrenberg
< R o l f . A h r e n b e r g @ s c i . f i > < R o l f . A h r e n b e r g @ s c i . f i >
Project's homepage: http://www.saunalahti.fi/~rahrenbe/vdr/satip/ Project's homepage: https://github.com/rofafor/vdr-plugin-satip
Latest version available at: http://www.saunalahti.fi/~rahrenbe/vdr/satip/ Latest version available at: https://github.com/rofafor/vdr-plugin-satip/releases
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as it under the terms of the GNU General Public License version 2 as
@ -23,7 +23,8 @@ 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/
- VDR >= 2.1.4 for scrambled channels - Glibc >= 2.12 - the GNU C library (recvmmsg)
http://www.gnu.org/software/libc/
Description: Description:
@ -41,13 +42,56 @@ make -C satip-X.Y.Z install
Configuration: Configuration:
The plugin accepts a "--devices" (-d) command-line parameter defaulting The plugin accepts a "--devices" (-d) command-line parameter defaulting
to one. This parameter defines how many simultaneous transponders can to two. 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. Multiple service entries can be given
separated by a semicolon:
[<srcaddress>@]<ipaddress>[:<port>]|<model>[:<filter>]|<description>[:<quirk>];...
- srcaddress (Optional) Source address can be used to define used
networking interface on a host, e.g. 127.0.0.1.
- ipaddress IP address of SAT>IP server, e.g. 127.0.0.1.
- port (Optional) IP port number of SAT>IP server, e.g 443.
- model Model defines DVB modulation system (DVBS2,
DVBT2, DVBT, DVBC) and number of available
frontends separated by a hyphen, e.g. DVBT2-4.
- filter (Optional) Filter can be used to limit satellite frontends
to certain satellite position, e.g. S19.2E.
- description Friendly name of SAT>IP server. This is used
for autodetection of quirks.
- quirk (Optional) Quirks are non-standard compliant features and
bug fixes of SAT>IP server defined by a
hexadecimal number. Multiple quirks can be
defined by combining values by addition:
0x01: Fix session id bug
0x02: Fix play parameter (addpids/delpids) bug
0x04: Fix frontend locking bug
0x08: Support for RTP over TCP
0x10: Support the X_PMT protocol extension
0x20: Support the CI TNR protocol extension
0x40: Fix auto-detection of pilot tones bug
0x80: Fix re-tuning bug by teardowning a session
Examples:
vdr -P 'satip -s 192.168.0.1|DVBS2-2,DVBT2-2|OctopusNet'
vdr -P 'satip -s 192.168.0.1|DVBS2-4|OctopusNet;192.168.0.2|DVBT2-4|minisatip:0x18'
vdr -P 'satip -s 192.168.0.1:554|DVBS2-2:S19.2E|OctopusNet;192.168.0.2:8554|DVBS2-4:S19.2E,S1W|minisatip'
The plugin accepts a "--portrange" (-p) command-line parameter, that can
be used to manually specify the RTP & RTCP port range and therefore
enables using the plugin through a NAT (e.g. Docker bridged network).
A minimum of 2 ports per device is required.
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,32 +102,60 @@ 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
low from VDR's device handling, set this low from VDR's device handling, set this
normal option to "off". Otherwise, if you want normal option to "off". Otherwise, if you want
high to keep SAT>IP at a low priority when high to keep SAT>IP at a low priority when
selecting available devices, set this selecting available devices, set this
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.
- Enable EPG scanning = yes If you want exclude all SAT>IP devices - Use CI extension = no If you want to use the CI extension found
from VDR's EIT background scanning, set in some SAT>IP hardware (e.g. Digital
this option to "no". Devices OctopusNet), set this option to
- Disabled filters = none Certain section filters might cause some "yes".
unwanted behaviour to VDR such as time - CICAM #<slot> = <system> If you want to assign a CA system into
being falsely synchronized etc. This option a specific CI slot, set this option to
allows creation of blacklists of ill-behaving a named one. Use "---" for autoselection.
filters. If this option is set to a non-zero - Enable EPG scanning = yes If you want exclude all SAT>IP devices
value, the menu page will contain that many from VDR's EIT background scanning, set
"Disable filter" options which allow you this option to "no".
to disable the individual section filters. - Disabled sources = none If your SAT>IP servers don't have certain
Valid range: "none" = 0 ... 7 satellite positions available you can
- [Red:Scan] Forces network scanning of SAT>IP hardware. disable them via this option.
- [Blue:Info] Opens SAT>IP information/statistics menu. - Disabled filters = none Certain section filters might cause some
- [Ok] Opens information menu of selected SAT>IP unwanted behaviour to VDR such as time
device. being falsely synchronized etc. This option
allows creation of blacklists of ill-behaving
filters. If this option is set to a non-zero
value, the menu page will contain that many
"Disable filter" options which allow you
to disable the individual section filters.
Valid range: "none" = 0 ... 7
- Transport mode = unicast If you want to use the non-standard
multicast RTP-over-TCP transport mode, set this option
rtp-o-tcp accordingly. Otherwise, the transport
mode will be RTP-over-UDP via unicast or
multicast.
- Enable frontend reuse = yes Certain devices might have artifacts if
multiple channels are assigned to the same
frontend. If you want to avoid such a
frontend assignment, set this option to "no".
- [Red:Scan] Forces network scanning of SAT>IP hardware.
- [Yellow:Devices] Opens SAT>IP device status menu.
- [Blue:Info] Opens SAT>IP information/statistics menu.
- [Ok] Opens information menu of selected SAT>IP
device.
Information menu: Information menu:
@ -94,19 +166,44 @@ Information menu:
Notes: Notes:
- If you are having problems receiving DVB-S2 channels, make sure your
channels.conf entry contains correct pilot tone setting.
- The stream id "-1" states about unsuccessful tuning. This might be a - 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.
- Stream decryption requires a separate CAM plugin that works without - Stream decryption requires a separate CAM plugin that works without
direct access to any DVB card devices. The integrated CAM slot in direct access to any DVB card devices. Also the integrated CAM slots
Octopus Net devices isn't supported. in Octopus Net devices are 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.
- FRITZ!OS 7.00 or greater recommended for FRITZ!Box Cable devices.
Older firmware versions require both PlayPids and ForceLock quirks.
- If you are experiencing glitches in the video stream, one possible
reason can be buffer overflows in RTP receive sockets. You can verify
this by checking "receive buffer errors" counter by running "netstat -s"
command. If the counter increases every time a video glitch happens,
you should try to tweak the RTP receive buffer size with the "--rcvbuf"
(-r) plugin parameter.
A good starting point for the buffer size is to double the operating
system default value until errors disappear or the maximum value is
reached. You can check these values in Linux by checking the kernel
parameters:
$ cat /proc/sys/net/core/rmem_default
$ cat /proc/sys/net/core/rmem_max
Acknowledgements: Acknowledgements:

View File

@ -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;
}

100
common.h
View File

@ -8,23 +8,16 @@
#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_DEFAULT_RTSP_PORT 554
#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_MAX_DEVICES MAXDEVICES
#define SATIP_BUFFER_SIZE MEGABYTE(1) #define SATIP_BUFFER_SIZE KILOBYTE(2048)
#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,32 +29,36 @@
#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); \ esyslog("curl_easy_getinfo(%s) [%s,%d] failed: %s (%d)", #Y, __FILE__, __LINE__, curl_easy_strerror(res), res); \
} }
#define SATIP_CURL_EASY_SETOPT(X, Y, Z) \ #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; \
} \ } \
} while (0) } while (0)
@ -87,7 +84,53 @@
} \ } \
} while (0) } while (0)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) #define ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
class cSatipMemoryBuffer {
private:
enum {
eMaxDataSize = MEGABYTE(2)
};
char *dataM;
size_t sizeM;
void *AllocBuffer(void *ptrP, size_t sizeP)
{
// There might be a realloc() out there that doesn't like reallocing NULL pointers, so we take care of it here
if (ptrP)
return realloc(ptrP, sizeP);
else
return malloc(sizeP);
}
// to prevent copy constructor and assignment
cSatipMemoryBuffer(const cSatipMemoryBuffer&);
cSatipMemoryBuffer& operator=(const cSatipMemoryBuffer&);
public:
cSatipMemoryBuffer() : dataM(NULL), sizeM(0) {}
~cSatipMemoryBuffer() { Reset(); }
size_t Add(char *dataP, size_t sizeP)
{
if (sizeP > 0) {
size_t len = sizeM + sizeP + 1;
if (len < eMaxDataSize) {
dataM = (char *)AllocBuffer(dataM, len);
if (dataM) {
memcpy(&(dataM[sizeM]), dataP, sizeP);
sizeM += sizeP;
dataM[sizeM] = 0;
return sizeP;
}
else
esyslog("[%s,%d]: Failed to allocate memory", __FILE__, __LINE__);
}
else
esyslog("[%s,%d]: Buffer overflow", __FILE__, __LINE__);
}
return 0;
};
char *Data(void) { return dataM; }
size_t Size(void) { return sizeM; }
void Reset(void) { FREE_POINTER(dataM); sizeM = 0; };
};
uint16_t ts_pid(const uint8_t *bufP); uint16_t ts_pid(const uint8_t *bufP);
uint8_t payload(const uint8_t *bufP); uint8_t payload(const uint8_t *bufP);
@ -106,6 +149,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

View File

@ -6,41 +6,79 @@
*/ */
#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),
frontendReuseM(1),
eitScanM(1), eitScanM(1),
useBytesM(1) useBytesM(1),
portRangeStartM(0),
portRangeStopM(0),
transportModeM(eTransportModeUnicast),
detachedModeM(false),
disableServerQuirksM(false),
useSingleModelServersM(false),
rtpRcvBufSizeM(0)
{ {
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");
}

View File

@ -15,19 +15,56 @@ class cSatipConfig
{ {
private: private:
unsigned int operatingModeM; unsigned int operatingModeM;
unsigned int traceModeM;
unsigned int ciExtensionM;
unsigned int frontendReuseM;
unsigned int eitScanM; unsigned int eitScanM;
unsigned int useBytesM; unsigned int useBytesM;
unsigned int portRangeStartM;
unsigned int portRangeStopM;
unsigned int transportModeM;
bool detachedModeM;
bool disableServerQuirksM;
bool useSingleModelServersM;
int cicamsM[MAX_CICAM_COUNT];
int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT];
int disabledFiltersM[SECTION_FILTER_TABLE_SIZE]; int disabledFiltersM[SECTION_FILTER_TABLE_SIZE];
char configDirectoryM[PATH_MAX]; size_t rtpRcvBufSizeM;
public: public:
enum { enum eOperatingMode {
eOperatingModeOff = 0, eOperatingModeOff = 0,
eOperatingModeLow, eOperatingModeLow,
eOperatingModeNormal, eOperatingModeNormal,
eOperatingModeHigh, eOperatingModeHigh,
eOperatingModeCount eOperatingModeCount
}; };
enum eTransportMode {
eTransportModeUnicast = 0,
eTransportModeMulticast,
eTransportModeRtpOverTcp,
eTransportModeCount
};
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,17 +72,44 @@ 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; }
unsigned int GetFrontendReuse(void) const { return frontendReuseM; }
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; } unsigned int GetTransportMode(void) const { return transportModeM; }
bool IsTransportModeUnicast(void) const { return (transportModeM == eTransportModeUnicast); }
bool IsTransportModeRtpOverTcp(void) const { return (transportModeM == eTransportModeRtpOverTcp); }
bool IsTransportModeMulticast(void) const { return (transportModeM == eTransportModeMulticast); }
bool GetDetachedMode(void) const { return detachedModeM; }
bool GetDisableServerQuirks(void) const { return disableServerQuirksM; }
bool GetUseSingleModelServers(void) const { return useSingleModelServersM; }
unsigned int GetDisabledSourcesCount(void) const;
int GetDisabledSources(unsigned int indexP) const;
unsigned int GetDisabledFiltersCount(void) const; unsigned int GetDisabledFiltersCount(void) const;
int GetDisabledFilters(unsigned int indexP) const; int GetDisabledFilters(unsigned int indexP) const;
unsigned int GetPortRangeStart(void) const { return portRangeStartM; }
unsigned int GetPortRangeStop(void) const { return portRangeStopM; }
size_t GetRtpRcvBufSize(void) const { return rtpRcvBufSizeM; }
void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; } void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; }
void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); }
void SetCIExtension(unsigned int onOffP) { ciExtensionM = onOffP; }
void SetFrontendReuse(unsigned int onOffP) { frontendReuseM = onOffP; }
void SetCICAM(unsigned int indexP, int cicamP);
void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; } void 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 SetTransportMode(unsigned int transportModeP) { transportModeM = transportModeP; }
void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; }
void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; }
void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; }
void SetDisabledSources(unsigned int indexP, int sourceP);
void SetDisabledFilters(unsigned int indexP, int numberP); void SetDisabledFilters(unsigned int indexP, int numberP);
void SetPortRangeStart(unsigned int rangeStartP) { portRangeStartM = rangeStartP; }
void SetPortRangeStop(unsigned int rangeStopP) { portRangeStopM = rangeStopP; }
void SetRtpRcvBufSize(size_t sizeP) { rtpRcvBufSizeM = sizeP; }
}; };
extern cSatipConfig SatipConfig; extern cSatipConfig SatipConfig;

98
detectsatip.py Executable file
View File

@ -0,0 +1,98 @@
#!/usr/bin/env python3
""" Simple tool to detect SAT>IP devices as JSON.
"""
import json
import socket
import sys
import xml.etree.ElementTree as ET
import requests
SSDP_BIND = "0.0.0.0"
SSDP_ADDR = "239.255.255.250"
SSDP_PORT = 1900
SSDP_MX = 1
SSDP_ST = "urn:ses-com:device:SatIPServer:1"
SSDP_REQUEST = "\r\n".join(
[
"M-SEARCH * HTTP/1.1",
f"HOST: {SSDP_ADDR}:{SSDP_PORT}",
'MAN: "ssdp:discover"',
f"MX: {SSDP_MX}",
f"ST: {SSDP_ST}",
"USER-AGENT: vdr-detectsatip",
"\r\n",
]
)
def parse_satip_xml(data):
"""Parse SAT>IP XML data.
Args:
data (str): XML input data..
Returns:
dict: Parsed SAT>IP device name and frontend information.
"""
result = {"name": "", "frontends": {}}
if data:
root = ET.fromstring(data)
name = root.find(".//*/{urn:schemas-upnp-org:device-1-0}friendlyName")
result["name"] = name.text
satipcap = root.find(".//*/{urn:ses-com:satip}X_SATIPCAP")
if satipcap is None:
# fallback for non-standard Panasonic
satipcap = root.find(".//*/{urn-ses-com:satip}X_SATIPCAP")
caps = {}
for system in satipcap.text.split(","):
cap = system.split("-")
if cap:
count = int(cap[1])
if cap[0] in caps:
count = count + caps[cap[0]]
caps[cap[0]] = count
result["frontends"] = caps
return result
def detect_satip_devices():
"""Detect available SAT>IP devices by sending a broadcast message.
Returns:
list: Found SAT>IP devices.
"""
urls = []
devices = []
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
except BaseException:
pass
sock.settimeout(1)
sock.bind((SSDP_BIND, SSDP_PORT))
sock.sendto(SSDP_REQUEST.encode("utf-8"), (SSDP_ADDR, SSDP_PORT))
try:
while 1:
data = sock.recv(1024).decode("utf-8")
if data:
for row in data.split("\r\n"):
if "LOCATION:" in row:
url = row.replace("LOCATION:", "").strip()
if url in urls:
continue
urls.append(url)
info = requests.get(url, timeout=2)
devices.append(parse_satip_xml(info.text))
else:
break
except BaseException:
pass
sock.close()
return devices
if __name__ == "__main__":
json.dump(detect_satip_devices(), fp=sys.stdout, sort_keys=True, indent=2)

292
device.c
View File

@ -5,31 +5,35 @@
* *
*/ */
#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 };
cMutex cSatipDevice::mutexS = cMutex();
cSatipDevice::cSatipDevice(unsigned int indexP) cSatipDevice::cSatipDevice(unsigned int indexP)
: deviceIndexM(indexP), : deviceIndexM(indexP),
isPacketDeliveredM(false), bytesDeliveredM(0),
isOpenDvrM(false), isOpenDvrM(false),
checkTsBufferM(false),
deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)), deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)),
channelM(), channelM(),
createdM(0), createdM(0),
mutexM() tunedM()
{ {
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 +44,9 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
cSatipDevice::~cSatipDevice() cSatipDevice::~cSatipDevice()
{ {
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM); debug1("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
// Release immediately any pending conditional wait
tunedM.Broadcast();
// Stop section handler // Stop section handler
StopSectionHandler(); StopSectionHandler();
DELETE_POINTER(pSectionFilterHandlerM); DELETE_POINTER(pSectionFilterHandlerM);
@ -50,7 +56,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 +68,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 +78,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,37 +88,75 @@ 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();
LOCK_TIMERS_READ;
for (const 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) {
if (channel->Number() > 0 && device->Receiving())
info = cString::sprintf("%sTransponder: %d Channel: %s\n", *info, channel->Transponder(), channel->Name());
else
info = cString::sprintf("%sTransponder: %d\n", *info, channel->Transponder());
}
if (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", LOCK_CHANNELS_READ;
return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s\n",
deviceIndexM, CardIndex(), deviceIndexM, CardIndex(),
pTunerM ? *pTunerM->GetInformation() : "", pTunerM ? *pTunerM->GetInformation() : "",
pTunerM ? *pTunerM->GetSignalStatus() : "", pTunerM ? *pTunerM->GetSignalStatus() : "",
pTunerM ? *pTunerM->GetTunerStatistic() : "", pTunerM ? *pTunerM->GetTunerStatistic() : "",
*GetBufferStatistic(), *GetBufferStatistic(),
*Channels.GetByNumber(cDevice::CurrentChannel())->ToText()); *Channels->GetByNumber(cDevice::CurrentChannel())->ToText());
} }
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 +192,83 @@ 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);
if (!Receiving())
return cString::sprintf("%s %d", *DeviceType(), 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();
} }
bool cSatipDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
{
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
Valid = DTV_STAT_VALID_NONE;
if (Strength && pTunerM) {
*Strength = pTunerM->SignalStrengthDBm();
Valid |= DTV_STAT_VALID_STRENGTH;
}
if (Status) {
*Status = HasLock() ? (DTV_STAT_HAS_SIGNAL | DTV_STAT_HAS_CARRIER | DTV_STAT_HAS_VITERBI | DTV_STAT_HAS_SYNC | DTV_STAT_HAS_LOCK) : DTV_STAT_HAS_NONE;
Valid |= DTV_STAT_VALID_STATUS;
}
return Valid != DTV_STAT_VALID_NONE;
}
int cSatipDevice::SignalStrength(void) const 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);
if (SatipConfig.GetDetachedMode())
return false;
// 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 +277,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;
@ -218,10 +295,10 @@ bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool
result = true; result = true;
} }
else else
result = true; result = !!SatipConfig.GetFrontendReuse();
} }
else else
needsDetachReceivers = Receiving(); needsDetachReceivers = true;
} }
} }
} }
@ -232,7 +309,11 @@ bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool
bool cSatipDevice::ProvidesEIT(void) const bool cSatipDevice::ProvidesEIT(void) const
{ {
#if defined(APIVERSNUM) && APIVERSNUM < 20403
return (SatipConfig.GetEITScan()); return (SatipConfig.GetEITScan());
#else
return (SatipConfig.GetEITScan()) && DeviceHooksProvidesEIT();
#endif
} }
int cSatipDevice::NumProvidedSystems(void) const int cSatipDevice::NumProvidedSystems(void) const
@ -272,35 +353,51 @@ bool cSatipDevice::MaySwitchTransponder(const cChannel *channelP) const
bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
{ {
cMutexLock MutexLock(&mutexS); // Global lock to prevent any simultaneous zapping
debug9("%s (%d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, liveViewP, deviceIndexM);
if (channelP) { 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()->AssignServer(deviceIndexM, 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;
} }
if (pTunerM && pTunerM->SetSource(server, *params, deviceIndexM)) { if (pTunerM && pTunerM->SetSource(server, channelP->Transponder(), *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));
// Wait for actual channel tuning to prevent simultaneous frontend allocation failures
tunedM.TimedWait(mutexS, eTuningTimeoutMs);
return true; return true;
} }
} }
else if (pTunerM) {
pTunerM->SetSource(NULL, 0, NULL, deviceIndexM);
deviceNameM = cString::sprintf("%s %d", *DeviceType(), deviceIndexM);
return true;
}
return false; return false;
} }
void cSatipDevice::SetChannelTuned(void)
{
debug9("%s () [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
// Release immediately any pending conditional wait
tunedM.Broadcast();
}
bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP) 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 ? handleP->pid : -1, typeP, onP, deviceIndexM);
if (pTunerM && handleP && handleP->pid >= 0) { if (pTunerM && handleP && handleP->pid >= 0 && handleP->pid <= 8191) {
if (onP) if (onP)
return pTunerM->SetPid(handleP->pid, typeP, true); return pTunerM->SetPid(handleP->pid, typeP, true);
else if (!handleP->used) else if (!handleP->used && pSectionFilterHandlerM && !pSectionFilterHandlerM->Exists(handleP->pid))
return pTunerM->SetPid(handleP->pid, typeP, false); return pTunerM->SetPid(handleP->pid, typeP, false);
} }
return true; return true;
@ -308,7 +405,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,18 +417,19 @@ 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; bytesDeliveredM = 0;
tsBufferM->Clear(); tsBufferM->Clear();
if (pTunerM) if (pTunerM)
pTunerM->Open(); pTunerM->Open();
@ -341,7 +439,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 +447,29 @@ 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);
if (timeoutMsP > 0) {
cTimeMs timer(timeoutMsP);
while (!timer.TimedOut()) {
if (pTunerM && pTunerM->HasLock())
return true;
cCondWait::SleepMs(100);
}
}
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,27 +479,61 @@ 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;
} }
uchar *cSatipDevice::GetData(int *availableP) int cSatipDevice::GetPmtPid(void)
{ {
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM); int pid = channelM.Ca() ? ::GetPmtPid(channelM.Source(), channelM.Transponder(), channelM.Sid()) : 0;
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;
}
cString cSatipDevice::GetTnrParameterString(void)
{
if (channelM.Ca())
return GetTnrUrlParameters(&channelM);
return NULL;
}
bool cSatipDevice::IsIdle(void)
{
return !Receiving();
}
uchar *cSatipDevice::GetData(int *availableP, bool checkTsBuffer)
{
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
if (isOpenDvrM && tsBufferM) { if (isOpenDvrM && tsBufferM) {
int count = 0; int count = 0;
if (isPacketDeliveredM) if (bytesDeliveredM) {
SkipData(TS_SIZE); tsBufferM->Del(bytesDeliveredM);
bytesDeliveredM = 0;
}
if (checkTsBuffer && tsBufferM->Available() < TS_SIZE)
return NULL;
uchar *p = tsBufferM->Get(count); uchar *p = tsBufferM->Get(count);
if (p && count >= TS_SIZE) { if (p && count >= TS_SIZE) {
if (*p != TS_SYNC_BYTE) { if (*p != TS_SYNC_BYTE) {
@ -407,7 +547,7 @@ uchar *cSatipDevice::GetData(int *availableP)
info("Skipped %d bytes to sync on TS packet", count); info("Skipped %d bytes to sync on TS packet", count);
return NULL; return NULL;
} }
isPacketDeliveredM = true; bytesDeliveredM = TS_SIZE;
if (availableP) if (availableP)
*availableP = count; *availableP = count;
// Update pid statistics // Update pid statistics
@ -420,35 +560,33 @@ 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); bytesDeliveredM = countP;
isPacketDeliveredM = false;
// Update buffer statistics // Update buffer statistics
AddBufferStatistic(countP, tsBufferM->Available()); AddBufferStatistic(countP, tsBufferM->Available());
} }
bool cSatipDevice::GetTSPacket(uchar *&dataP) bool cSatipDevice::GetTSPacket(uchar *&dataP)
{ {
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM); debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
if (SatipConfig.GetDetachedMode())
return false;
if (tsBufferM) { if (tsBufferM) {
#if defined(APIVERSNUM) && APIVERSNUM >= 20104
if (cCamSlot *cs = CamSlot()) { if (cCamSlot *cs = CamSlot()) {
if (cs->WantsTsData()) { if (cs->WantsTsData()) {
int available; int available;
dataP = GetData(&available); dataP = GetData(&available, checkTsBufferM);
if (dataP) { if (!dataP)
dataP = cs->Decrypt(dataP, available); available = 0;
SkipData(available); dataP = cs->Decrypt(dataP, available);
} SkipData(available);
checkTsBufferM = dataP != NULL;
return true; return true;
} }
} }
#endif
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;
} }

View File

@ -18,31 +18,34 @@
class cSatipDevice : public cDevice, public cSatipPidStatistics, public cSatipBufferStatistics, public cSatipDeviceIf { class cSatipDevice : public cDevice, public cSatipPidStatistics, public cSatipBufferStatistics, public cSatipDeviceIf {
// static ones // static ones
public: public:
static unsigned int deviceCount; static cMutex mutexS;
static bool Initialize(unsigned int DeviceCount); static bool Initialize(unsigned int DeviceCount);
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:
enum { enum {
eReadyTimeoutMs = 2000 // in milliseconds eReadyTimeoutMs = 2000, // in milliseconds
eTuningTimeoutMs = 1000 // in milliseconds
}; };
unsigned int deviceIndexM; unsigned int deviceIndexM;
bool isPacketDeliveredM; int bytesDeliveredM;
bool isOpenDvrM; bool isOpenDvrM;
bool checkTsBufferM;
cString deviceNameM; cString deviceNameM;
cChannel channelM; cChannel channelM;
cRingBufferLinear *tsBufferM; cRingBufferLinear *tsBufferM;
cSatipTuner *pTunerM; cSatipTuner *pTunerM;
cSatipSectionFilterHandler *pSectionFilterHandlerM; cSatipSectionFilterHandler *pSectionFilterHandlerM;
cTimeMs createdM; cTimeMs createdM;
cMutex mutexM; cCondVar tunedM;
// constructor & destructor // constructor & destructor
public: public:
cSatipDevice(unsigned int deviceIndexP); explicit cSatipDevice(unsigned int deviceIndexP);
virtual ~cSatipDevice(); virtual ~cSatipDevice();
cString GetInformation(unsigned int pageP = SATIP_DEVICE_INFO_ALL); cString GetInformation(unsigned int pageP = SATIP_DEVICE_INFO_ALL);
@ -62,6 +65,7 @@ public:
virtual cString DeviceType(void) const; virtual cString DeviceType(void) const;
virtual cString DeviceName(void) const; virtual cString DeviceName(void) const;
virtual bool AvoidRecording(void) const; virtual bool AvoidRecording(void) const;
virtual bool SignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL, int *Status = NULL) const;
virtual int SignalStrength(void) const; virtual int SignalStrength(void) const;
virtual int SignalQuality(void) const; virtual int SignalQuality(void) const;
@ -81,7 +85,7 @@ protected:
// for recording // for recording
private: private:
uchar *GetData(int *availableP = NULL); uchar *GetData(int *availableP = NULL, bool checkTsBuffer = false);
void SkipData(int countP); void SkipData(int countP);
protected: protected:
@ -97,7 +101,7 @@ public:
// for transponder lock // for transponder lock
public: public:
virtual bool HasLock(int timeoutMsP) const; virtual bool HasLock(int timeoutMsP = 0) const;
// for common interface // for common interface
public: public:
@ -106,8 +110,12 @@ 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 void SetChannelTuned(void);
virtual int GetId(void); virtual int GetId(void);
virtual int GetPmtPid(void);
virtual int GetCISlot(void);
virtual cString GetTnrParameterString(void);
virtual bool IsIdle(void);
}; };
#endif // __SATIP_DEVICE_H #endif // __SATIP_DEVICE_H

View File

@ -13,11 +13,15 @@ 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 void SetChannelTuned(void) = 0;
virtual int GetId(void) = 0; virtual int GetId(void) = 0;
virtual int GetPmtPid(void) = 0;
virtual int GetCISlot(void) = 0;
virtual cString GetTnrParameterString(void) = 0;
virtual bool IsIdle(void) = 0;
private: private:
cSatipDeviceIf(const cSatipDeviceIf&); explicit cSatipDeviceIf(const cSatipDeviceIf&);
cSatipDeviceIf& operator=(const cSatipDeviceIf&); cSatipDeviceIf& operator=(const cSatipDeviceIf&);
}; };

View File

@ -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,87 +26,105 @@ 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->SrcAddress(), s->IpAddress(), s->IpPort(), s->Model(), s->Filters(), s->Description(), s->Quirk());
}
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();
} }
size_t cSatipDiscover::WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP) size_t cSatipDiscover::HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
{ {
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 && (len > 0))
CURLcode res = CURLE_OK; obj->headerBufferM.Add(ptrP, len);
const char *desc = NULL, *model = NULL, *addr = NULL;
#ifdef USE_TINYXML
TiXmlDocument doc;
char *xml = MALLOC(char, len + 1);
memcpy(xml, ptrP, len);
*(xml + len + 1) = 0;
doc.Parse((const char *)xml);
TiXmlHandle docHandle(&doc);
TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement();
if (descElement)
desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware";
TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement();
if (modelElement)
model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1";
#else
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_buffer(ptrP, len);
if (result) {
pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName");
if (descNode)
desc = descNode.text().as_string("MyBrokenHardware");
pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP");
if (modelNode)
model = modelNode.text().as_string("DVBS2-1");
}
#endif
SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr);
obj->AddServer(addr, desc, model);
}
return len; return len;
} }
size_t cSatipDiscover::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
{
cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP);
size_t len = sizeP * nmembP;
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
if (obj && (len > 0))
obj->dataBufferM.Add(ptrP, len);
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(),
headerBufferM(),
dataBufferM(),
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 +135,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 +144,163 @@ 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(eCleanupTimeoutMs);
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) const char *addr = NULL;
serversM->Cleanup(eProbeIntervalMs * 2); long rc = 0;
} 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 header and data callbacks
while (Running() && !timeout.TimedOut()) { SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipDiscover::HeaderCallback);
Read(); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
// to avoid busy loop and reduce cpu load SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::DataCallback);
sleepM.Wait(100); SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
}
socketM->Close(); // No progress meter and no signaling
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
// Set timeouts
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
// Set user-agent
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
// Set URL
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, urlP);
// Fetch the data
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_PRIMARY_IP, &addr);
if (rc == 200) {
ParseDeviceInfo(addr, ParseRtspPort());
headerBufferM.Reset();
dataBufferM.Reset();
}
else
error("Discovery detected invalid status code: %ld", rc);
} }
} }
void cSatipDiscover::Read(void) int cSatipDiscover::ParseRtspPort(void)
{ {
//debug("cSatipDiscover::%s()", __FUNCTION__); debug1("%s", __PRETTY_FUNCTION__);
if (socketM) { char *s, *p = headerBufferM.Data();
unsigned char *buf = MALLOC(unsigned char, eProbeBufferSize + 1); char *r = strtok_r(p, "\r\n", &s);
if (buf) { int port = SATIP_DEFAULT_RTSP_PORT;
memset(buf, 0, eProbeBufferSize + 1);
int len = socketM->Read(buf, eProbeBufferSize);
if (len > 0) {
//debug("cSatipDiscover::%s(): len=%d", __FUNCTION__, len);
bool status = false, valid = false;
char *s, *p = reinterpret_cast<char *>(buf), *location = NULL;
char *r = strtok_r(p, "\r\n", &s);
while (r) {
//debug("cSatipDiscover::%s(): %s", __FUNCTION__, r);
// Check the status code
// HTTP/1.1 200 OK
if (!status && startswith(r, "HTTP/1.1 200 OK")) {
status = true;
}
if (status) {
// Check the location data
// LOCATION: http://192.168.0.115:8888/octonet.xml
if (startswith(r, "LOCATION:")) {
location = compactspace(r + 9);
debug("cSatipDiscover::%s(): location='%s'", __FUNCTION__, location);
}
// Check the source type
// ST: urn:ses-com:device:SatIPServer:1
else if (startswith(r, "ST:")) {
char *st = compactspace(r + 3);
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
valid = true;
debug("cSatipDiscover::%s(): st='%s'", __FUNCTION__, st);
}
// Check whether all the required data is found
if (valid && !isempty(location))
break;
}
r = strtok_r(NULL, "\r\n", &s);
}
if (handleM && valid && !isempty(location)) {
long rc = 0;
CURLcode res = CURLE_OK;
#ifdef DEBUG
// Verbose output
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
#endif
// Set callback
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
// No progress meter and no signaling while (r) {
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L); debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L); r = skipspace(r);
if (strstr(r, "X-SATIP-RTSP-Port")) {
// Set timeouts int tmp = -1;
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs); if (sscanf(r, "X-SATIP-RTSP-Port:%11d", &tmp) == 1) {
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs); port = tmp;
break;
// Set user-agent
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
// Set URL
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, location);
// Fetch the data
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
if (rc != 200)
error("Discovery detected invalid status code: %ld", rc);
} }
} }
free(buf); r = strtok_r(NULL, "\r\n", &s);
} }
}
return port;
} }
void cSatipDiscover::AddServer(const char *addrP, const char *descP, const char * modelP) void cSatipDiscover::ParseDeviceInfo(const char *addrP, const int portP)
{ {
debug("cSatipDiscover::%s(%s, %s, %s)", __FUNCTION__, addrP, descP, modelP); debug1("%s (%s, %d)", __PRETTY_FUNCTION__, addrP, portP);
const char *desc = NULL, *model = NULL;
#ifdef USE_TINYXML
TiXmlDocument doc;
doc.Parse(dataBufferM.Data());
TiXmlHandle docHandle(&doc);
TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement();
if (descElement)
desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware";
TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement();
if (modelElement)
model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1";
#else
pugi::xml_document doc;
if (doc.load_buffer(dataBufferM.Data(), dataBufferM.Size())) {
pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName");
if (descNode)
desc = descNode.text().as_string("MyBrokenHardware");
pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP");
if (modelNode)
model = modelNode.text().as_string("DVBS2-1");
}
#endif
AddServer(NULL, addrP, portP, model, NULL, desc, cSatipServer::eSatipQuirkNone);
}
void cSatipDiscover::AddServer(const char *srcAddrP, const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP)
{
debug1("%s (%s, %s, %d, %s, %s, %s, %d)", __PRETTY_FUNCTION__, srcAddrP, addrP, portP, modelP, filtersP, descP, quirkP);
cMutexLock MutexLock(&mutexM); cMutexLock MutexLock(&mutexM);
if (serversM) { if (SatipConfig.GetUseSingleModelServers() && modelP && !isempty(modelP)) {
cSatipServer *tmp = new cSatipServer(addrP, descP, modelP); int n = 0;
// Validate against existing servers char *s, *p = strdup(modelP);
if (!serversM->Update(tmp)) { char *r = strtok_r(p, ",", &s);
info("Adding device %s (%s %s)", tmp->Description(), tmp->Address(), tmp->Model()); while (r) {
serversM->Add(tmp); r = skipspace(r);
cString desc = cString::sprintf("%s #%d", !isempty(descP) ? descP : "MyBrokenHardware", n++);
cSatipServer *tmp = new cSatipServer(srcAddrP, addrP, portP, r, filtersP, desc, quirkP);
if (!serversM.Update(tmp)) {
info("Adding server '%s|%s|%s' Bind: %s Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->SrcAddress()) ? tmp->SrcAddress() : "default", !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
serversM.Add(tmp);
}
else
DELETENULL(tmp);
r = strtok_r(NULL, ",", &s);
}
FREE_POINTER(p);
}
else {
cSatipServer *tmp = new cSatipServer(srcAddrP, addrP, portP, modelP, filtersP, descP, quirkP);
if (!serversM.Update(tmp)) {
info("Adding server '%s|%s|%s' Bind: %s Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->SrcAddress()) ? tmp->SrcAddress() : "default", !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none");
serversM.Add(tmp);
} }
else else
DELETENULL(tmp); DELETENULL(tmp);
@ -265,57 +309,121 @@ 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::AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP)
{ {
//debug("cSatipDiscover::%s(%d, %d)", __FUNCTION__, sourceP, systemP); debug16("%s (%d, %d, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, sourceP, transponderP, systemP);
cMutexLock MutexLock(&mutexM); cMutexLock MutexLock(&mutexM);
return serversM ? serversM->Find(sourceP, systemP) : NULL; return serversM.Assign(deviceIdP, sourceP, transponderP, systemP);
}
cSatipServer *cSatipDiscover::GetServer(int sourceP)
{
debug16("%s (%d)", __PRETTY_FUNCTION__, sourceP);
cMutexLock MutexLock(&mutexM);
return serversM.Find(sourceP);
} }
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::UseServer(cSatipServer *serverP, bool onOffP) void cSatipDiscover::ActivateServer(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.Activate(serverP, onOffP);
serversM->Use(serverP, onOffP); }
void cSatipDiscover::AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP)
{
debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
cMutexLock MutexLock(&mutexM);
serversM.Attach(serverP, deviceIdP, transponderP);
}
void cSatipDiscover::DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP)
{
debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
cMutexLock MutexLock(&mutexM);
serversM.Detach(serverP, deviceIdP, transponderP);
}
bool cSatipDiscover::IsServerQuirk(cSatipServer *serverP, int quirkP)
{
debug16("%s (, %d)", __PRETTY_FUNCTION__, quirkP);
cMutexLock MutexLock(&mutexM);
return serversM.IsQuirk(serverP, quirkP);
}
bool cSatipDiscover::HasServerCI(cSatipServer *serverP)
{
debug16("%s", __PRETTY_FUNCTION__);
cMutexLock MutexLock(&mutexM);
return serversM.HasCI(serverP);
}
cString cSatipDiscover::GetSourceAddress(cSatipServer *serverP)
{
debug16("%s", __PRETTY_FUNCTION__);
cMutexLock MutexLock(&mutexM);
return serversM.GetSrcAddress(serverP);
}
cString cSatipDiscover::GetServerAddress(cSatipServer *serverP)
{
debug16("%s", __PRETTY_FUNCTION__);
cMutexLock MutexLock(&mutexM);
return serversM.GetAddress(serverP);
}
int cSatipDiscover::GetServerPort(cSatipServer *serverP)
{
debug16("%s", __PRETTY_FUNCTION__);
cMutexLock MutexLock(&mutexM);
return serversM.GetPort(serverP);
} }
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();
} }

View File

@ -13,34 +13,66 @@
#include <vdr/thread.h> #include <vdr/thread.h>
#include <vdr/tools.h> #include <vdr/tools.h>
#include "common.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:
int ipPortM;
int quirkM;
cString srcAddressM;
cString ipAddressM;
cString descriptionM;
cString modelM;
cString filtersM;
public:
cSatipDiscoverServer(const char *srcAddressP, const char *ipAddressP, const int ipPortP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP)
{
srcAddressM = srcAddressP; ipAddressM = ipAddressP; ipPortM = ipPortP; modelM = modelP; filtersM = filtersP; descriptionM = descriptionP; quirkM = quirkP;
}
int IpPort(void) { return ipPortM; }
int Quirk(void) { return quirkM; }
const char *SrcAddress(void) { return *srcAddressM; }
const char *IpAddress(void) { return *ipAddressM; }
const char *Model(void) { return *modelM; }
const char *Filters(void) { return *filtersM; }
const char *Description(void) { return *descriptionM; }
};
class cSatipDiscoverServers : public cList<cSatipDiscoverServer> {
};
class cSatipDiscover : public cThread, public cSatipDiscoverIf {
private: private:
enum { enum {
eConnectTimeoutMs = 1500, // in milliseconds eSleepTimeoutMs = 500, // in milliseconds
eDiscoveryPort = 1900, eConnectTimeoutMs = 1500, // in milliseconds
eProbeBufferSize = 1024, // in bytes eProbeTimeoutMs = 2000, // in milliseconds
eProbeTimeoutMs = 2000, // in milliseconds eProbeIntervalMs = 60000, // in milliseconds
eProbeIntervalMs = 60000 // in milliseconds eCleanupTimeoutMs = 124000 // in milliseoonds
}; };
static cSatipDiscover *instanceS; static cSatipDiscover *instanceS;
static const char *bcastAddressS; static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static const char *bcastMessageS; static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
cMutex mutexM; cMutex mutexM;
cSatipMemoryBuffer headerBufferM;
cSatipMemoryBuffer dataBufferM;
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); int ParseRtspPort(void);
void Probe(void); void ParseDeviceInfo(const char *addrP, const int portP);
void Read(void); void AddServer(const char *srcAddrP, const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP);
void AddServer(const char *addrP, const char *descP, const char *modelP); void Fetch(const char *urlP);
// constructor // constructor
cSatipDiscover(); cSatipDiscover();
// to prevent copy constructor and assignment // to prevent copy constructor and assignment
@ -52,18 +84,30 @@ 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 *AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP);
cSatipServer *GetServer(int sourceP);
cSatipServer *GetServer(cSatipServer *serverP); cSatipServer *GetServer(cSatipServer *serverP);
cSatipServers *GetServers(void); cSatipServers *GetServers(void);
cString GetServerString(cSatipServer *serverP); cString GetServerString(cSatipServer *serverP);
void UseServer(cSatipServer *serverP, bool onOffP); void ActivateServer(cSatipServer *serverP, bool onOffP);
void AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP);
void DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP);
bool IsServerQuirk(cSatipServer *serverP, int quirkP);
bool HasServerCI(cSatipServer *serverP);
cString GetServerAddress(cSatipServer *serverP);
cString GetSourceAddress(cSatipServer *serverP);
int GetServerPort(cSatipServer *serverP);
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
View 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:
explicit cSatipDiscoverIf(const cSatipDiscoverIf&);
cSatipDiscoverIf& operator=(const cSatipDiscoverIf&);
};
#endif // __SATIP_DISCOVERIF_H

48
log.h Normal file
View File

@ -0,0 +1,48 @@
/*
* 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: Pids
#define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() )
// 0x1000: Discovery
#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

111
msearch.c Normal file
View File

@ -0,0 +1,111 @@
/*
* 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, true))
error("Cannot open Msearch port!");
}
cSatipMsearch::~cSatipMsearch()
{
FREE_POINTER(bufferM);
}
void cSatipMsearch::Probe(void)
{
debug1("%s", __PRETTY_FUNCTION__);
if (!registeredM) {
cSatipPoller::GetInstance()->Register(*this);
registeredM = true;
}
// Send two queries with one second interval
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
cCondWait::SleepMs(1000);
Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS));
}
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;
debug13("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM);
bool status = false, valid = false;
char *s, *p = reinterpret_cast<char *>(bufferM), *location = NULL;
char *r = strtok_r(p, "\r\n", &s);
while (r) {
debug13("%s r=%s", __PRETTY_FUNCTION__, r);
// 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 (strcasestr(r, "LOCATION:") == r) {
location = compactspace(r + 9);
debug1("%s location='%s'", __PRETTY_FUNCTION__, location);
}
// Check the source type
// ST: urn:ses-com:device:SatIPServer:1
else if (strcasestr(r, "ST:") == r) {
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);
}
}
}
}
void cSatipMsearch::Process(unsigned char *dataP, int lengthP)
{
debug16("%s", __PRETTY_FUNCTION__);
}
cString cSatipMsearch::ToString(void) const
{
return "MSearch";
}

41
msearch.h Normal file
View File

@ -0,0 +1,41 @@
/*
* 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:
explicit cSatipMsearch(cSatipDiscoverIf &discoverP);
virtual ~cSatipMsearch();
void Probe(void);
// for internal poller interface
public:
virtual int GetFd(void);
virtual void Process(void);
virtual void Process(unsigned char *dataP, int lengthP);
virtual cString ToString(void) const;
};
#endif /* __SATIP_MSEARCH_H_ */

426
param.c
View File

@ -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,36 +52,45 @@ 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[] = {
{ QPSK, "&mtype=qpsk" }, { QPSK, "&mtype=qpsk" },
{ PSK_8, "&mtype=8psk" }, { PSK_8, "&mtype=8psk" },
{ APSK_16, "&mtype=16apsk" },
{ APSK_32, "&mtype=32apsk" },
{ VSB_8, "&mtype=8vsb" },
{ VSB_16, "&mtype=16vsb" },
{ QAM_16, "&mtype=16qam" }, { QAM_16, "&mtype=16qam" },
{ 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 }
};
static const tSatipParameterMap SatipSystemValuesAtsc[] = {
{ 0, "&msys=atsc" },
{ -1, NULL } { -1, NULL }
}; };
@ -92,8 +101,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 +113,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,15 +154,8 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
if (channelP) { if (channelP) {
char buffer[255]; char buffer[255];
cDvbTransponderParameters dtp(channelP->Parameters()); cDvbTransponderParameters dtp(channelP->Parameters());
#if defined(APIVERSNUM) && APIVERSNUM < 20106 int DataSlice = 0;
int Pilot = PILOT_AUTO; int C2TuningFrequencyType = 0;
int T2SystemId = 0;
int SisoMiso = 0;
#else
int Pilot = dtp.Pilot();
int T2SystemId = dtp.T2SystemId();
int SisoMiso = dtp.SisoMiso();
#endif
float freq = channelP->Frequency(); float freq = channelP->Frequency();
char type = cSource::ToChar(channelP->Source()); char type = cSource::ToChar(channelP->Source());
cSource *source = Sources.Get(channelP->Source()); cSource *source = Sources.Get(channelP->Source());
@ -158,26 +167,353 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
freq /= 1000L; freq /= 1000L;
#define ST(s) if (strchr(s, type) && (strchr(s, '0' + dtp.System() + 1) || strchr(s, '*'))) #define ST(s) if (strchr(s, type) && (strchr(s, '0' + dtp.System() + 1) || strchr(s, '*')))
#define STBUFLEFT (sizeof(buffer) - (q - buffer)) #define STBUFLEFT (sizeof(buffer) - (q - buffer))
q += snprintf(q, STBUFLEFT, "freq=%s", *dtoa(freq, "%lg")); ST(" S 1") { // to comply with SAT>IP protocol specification 1.2.2
ST(" S *") q += snprintf(q, STBUFLEFT, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1); dtp.SetPilot(PILOT_OFF);
ST("CS *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate()); dtp.SetModulation(QPSK);
ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization())); dtp.SetRollOff(ROLLOFF_35);
ST("C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId()); }
ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", T2SystemId); if ((channelP->Rid() % 100) > 0)
ST(" T2") q += PrintUrlString(q, STBUFLEFT, SisoMiso, SatipSisoMisoValues); q += snprintf(q, STBUFLEFT, "&fe=%d", channelP->Rid() % 100);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues); ST(" S *") q += snprintf(q, STBUFLEFT, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(), SatipGuardValues); if (freq >= 0L)
ST("CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(), SatipCodeRateValues); q += snprintf(q, STBUFLEFT, "&freq=%s", *dtoa(freq, "%lg"));
ST(" S 2") q += PrintUrlString(q, STBUFLEFT, Pilot, SatipPilotValues); ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization()));
ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues); ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues);
ST("C T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues); ST(" C 2") q += snprintf(q, STBUFLEFT, "&c2tft=%d", C2TuningFrequencyType);
ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(), SatipRollOffValues); ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues);
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesSat); ST(" C 2") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(), SatipBandwidthValues);
ST("C *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesCable); ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesSat);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesTerrestrial); ST(" C *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesCable);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues); ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesTerrestrial);
ST("A *") q += PrintUrlString(q, STBUFLEFT, dtp.System(), SatipSystemValuesAtsc);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues);
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
ST(" C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
ST("A *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(), SatipModulationValues);
ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Pilot(), SatipPilotValues);
ST(" S *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
ST(" C 1") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
ST(" T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(), SatipGuardValues);
ST(" CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(), SatipCodeRateValues);
ST(" C 2") q += snprintf(q, STBUFLEFT, "&ds=%d", DataSlice);
ST(" C T2") q += snprintf(q, STBUFLEFT, "&plp=%d", dtp.StreamId());
ST(" T2") q += snprintf(q, STBUFLEFT, "&t2id=%d", dtp.T2SystemId());
ST(" T2") q += PrintUrlString(q, STBUFLEFT, dtp.SisoMiso(), SatipSisoMisoValues);
ST(" C 1") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues);
ST("A *") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(), SatipInversionValues);
#undef ST #undef ST
return buffer; return &buffer[1];
}
return NULL;
}
cString GetTnrUrlParameters(const cChannel *channelP)
{
if (channelP) {
cDvbTransponderParameters dtp(channelP->Parameters());
eTrackType track = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
// TunerType: Byte;
// 0 = cable, 1 = satellite, 2 = terrestrial, 3 = atsc, 4 = iptv, 5 = stream (URL, DVBViewer GE)
int TunerType = 0;
if (channelP->IsCable())
TunerType = 0;
else if (channelP->IsSat())
TunerType = 1;
else if (channelP->IsTerr())
TunerType = 2;
else if (channelP->IsAtsc())
TunerType = 3;
// Frequency: DWord;
// DVB-S: MHz if < 1000000, kHz if >= 1000000
// DVB-T/C, ATSC: kHz
// IPTV: IP address Byte3.Byte2.Byte1.Byte0
int Frequency = channelP->Frequency() / 1000;
// Symbolrate: DWord;
// DVB S/C: in kSym/s
// DVB-T, ATSC: 0
// IPTV: Port
int Symbolrate = (channelP->IsSat() || channelP->IsCable()) ? channelP->Srate() : 0;
// LNB_LOF: Word;
// DVB-S: Local oscillator frequency of the LNB
// DVB-T/C, ATSC: 0
// IPTV: Byte0 and Byte1 of Source IP
int LNB_LOF = channelP->IsSat() ? Setup.LnbSLOF : 0;
// Tone: Byte;
// 0 = off, 1 = 22 khz
int Tone = (channelP->Frequency() < Setup.LnbSLOF) ? 0 : 1;
// Polarity: Byte;
// DVB-S polarity: 0 = horizontal, 1 = vertical, 2 = circular left, 3 = circular right
// DVB-C modulation: 0 = Auto, 1 = 16QAM, 2 = 32QAM, 3 = 64QAM, 4 = 128QAM, 5 = 256 QAM
// DVB-T bandwidth: 0 = 6 MHz, 1 = 7 MHz, 2 = 8 MHz
// IPTV: Byte3 of SourceIP
int Polarity = 0;
if (channelP->IsSat()) {
switch (tolower(dtp.Polarization())) {
case 'h':
Polarity = 0;
break;
case 'v':
Polarity = 1;
break;
case 'l':
Polarity = 2;
break;
case 'r':
Polarity = 3;
break;
default:
break;
}
}
else if (channelP->IsCable()) {
switch (dtp.Modulation()) {
case 999:
Polarity = 0;
break;
case 16:
Polarity = 1;
break;
case 32:
Polarity = 2;
break;
case 64:
Polarity = 3;
break;
case 128:
Polarity = 4;
break;
case 256:
Polarity = 5;
break;
default:
break;
}
}
else if (channelP->IsTerr()) {
switch (dtp.Bandwidth()) {
case 6:
Polarity = 0;
break;
case 7:
Polarity = 1;
break;
case 8:
Polarity = 2;
break;
default:
break;
}
}
// DiSEqC: Byte;
// 0 = None
// 1 = Pos A (mostly translated to PosA/OptA)
// 2 = Pos B (mostly translated to PosB/OptA)
// 3 = PosA/OptA
// 4 = PosB/OptA
// 5 = PosA/OptB
// 6 = PosB/OptB
// 7 = Preset Position (DiSEqC 1.2, see DiSEqCExt)
// 8 = Angular Position (DiSEqC 1.2, see DiSEqCExt)
// 9 = DiSEqC Command Sequence (see DiSEqCExt)
int DiSEqC = 0;
// FEC: Byte;
// 0 = Auto
// 1 = 1/2
// 2 = 2/3
// 3 = 3/4
// 4 = 5/6
// 5 = 7/8
// 6 = 8/9
// 7 = 3/5
// 8 = 4/5
// 9 = 9/10
// IPTV: Byte2 of SourceIP
// DVB C/T, ATSC: 0
int FEC = 0;
if (channelP->IsSat()) {
switch (dtp.CoderateH()) {
case 999:
FEC = 0;
break;
case 12:
FEC = 1;
break;
case 23:
FEC = 2;
break;
case 34:
FEC = 3;
break;
case 56:
FEC = 4;
break;
case 78:
FEC = 5;
break;
case 89:
FEC = 6;
break;
case 35:
FEC = 7;
break;
case 45:
FEC = 8;
break;
case 910:
FEC = 9;
break;
default:
break;
}
}
// Audio_PID: Word;
int Audio_PID = channelP->Apid(0);
if (IS_AUDIO_TRACK(track))
Audio_PID = channelP->Apid(int(track - ttAudioFirst));
else if (IS_DOLBY_TRACK(track))
Audio_PID = channelP->Dpid(int(track - ttDolbyFirst));
// Video_PID: Word;
int Video_PID = channelP->Vpid();
// PMT_PID: Word;
int PMT_PID = channelP->Ppid();
// Service_ID: Word;
int Service_ID = channelP->Sid();
// SatModulation: Byte;
// Bit 0..1: satellite modulation. 0 = Auto, 1 = QPSK, 2 = 8PSK, 3 = 16QAM or APSK for DVB-S2
// Bit 2: modulation system. 0 = DVB-S/T/C, 1 = DVB-S2/T2/C2
// Bit 3..4: DVB-S2: roll-off. 0 = 0.35, 1 = 0.25, 2 = 0.20, 3 = reserved
// Bit 5..6: spectral inversion, 0 = undefined, 1 = auto, 2 = normal, 3 = inverted
// Bit 7: DVB-S2: pilot symbols, 0 = off, 1 = on
// DVB-T2: DVB-T2 Lite, 0 = off, 1 = on
int SatModulation = 0;
if (channelP->IsSat() && dtp.System()) {
switch (dtp.Modulation()) {
case 999:
SatModulation |= (0 & 0x3) << 0;
break;
case 2:
SatModulation |= (1 & 0x3) << 0;
break;
case 5:
SatModulation |= (2 & 0x3) << 0;
break;
case 6:
SatModulation |= (3 & 0x3) << 0;
break;
default:
break;
}
}
SatModulation |= (dtp.System() & 0x1) << 2;
if (channelP->IsSat() && dtp.System()) {
switch (dtp.RollOff()) {
case 35:
SatModulation |= (0 & 0x3) << 3;
break;
case 25:
SatModulation |= (1 & 0x3) << 3;
break;
case 20:
SatModulation |= (2 & 0x3) << 3;
break;
default:
break;
}
}
switch (dtp.Inversion()) {
case 999:
SatModulation |= (1 & 0x3) << 5;
break;
case 0:
SatModulation |= (2 & 0x3) << 5;
break;
case 1:
SatModulation |= (3 & 0x3) << 5;
break;
default:
break;
}
if (channelP->IsSat() && dtp.System()) {
switch (dtp.Pilot()) {
case 0:
SatModulation |= (0 & 0x1) << 7;
break;
case 1:
SatModulation |= (1 & 0x1) << 7;
break;
default:
break;
}
}
// DiSEqCExt: Word;
// DiSEqC Extension, meaning depends on DiSEqC
// DiSEqC = 0..6: 0
// DiSEqC = 7: Preset Position (DiSEqC 1.2)
// DiSEqC = 8: Orbital Position (DiSEqC 1.2, USALS, for calculating motor angle)
// Same format as OrbitalPos above
// DiSEQC = 9: Orbital Position referencing DiSEqC sequence defined in DiSEqC.xml/ini
// Same format as OrbitalPos above
int DiSEqCExt = 0;
// Flags: Byte;
// Bit 0: 1 = encrypted channel
// Bit 1: reserved, set to 0
// Bit 2: 1 = channel broadcasts RDS data
// Bit 3: 1 = channel is a video service (even if the Video PID is temporarily = 0)
// Bit 4: 1 = channel is an audio service (even if the Audio PID is temporarily = 0)
// Bit 5: 1 = audio has a different samplerate than 48 KHz
// Bit 6: 1 = bandstacking, internally polarisation is always set to H
// Bit 7: 1 = channel entry is an additional audio track of the preceding
// channel with bit 7 = 0
int Flags = (channelP->Ca() > 0xFF) ? 1 : 0;
// ChannelGroup: Byte;
// 0 = Group A, 1 = Group B, 2 = Group C etc.
int ChannelGroup = 0;
// TransportStream_ID: Word;
int TransportStream_ID = channelP->Tid();
// OriginalNetwork_ID: Word;
int OriginalNetwork_ID = channelP->Nid();
// Substream: Word;
// DVB-S/C/T, ATSC, IPTV: 0
// DVB-T2: 0 = PLP_ID not set, 1..256: PLP_ID + 1, 257... reserved
int Substream = (channelP->IsTerr() && dtp.System()) ? dtp.StreamId() - 1 : 0;
// OrbitalPos: Word;
// DVB-S: orbital position x 10, 0 = undefined, 1..1800 east, 1801..3599 west (1°W = 3599)
// DVB-C: 4000..4999
// DVB-T: 5000..5999
// ATSC: 6000..6999
// IPTV: 7000..7999
// Stream: 8000..8999
int OrbitalPos = 0;
if (channelP->IsSat()) {
OrbitalPos = cSource::Position(channelP->Source());
if (OrbitalPos != 3600)
OrbitalPos += 1800;
}
return cString::sprintf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
TunerType, Frequency, Symbolrate, LNB_LOF, Tone, Polarity, DiSEqC, FEC, Audio_PID, Video_PID, PMT_PID, Service_ID,
SatModulation, DiSEqCExt, Flags, ChannelGroup, TransportStream_ID, OriginalNetwork_ID, Substream, OrbitalPos);
} }
return NULL; return NULL;
} }

View File

@ -11,5 +11,6 @@
#include "common.h" #include "common.h"
cString GetTransponderUrlParameters(const cChannel *channelP); cString GetTransponderUrlParameters(const cChannel *channelP);
cString GetTnrUrlParameters(const cChannel *channelP);
#endif // __SATIP_PARAM_H #endif // __SATIP_PARAM_H

View File

@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007-2014 Rolf Ahrenberg # Copyright (C) 2007-2019 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-2017
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-satip 0.3.3\n" "Project-Id-Version: vdr-satip 2.4.0\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: 2019-10-27 19:12+0200\n"
"PO-Revision-Date: 2014-05-18 05:18+0200\n" "PO-Revision-Date: 2019-10-27 10:27+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,18 @@ msgstr "Normal"
msgid "high" msgid "high"
msgstr "Alt" msgstr "Alt"
msgid "Unicast"
msgstr "Unicast"
msgid "Multicast"
msgstr "Multicast"
msgid "RTP-over-TCP"
msgstr "RTP-per sobre-TCP"
msgid "Button$Devices"
msgstr "Dispositius"
msgid "Operating mode" msgid "Operating mode"
msgstr "Mode de operació" msgstr "Mode de operació"
@ -90,13 +108,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 +151,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 +187,23 @@ 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 "Transport mode"
msgstr "Dispositius SAT>IP actius:" msgstr "Tipus de Transmissió"
msgid ""
"Define which transport mode shall be used.\n"
"\n"
"Unicast, Multicast, RTP-over-TCP"
msgstr ""
msgid "Enable frontend reuse"
msgstr ""
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
msgstr ""
msgid "Active SAT>IP servers:"
msgstr "Activa SAT>IP servers:"
msgid "Help" msgid "Help"
msgstr "Ajuda" msgstr "Ajuda"

View File

@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007-2014 Rolf Ahrenberg # Copyright (C) 2007-2019 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-2017
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-satip 0.3.3\n" "Project-Id-Version: vdr-satip 2.4.0\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: 2019-10-27 19:12+0200\n"
"PO-Revision-Date: 2014-05-18 05:18+0200\n" "PO-Revision-Date: 2019-10-27 10:27+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ätestatus"
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,8 +85,20 @@ msgstr "normal"
msgid "high" msgid "high"
msgstr "hoch" msgstr "hoch"
msgid "Unicast"
msgstr "Unicast"
msgid "Multicast"
msgstr "Multicast"
msgid "RTP-over-TCP"
msgstr "RTP-over-TCP"
msgid "Button$Devices"
msgstr "Geräte"
msgid "Operating mode" msgid "Operating mode"
msgstr "Betriebsmodus" msgstr "Betriebsart"
msgid "" msgid ""
"Define the used operating mode for all SAT>IP devices:\n" "Define the used operating mode for all SAT>IP devices:\n"
@ -90,12 +108,36 @@ 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 ""
"Bestimme den Betriebsmodus für alle SAT>IP Geräte:\n" "Bestimme die Betriebsart für alle SAT>IP Geräte:\n"
"\n" "\n"
"aus - Geräte sind abgeschaltet\n" "aus - Geräte sind deaktiviert\n"
"niedrig - Geräte arbeiten mit geringster Priorität\n" "niedrig - Geräte arbeiten mit geringster Priorität\n"
"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öchster 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,33 +147,66 @@ 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 aus."
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"
"Bestimmte Abschnittsfilter können unerwünschtes Verhalten mit VDR, z.B. falsche Zeit-Synchronisation, verursachen. Durch das Ausblenden einzelner Filter können nützliche Daten dieser Abschnitte für den VDR erhalten werden." "Bestimmte Abschnittsfilter können unerwünschtes Verhalten mit VDR, z.B. falsche Zeit-Synchronisation, verursachen. Durch das Ausblenden einzelner Filter können nützliche Daten dieser Abschnitte für den VDR erhalten bleiben."
msgid "Filter" msgid "Filter"
msgstr "Filter" 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 fehlerhafte Filter die ausgeblendet werden sollen."
msgid "Active SAT>IP devices:" msgid "Transport mode"
msgstr "Aktive SAT>IP Geräte:" msgstr "Übertragungsart"
msgid ""
"Define which transport mode shall be used.\n"
"\n"
"Unicast, Multicast, RTP-over-TCP"
msgstr ""
"Lege die gewünschte Übertragungsart fest.\n"
"\n"
"Unicast, Multicast, RTP-over-TCP"
msgid "Enable frontend reuse"
msgstr "Frontend Mehrfachnutzung aktivieren"
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
msgstr "Festlegung ob ein Tuner-Frontend für mehrere Kanäle genutzt wird."
msgid "Active SAT>IP servers:"
msgstr "Aktive SAT>IP Server:"
msgid "Help" msgid "Help"
msgstr "Hilfe" msgstr "Hilfe"

View File

@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007-2014 Rolf Ahrenberg # Copyright (C) 2007-2019 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-2017
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-satip 0.3.3\n" "Project-Id-Version: vdr-satip 2.4.0\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: 2019-10-27 19:12+0200\n"
"PO-Revision-Date: 2014-05-18 05:18+0200\n" "PO-Revision-Date: 2019-10-27 10:27+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,18 @@ msgstr "Normal"
msgid "high" msgid "high"
msgstr "Alto" msgstr "Alto"
msgid "Unicast"
msgstr "Unicast"
msgid "Multicast"
msgstr "Multicast"
msgid "RTP-over-TCP"
msgstr "RTP-antes que-TCP"
msgid "Button$Devices"
msgstr "Dispositivos"
msgid "Operating mode" msgid "Operating mode"
msgstr "Modo de operación" msgstr "Modo de operación"
@ -97,6 +115,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 +151,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 +187,23 @@ 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 "Transport mode"
msgstr "Dispositivos SAT>IP activos:" msgstr "Tipo de Transmisión"
msgid ""
"Define which transport mode shall be used.\n"
"\n"
"Unicast, Multicast, RTP-over-TCP"
msgstr ""
msgid "Enable frontend reuse"
msgstr ""
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
msgstr ""
msgid "Active SAT>IP servers:"
msgstr "Activa SAT>IP servers:"
msgid "Help" msgid "Help"
msgstr "Ayuda" msgstr "Ayuda"

View File

@ -1,14 +1,14 @@
# VDR plugin language source file. # VDR plugin language source file.
# Copyright (C) 2007-2014 Rolf Ahrenberg # Copyright (C) 2007-2019 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-2019
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: vdr-satip 0.3.3\n" "Project-Id-Version: vdr-satip 2.4.0\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: 2019-10-27 19:12+0200\n"
"PO-Revision-Date: 2014-05-18 05:18+0200\n" "PO-Revision-Date: 2019-10-27 10:27+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,18 @@ msgstr "normaali"
msgid "high" msgid "high"
msgstr "korkea" msgstr "korkea"
msgid "Unicast"
msgstr "Unicast"
msgid "Multicast"
msgstr "Multicast"
msgid "RTP-over-TCP"
msgstr "RTP-over-TCP"
msgid "Button$Devices"
msgstr "Laitteet"
msgid "Operating mode" msgid "Operating mode"
msgstr "Laitteiden toimintatapa" msgstr "Laitteiden toimintatapa"
@ -96,6 +114,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 +150,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 +186,26 @@ 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 "Transport mode"
msgstr "Aktiiviset SAT>IP-laitteet:" msgstr "Siirtoyhteystapa"
msgid ""
"Define which transport mode shall be used.\n"
"\n"
"Unicast, Multicast, RTP-over-TCP"
msgstr ""
"Määrittele käytettävä siirtoyhteystapa.\n"
"\n"
"Unicast, Multicast, RTP-over-TCP"
msgid "Enable frontend reuse"
msgstr "Uusiokäytä virittimiä"
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
msgstr "Määrittele virittien uusiokäyttö kanaville, jotka ovat samalla transponderilla."
msgid "Active SAT>IP servers:"
msgstr "Aktiiviset SAT>IP-palvelimet:"
msgid "Help" msgid "Help"
msgstr "Opaste" msgstr "Opaste"

212
po/pl_PL.po Normal file
View File

@ -0,0 +1,212 @@
# VDR plugin language source file.
# Copyright (C) 2007-2019 Rolf Ahrenberg
# This file is distributed under the same license as the vdr-satip package.
# Tomasz Maciej Nowak, 2017
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 2.4.0\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2019-10-27 19:12+0200\n"
"PO-Revision-Date: 2019-10-27 10:27+0200\n"
"Last-Translator: Tomasz Maciej Nowak <tomek_n@o2.pl>\n"
"Language-Team: Polish <vdr@linuxtv.org>\n"
"Language: pl_PL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.11\n"
msgid "PAT (0x00)"
msgstr "PAT (0x00)"
msgid "NIT (0x40)"
msgstr "NIT (0x40)"
msgid "SDT (0x42)"
msgstr "SDT (0x42)"
msgid "EIT (0x4E/0x4F/0x5X/0x6X)"
msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
msgid "TDT (0x70)"
msgstr "TDT (0x70)"
msgid "SAT>IP information not available!"
msgstr "Informacja o SAT>IP niedostępna!"
msgid "SAT>IP Devices"
msgstr "Urządzenia SAT>IP"
msgid "SAT>IP Server"
msgstr "Serwer SAT>IP"
msgid "Address"
msgstr "Adres"
msgid "Model"
msgstr "Model"
msgid "Description"
msgstr "Opis"
msgid "CI extension"
msgstr "Rozszerzenie CI"
msgid "Creation date"
msgstr "Data produkcji"
msgid "SAT>IP Device Status"
msgstr "Status urządzenia SAT>IP"
msgid "SAT>IP Information"
msgstr "SAT>IP - informacje"
msgid "General"
msgstr "Główne"
msgid "Pids"
msgstr "Pidy"
msgid "Filters"
msgstr "Filtry"
msgid "Bits/bytes"
msgstr "Bity/bajty"
msgid "off"
msgstr "wyłączone"
msgid "low"
msgstr "niski"
msgid "normal"
msgstr "normalny"
msgid "high"
msgstr "wysoki"
msgid "Unicast"
msgstr "Unicast"
msgid "Multicast"
msgstr "Multicast"
msgid "RTP-over-TCP"
msgstr "RTP-over-TCP"
msgid "Button$Devices"
msgstr "Urządzenia"
msgid "Operating mode"
msgstr "Tryb pracy"
msgid ""
"Define the used operating mode for all SAT>IP devices:\n"
"\n"
"off - devices are disabled\n"
"low - devices are working at the lowest priority\n"
"normal - devices are working within normal parameters\n"
"high - devices are working at the highest priority"
msgstr ""
"Określa tryb pracy wszystkich urządzeń SAT>IP:\n"
"\n"
"wyłączone - urządzenia są wyłączone\n"
"niski - urządzenia pracują z najniższym priorytetem\n"
"normalny - urządzenia pracują z normalnymi parametrami\n"
"wysoki - urządzenia pracują z najwyższym priorytetem"
msgid "Enable CI extension"
msgstr "Włącz rozszerzenie CI"
msgid ""
"Define whether a CI extension shall be used.\n"
"\n"
"This setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)."
msgstr ""
"Określa czy korzystać z rozszerzenia CI.\n"
"\n"
"To ustawienie włącza obsługę dostępnego czytnika CI/CAM w niektórych urządzeniach SAT>IP (np. Digital Devices OctopusNet)."
msgid "CI/CAM"
msgstr "CI/CAM"
msgid ""
"Define a desired CAM type for the CI slot.\n"
"\n"
"The '---' option lets SAT>IP hardware do the auto-selection."
msgstr ""
"Określa typ modułu CAM w czytniku CI.\n"
"\n"
"Opcja '---' pozwala urządzeniu SAT>IP automatycznie wybrać typ."
msgid "Enable EPG scanning"
msgstr "Włącz skanowanie EPG"
msgid ""
"Define whether the EPG background scanning shall be used.\n"
"\n"
"This setting disables the automatic EIT scanning functionality for all SAT>IP devices."
msgstr ""
"Określa czy przeprowadzać skanowanie EPG w tle.\n"
"\n"
"To ustawienie wyłącza funkcję automatycznego skanowania EIT dla wszystkich urządzeń SAT>IP."
msgid "Disabled sources"
msgstr "Wyłączone źródła"
msgid "none"
msgstr "brak"
msgid ""
"Define number of sources to be disabled.\n"
"\n"
"SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here."
msgstr ""
"Określa liczbę wyłączonych źródeł.\n"
"\n"
"Serwery SAT>IP mogą nie mieć dostępu do niektórych pozycji satelitarnych, więc tutaj można je wyłączyć."
msgid "Define a source to be blacklisted."
msgstr "Określ źródła do wyłączenia."
msgid "Disabled filters"
msgstr "Wyłączone filtry"
msgid ""
"Define number of section filters to be disabled.\n"
"\n"
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By blacklisting the filters here, useful section data can be left intact for VDR to process."
msgstr ""
"Określa liczbę wyłączonych filtrów sekcji.\n"
"\n"
"Niektóre filtry sekcji mogą powodować niezamierzone efekty w VDR, takie jak zły czas synchronizacji. Poprzez wyłączenie niektórych filtrów, użyteczne dane sekcji będą dostępne do przetworzenia dla VDR."
msgid "Filter"
msgstr "Filtr"
msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Określa filtry powodujące zakłócenia, które mają być wyłączone."
msgid "Transport mode"
msgstr "Tryb"
msgid ""
"Define which transport mode shall be used.\n"
"\n"
"Unicast, Multicast, RTP-over-TCP"
msgstr ""
"Określa tryb transmisji.\n"
"Unicast, Multicast, RTP-over-TCP."
msgid "Enable frontend reuse"
msgstr ""
msgid "Define whether reusing a frontend for multiple channels in a transponder should be enabled."
msgstr ""
msgid "Active SAT>IP servers:"
msgstr "Aktywne serwery SAT>IP:"
msgid "Help"
msgstr "Pomoc"

122
poller.c Normal file
View 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 && errno != EINTR), "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
View 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

25
pollerif.h Normal file
View File

@ -0,0 +1,25 @@
/*
* 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 void Process(unsigned char *dataP, int lengthP) = 0;
virtual cString ToString(void) const = 0;
private:
explicit cSatipPollerIf(const cSatipPollerIf&);
cSatipPollerIf& operator=(const cSatipPollerIf&);
};
#endif // __SATIP_POLLERIF_H

108
rtcp.c Normal file
View File

@ -0,0 +1,108 @@
/*
* 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());
FREE_POINTER(bufferM);
}
int cSatipRtcp::GetFd(void)
{
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
return Fd();
}
int cSatipRtcp::GetApplicationOffset(unsigned char *bufferP, int *lengthP)
{
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP ? *lengthP : -1, tunerM.GetId());
if (!lengthP)
return -1;
int offset = 0;
int total = *lengthP;
while (total > 0) {
// Version
unsigned int v = (bufferP[offset] >> 6) & 0x03;
// Padding
//unsigned int p = (bufferP[offset] >> 5) & 0x01;
// Subtype
//unsigned int st = bufferP[offset] & 0x1F;
// Payload type
unsigned int pt = bufferP[offset + 1] & 0xFF;
// Length
unsigned int length = ((bufferP[offset + 2] & 0xFF) << 8) | (bufferP[offset + 3] & 0xFF);
// Convert it to bytes
length = (length + 1) * 4;
// V=2, APP = 204
if ((v == 2) && (pt == 204)) {
// SSCR/CSCR
//unsigned int ssrc = ((bufferP[offset + 4] & 0xFF) << 24) | ((bufferP[offset + 5] & 0xFF) << 16) |
// ((bufferP[offset + 6] & 0xFF) << 8) | (bufferP[offset + 7] & 0xFF);
// Name
if ((bufferP[offset + 8] == 'S') && (bufferP[offset + 9] == 'E') &&
(bufferP[offset + 10] == 'S') && (bufferP[offset + 11] == '1')) {
// Identifier
//unsigned int id = ((bufferP[offset + 12] & 0xFF) << 8) | (bufferP[offset + 13] & 0xFF);
// String length
int string_length = ((bufferP[offset + 14] & 0xFF) << 8) | (bufferP[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(bufferM, &length);
if (offset >= 0)
tunerM.ProcessApplicationData(bufferM + offset, length);
}
}
}
void cSatipRtcp::Process(unsigned char *dataP, int lengthP)
{
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
if (dataP && lengthP > 0) {
int offset = GetApplicationOffset(dataP, &lengthP);
if (offset >= 0)
tunerM.ProcessApplicationData(dataP + offset, lengthP);
}
}
cString cSatipRtcp::ToString(void) const
{
return cString::sprintf("RTCP [device %d]", tunerM.GetId());
}

37
rtcp.h Normal file
View File

@ -0,0 +1,37 @@
/*
* 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(unsigned char *bufferP, int *lengthP);
public:
explicit cSatipRtcp(cSatipTunerIf &tunerP);
virtual ~cSatipRtcp();
// for internal poller interface
public:
virtual int GetFd(void);
virtual void Process(void);
virtual void Process(unsigned char *dataP, int lengthP);
virtual cString ToString(void) const;
};
#endif /* __SATIP_RTCP_H_ */

165
rtp.c Normal file
View File

@ -0,0 +1,165 @@
/*
* 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)
: cSatipSocket(SatipConfig.GetRtpRcvBufSize()),
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());
FREE_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 error%s [device %d]", packetErrorsM, packetErrorsM == 1 ? "": "s", 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 error%s [device %d]", packetErrorsM, packetErrorsM == 1 ? "": "s", 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);
elapsed = processing.Elapsed();
if (elapsed > 1)
debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, count, elapsed, tunerM.GetId());
}
}
void cSatipRtp::Process(unsigned char *dataP, int lengthP)
{
debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
if (dataP && lengthP > 0) {
uint64_t elapsed;
cTimeMs processing(0);
int headerlen = GetHeaderLength(dataP, lengthP);
if ((headerlen >= 0) && (headerlen < lengthP))
tunerM.ProcessVideoData(dataP + headerlen, lengthP - headerlen);
elapsed = processing.Elapsed();
if (elapsed > 1)
debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, lengthP, elapsed, tunerM.GetId());
}
}
cString cSatipRtp::ToString(void) const
{
return cString::sprintf("RTP [device %d]", tunerM.GetId());
}

43
rtp.h Normal file
View File

@ -0,0 +1,43 @@
/*
* 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:
explicit cSatipRtp(cSatipTunerIf &tunerP);
virtual ~cSatipRtp();
virtual void Close(void);
// for internal poller interface
public:
virtual int GetFd(void);
virtual void Process(void);
virtual void Process(unsigned char *dataP, int lengthP);
virtual cString ToString(void) const;
};
#endif /* __SATIP_RTP_H_ */

568
rtsp.c Normal file
View File

@ -0,0 +1,568 @@
/*
* 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),
headerBufferM(),
dataBufferM(),
handleM(NULL),
headerListM(NULL),
errorNoMoreM(""),
errorOutOfRangeM(""),
errorCheckSyntaxM(""),
modeM(cSatipConfig::eTransportModeUnicast),
interleavedRtpIdM(0),
interleavedRtcpIdM(1)
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
Create();
}
cSatipRtsp::~cSatipRtsp()
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
Destroy();
}
size_t cSatipRtsp::HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
{
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP);
size_t len = sizeP * nmembP;
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
if (obj && (len > 0))
obj->headerBufferM.Add(ptrP, len);
return len;
}
size_t cSatipRtsp::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
{
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP);
size_t len = sizeP * nmembP;
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
if (obj)
obj->dataBufferM.Add(ptrP, len);
return len;
}
size_t cSatipRtsp::InterleaveCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP)
{
cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP);
size_t len = sizeP * nmembP;
debug16("%s len=%zu", __PRETTY_FUNCTION__, len);
if (obj && ptrP && len > 0) {
char tag = ptrP[0] & 0xFF;
if (tag == '$') {
int count = ((ptrP[2] & 0xFF) << 8) | (ptrP[3] & 0xFF);
if (count > 0) {
unsigned int channel = ptrP[1] & 0xFF;
u_char *data = (u_char *)&ptrP[4];
if (channel == obj->interleavedRtpIdM)
obj->tunerM.ProcessRtpData(data, count);
else if (channel == obj->interleavedRtcpIdM)
obj->tunerM.ProcessRtcpData(data, count);
}
}
}
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::GetActiveMode(void)
{
switch (modeM) {
case cSatipConfig::eTransportModeUnicast:
return "Unicast";
case cSatipConfig::eTransportModeMulticast:
return "Multicast";
case cSatipConfig::eTransportModeRtpOverTcp:
return "RTP-over-TCP";
default:
break;
}
return "";
}
cString cSatipRtsp::RtspUnescapeString(const char *strP)
{
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId());
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::SetInterface(const char *bindAddrP)
{
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, bindAddrP, tunerM.GetId());
bool result = true;
CURLcode res = CURLE_OK;
if (handleM && !isempty(bindAddrP)) {
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERFACE, *cString::sprintf("host!%s", bindAddrP));
}
else {
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERFACE, NULL);
}
return result;
}
bool cSatipRtsp::Receive(const char *uriP)
{
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
bool result = false;
if (handleM && !isempty(uriP) && modeM == cSatipConfig::eTransportModeRtpOverTcp) {
long rc = 0;
cTimeMs processing(0);
CURLcode res = CURLE_OK;
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_URL, uriP);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS); // FIXME: this really should be CURL_RTSPREQ_RECEIVE, but getting timeout errors
SATIP_CURL_EASY_PERFORM(handleM);
result = ValidateLatestResponse(&rc);
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
}
return result;
}
bool cSatipRtsp::Options(const char *uriP)
{
debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, uriP, tunerM.GetId());
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, bool useTcpP)
{
debug1("%s (%s, %d, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, useTcpP, tunerM.GetId());
bool result = false;
if (handleM && !isempty(uriP)) {
cString transport;
long rc = 0;
cTimeMs processing(0);
CURLcode res = CURLE_OK;
switch (SatipConfig.GetTransportMode()) {
case cSatipConfig::eTransportModeMulticast:
// RTP/AVP;multicast;destination=<multicast group address>;port=<RTP port>-<RTCP port>;ttl=<ttl>[;source=<multicast source address>]
transport = cString::sprintf("RTP/AVP;multicast");
break;
default:
// RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port>
// RTP/AVP/TCP;unicast;client_port=<client RTP port>-<client RTCP port>
if (useTcpP)
transport = cString::sprintf("RTP/AVP/TCP;unicast;interleaved=%u-%u", interleavedRtpIdM, interleavedRtcpIdM);
else
transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP);
break;
}
// 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_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
SATIP_CURL_EASY_PERFORM(handleM);
// Session id is now known - disable header parsing
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
if (headerBufferM.Size() > 0) {
ParseHeader();
headerBufferM.Reset();
}
if (dataBufferM.Size() > 0) {
ParseData();
dataBufferM.Reset();
}
result = ValidateLatestResponse(&rc);
debug5("%s (%s, %d, %d) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, rc, processing.Elapsed(), tunerM.GetId());
}
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::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
if (dataBufferM.Size() > 0) {
tunerM.ProcessApplicationData((u_char *)dataBufferM.Data(), dataBufferM.Size());
dataBufferM.Reset();
}
result = ValidateLatestResponse(&rc);
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
}
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_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
if (dataBufferM.Size() > 0) {
ParseData();
dataBufferM.Reset();
}
result = ValidateLatestResponse(&rc);
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
}
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_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
SATIP_CURL_EASY_PERFORM(handleM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL);
if (dataBufferM.Size() > 0) {
ParseData();
dataBufferM.Reset();
}
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_CLIENT_CSEQ, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL);
result = ValidateLatestResponse(&rc);
debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId());
}
return result;
}
void cSatipRtsp::ParseHeader(void)
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
char *s, *p = headerBufferM.Data();
char *r = strtok_r(p, "\r\n", &s);
while (r) {
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r);
r = skipspace(r);
if (strstr(r, "com.ses.streamID")) {
int streamid = -1;
if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1)
tunerM.SetStreamId(streamid);
}
else if (strstr(r, "Session:")) {
int timeout = -1;
char *session = NULL;
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
tunerM.SetSessionTimeout(skipspace(session), timeout * 1000);
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
tunerM.SetSessionTimeout(skipspace(session), -1);
FREE_POINTER(session);
}
else if (strstr(r, "Transport:")) {
CURLcode res = CURLE_OK;
int rtp = -1, rtcp = -1, ttl = -1;
char *tmp = NULL, *destination = NULL, *source = NULL;
interleavedRtpIdM = 0;
interleavedRtcpIdM = 1;
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL);
if (sscanf(r, "Transport:%m[^;];unicast;client_port=%11d-%11d", &tmp, &rtp, &rtcp) == 3) {
modeM = cSatipConfig::eTransportModeUnicast;
tunerM.SetupTransport(rtp, rtcp, NULL, NULL);
}
else if (sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d;source=%m[^;]", &tmp, &destination, &rtp, &rtcp, &ttl, &source) == 6 ||
sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d", &tmp, &destination, &rtp, &rtcp, &ttl) == 5) {
modeM = cSatipConfig::eTransportModeMulticast;
tunerM.SetupTransport(rtp, rtcp, destination, source);
}
else if (sscanf(r, "Transport:%m[^;];interleaved=%11d-%11d", &tmp, &rtp, &rtcp) == 3) {
interleavedRtpIdM = rtp;
interleavedRtcpIdM = rtcp;
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, cSatipRtsp::InterleaveCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, this);
modeM = cSatipConfig::eTransportModeRtpOverTcp;
tunerM.SetupTransport(-1, -1, NULL, NULL);
}
FREE_POINTER(tmp);
FREE_POINTER(destination);
FREE_POINTER(source);
}
r = strtok_r(NULL, "\r\n", &s);
}
}
void cSatipRtsp::ParseData(void)
{
debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId());
char *s, *p = dataBufferM.Data();
char *r = strtok_r(p, "\r\n", &s);
while (r) {
debug16("%s (%zu): %s", __PRETTY_FUNCTION__, dataBufferM.Size(), r);
r = skipspace(r);
if (strstr(r, "No-More:")) {
char *tmp = NULL;
if (sscanf(r, "No-More:%m[^;]", &tmp) == 1) {
errorNoMoreM = skipspace(tmp);
debug3("%s No-More: %s [device %d]", __PRETTY_FUNCTION__, *errorNoMoreM, tunerM.GetId());
}
FREE_POINTER(tmp);
}
else if (strstr(r, "Out-of-Range:")) {
char *tmp = NULL;
if (sscanf(r, "Out-of-Range:%m[^;]", &tmp) == 1) {
errorOutOfRangeM = skipspace(tmp);
debug3("%s Out-of-Range: %s [device %d]", __PRETTY_FUNCTION__, *errorOutOfRangeM, tunerM.GetId());
}
FREE_POINTER(tmp);
}
else if (strstr(r, "Check-Syntax:")) {
char *tmp = NULL;
if (sscanf(r, "Check-Syntax:%m[^;]", &tmp) == 1) {
errorCheckSyntaxM = skipspace(tmp);
debug3("%s Check-Syntax: %s [device %d]", __PRETTY_FUNCTION__, *errorCheckSyntaxM, tunerM.GetId());
}
FREE_POINTER(tmp);
}
r = strtok_r(NULL, "\r\n", &s);
}
}
bool cSatipRtsp::ValidateLatestResponse(long *rcP)
{
bool result = false;
if (handleM) {
char *url = NULL;
long rc = 0;
CURLcode res = CURLE_OK;
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc);
switch (rc) {
case 200:
result = true;
break;
case 400:
// SETUP PLAY TEARDOWN
// The message body of the response may contain the "Check-Syntax:" parameter followed
// by the malformed syntax
if (!isempty(*errorCheckSyntaxM)) {
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("Check syntax: %s (error code %ld: %s) [device %d]", *errorCheckSyntaxM, rc, url, tunerM.GetId());
break;
}
case 403:
// SETUP PLAY TEARDOWN
// The message body of the response may contain the "Out-of-Range:" parameter followed
// by a space-separated list of the attribute names that are not understood:
// "src" "fe" "freq" "pol" "msys" "mtype" "plts" "ro" "sr" "fec" "pids" "addpids" "delpids" "mcast"
if (!isempty(*errorOutOfRangeM)) {
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("Out of range: %s (error code %ld: %s) [device %d]", *errorOutOfRangeM, rc, url, tunerM.GetId());
// Reseting the connection wouldn't help anything due to invalid channel configuration, so let it be successful
result = true;
break;
}
case 503:
// SETUP PLAY
// The message body of the response may contain the "No-More:" parameter followed
// by a space-separated list of the missing ressources: “sessions” "frontends" "pids
if (!isempty(*errorNoMoreM)) {
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("No more: %s (error code %ld: %s) [device %d]", *errorNoMoreM, rc, url, tunerM.GetId());
break;
}
default:
SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url);
error("Detected invalid status code %ld: %s [device %d]", rc, url, tunerM.GetId());
break;
}
if (rcP)
*rcP = rc;
}
errorNoMoreM = "";
errorOutOfRangeM = "";
errorCheckSyntaxM = "";
debug1("%s result=%s [device %d]", __PRETTY_FUNCTION__, result ? "ok" : "failed", tunerM.GetId());
return result;
}

71
rtsp.h Normal file
View File

@ -0,0 +1,71 @@
/*
* 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 "common.h"
#include "tunerif.h"
class cSatipRtsp {
private:
static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static size_t InterleaveCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP);
static int DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP);
enum {
eConnectTimeoutMs = 1500, // in milliseconds
};
cSatipTunerIf &tunerM;
cSatipMemoryBuffer headerBufferM;
cSatipMemoryBuffer dataBufferM;
CURL *handleM;
struct curl_slist *headerListM;
cString errorNoMoreM;
cString errorOutOfRangeM;
cString errorCheckSyntaxM;
int modeM;
unsigned int interleavedRtpIdM;
unsigned int interleavedRtcpIdM;
void Create(void);
void Destroy(void);
void ParseHeader(void);
void ParseData(void);
bool ValidateLatestResponse(long *rcP);
// to prevent copy constructor and assignment
cSatipRtsp(const cSatipRtsp&);
cSatipRtsp& operator=(const cSatipRtsp&);
public:
explicit cSatipRtsp(cSatipTunerIf &tunerP);
virtual ~cSatipRtsp();
cString GetActiveMode(void);
cString RtspUnescapeString(const char *strP);
void Reset(void);
bool SetInterface(const char *bindAddrP);
bool Receive(const char *uriP);
bool Options(const char *uriP);
bool Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTcpP);
bool SetSession(const char *sessionP);
bool Describe(const char *uriP);
bool Play(const char *uriP);
bool Teardown(const char *uriP);
};
#endif // __SATIP_RTSP_H

362
satip.c
View File

@ -5,33 +5,40 @@
* *
*/ */
#include <ctype.h>
#include <getopt.h> #include <getopt.h>
#include <vdr/plugin.h> #include <vdr/plugin.h>
#include "common.h" #include "common.h"
#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
#warning "CURL version >= 7.36.0 is recommended" #warning "CURL version >= 7.36.0 is recommended"
#endif #endif
#if defined(APIVERSNUM) && APIVERSNUM < 20000 #if defined(APIVERSNUM) && APIVERSNUM < 20400
#error "VDR-2.0.0 API version or greater is required!" #error "VDR-2.4.0 API version or greater is required!"
#endif #endif
#ifndef GITVERSION #ifndef GITVERSION
#define GITVERSION "" #define GITVERSION ""
#endif #endif
const char VERSION[] = "0.3.3" GITVERSION; const char VERSION[] = "2.4.1" 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);
void ParsePortRange(const char *paramP);
int ParseCicams(const char *valueP, int *cicamsP);
int ParseSources(const char *valueP, int *sourcesP);
int ParseFilters(const char *valueP, int *filtersP); int ParseFilters(const char *valueP, int *filtersP);
public: public:
cPluginSatip(void); cPluginSatip(void);
@ -57,10 +64,10 @@ public:
}; };
cPluginSatip::cPluginSatip(void) cPluginSatip::cPluginSatip(void)
: deviceCountM(1), : deviceCountM(2),
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 +75,120 @@ 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=[<srcaddress>@]<ipaddress>[:<port>]|<model>[:<filter>]|<description>[:<quirk>];...\n"
" define hard-coded SAT>IP server(s)\n\n"
" srcaddress (Optional) Source address can be used to define used\n"
" networking interface on a host, e.g. 127.0.0.1.\n"
" ipaddress IP address of SAT>IP server, e.g. 127.0.0.1.\n"
" port (Optional) IP port number of SAT>IP server, e.g 443.\n"
" model Model defines DVB modulation system (DVBS2,\n"
" DVBT2, DVBT, DVBC) and number of available\n"
" frontends separated by a hyphen, e.g. DVBT2-4.\n"
" filter (Optional) Filter can be used to limit satellite frontends\n"
" to certain satellite position, e.g. S19.2E.\n"
" description Friendly name of SAT>IP server. This is used\n"
" for autodetection of quirks.\n"
" quirk (Optional) Quirks are non-standard compliant features and\n"
" bug fixes of SAT>IP server defined by a\n"
" hexadecimal number. Multiple quirks can be\n"
" defined by combining values by addition:\n\n"
" 0x01: Fix session id bug\n"
" 0x02: Fix play parameter (addpids/delpids) bug\n"
" 0x04: Fix frontend locking bug\n"
" 0x08: Support for RTP over TCP\n"
" 0x10: Support the X_PMT protocol extension\n"
" 0x20: Support the CI TNR protocol extension\n"
" 0x40: Fix auto-detection of pilot tones bug\n"
" 0x80: Fix re-tuning bug by teardowning a session\n"
" -D, --detach set the detached mode on\n"
" -S, --single set the single model server mode on\n"
" -n, --noquirks disable autodetection of the server quirks\n"
" -p, --portrange=<start>-<end> set a range of ports used for the RT[C]P server\n"
" a minimum of 2 ports per device is required.\n"
" -r, --rcvbuf override the size of the RTP receive buffer in bytes\n";
} }
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' },
{ "portrange",required_argument, NULL, 'p' },
{ "rcvbuf", required_argument, NULL, 'r' },
{ "detach", no_argument, NULL, 'D' },
{ "single", no_argument, NULL, 'S' },
{ "noquirks", no_argument, NULL, 'n' },
{ NULL, no_argument, NULL, 0 }
}; };
cString server;
cString portrange;
int c; int c;
while ((c = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) { while ((c = getopt_long(argc, argv, "d:t:s:p:r:DSn", 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 'D':
SatipConfig.SetDetachedMode(true);
break;
case 'S':
SatipConfig.SetUseSingleModelServers(true);
break;
case 'n':
SatipConfig.SetDisableServerQuirks(true);
break;
case 'p':
portrange = optarg;
break;
case 'r':
SatipConfig.SetRtpRcvBufSize(strtol(optarg, NULL, 0));
break; break;
default: default:
return false; return false;
} }
} }
if (!isempty(*portrange))
ParsePortRange(portrange);
// 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 +203,202 @@ 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 sourceAddr, serverAddr, serverModel, serverFilters, serverDescription;
int serverQuirk = cSatipServer::eSatipQuirkNone;
int serverPort = SATIP_DEFAULT_RTSP_PORT;
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:
{
char *r3 = strchr(r2, '@');
if (r3) {
*r3 = 0;
sourceAddr = r2;
r2 = r3 + 1;
}
serverAddr = r2;
r3 = strchr(r2, ':');
if (r3) {
serverPort = strtol(r3 + 1, NULL, 0);
serverAddr = serverAddr.Truncate(r3 - r2);
}
}
break;
case 1:
{
serverModel = r2;
char *r3 = strchr(r2, ':');
if (r3) {
serverFilters = r3 + 1;
serverModel = serverModel.Truncate(r3 - r2);
}
}
break;
case 2:
{
serverDescription = r2;
char *r3 = strchr(r2, ':');
if (r3) {
serverQuirk = strtol(r3 + 1, NULL, 0);
serverDescription = serverDescription.Truncate(r3 - r2);
}
}
break;
default:
break;
}
r2 = strtok_r(NULL, "|", &s2);
}
if (*serverAddr && *serverModel && *serverDescription) {
debug1("%s srcaddr=%s ipaddr=%s port=%d model=%s (%s) desc=%s (%d)", __PRETTY_FUNCTION__, *sourceAddr, *serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk);
if (!serversM)
serversM = new cSatipDiscoverServers();
serversM->Add(new cSatipDiscoverServer(*sourceAddr, *serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk));
}
++n;
r = strtok_r(NULL, ";", &s);
}
FREE_POINTER(p);
}
void cPluginSatip::ParsePortRange(const char *paramP)
{
char *s, *p = skipspace(paramP);
char *r = strtok_r(p, "-", &s);
unsigned int rangeStart = 0;
unsigned int rangeStop = 0;
if (r) {
rangeStart = strtol(r, NULL, 0);
r = strtok_r(NULL, "-", &s);
}
if (r)
rangeStop = strtol(r, NULL, 0);
else {
error("Port range argument not valid '%s'", paramP);
rangeStart = 0;
rangeStop = 0;
}
if (rangeStart % 2) {
error("The given range start port must be even!");
rangeStart = 0;
rangeStop = 0;
}
else if (rangeStop - rangeStart + 1 < deviceCountM * 2) {
error("The given port range is to small: %d < %d!", rangeStop - rangeStart + 1, deviceCountM * 2);
rangeStart = 0;
rangeStop = 0;
}
SatipConfig.SetPortRangeStart(rangeStart);
SatipConfig.SetPortRangeStop(rangeStop);
}
int cPluginSatip::ParseCicams(const char *valueP, int *cicamsP)
{
debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP);
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,20 +409,42 @@ 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, "EnableFrontendReuse"))
SatipConfig.SetFrontendReuse(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)
SatipConfig.SetDisabledFilters(i, DisabledFilters[i]); SatipConfig.SetDisabledFilters(i, DisabledFilters[i]);
} }
else if (!strcasecmp(nameP, "TransportMode"))
SatipConfig.SetTransportMode(atoi(valueP));
else else
return false; return false;
return true; return true;
@ -217,13 +452,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 +468,20 @@ 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 [ off | low | normal | high ]\n"
" Toggles operating mode of SAT>IP devices.\n", " Gets and(or sets operating mode of SAT>IP devices.\n",
"ATTA\n"
" Attach active SAT>IP servers.\n",
"DETA\n"
" Detachs active SAT>IP servers.\n",
"TRAC [ <mode> ]\n"
" Gets and/or sets used tracing mode.\n",
NULL NULL
}; };
return HelpPages; return HelpPages;
@ -244,7 +489,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 +516,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,16 +531,34 @@ 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;
SatipConfig.ToggleOperatingMode(); unsigned int oper = SatipConfig.GetOperatingMode();
switch (SatipConfig.GetOperatingMode()) { if (optionP && *optionP) {
if (strcasecmp(optionP, "off") == 0)
oper = cSatipConfig::eOperatingModeOff;
else if (strcasecmp(optionP, "low") == 0)
oper = cSatipConfig::eOperatingModeLow;
else if (strcasecmp(optionP, "normal") == 0)
oper = cSatipConfig::eOperatingModeNormal;
else if (strcasecmp(optionP, "high") == 0)
oper = cSatipConfig::eOperatingModeHigh;
SatipConfig.SetOperatingMode(oper);
}
switch (oper) {
case cSatipConfig::eOperatingModeOff: case cSatipConfig::eOperatingModeOff:
mode = "off"; mode = "off";
break; break;
@ -312,7 +575,22 @@ 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, "ATTA") == 0) {
SatipConfig.SetDetachedMode(false);
info("SATIP servers attached");
return cString("SATIP servers attached");
}
else if (strcasecmp(commandP, "DETA") == 0) {
SatipConfig.SetDetachedMode(true);
info("SATIP servers detached");
return cString("SATIP servers detached");
}
else if (strcasecmp(commandP, "TRAC") == 0) {
if (optionP && *optionP)
SatipConfig.SetTraceMode(strtol(optionP, NULL, 0));
return cString::sprintf("SATIP tracing mode: 0x%04X\n", SatipConfig.GetTraceMode());
} }
return NULL; return NULL;

View File

@ -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)
@ -17,35 +18,14 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
secLenM(0), secLenM(0),
tsFeedpM(0), tsFeedpM(0),
pidM(pidP), pidM(pidP),
tidM(tidP),
maskM(maskP),
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;
memset(secBufBaseM, 0, sizeof(secBufBaseM)); memset(secBufBaseM, 0, sizeof(secBufBaseM));
memset(filterValueM, 0, sizeof(filterValueM));
memset(filterMaskM, 0, sizeof(filterMaskM));
memset(filterModeM, 0, sizeof(filterModeM));
memset(maskAndModeM, 0, sizeof(maskAndModeM));
memset(maskAndNotModeM, 0, sizeof(maskAndNotModeM));
filterValueM[0] = tidP;
filterMaskM[0] = maskP;
// Invert the filter
for (i = 0; i < eDmxMaxFilterSize; ++i)
filterValueM[i] ^= 0xFF;
uint8_t mask, mode, doneq = 0;
for (i = 0; i < eDmxMaxFilterSize; ++i) {
mode = filterModeM[i];
mask = filterMaskM[i];
maskAndModeM[i] = (uint8_t)(mask & mode);
maskAndNotModeM[i] = (uint8_t)(mask & ~mode);
doneq |= maskAndNotModeM[i];
}
doneqM = doneq ? 1 : 0;
// Create sockets // Create sockets
socketM[0] = socketM[1] = -1; socketM[0] = socketM[1] = -1;
@ -61,7 +41,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)
@ -88,21 +68,13 @@ void cSatipSectionFilter::New(void)
int cSatipSectionFilter::Filter(void) int cSatipSectionFilter::Filter(void)
{ {
if (secBufM) { if (secBufM) {
int i; if ((tidM & maskM) == (secBufM[0] & maskM)) {
uint8_t neq = 0; if (ringBufferM && (secLenM > 0)) {
cFrame* section = new cFrame(secBufM, secLenM);
for (i = 0; i < eDmxMaxFilterSize; ++i) { if (!ringBufferM->Put(section))
uint8_t calcxor = (uint8_t)(filterValueM[i] ^ secBufM[i]); DELETE_POINTER(section);
if (maskAndModeM[i] & calcxor) }
return 0; }
neq |= (maskAndNotModeM[i] & calcxor);
}
if (doneqM && !neq)
return 0;
if (ringBufferM && (secLenM > 0))
ringBufferM->Put(new cFrame(secBufM, secLenM));
} }
return 0; return 0;
} }
@ -117,7 +89,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;
@ -125,7 +97,7 @@ int cSatipSectionFilter::CopyDump(const uint8_t *bufP, uint8_t lenP)
if (tsFeedpM + lenP > eDmxMaxSectionFeedSize) if (tsFeedpM + lenP > eDmxMaxSectionFeedSize)
lenP = (uint8_t)(eDmxMaxSectionFeedSize - tsFeedpM); lenP = (uint8_t)(eDmxMaxSectionFeedSize - tsFeedpM);
if (lenP <= 0) if (lenP == 0)
return 0; return 0;
memcpy(secBufBaseM + tsFeedpM, bufP, lenP); memcpy(secBufBaseM + tsFeedpM, bufP, lenP);
@ -139,8 +111,8 @@ 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 > eDmxMaxSectionSize) || ((seclen + secBufpM) > limit))
return 0; return 0;
secLenM = seclen; secLenM = seclen;
if (pusiSeenM) if (pusiSeenM)
@ -208,35 +180,36 @@ void cSatipSectionFilter::Process(const uint8_t* dataP)
} }
} }
bool cSatipSectionFilter::Send(void) void cSatipSectionFilter::Send(void)
{ {
bool result = false;
cFrame *section = ringBufferM->Get(); cFrame *section = ringBufferM->Get();
if (section) { if (section) {
uchar *data = section->Data(); uchar *data = section->Data();
int count = section->Count(); int count = section->Count();
if (data && (count > 0) && (socketM[1] >= 0) && (socketM[0] >= 0)) { if (data && (count > 0) && (socketM[1] >= 0) && (socketM[0] >= 0)) {
ssize_t len = send(socketM[1], data, count, MSG_EOR); if (send(socketM[1], data, count, MSG_EOR) > 0) {
ERROR_IF(len < 0 && errno != EAGAIN, "send()");
if (len > 0) {
ringBufferM->Drop(section);
result = !!ringBufferM->Available();
// Update statistics // Update statistics
AddSectionStatistic(len, 1); AddSectionStatistic(count, 1);
} }
else if (errno != EAGAIN)
error("failed to send section data (%i bytes) [device=%d]", count, deviceIndexM);
} }
ringBufferM->Drop(section);
} }
return result;
} }
int cSatipSectionFilter::Available(void) const
{
return ringBufferM->Available();
}
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 +220,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);
@ -266,61 +239,80 @@ cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
Delete(i); Delete(i);
} }
void cSatipSectionFilterHandler::SendAll(void)
{
cMutexLock MutexLock(&mutexM);
bool pendingData;
do {
pendingData = false;
// zero polling structures
memset(pollFdsM, 0, sizeof(pollFdsM));
// assemble all handlers to poll (use -1 to ignore handlers)
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i] && filtersM[i]->Available() != 0) {
pollFdsM[i].fd = filtersM[i]->GetFd();
pollFdsM[i].events = POLLOUT;
pendingData = true;
}
else
pollFdsM[i].fd = -1;
}
// exit if there isn't any pending data or we time out
if (!pendingData || poll(pollFdsM, eMaxSecFilterCount, eSecFilterSendTimeoutMs) <= 0)
return;
// send data (if available)
for (unsigned int i = 0; i < eMaxSecFilterCount && pendingData; ++i) {
if (pollFdsM[i].revents & POLLOUT)
filtersM[i]->Send();
}
} while (pendingData);
}
void cSatipSectionFilterHandler::Action(void) void cSatipSectionFilterHandler::Action(void)
{ {
debug("cSatipSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM); debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIndexM);
bool processed = false;
// Do the thread loop // Do the thread loop
while (Running()) { while (Running()) {
// Send demuxed section packets through all filters uchar *p = NULL;
bool retry = false; int len = 0;
mutexM.Lock(); // Process all pending TS packets
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { while ((p = ringBufferM->Get(len)) != NULL) {
if (filtersM[i] && filtersM[i]->Send()) if (p && (len >= TS_SIZE)) {
retry = true; if (*p != TS_SYNC_BYTE) {
} for (int i = 1; i < len; ++i) {
mutexM.Unlock(); if (p[i] == TS_SYNC_BYTE) {
if (retry) len = i;
continue; break;
// Read one TS packet }
if (ringBufferM) {
int len = 0;
if (processed) {
ringBufferM->Del(TS_SIZE);
processed = false;
}
uchar *p = ringBufferM->Get(len);
if (p && (len >= TS_SIZE)) {
if (*p != TS_SYNC_BYTE) {
for (int i = 1; i < len; ++i) {
if (p[i] == TS_SYNC_BYTE) {
len = i;
break;
} }
} ringBufferM->Del(len);
ringBufferM->Del(len); debug1("%s Skipped %d bytes to sync on TS packet [device %d]", __PRETTY_FUNCTION__, len, deviceIndexM);
debug("cSatipSectionFilterHandler::%s(%d): Skipped %d bytes to sync on TS packet", __FUNCTION__, deviceIndexM, len); continue;
continue; }
} // Process TS packet through all filters
// Process TS packet through all filters mutexM.Lock();
mutexM.Lock(); for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { if (filtersM[i])
if (filtersM[i]) filtersM[i]->Process(p);
filtersM[i]->Process(p); }
} mutexM.Unlock();
mutexM.Unlock(); ringBufferM->Del(TS_SIZE);
processed = true; }
continue; }
}
} // Send demuxed section packets through all filters
cCondWait::SleepMs(10); // to avoid busy loop and reduce cpu load SendAll();
} }
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 = "";
@ -337,11 +329,24 @@ cString cSatipSectionFilterHandler::GetInformation(void)
return s; return s;
} }
bool cSatipSectionFilterHandler::Exists(u_short pidP)
{
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM);
cMutexLock MutexLock(&mutexM);
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i] && (pidP == filtersM[i]->GetPid())) {
debug12("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM);
return true;
}
}
return false;
}
bool cSatipSectionFilterHandler::Delete(unsigned int indexP) 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 +357,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 +365,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 +374,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 +382,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 +392,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 +405,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 +418,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);

View File

@ -8,6 +8,7 @@
#ifndef __SATIP_SECTIONFILTER_H #ifndef __SATIP_SECTIONFILTER_H
#define __SATIP_SECTIONFILTER_H #define __SATIP_SECTIONFILTER_H
#include <poll.h>
#include <vdr/device.h> #include <vdr/device.h>
#include "common.h" #include "common.h"
@ -32,18 +33,13 @@ private:
uint16_t secLenM; uint16_t secLenM;
uint16_t tsFeedpM; uint16_t tsFeedpM;
uint16_t pidM; uint16_t pidM;
uint8_t tidM;
uint8_t maskM;
cRingBufferFrame *ringBufferM; cRingBufferFrame *ringBufferM;
int deviceIndexM; int deviceIndexM;
int socketM[2]; int socketM[2];
uint8_t filterValueM[eDmxMaxFilterSize];
uint8_t filterMaskM[eDmxMaxFilterSize];
uint8_t filterModeM[eDmxMaxFilterSize];
uint8_t maskAndModeM[eDmxMaxFilterSize];
uint8_t maskAndNotModeM[eDmxMaxFilterSize];
inline uint16_t GetLength(const uint8_t *dataP); inline uint16_t GetLength(const uint8_t *dataP);
void New(void); void New(void);
int Filter(void); int Filter(void);
@ -55,23 +51,27 @@ public:
cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP); cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP);
virtual ~cSatipSectionFilter(); virtual ~cSatipSectionFilter();
void Process(const uint8_t* dataP); void Process(const uint8_t* dataP);
bool Send(void); void Send(void);
int GetFd(void) { return socketM[0]; } int GetFd(void) { return socketM[0]; }
uint16_t GetPid(void) const { return pidM; } uint16_t GetPid(void) const { return pidM; }
int Available(void) const;
}; };
class cSatipSectionFilterHandler : public cThread { class cSatipSectionFilterHandler : public cThread {
private: private:
enum { enum {
eMaxSecFilterCount = 32 eMaxSecFilterCount = 32,
eSecFilterSendTimeoutMs = 10
}; };
cRingBufferLinear *ringBufferM; cRingBufferLinear *ringBufferM;
cMutex mutexM; cMutex mutexM;
int deviceIndexM; int deviceIndexM;
cSatipSectionFilter *filtersM[eMaxSecFilterCount]; cSatipSectionFilter *filtersM[eMaxSecFilterCount];
struct pollfd pollFdsM[eMaxSecFilterCount];
bool Delete(unsigned int indexP); bool Delete(unsigned int indexP);
bool IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const; bool IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const;
void SendAll(void);
protected: protected:
virtual void Action(void); virtual void Action(void);
@ -80,6 +80,7 @@ public:
cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP); cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP);
virtual ~cSatipSectionFilterHandler(); virtual ~cSatipSectionFilterHandler();
cString GetInformation(void); cString GetInformation(void);
bool Exists(u_short pidP);
int Open(u_short pidP, u_char tidP, u_char maskP); int Open(u_short pidP, u_char tidP, u_char maskP);
void Close(int handleP); void Close(int handleP);
int GetPid(int handleP); int GetPid(int handleP);

534
server.c
View File

@ -7,66 +7,234 @@
#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"
// --- cSatipFrontend ---------------------------------------------------------
cSatipFrontend::cSatipFrontend(const int indexP, const char *descriptionP)
: indexM(indexP),
transponderM(0),
deviceIdM(-1),
descriptionM(descriptionP)
{
}
cSatipFrontend::~cSatipFrontend()
{
}
// --- cSatipFrontends --------------------------------------------------------
bool cSatipFrontends::Matches(int deviceIdP, int transponderP)
{
for (cSatipFrontend *f = First(); f; f = Next(f)) {
if (f->Attached() && (f->DeviceId() == deviceIdP) && (f->Transponder() == transponderP))
return true;
}
return false;
}
bool cSatipFrontends::Assign(int deviceIdP, int transponderP)
{
cSatipFrontend *tmp = NULL;
// Prefer any used one
for (cSatipFrontend *f = First(); f; f = Next(f)) {
if (f->DeviceId() == deviceIdP) { // give deviceID priority, but take detached frontend if deviceID ist not yet attached
tmp = f;
break;
}
if (!f->Attached()) {
tmp = f;
}
}
if (tmp) {
tmp->SetTransponder(transponderP);
debug9("%s assigned TP %d to %s/#%d", __PRETTY_FUNCTION__, transponderP, *tmp->Description(), tmp->Index());
return true;
}
error("no assignable frontend found [device %u]", deviceIdP);
return false;
}
bool cSatipFrontends::Attach(int deviceIdP, int transponderP)
{
cSatipFrontend *tmp = NULL;
for (cSatipFrontend *f = First(); f; f = Next(f)) {
if (f->Transponder() == transponderP) {
tmp = f;
if (f->DeviceId() == deviceIdP) {
break;
}
}
}
if (tmp) {
tmp->Attach(deviceIdP);
debug9("%s attached deviceId %d (TP %d) to %s/#%d", __PRETTY_FUNCTION__, deviceIdP, transponderP, *tmp->Description(), tmp->Index());
return true;
}
error("%s no Frontend found for attaching deviceID %d (TP %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP);
return false;
}
bool cSatipFrontends::Detach(int deviceIdP, int transponderP)
{
for (cSatipFrontend *f = First(); f; f = Next(f)) {
if (f->Transponder() == transponderP) {
f->Detach(deviceIdP);
debug9("%s detached deviceID %d (TP %d) from %s/#%d", __PRETTY_FUNCTION__, deviceIdP, transponderP, *f->Description(), f->Index());
return true;
}
}
return false;
}
// --- cSatipServer ----------------------------------------------------------- // --- cSatipServer -----------------------------------------------------------
cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const char *modelP) cSatipServer::cSatipServer(const char *srcAddressP, const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP)
: addressM(addressP), : srcAddressM((srcAddressP && *srcAddressP) ? srcAddressP : ""),
descriptionM(descriptionP), addressM((addressP && *addressP) ? addressP : "0.0.0.0"),
modelM(modelP), modelM((modelP && *modelP) ? modelP : "DVBS-1"),
modelTypeM(eSatipModelTypeNone), filtersM((filtersP && *filtersP) ? filtersP : ""),
quirkM(eSatipQuirkNone), descriptionM(!isempty(descriptionP) ? descriptionP : "MyBrokenHardware"),
useCountM(0), quirksM(""),
portM(portP),
quirkM(quirkP),
hasCiM(false),
activeM(true),
createdM(time(NULL)), createdM(time(NULL)),
lastSeenM(0) lastSeenM(0)
{ {
memset(modelCountM, 0, sizeof(modelCountM)); memset(sourceFiltersM, 0, sizeof(sourceFiltersM));
if (isempty(*modelM)) if (!isempty(*filtersM)) {
modelM = "DVBS-1"; char *s, *p = strdup(*filtersM);
// These devices contain a session id bug: char *r = strtok_r(p, ",", &s);
// Inverto Airscreen Server IDL 400 ? unsigned int i = 0;
// Telestar Digibit R1 ? while (r) {
// Elgato EyeTV Netstream 4Sat ? int t = cSource::FromString(skipspace(r));
if (!isempty(*descriptionM) && if (t && i < ELEMENTS(sourceFiltersM))
(strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400 sourceFiltersM[i++] = t;
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400 r = strtok_r(NULL, ",", &s);
)) }
quirkM |= eSatipQuirkSessionId; if (i) {
filtersM = "";
for (unsigned int j = 0; j < i; ++j)
filtersM = cString::sprintf("%s%s%s", *filtersM, isempty(*filtersM) ? "" : ",", *cSource::ToString(sourceFiltersM[j]));
debug3("%s filters=%s", __PRETTY_FUNCTION__, *filtersM);
}
FREE_POINTER(p);
}
if (!SatipConfig.GetDisableServerQuirks()) {
// These devices contain a session id bug:
// Inverto Airscreen Server IDL 400 ?
// Elgato EyeTV Netstream 4Sat ?
if (strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
strstr(*descriptionM, "DIGIBIT") || // Telestar Digibit R1
strstr(*descriptionM, "Multibox-") || // Inverto IDL-400s: Multibox-<MMAACC>:SAT>IP
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
)
quirkM |= eSatipQuirkSessionId;
// These devices contain support for RTP over TCP:
if (strstr(*descriptionM, "minisatip") || // minisatip server
strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
)
quirkM |= eSatipQuirkRtpOverTcp;
// These devices contain a play (add/delpids) parameter bug:
if (strstr(*descriptionM, "FRITZ!WLAN Repeater DVB-C") || // FRITZ!WLAN Repeater DVB-C
strstr(*descriptionM, "fritzdvbc") // FRITZ!WLAN Repeater DVB-C (old firmware)
)
quirkM |= eSatipQuirkPlayPids;
// These devices contain a frontend locking bug:
if (strstr(*descriptionM, "FRITZ!WLAN Repeater DVB-C") || // FRITZ!WLAN Repeater DVB-C
strstr(*descriptionM, "fritzdvbc") || // FRITZ!WLAN Repeater DVB-C (old firmware)
strstr(*descriptionM, "Schwaiger Sat>IP Server") // Schwaiger MS41IP
)
quirkM |= eSatipQuirkForceLock;
// These devices support the X_PMT protocol extension:
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
strstr(*descriptionM, "minisatip") // minisatip server
)
quirkM |= eSatipQuirkCiXpmt;
// These devices support the TNR protocol extension:
if (strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
)
quirkM |= eSatipQuirkCiTnr;
// These devices don't support auto-detection of pilot tones:
if (strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
strstr(*descriptionM, "DIGIBIT") || // Telestar Digibit R1
strstr(*descriptionM, "Multibox-") || // Inverto IDL-400s: Multibox-<MMAACC>:SAT>IP
strstr(*descriptionM, "Triax SatIP Converter") || // Triax TSS 400
strstr(*descriptionM, "KATHREIN SatIP Server") // Kathrein ExIP 414/E
)
quirkM |= eSatipQuirkForcePilot;
// These devices require TEARDOWN before new PLAY command:
if (strstr(*descriptionM, "FRITZ!WLAN Repeater DVB-C") || // FRITZ!WLAN Repeater DVB-C
strstr(*descriptionM, "fritzdvbc") // FRITZ!WLAN Repeater DVB-C (old firmware)
)
quirkM |= eSatipQuirkTearAndPlay;
}
if ((quirkM & eSatipQuirkMask) & eSatipQuirkSessionId)
quirksM = cString::sprintf("%s%sSessionId", *quirksM, isempty(*quirksM) ? "" : ",");
if ((quirkM & eSatipQuirkMask) & eSatipQuirkPlayPids)
quirksM = cString::sprintf("%s%sPlayPids", *quirksM, isempty(*quirksM) ? "" : ",");
if ((quirkM & eSatipQuirkMask) & eSatipQuirkForceLock)
quirksM = cString::sprintf("%s%sForceLock", *quirksM, isempty(*quirksM) ? "" : ",");
if ((quirkM & eSatipQuirkMask) & eSatipQuirkRtpOverTcp)
quirksM = cString::sprintf("%s%sRtpOverTcp", *quirksM, isempty(*quirksM) ? "" : ",");
if ((quirkM & eSatipQuirkMask) & eSatipQuirkCiXpmt)
quirksM = cString::sprintf("%s%sCiXpmt", *quirksM, isempty(*quirksM) ? "" : ",");
if ((quirkM & eSatipQuirkMask) & eSatipQuirkCiTnr)
quirksM = cString::sprintf("%s%sCiTnr", *quirksM, isempty(*quirksM) ? "" : ",");
if ((quirkM & eSatipQuirkMask) & eSatipQuirkForcePilot)
quirksM = cString::sprintf("%s%sForcePilot", *quirksM, isempty(*quirksM) ? "" : ",");
debug3("%s description=%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM, *quirksM);
// These devices support external CI
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
strstr(*descriptionM, "minisatip") || // minisatip server
strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
) {
hasCiM = true;
}
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")) { char *c;
modelTypeM |= cSatipServer::eSatipModelTypeDVBS2; if (c = strstr(r, "DVBS2-")) {
if (char *c = strstr(r, "-")) int count = atoi(c + 6);
modelCountM[eSatipModuleDVBS2] = atoi(++c); for (int i = 1; i <= count; ++i)
else frontendsM[eSatipFrontendDVBS2].Add(new cSatipFrontend(i, "DVB-S2"));
modelCountM[eSatipModuleDVBS2] = 1;
} }
if (strstr(r, "DVBT2")) { else if (c = strstr(r, "DVBT-")) {
modelTypeM |= cSatipServer::eSatipModelTypeDVBT | cSatipServer::eSatipModelTypeDVBT2; int count = atoi(c + 5);
if (char *c = strstr(r, "-")) for (int i = 1; i <= count; ++i)
modelCountM[eSatipModuleDVBT2] = atoi(++c); frontendsM[eSatipFrontendDVBT].Add(new cSatipFrontend(i, "DVB-T"));
else
modelCountM[eSatipModuleDVBT2] = 1;
// Add model quirks here
if (!isempty(*descriptionM) && strstr(*descriptionM, "OctopusNet"))
modelTypeM |= cSatipServer::eSatipModelTypeDVBC;
} }
if (strstr(r, "DVBT")) { else if (c = strstr(r, "DVBT2-")) {
modelTypeM |= cSatipServer::eSatipModelTypeDVBT; int count = atoi(c + 6);
if (char *c = strstr(r, "-")) for (int i = 1; i <= count; ++i)
modelCountM[eSatipModuleDVBT] = atoi(++c); frontendsM[eSatipFrontendDVBT2].Add(new cSatipFrontend(i, "DVB-T2"));
else }
modelCountM[eSatipModuleDVBT] = 1; else if (c = strstr(r, "DVBC-")) {
// Add model quirks here int count = atoi(c + 5);
if (!isempty(*descriptionM) && strstr(*descriptionM, "OctopusNet")) for (int i = 1; i <= count; ++i)
modelTypeM |= cSatipServer::eSatipModelTypeDVBC; frontendsM[eSatipFrontendDVBC].Add(new cSatipFrontend(i, "DVB-C"));
}
else if (c = strstr(r, "DVBC2-")) {
int count = atoi(c + 6);
for (int i = 1; i <= count; ++i)
frontendsM[eSatipFrontendDVBC2].Add(new cSatipFrontend(i, "DVB-C2"));
}
else if (c = strstr(r, "ATSC-")) {
int count = atoi(c + 5);
for (int i = 1; i <= count; ++i)
frontendsM[eSatipFrontendATSC].Add(new cSatipFrontend(i, "ATSC"));
} }
r = strtok_r(NULL, ",", &s); r = strtok_r(NULL, ",", &s);
} }
free(p); FREE_POINTER(p);
} }
cSatipServer::~cSatipServer() cSatipServer::~cSatipServer()
@ -76,15 +244,135 @@ 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) bool cSatipServer::IsValidSource(int sourceP)
{ {
if (onOffP) if (sourceFiltersM[0]) {
++useCountM; for (unsigned int i = 0; i < ELEMENTS(sourceFiltersM); ++i) {
else if (sourceP == sourceFiltersM[i]) {
--useCountM; return true;
}
}
return false;
}
return true;
}
bool cSatipServer::Assign(int deviceIdP, int sourceP, int systemP, int transponderP)
{
bool result = false;
if (IsValidSource(sourceP)) {
if (cSource::IsType(sourceP, 'S'))
result = frontendsM[eSatipFrontendDVBS2].Assign(deviceIdP, transponderP);
else if (cSource::IsType(sourceP, 'T')) {
if (systemP)
result = frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
else
result = frontendsM[eSatipFrontendDVBT].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Assign(deviceIdP, transponderP);
}
else if (cSource::IsType(sourceP, 'C')) {
if (systemP)
result = frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
else
result = frontendsM[eSatipFrontendDVBC].Assign(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Assign(deviceIdP, transponderP);
}
else if (cSource::IsType(sourceP, 'A'))
result = frontendsM[eSatipFrontendATSC].Assign(deviceIdP, transponderP);
}
return result;
}
bool cSatipServer::Matches(int sourceP)
{
if (IsValidSource(sourceP)) {
if (cSource::IsType(sourceP, 'S'))
return GetModulesDVBS2();
else if (cSource::IsType(sourceP, 'T'))
return GetModulesDVBT() || GetModulesDVBT2();
else if (cSource::IsType(sourceP, 'C'))
return GetModulesDVBC() || GetModulesDVBC2();
else if (cSource::IsType(sourceP, 'A'))
return GetModulesATSC();
}
return false;
}
bool cSatipServer::Matches(int deviceIdP, int sourceP, int systemP, int transponderP)
{
bool result = false;
if (IsValidSource(sourceP)) {
if (cSource::IsType(sourceP, 'S'))
result = frontendsM[eSatipFrontendDVBS2].Matches(deviceIdP, transponderP);
else if (cSource::IsType(sourceP, 'T')) {
if (systemP)
result = frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
else
result = frontendsM[eSatipFrontendDVBT].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBT2].Matches(deviceIdP, transponderP);
}
else if (cSource::IsType(sourceP, 'C')) {
if (systemP)
result = frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
else
result = frontendsM[eSatipFrontendDVBC].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP);
}
else if (cSource::IsType(sourceP, 'A'))
result = frontendsM[eSatipFrontendATSC].Matches(deviceIdP, transponderP);
}
return result;
}
void cSatipServer::Attach(int deviceIdP, int transponderP)
{
for (int i = 0; i < eSatipFrontendCount; ++i) {
if (frontendsM[i].Attach(deviceIdP, transponderP))
return;
}
}
void cSatipServer::Detach(int deviceIdP, int transponderP)
{
for (int i = 0; i < eSatipFrontendCount; ++i) {
if (frontendsM[i].Detach(deviceIdP, transponderP))
return;
}
}
int cSatipServer::GetModulesDVBS2(void)
{
return frontendsM[eSatipFrontendDVBS2].Count();
}
int cSatipServer::GetModulesDVBT(void)
{
return frontendsM[eSatipFrontendDVBT].Count();
}
int cSatipServer::GetModulesDVBT2(void)
{
return frontendsM[eSatipFrontendDVBT2].Count();
}
int cSatipServer::GetModulesDVBC(void)
{
return frontendsM[eSatipFrontendDVBC].Count();
}
int cSatipServer::GetModulesDVBC2(void)
{
return frontendsM[eSatipFrontendDVBC2].Count();
}
int cSatipServer::GetModulesATSC(void)
{
return frontendsM[eSatipFrontendATSC].Count();
} }
// --- cSatipServers ---------------------------------------------------------- // --- cSatipServers ----------------------------------------------------------
@ -92,35 +380,32 @@ void cSatipServer::Use(bool onOffP)
cSatipServer *cSatipServers::Find(cSatipServer *serverP) cSatipServer *cSatipServers::Find(cSatipServer *serverP)
{ {
for (cSatipServer *s = First(); s; s = Next(s)) { for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) if (s->Compare(*serverP) == 0)
return s; return s;
} }
return NULL; return NULL;
} }
cSatipServer *cSatipServers::Find(int sourceP, int systemP) cSatipServer *cSatipServers::Find(int sourceP)
{ {
cSatipServer *result = NULL;
int model = 0;
if (cSource::IsType(sourceP, 'S'))
model |= cSatipServer::eSatipModelTypeDVBS2;
else if (cSource::IsType(sourceP, 'T')) {
if (systemP < 0)
model |= cSatipServer::eSatipModelTypeDVBT2 | cSatipServer::eSatipModelTypeDVBT;
else
model |= systemP ? cSatipServer::eSatipModelTypeDVBT2 : cSatipServer::eSatipModelTypeDVBT;
}
else if (cSource::IsType(sourceP, 'C'))
model |= cSatipServer::eSatipModelTypeDVBC;
for (cSatipServer *s = First(); s; s = Next(s)) { for (cSatipServer *s = First(); s; s = Next(s)) {
if (s->Match(model)) { if (s->Matches(sourceP))
result = s; return s;
if (!s->Used()) {
break;
}
}
} }
return result; return NULL;
}
cSatipServer *cSatipServers::Assign(int deviceIdP, int sourceP, int transponderP, int systemP)
{
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s->IsActive() && s->Matches(deviceIdP, sourceP, systemP, transponderP))
return s;
}
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s->IsActive() && s->Assign(deviceIdP, sourceP, systemP, transponderP))
return s;
}
return NULL;
} }
cSatipServer *cSatipServers::Update(cSatipServer *serverP) cSatipServer *cSatipServers::Update(cSatipServer *serverP)
@ -134,26 +419,106 @@ cSatipServer *cSatipServers::Update(cSatipServer *serverP)
return NULL; return NULL;
} }
void cSatipServers::Use(cSatipServer *serverP, bool onOffP) void cSatipServers::Activate(cSatipServer *serverP, bool onOffP)
{ {
for (cSatipServer *s = First(); s; s = Next(s)) { for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) { if (s == serverP) {
s->Use(onOffP); s->Activate(onOffP);
break; break;
} }
} }
} }
void cSatipServers::Attach(cSatipServer *serverP, int deviceIdP, int transponderP)
{
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
s->Attach(deviceIdP, transponderP);
break;
}
}
}
void cSatipServers::Detach(cSatipServer *serverP, int deviceIdP, int transponderP)
{
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
s->Detach(deviceIdP, transponderP);
break;
}
}
}
bool cSatipServers::IsQuirk(cSatipServer *serverP, int quirkP)
{
bool result = false;
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
result = s->Quirk(quirkP);
break;
}
}
return result;
}
bool cSatipServers::HasCI(cSatipServer *serverP)
{
bool result = false;
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
result = s->HasCI();
break;
}
}
return result;
}
void cSatipServers::Cleanup(uint64_t intervalMsP) 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);
} }
} }
} }
cString cSatipServers::GetSrcAddress(cSatipServer *serverP)
{
cString address = "";
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
address = s->SrcAddress();
break;
}
}
return address;
}
cString cSatipServers::GetAddress(cSatipServer *serverP)
{
cString address = "";
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
address = s->Address();
break;
}
}
return address;
}
int cSatipServers::GetPort(cSatipServer *serverP)
{
int port = SATIP_DEFAULT_RTSP_PORT;
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
port = s->Port();
break;
}
}
return port;
}
cString cSatipServers::GetString(cSatipServer *serverP) cString cSatipServers::GetString(cSatipServer *serverP)
{ {
cString list = ""; cString list = "";
@ -170,7 +535,10 @@ cString cSatipServers::List(void)
{ {
cString list = ""; cString list = "";
for (cSatipServer *s = First(); s; s = Next(s)) for (cSatipServer *s = First(); s; s = Next(s))
list = cString::sprintf("%s%s|%s|%s\n", *list, s->Address(), s->Model(), s->Description()); if (isempty(s->SrcAddress()))
list = cString::sprintf("%s%c %s|%s|%s\n", *list, s->IsActive() ? '+' : '-', s->Address(), s->Model(), s->Description());
else
list = cString::sprintf("%s%c %s@%s|%s|%s\n", *list, s->IsActive() ? '+' : '-', s->SrcAddress(), s->Address(), s->Model(), s->Description());
return list; return list;
} }
@ -178,10 +546,18 @@ 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->GetModulesDVBS2() * 4;
// DVB-T*: qpsk, qam16, qam64, qam256 // DVB-T: qpsk, qam16, qam64
count += (s->Terrestrial2() ? s->Terrestrial2() : s->Terrestrial()) * 4; count += s->GetModulesDVBT() * 3;
// DVB-T2: qpsk, qam16, qam64, qam256
count += s->GetModulesDVBT2() * 4;
// DVB-C: qam64, qam128, qam256
count += s->GetModulesDVBC() * 3;
// DVB-C2: qam16, qam32, qam64, qam128, qam256
count += s->GetModulesDVBC2() * 5;
// ATSC: 8vbs, 16vbs, qam256
count += s->GetModulesATSC() * 3;
} }
return count; return count;
} }

140
server.h
View File

@ -8,58 +8,114 @@
#ifndef __SATIP_SERVER_H #ifndef __SATIP_SERVER_H
#define __SATIP_SERVER_H #define __SATIP_SERVER_H
class cSatipServer;
// --- cSatipFrontend ---------------------------------------------------------
class cSatipFrontend : public cListObject {
private:
int indexM;
int transponderM;
int deviceIdM;
cString descriptionM;
public:
cSatipFrontend(const int indexP, const char *descriptionP);
virtual ~cSatipFrontend();
void Attach(int deviceIdP) { deviceIdM = deviceIdP; }
void Detach(int deviceIdP) { if (deviceIdP == deviceIdM) deviceIdM = -1; }
cString Description(void) { return descriptionM; }
bool Attached(void) { return (deviceIdM >= 0); }
int Index(void) { return indexM; }
int Transponder(void) { return transponderM; }
int DeviceId(void) { return deviceIdM; }
void SetTransponder(int transponderP) { transponderM = transponderP; }
};
// --- cSatipFrontends --------------------------------------------------------
class cSatipFrontends : public cList<cSatipFrontend> {
public:
bool Matches(int deviceIdP, int transponderP);
bool Assign(int deviceIdP, int transponderP);
bool Attach(int deviceIdP, int transponderP);
bool Detach(int deviceIdP, int transponderP);
};
// --- cSatipServer ----------------------------------------------------------- // --- cSatipServer -----------------------------------------------------------
class cSatipServer : public cListObject { class cSatipServer : public cListObject {
private: private:
enum eSatipModule { enum eSatipFrontend {
eSatipModuleDVBS2 = 0, eSatipFrontendDVBS2 = 0,
eSatipModuleDVBT, eSatipFrontendDVBT,
eSatipModuleDVBT2, eSatipFrontendDVBT2,
eSatipModuleCount eSatipFrontendDVBC,
eSatipFrontendDVBC2,
eSatipFrontendATSC,
eSatipFrontendCount
}; };
enum {
eSatipMaxSourceFilters = 16
};
cString srcAddressM;
cString addressM; cString addressM;
cString descriptionM;
cString modelM; cString modelM;
int modelCountM[eSatipModuleCount]; cString filtersM;
int modelTypeM; cString descriptionM;
cString quirksM;
cSatipFrontends frontendsM[eSatipFrontendCount];
int sourceFiltersM[eSatipMaxSourceFilters];
int portM;
int quirkM; int quirkM;
int useCountM; bool hasCiM;
bool activeM;
time_t createdM; time_t createdM;
cTimeMs lastSeenM; cTimeMs lastSeenM;
bool IsValidSource(int sourceP);
public: public:
enum eSatipQuirk { enum eSatipQuirk {
eSatipQuirkNone = 0x00, eSatipQuirkNone = 0x00,
eSatipQuirkSessionId = 0x01, eSatipQuirkSessionId = 0x01,
eSatipQuirkMask = 0x0F eSatipQuirkPlayPids = 0x02,
eSatipQuirkForceLock = 0x04,
eSatipQuirkRtpOverTcp = 0x08,
eSatipQuirkCiXpmt = 0x10,
eSatipQuirkCiTnr = 0x20,
eSatipQuirkForcePilot = 0x40,
eSatipQuirkTearAndPlay = 0x80,
eSatipQuirkMask = 0xFF
}; };
enum eSatipModelType { cSatipServer(const char *srcAddressP, const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP);
eSatipModelTypeNone = 0x00,
eSatipModelTypeDVBS2 = 0x01,
eSatipModelTypeDVBT = 0x02,
eSatipModelTypeDVBT2 = 0x04,
eSatipModelTypeDVBC = 0x08,
eSatipModelTypeMask = 0x0F
};
cSatipServer(const char *addressP, const char *descriptionP, const char *modelP);
virtual ~cSatipServer(); virtual ~cSatipServer();
virtual int Compare(const cListObject &listObjectP) const; virtual int Compare(const cListObject &listObjectP) const;
void Use(bool onOffP); bool Assign(int deviceIdP, int sourceP, int systemP, int transponderP);
bool Used(void) { return !!useCountM; } bool Matches(int sourceP);
const char *Description() { return *descriptionM; } bool Matches(int deviceIdP, int sourceP, int systemP, int transponderP);
const char *Address() { return *addressM; } void Attach(int deviceIdP, int transponderP);
const char *Model(void) { return modelM; } void Detach(int deviceIdP, int transponderP);
bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); } int GetModulesDVBS2(void);
int ModelType(void) { return modelTypeM; } int GetModulesDVBT(void);
bool Match(int modelP) { return ((modelP & eSatipModelTypeMask) & modelTypeM); } int GetModulesDVBT2(void);
int Cable() { return Match(eSatipModelTypeDVBC) ? (Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : modelCountM[eSatipModuleDVBT]) : 0; } // an ugly hack int GetModulesDVBC(void);
int Satellite() { return Match(eSatipModelTypeDVBS2) ? modelCountM[eSatipModuleDVBS2] : 0; } int GetModulesDVBC2(void);
int Terrestrial() { return Match(eSatipModelTypeDVBT) ? modelCountM[eSatipModuleDVBT] : 0; } int GetModulesATSC(void);
int Terrestrial2() { return Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : 0; } void Activate(bool onOffP) { activeM = onOffP; }
void Update(void) { lastSeenM.Set(); } const char *SrcAddress(void) { return *srcAddressM; }
uint64_t LastSeen(void) { return lastSeenM.Elapsed(); } const char *Address(void) { return *addressM; }
time_t Created(void) { return createdM; } const char *Model(void) { return *modelM; }
const char *Filters(void) { return *filtersM; }
const char *Description(void) { return *descriptionM; }
const char *Quirks(void) { return *quirksM; }
int Port(void) { return portM; }
bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); }
bool HasQuirk(void) { return (quirkM != eSatipQuirkNone); }
bool HasCI(void) { return hasCiM; }
bool IsActive(void) { return activeM; }
void Update(void) { lastSeenM.Set(); }
uint64_t LastSeen(void) { return lastSeenM.Elapsed(); }
time_t Created(void) { return createdM; }
}; };
// --- cSatipServers ---------------------------------------------------------- // --- cSatipServers ----------------------------------------------------------
@ -67,11 +123,19 @@ 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);
cSatipServer *Assign(int deviceIdP, int sourceP, int transponderP, int systemP);
cSatipServer *Update(cSatipServer *serverP); cSatipServer *Update(cSatipServer *serverP);
void Use(cSatipServer *serverP, bool onOffP); void Activate(cSatipServer *serverP, bool onOffP);
void Attach(cSatipServer *serverP, int deviceIdP, int transponderP);
void Detach(cSatipServer *serverP, int deviceIdP, int transponderP);
bool IsQuirk(cSatipServer *serverP, int quirkP);
bool HasCI(cSatipServer *serverP);
void Cleanup(uint64_t intervalMsP = 0); void Cleanup(uint64_t intervalMsP = 0);
cString GetAddress(cSatipServer *serverP);
cString GetSrcAddress(cSatipServer *serverP);
cString GetString(cSatipServer *serverP); cString GetString(cSatipServer *serverP);
int GetPort(cSatipServer *serverP);
cString List(void); cString List(void);
int NumProvidedSystems(void); int NumProvidedSystems(void);
}; };

321
setup.c
View File

@ -12,30 +12,103 @@
#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
{ {
private: private:
cSatipServer *serverM;
int activeM;
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);
public: public:
cSatipServerInfo(cSatipServer *serverP); explicit cSatipServerInfo(cSatipServer *serverP);
virtual ~cSatipServerInfo(); virtual ~cSatipServerInfo();
virtual eOSState ProcessKey(eKeys keyP); virtual eOSState ProcessKey(eKeys keyP);
}; };
cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP) cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP)
: cOsdMenu(tr("SAT>IP Device"), 20), : cOsdMenu(tr("SAT>IP Server"), 20),
addressM(serverP ? serverP->Address() : "---"), serverM(serverP),
activeM(serverP && serverP->IsActive()),
addressM(serverP ? (isempty(serverP->SrcAddress()) ? serverP->Address() : *cString::sprintf("%s@%s", serverP->SrcAddress(), serverP->Address())) : "---"),
modelM(serverP ? serverP->Model() : "---"), modelM(serverP ? serverP->Model() : "---"),
descriptionM(serverP ? serverP->Description() : "---"), descriptionM(serverP ? serverP->Description() : "---"),
ciExtensionM(serverP && serverP->HasCI() ? trVDR("yes") : trVDR("no")),
createdM(serverP ? serverP->Created() : 0) createdM(serverP ? serverP->Created() : 0)
{ {
SetMenuCategory(mcSetupPlugins); SetMenuCategory(mcSetupPlugins);
@ -49,14 +122,17 @@ cSatipServerInfo::~cSatipServerInfo()
void cSatipServerInfo::Setup(void) void cSatipServerInfo::Setup(void)
{ {
Add(new cMenuEditBoolItem(trVDR("Active"), &activeM));
Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Address"), *addressM), osUnknown, false)); Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("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));
} }
eOSState cSatipServerInfo::ProcessKey(eKeys keyP) eOSState cSatipServerInfo::ProcessKey(eKeys keyP)
{ {
int oldActive = activeM;
eOSState state = cOsdMenu::ProcessKey(keyP); eOSState state = cOsdMenu::ProcessKey(keyP);
if (state == osUnknown) { if (state == osUnknown) {
@ -65,6 +141,12 @@ eOSState cSatipServerInfo::ProcessKey(eKeys keyP)
default: state = osContinue; break; default: state = osContinue; break;
} }
} }
if (keyP != kNone && oldActive != activeM) {
cSatipDiscover::GetInstance()->ActivateServer(serverM, activeM);
Setup();
}
return state; return state;
} }
@ -75,7 +157,7 @@ private:
cSatipServer *serverM; cSatipServer *serverM;
public: public:
cSatipServerItem(cSatipServer *serverP); explicit cSatipServerItem(cSatipServer *serverP);
cSatipServer *Server(void) { return serverM; } cSatipServer *Server(void) { return serverM; }
virtual void SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP); virtual void SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP);
}; };
@ -85,7 +167,7 @@ cSatipServerItem::cSatipServerItem(cSatipServer *serverP)
{ {
SetSelectable(true); SetSelectable(true);
// Must begin with a '#' character! // Must begin with a '#' character!
SetText(*cString::sprintf("# %s (%s)\t%s", serverM->Address(), serverM->Model(), serverM->Description())); SetText(*cString::sprintf("%s %s (%s)\t%s", serverM->IsActive() ? "+" : "-", isempty(serverM->SrcAddress()) ? serverM->Address() : *cString::sprintf("%s@%s", serverM->SrcAddress(), serverM->Address()), serverM->Model(), serverM->Description()));
} }
void cSatipServerItem::SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP) void cSatipServerItem::SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP)
@ -94,6 +176,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
@ -195,16 +342,32 @@ eOSState cSatipMenuInfo::ProcessKey(eKeys keyP)
// --- cSatipPluginSetup ------------------------------------------------------ // --- cSatipPluginSetup ------------------------------------------------------
cSatipPluginSetup::cSatipPluginSetup() cSatipPluginSetup::cSatipPluginSetup()
: deviceCountM(0), : detachedModeM(SatipConfig.GetDetachedMode()),
deviceCountM(0),
operatingModeM(SatipConfig.GetOperatingMode()), operatingModeM(SatipConfig.GetOperatingMode()),
transportModeM(SatipConfig.GetTransportMode()),
ciExtensionM(SatipConfig.GetCIExtension()),
frontendReuseM(SatipConfig.GetFrontendReuse()),
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");
transportModeTextsM[cSatipConfig::eTransportModeUnicast] = tr("Unicast");
transportModeTextsM[cSatipConfig::eTransportModeMulticast] = tr("Multicast");
transportModeTextsM[cSatipConfig::eTransportModeRtpOverTcp] = tr("RTP-over-TCP");
for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i)
cicamsM[i] = SatipConfig.GetCICAM(i);
for (unsigned int i = 0; i < ELEMENTS(ca_systems_table); ++i)
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 +376,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,26 +390,51 @@ 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 cMenuEditStraItem(tr("Transport mode"), &transportModeM, ELEMENTS(transportModeTextsM), transportModeTextsM));
helpM.Append(tr("Define which transport mode shall be used.\n\nUnicast, Multicast, RTP-over-TCP"));
Add(new cMenuEditBoolItem(tr("Enable frontend reuse"), &frontendReuseM));
helpM.Append(tr("Define whether reusing a frontend for multiple channels in a transponder should be enabled."));
Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false));
helpM.Append(""); helpM.Append("");
cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers(); detachedModeM = SatipConfig.GetDetachedMode();
deviceCountM = servers->Count(); if (!detachedModeM) {
for (cSatipServer *s = servers->First(); s; s = servers->Next(s)) { cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers();
Add(new cSatipServerItem(s)); deviceCountM = servers->Count();
helpM.Append(""); for (cSatipServer *s = servers->First(); s; s = servers->Next(s)) {
} Add(new cSatipServerItem(s));
helpM.Append("");
}
}
SetCurrent(Get(current)); SetCurrent(Get(current));
Display(); Display();
@ -254,7 +442,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 +450,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 +461,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,28 +483,36 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP)
{ {
bool hadSubMenu = HasSubMenu(); bool hadSubMenu = HasSubMenu();
int oldOperatingMode = operatingModeM; int oldOperatingMode = operatingModeM;
int oldCiExtension = ciExtensionM;
int oldFrontendReuse = frontendReuseM;
int oldNumDisabledSources = numDisabledSourcesM;
int oldNumDisabledFilters = numDisabledFiltersM; int oldNumDisabledFilters = numDisabledFiltersM;
eOSState state = cMenuSetupPage::ProcessKey(keyP); eOSState state = cMenuSetupPage::ProcessKey(keyP);
// Ugly hack with hardcoded '#' character :( // Ugly hack with hardcoded '+/-' characters :(
const char *p = Get(Current())->Text(); const char *p = Get(Current())->Text();
if (!hadSubMenu && !HasSubMenu() && (*p == '#') && (keyP == kOk)) if (!hadSubMenu && !HasSubMenu() && p && (*p == '+' || *p == '-') && (keyP == kOk))
return DeviceInfo(); return DeviceInfo();
if (hadSubMenu && !HasSubMenu())
Setup();
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) || ( oldFrontendReuse != frontendReuseM) || (detachedModeM != SatipConfig.GetDetachedMode()))) {
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 +521,74 @@ 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("TransportMode", transportModeM);
SetupStore("EnableCIExtension", ciExtensionM);
SetupStore("EnableFrontendReuse", frontendReuseM);
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.SetTransportMode(transportModeM);
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]);
} }

12
setup.h
View File

@ -15,10 +15,19 @@
class cSatipPluginSetup : public cMenuSetupPage class cSatipPluginSetup : public cMenuSetupPage
{ {
private: private:
bool detachedModeM;
int deviceCountM; int deviceCountM;
int operatingModeM; int operatingModeM;
int transportModeM;
const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount]; const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount];
const char *transportModeTextsM[cSatipConfig::eTransportModeCount];
int ciExtensionM;
int frontendReuseM;
int cicamsM[MAX_CICAM_COUNT];
const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE];
int eitScanM; 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 +35,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:

355
socket.c
View File

@ -16,31 +16,61 @@
#include "common.h" #include "common.h"
#include "config.h" #include "config.h"
#include "log.h"
#include "socket.h" #include "socket.h"
#if defined(__GLIBC__)
#if defined(__GLIBC_PREREQ)
#if !__GLIBC_PREREQ(2,12)
#define __SATIP_DISABLE_RECVMMSG__
#endif
#endif
#endif
cSatipSocket::cSatipSocket() cSatipSocket::cSatipSocket()
: socketPortM(0), : socketPortM(0),
socketDescM(-1), socketDescM(-1),
lastErrorReportM(0), isMulticastM(false),
packetErrorsM(0), useSsmM(false),
sequenceNumberM(-1) streamAddrM(htonl(INADDR_ANY)),
sourceAddrM(htonl(INADDR_ANY)),
rcvBufSizeM(0)
{ {
debug("cSatipSocket::%s()", __FUNCTION__); debug1("%s", __PRETTY_FUNCTION__);
memset(&sockAddrM, 0, sizeof(sockAddrM));
}
cSatipSocket::cSatipSocket(size_t rcvBufSizeP)
: socketPortM(0),
socketDescM(-1),
isMulticastM(false),
useSsmM(false),
streamAddrM(htonl(INADDR_ANY)),
sourceAddrM(htonl(INADDR_ANY)),
rcvBufSizeM(rcvBufSizeP)
{
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, const bool reuseP)
{ {
debug("cSatipSocket::%s(%d)", __FUNCTION__, portP); // If socket is there already and it is bound to a different port, it must
// be closed first
if (portP != socketPortM) {
debug1("%s (%d, %d) Socket tear-down", __PRETTY_FUNCTION__, portP, reuseP);
Close();
}
// Bind to the socket if it is not active already // Bind to the socket if it is not active already
if (socketDescM < 0) { if (socketDescM < 0) {
int yes;
socklen_t len = sizeof(sockAddrM); socklen_t len = sizeof(sockAddrM);
// Create socket // Create socket
socketDescM = socket(PF_INET, SOCK_DGRAM, 0); socketDescM = socket(PF_INET, SOCK_DGRAM, 0);
@ -49,9 +79,24 @@ bool cSatipSocket::Open(const int portP)
ERROR_IF_FUNC(fcntl(socketDescM, F_SETFL, O_NONBLOCK), "fcntl(O_NONBLOCK)", ERROR_IF_FUNC(fcntl(socketDescM, F_SETFL, O_NONBLOCK), "fcntl(O_NONBLOCK)",
Close(), return false); Close(), return false);
// Allow multiple sockets to use the same PORT number // Allow multiple sockets to use the same PORT number
int yes = 1; yes = reuseP;
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0, ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0,
"setsockopt(SO_REUSEADDR)", Close(), return false); "setsockopt(SO_REUSEADDR)", Close(), return false);
yes = reuseP;
#ifdef SO_REUSEPORT
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0 && errno != ENOPROTOOPT,
"setsockopt(SO_REUSEPORT)", Close(), return false);
#endif
#ifndef __FreeBSD__
// Allow packet information to be fetched
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0,
"setsockopt(IP_PKTINFO)", Close(), return false);
#endif // __FreeBSD__
// Tweak receive buffer size if requested
if (rcvBufSizeM > 0) {
ERROR_IF_FUNC(setsockopt(socketDescM, SOL_SOCKET, SO_RCVBUF, &rcvBufSizeM, sizeof(rcvBufSizeM)) < 0,
"setsockopt(SO_RCVBUF)", Close(), return false);
}
// Bind socket // Bind socket
memset(&sockAddrM, 0, sizeof(sockAddrM)); memset(&sockAddrM, 0, sizeof(sockAddrM));
sockAddrM.sin_family = AF_INET; sockAddrM.sin_family = AF_INET;
@ -60,34 +105,47 @@ bool cSatipSocket::Open(const int portP)
ERROR_IF_FUNC(bind(socketDescM, (struct sockaddr *)&sockAddrM, sizeof(sockAddrM)) < 0, ERROR_IF_FUNC(bind(socketDescM, (struct sockaddr *)&sockAddrM, sizeof(sockAddrM)) < 0,
"bind()", Close(), return false); "bind()", Close(), return false);
// Update socket port // Update socket port
ERROR_IF_FUNC(getsockname(socketDescM,(struct sockaddr*)&sockAddrM, &len) < 0, ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0,
"getsockname()", Close(), return false); "getsockname()", Close(), return false);
socketPortM = ntohs(sockAddrM.sin_port); socketPortM = ntohs(sockAddrM.sin_port);
isMulticastM = false;
} }
debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM);
return true; return true;
} }
bool cSatipSocket::OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP)
{
debug1("%s (%d, %s, %s)", __PRETTY_FUNCTION__, portP, streamAddrP, sourceAddrP);
if (Open(portP)) {
CheckAddress(streamAddrP, &streamAddrM);
if (!isempty(sourceAddrP))
useSsmM = CheckAddress(sourceAddrP, &sourceAddrM);
return Join();
}
return false;
}
void cSatipSocket::Close(void) void cSatipSocket::Close(void)
{ {
debug("cSatipSocket::%s()", __FUNCTION__); debug1("%s socketPort=%d", __PRETTY_FUNCTION__, socketPortM);
// Check if socket exists // Check if socket exists
if (socketDescM >= 0) { if (socketDescM >= 0) {
Leave();
close(socketDescM); close(socketDescM);
socketDescM = -1; socketDescM = -1;
socketPortM = 0; socketPortM = 0;
sequenceNumberM = -1;
memset(&sockAddrM, 0, sizeof(sockAddrM)); memset(&sockAddrM, 0, sizeof(sockAddrM));
} streamAddrM = htonl(INADDR_ANY);
if (packetErrorsM) { sourceAddrM = htonl(INADDR_ANY);
info("detected %d RTP packet errors", packetErrorsM); isMulticastM = false;
packetErrorsM = 0; useSsmM = false;
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);
@ -104,12 +162,102 @@ bool cSatipSocket::Flush(void)
return false; return false;
} }
bool cSatipSocket::CheckAddress(const char *addrP, in_addr_t *inAddrP)
{
if (inAddrP) {
// First try only the IP address
*inAddrP = inet_addr(addrP);
if (*inAddrP == htonl(INADDR_NONE)) {
debug1("%s (%s, ) Cannot convert to address", __PRETTY_FUNCTION__, addrP);
// It may be a host name, get the name
struct hostent *host = gethostbyname(addrP);
if (!host) {
char tmp[64];
error("gethostbyname() failed: %s is not valid address: %s", addrP,
strerror_r(h_errno, tmp, sizeof(tmp)));
return false;
}
*inAddrP = inet_addr(*host->h_addr_list);
}
return true;
}
return false;
}
bool cSatipSocket::Join(void)
{
debug1("%s", __PRETTY_FUNCTION__);
// Check if socket exists
if (socketDescM >= 0 && !isMulticastM) {
// Join a new multicast group
if (useSsmM) {
// Source-specific multicast (SSM) is used
struct group_source_req gsr;
struct sockaddr_in *grp;
struct sockaddr_in *src;
gsr.gsr_interface = 0; // if_nametoindex("any") ?
grp = (struct sockaddr_in*)&gsr.gsr_group;
grp->sin_family = AF_INET;
grp->sin_addr.s_addr = streamAddrM;
grp->sin_port = 0;
src = (struct sockaddr_in*)&gsr.gsr_source;
src->sin_family = AF_INET;
src->sin_addr.s_addr = sourceAddrM;
src->sin_port = 0;
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_JOIN_SOURCE_GROUP)", return false);
}
else {
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = streamAddrM;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false);
}
// Update multicasting flag
isMulticastM = true;
}
return true;
}
bool cSatipSocket::Leave(void)
{
debug1("%s", __PRETTY_FUNCTION__);
// Check if socket exists
if (socketDescM >= 0 && isMulticastM) {
// Leave the existing multicast group
if (useSsmM) {
// Source-specific multicast (SSM) is used
struct group_source_req gsr;
struct sockaddr_in *grp;
struct sockaddr_in *src;
gsr.gsr_interface = 0; // if_nametoindex("any") ?
grp = (struct sockaddr_in*)&gsr.gsr_group;
grp->sin_family = AF_INET;
grp->sin_addr.s_addr = streamAddrM;
grp->sin_port = 0;
src = (struct sockaddr_in*)&gsr.gsr_source;
src->sin_family = AF_INET;
src->sin_addr.s_addr = sourceAddrM;
src->sin_port = 0;
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_LEAVE_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_LEAVE_SOURCE_GROUP)", return false);
}
else {
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = streamAddrM;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false);
}
// Update multicasting flag
isMulticastM = false;
}
return true;
}
int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP) 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,123 +276,86 @@ 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;
if (socketDescM && bufferAddrP && (bufferLenP > 0)) if (socketDescM && bufferAddrP && (bufferLenP > 0))
len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT); len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT);
if (len > 0) if (len > 0) {
return len; #ifndef __FreeBSD__
} while (len > 0); if (isMulticastM) {
ERROR_IF_RET(len < 0 && errno != EAGAIN, "recvmsg()", return -1); // Process auxiliary received data and validate source address
return 0; for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
} if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg);
int cSatipSocket::ReadVideo(unsigned char *bufferAddrP, unsigned int bufferLenP) if ((i->ipi_addr.s_addr == streamAddrM) || (htonl(INADDR_ANY) == streamAddrM))
{ return len;
//debug("cSatipSocket::%s()", __FUNCTION__);
int len = Read(bufferAddrP, bufferLenP);
if (len > 0) {
if (bufferAddrP[0] == TS_SYNC_BYTE)
return len;
else if (len > 3) {
// http://tools.ietf.org/html/rfc3550
// http://tools.ietf.org/html/rfc2250
// Version
unsigned int v = (bufferAddrP[0] >> 6) & 0x03;
// Extension bit
unsigned int x = (bufferAddrP[0] >> 4) & 0x01;
// CSCR count
unsigned int cc = bufferAddrP[0] & 0x0F;
// Payload type: MPEG2 TS = 33
//unsigned int pt = bufferAddrP[1] & 0x7F;
// Sequence number
int seq = ((bufferAddrP[2] & 0xFF) << 8) | (bufferAddrP[3] & 0xFF);
if ((((sequenceNumberM + 1) % 0xFFFF) == 0) && (seq == 0xFFFF))
sequenceNumberM = -1;
else if ((sequenceNumberM >= 0) && (((sequenceNumberM + 1) % 0xFFFF) != seq)) {
packetErrorsM++;
if (time(NULL) - lastErrorReportM > eReportIntervalS) {
info("detected %d RTP packet errors", packetErrorsM);
packetErrorsM = 0;
lastErrorReportM = time(NULL);
}
sequenceNumberM = seq;
}
else
sequenceNumberM = seq;
// Header lenght
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
// Check if extension
if (x) {
// Extension header length
unsigned int ehl = (((bufferAddrP[headerlen + 2] & 0xFF) << 8) |
(bufferAddrP[headerlen + 3] & 0xFF));
// Update header length
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
}
// Check that rtp is version 2 and payload contains multiple of TS packet data
if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) &&
(bufferAddrP[headerlen] == TS_SYNC_BYTE)) {
// Set argument point to payload in read buffer
memmove(bufferAddrP, &bufferAddrP[headerlen], (len - headerlen));
return (len - headerlen);
}
}
}
return 0;
}
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; else
len -= length; #endif // __FreeBSD__
} return len;
}
} while (len > 0);
ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1);
return 0; return 0;
} }
int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP)
{
debug16("%s (, , %d, %d)", __PRETTY_FUNCTION__, elementCountP, elementBufferSizeP);
int count = -1;
// Error out if socket not initialized
if (socketDescM <= 0) {
error("%s Invalid socket", __PRETTY_FUNCTION__);
return -1;
}
if (!bufferAddrP || !elementRecvSizeP || !elementCountP || !elementBufferSizeP) {
error("%s Invalid parameter(s)", __PRETTY_FUNCTION__);
return -1;
}
#ifndef __SATIP_DISABLE_RECVMMSG__
// Initialize iov and msgh structures
struct mmsghdr mmsgh[elementCountP];
struct iovec iov[elementCountP];
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
count = (int)recvmmsg(socketDescM, mmsgh, elementCountP, MSG_DONTWAIT, NULL);
ERROR_IF_RET(count < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmmsg()", return -1);
for (int i = 0; i < count; ++i)
elementRecvSizeP[i] = mmsgh[i].msg_len;
#else
count = 0;
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;
}
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;

View File

@ -12,27 +12,33 @@
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; bool isMulticastM;
int packetErrorsM; bool useSsmM;
int sequenceNumberM; in_addr_t streamAddrM;
in_addr_t sourceAddrM;
size_t rcvBufSizeM;
bool CheckAddress(const char *addrP, in_addr_t *inAddrP);
bool Join(void);
bool Leave(void);
public: public:
cSatipSocket(); cSatipSocket();
~cSatipSocket(); explicit cSatipSocket(size_t rcvBufSizeP);
bool Open(const int portP = 0); virtual ~cSatipSocket();
void Close(void); bool Open(const int portP = 0, const bool reuseP = false);
bool OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP);
virtual void Close(void);
int Fd(void) { return socketDescM; }
int Port(void) { return socketPortM; } int Port(void) { return socketPortM; }
bool IsMulticast(void) { return isMulticastM; }
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);
}; };

View File

@ -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)

885
tuner.c

File diff suppressed because it is too large Load Diff

159
tuner.h
View File

@ -8,69 +8,141 @@
#ifndef __SATIP_TUNER_H #ifndef __SATIP_TUNER_H
#define __SATIP_TUNER_H #define __SATIP_TUNER_H
#include <curl/curl.h>
#include <curl/easy.h>
#ifndef CURLOPT_RTSPHEADER
#error "libcurl is missing required RTSP support"
#endif
#include <vdr/thread.h> #include <vdr/thread.h>
#include <vdr/tools.h> #include <vdr/tools.h>
#include "deviceif.h" #include "deviceif.h"
#include "discover.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:
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 cSatipTunerServer
{
private:
cSatipServer *serverM;
int deviceIdM;
int transponderM;
public:
cSatipTunerServer(cSatipServer *serverP, const int deviceIdP, const int transponderP) : serverM(serverP), deviceIdM(deviceIdP), transponderM(transponderP) {}
~cSatipTunerServer() {}
cSatipTunerServer(const cSatipTunerServer &objP) { serverM = NULL; deviceIdM = -1; transponderM = 0; }
cSatipTunerServer& operator= (const cSatipTunerServer &objP) { serverM = objP.serverM; deviceIdM = objP.deviceIdM; transponderM = objP.transponderM; return *this; }
bool IsValid(void) { return !!serverM; }
bool IsQuirk(int quirkP) { return (serverM && cSatipDiscover::GetInstance()->IsServerQuirk(serverM, quirkP)); }
bool HasCI(void) { return (serverM && cSatipDiscover::GetInstance()->HasServerCI(serverM)); }
void Attach(void) { if (serverM) cSatipDiscover::GetInstance()->AttachServer(serverM, deviceIdM, transponderM); }
void Detach(void) { if (serverM) cSatipDiscover::GetInstance()->DetachServer(serverM, deviceIdM, transponderM); }
void Set(cSatipServer *serverP, const int transponderP) { serverM = serverP; transponderM = transponderP; }
void Reset(void) { serverM = NULL; transponderM = 0; }
cString GetAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerAddress(serverM) : ""; }
cString GetSrcAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetSourceAddress(serverM) : ""; }
int GetPort(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerPort(serverM) : SATIP_DEFAULT_RTSP_PORT; }
cString GetInfo(void) { return cString::sprintf("server=%s deviceid=%d transponder=%d", serverM ? "assigned" : "null", deviceIdM, transponderM); }
};
class cSatipTuner : public cThread, public cSatipTunerStatistics, public cSatipTunerIf
{
private: private:
enum { enum {
eConnectTimeoutMs = 1500, // in milliseconds eDummyPid = 100,
ePidUpdateIntervalMs = 250, // in milliseconds eDefaultSignalStrengthDBm = -25,
eReConnectTimeoutMs = 5000, // in milliseconds eDefaultSignalStrength = 224,
eMinKeepAliveIntervalMs = 30000 // in milliseconds eDefaultSignalQuality = 15,
eSleepTimeoutMs = 250, // in milliseconds
eStatusUpdateTimeoutMs = 1000, // in milliseconds
ePidUpdateIntervalMs = 250, // in milliseconds
eConnectTimeoutMs = 5000, // in milliseconds
eIdleCheckTimeoutMs = 15000, // in milliseconds
eTuningTimeoutMs = 20000, // in milliseconds
eMinKeepAliveIntervalMs = 30000, // in milliseconds
eKeepAlivePreBufferMs = 2000, // in milliseconds
eSetupTimeoutMs = 2000 // in milliseconds
}; };
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; cString lastAddrM;
cSatipServer *nextServerM; cString lastParamM;
cString tnrParamM;
int streamPortM;
cSatipTunerServer currentServerM;
cSatipTunerServer 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;
cTimeMs setupTimeoutM;
cString sessionM; cString sessionM;
eTunerState currentStateM;
cVector<eTunerState> internalStateM;
cVector<eTunerState> externalStateM;
int timeoutM; int timeoutM;
bool openedM;
bool tunedM;
bool hasLockM; bool hasLockM;
double signalStrengthDBmM;
int signalStrengthM; int signalStrengthM;
int signalQualityM; int signalQualityM;
int frontendIdM;
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 Receive(void);
void ParseReceptionParameters(const char *paramP); bool KeepAlive(bool forceP = false);
void SetStreamId(int streamIdP); bool ReadReceptionStatus(bool forceP = false);
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);
cString GetBaseUrl(const char *addressP, const int portP);
protected: protected:
virtual void Action(void); virtual void Action(void);
@ -78,16 +150,29 @@ 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 int transponderP, 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);
bool Close(void); bool Close(void);
int FrontendId(void);
int SignalStrength(void); int SignalStrength(void);
double SignalStrengthDBm(void);
int SignalQuality(void); int SignalQuality(void);
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 ProcessRtpData(u_char *bufferP, int lengthP);
virtual void ProcessRtcpData(u_char *bufferP, int lengthP);
virtual void SetStreamId(int streamIdP);
virtual void SetSessionTimeout(const char *sessionP, int timeoutP);
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP);
virtual int GetId(void);
}; };
#endif // __SATIP_TUNER_H #endif // __SATIP_TUNER_H

29
tunerif.h Normal file
View File

@ -0,0 +1,29 @@
/*
* 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 ProcessRtpData(u_char *bufferP, int lengthP) = 0;
virtual void ProcessRtcpData(u_char *bufferP, int lengthP) = 0;
virtual void SetStreamId(int streamIdP) = 0;
virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0;
virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP) = 0;
virtual int GetId(void) = 0;
private:
explicit cSatipTunerIf(const cSatipTunerIf&);
cSatipTunerIf& operator=(const cSatipTunerIf&);
};
#endif // __SATIP_TUNERIF_H