mirror of
				https://github.com/rofafor/vdr-plugin-satip.git
				synced 2023-10-10 11:37:42 +00:00 
			
		
		
		
	Compare commits
	
		
			119 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 20e9dc99f9 | ||
|  | d26658a22e | ||
|  | a5d57e9390 | ||
|  | af64cb3011 | ||
|  | 48862f99d3 | ||
|  | 6ed729c153 | ||
|  | 0fc044a316 | ||
|  | 94b7f1132f | ||
|  | e7c9b04ad2 | ||
|  | 9c91e01a87 | ||
|  | 7a84ba78c8 | ||
|  | c2fe2b748d | ||
|  | 13a6b5938f | ||
|  | 5db9f93a11 | ||
|  | cede4743cb | ||
|  | 4e9b6f11eb | ||
|  | 4b1892d754 | ||
|  | 473e016152 | ||
|  | 793aab17d7 | ||
|  | 8222d05f5d | ||
|  | 9d7c745fe1 | ||
|  | c8a5245b6c | ||
|  | ff459f426e | ||
|  | 4c216d81c8 | ||
|  | 23e2b4d54d | ||
|  | 954e1be6b3 | ||
|  | e46340f5f3 | ||
|  | d5e9b1050e | ||
|  | 6e9b5fc414 | ||
|  | 6e9b43b0d8 | ||
|  | 97aba6db0f | ||
|  | 660c48a9f4 | ||
|  | 67b6c9f4f7 | ||
|  | 37a0572a64 | ||
|  | 613c0aed7c | ||
|  | c3ad29eb27 | ||
|  | e90b8651e6 | ||
|  | 0f370aa36a | ||
|  | 49e2dd1fc1 | ||
|  | ba0b808ec4 | ||
|  | 4e2535a7e2 | ||
|  | 6384b8694e | ||
|  | 6c4c8a10b7 | ||
|  | 8b43cdc634 | ||
|  | fe010ab72c | ||
|  | 7bdc152f76 | ||
|  | bd6774ba28 | ||
|  | fbf7977853 | ||
|  | 19a6a4a5ee | ||
|  | 7b683dba8d | ||
|  | 942d3a936e | ||
|  | 748ea15d1d | ||
|  | 1d75da403a | ||
|  | 4d8263e8fd | ||
|  | 7019b719a5 | ||
|  | 39249ca2d5 | ||
|  | 68e0d1474e | ||
|  | ad5c221e44 | ||
|  | 826e53e8ea | ||
|  | f4dd02a9aa | ||
|  | 8184a785b7 | ||
|  | 1b4094696a | ||
|  | 4139e87f4a | ||
|  | 7196c9403b | ||
|  | e1c896c1a6 | ||
|  | 6b63ad145f | ||
|  | 84dfc6701e | ||
|  | 653d9d659b | ||
|  | 26cd34f965 | ||
|  | df258d127f | ||
|  | 3e4b1c0383 | ||
|  | 73ed299ed9 | ||
|  | 37e151b3e3 | ||
|  | b1aad3fb80 | ||
|  | a87dfc43f7 | ||
|  | 26be862d89 | ||
|  | ab2a47e3e7 | ||
|  | 3d1efe7a80 | ||
|  | c9898bfbfd | ||
|  | 46bfc805e6 | ||
|  | 30925337cb | ||
|  | 63e47ad24a | ||
|  | 14123e160f | ||
|  | 278d0478cf | ||
|  | 9989c36eee | ||
|  | d2064f0c04 | ||
|  | 714d3ed902 | ||
|  | b466d6836e | ||
|  | 184ddf2a53 | ||
|  | 65a2158051 | ||
|  | e833ca6fdd | ||
|  | c9abfddf11 | ||
|  | fb7a7fe3a2 | ||
|  | 3b9269e9de | ||
|  | 09e6c272cd | ||
|  | 266aadb999 | ||
|  | aed5a7820a | ||
|  | bcb11b6257 | ||
|  | 21261f8042 | ||
|  | 2f11ad7a98 | ||
|  | 83a0233780 | ||
|  | 6f3715eb8b | ||
|  | 92991cd144 | ||
|  | 304addbc00 | ||
|  | 26ff10ce1e | ||
|  | e654b3bbd2 | ||
|  | acea8748a4 | ||
|  | 755f1049bb | ||
|  | 2f6315280f | ||
|  | 695dd53bfc | ||
|  | 5fef77518e | ||
|  | 791767f02b | ||
|  | 0d52649dbd | ||
|  | 0c03c1b8d4 | ||
|  | db59aa9c29 | ||
|  | 0fd559ce79 | ||
|  | e10ce57210 | ||
|  | c7f4b265d5 | ||
|  | 35c0f25c38 | 
							
								
								
									
										86
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								HISTORY
									
									
									
									
									
								
							| @@ -88,3 +88,89 @@ VDR Plugin 'satip' Revision History | |||||||
| - Added plenty of performance tweaks (Thanks to | - Added plenty of performance tweaks (Thanks to | ||||||
|   Stefan Schallenberg). |   Stefan Schallenberg). | ||||||
| - Fixed EIT scan (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. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | =================================== | ||||||
|  | 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. | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								Makefile
									
									
									
									
									
								
							| @@ -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 | ||||||
| @@ -140,9 +129,7 @@ install-i18n: $(I18Nmsgs) | |||||||
|  |  | ||||||
| $(SOFILE): $(OBJS) | $(SOFILE): $(OBJS) | ||||||
| 	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@ | 	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@ | ||||||
| ifndef SATIP_DEBUG |  | ||||||
| 	@$(STRIP) $@ | 	@$(STRIP) $@ | ||||||
| endif |  | ||||||
|  |  | ||||||
| install-lib: $(SOFILE) | install-lib: $(SOFILE) | ||||||
| 	install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) | 	install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								README
									
									
									
									
									
								
							| @@ -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,17 +42,30 @@ 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 | The plugin accepts also a "--server" (-s) command-line parameter, that | ||||||
| can be used to manually configure static SAT>IP servers if autodetection | can be used to manually configure static SAT>IP servers if autodetection | ||||||
| via UPnP somehow can't be used. | via UPnP somehow can't be used. The parameter string is a semicolon | ||||||
|  | separated list of "<ipaddress>|<model>|<description>" entries. The model | ||||||
|  | consists of a DVB system (DVBS2,DVBT2,DVBT,DVBC) and number of available | ||||||
|  | frontends separated by a hyphen: | ||||||
|  |  | ||||||
|  | vdr -P 'satip -s <ipaddress>[:<port>]|<model>[:<filter>]|<description>[:<quirk>];...' | ||||||
|  | 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 | ||||||
| @@ -62,9 +76,13 @@ 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 | A channel can be assigned into a specific SAT>IP frontend by giving the | ||||||
| identifier number in RID field of a channels.conf entry. | identifier number in RID field of a channels.conf entry: | ||||||
| Valid range: 1 ... 8 | FE = RID % 100 | ||||||
|  | Valid range: 1 ... 99 | ||||||
|  |  | ||||||
| Setup menu: | Setup menu: | ||||||
|  |  | ||||||
| @@ -76,6 +94,13 @@ Setup menu: | |||||||
|                              option to "low". Similarly, the "high" |                              option to "low". Similarly, the "high" | ||||||
|                              value prefers the SAT>IP over the local |                              value prefers the SAT>IP over the local | ||||||
|                              DVB cards when selecting available devices. |                              DVB cards when selecting available devices. | ||||||
|  | - Use CI extension = no      If you want to use the CI extension found | ||||||
|  |                              in some SAT>IP hardware (e.g. Digital | ||||||
|  |                              Devices OctopusNet), set this option to | ||||||
|  |                              "yes". | ||||||
|  | - CICAM #<slot> = <system>   If you want to assign a CA system into | ||||||
|  |                              a specific CI slot, set this option to | ||||||
|  |                              a named one. Use "---" for autoselection. | ||||||
| - Enable EPG scanning = yes  If you want exclude all SAT>IP devices | - Enable EPG scanning = yes  If you want exclude all SAT>IP devices | ||||||
|                              from VDR's EIT background scanning, set |                              from VDR's EIT background scanning, set | ||||||
|                              this option to "no". |                              this option to "no". | ||||||
| @@ -91,6 +116,11 @@ Setup menu: | |||||||
|                              "Disable filter" options which allow you |                              "Disable filter" options which allow you | ||||||
|                              to disable the individual section filters. |                              to disable the individual section filters. | ||||||
|                              Valid range: "none" = 0 ... 7 |                              Valid range: "none" = 0 ... 7 | ||||||
|  | - 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. | ||||||
| - [Red:Scan]                 Forces network scanning of SAT>IP hardware. | - [Red:Scan]                 Forces network scanning of SAT>IP hardware. | ||||||
| - [Yellow:Devices]           Opens SAT>IP device status menu. | - [Yellow:Devices]           Opens SAT>IP device status menu. | ||||||
| - [Blue:Info]                Opens SAT>IP information/statistics menu. | - [Blue:Info]                Opens SAT>IP information/statistics menu. | ||||||
| @@ -106,6 +136,9 @@ 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. | ||||||
|  |  | ||||||
| @@ -113,12 +146,19 @@ Notes: | |||||||
|   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 | - Tracing can be set on/off dynamically via command-line switch or | ||||||
|   SVDRP command. |   SVDRP command. | ||||||
|  |  | ||||||
|  | - OctopusNet firmware 1.0.40 or greater recommended. | ||||||
|  |  | ||||||
|  | - Inverto OEM firmware 1.17.0.120 or greater recommended. | ||||||
|  |   The firmware 1.16.0.120 can be downloaded and installed | ||||||
|  |   from their webpage: http://www.inverto.tv/support/ | ||||||
|  |   An update to a newer firmware should be offered afterwards. | ||||||
|  |  | ||||||
| Acknowledgements: | Acknowledgements: | ||||||
|  |  | ||||||
| - Big thanks to Digital Devices GmbH for providing the Octopus Net | - Big thanks to Digital Devices GmbH for providing the Octopus Net | ||||||
|   | |||||||
							
								
								
									
										64
									
								
								common.c
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								common.c
									
									
									
									
									
								
							| @@ -79,10 +79,72 @@ cString ChangeCase(const cString &strP, bool upperP) | |||||||
|  |  | ||||||
| const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE] = | const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE] = | ||||||
| { | { | ||||||
|   /* description                        tag    pid   tid   mask */ |   // description                        tag    pid   tid   mask | ||||||
|   {trNOOP("PAT (0x00)"),                "PAT", 0x00, 0x00, 0xFF}, |   {trNOOP("PAT (0x00)"),                "PAT", 0x00, 0x00, 0xFF}, | ||||||
|   {trNOOP("NIT (0x40)"),                "NIT", 0x10, 0x40, 0xFF}, |   {trNOOP("NIT (0x40)"),                "NIT", 0x10, 0x40, 0xFF}, | ||||||
|   {trNOOP("SDT (0x42)"),                "SDT", 0x11, 0x42, 0xFF}, |   {trNOOP("SDT (0x42)"),                "SDT", 0x11, 0x42, 0xFF}, | ||||||
|   {trNOOP("EIT (0x4E/0x4F/0x5X/0x6X)"), "EIT", 0x12, 0x40, 0xC0}, |   {trNOOP("EIT (0x4E/0x4F/0x5X/0x6X)"), "EIT", 0x12, 0x40, 0xC0}, | ||||||
|   {trNOOP("TDT (0x70)"),                "TDT", 0x14, 0x70, 0xFF}, |   {trNOOP("TDT (0x70)"),                "TDT", 0x14, 0x70, 0xFF}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const ca_systems_table_type ca_systems_table[CA_SYSTEMS_TABLE_SIZE] = | ||||||
|  | { | ||||||
|  |   // http://www.dvb.org/index.php?id=174 | ||||||
|  |   // http://en.wikipedia.org/wiki/Conditional_access_system | ||||||
|  |   // start end     description | ||||||
|  |   {0x0000, 0x0000, "---"                       }, // 0 | ||||||
|  |   {0x0100, 0x01FF, "SECA Mediaguard (100..1FF)"}, // 1 | ||||||
|  |   {0x0464, 0x0464, "EuroDec (464)"             }, // 2 | ||||||
|  |   {0x0500, 0x05FF, "Viaccess (500..5FF)"       }, // 3 | ||||||
|  |   {0x0600, 0x06FF, "Irdeto (600..6FF)"         }, // 4 | ||||||
|  |   {0x0700, 0x07FF, "DigiCipher 2 (700..7FF)"   }, // 5 | ||||||
|  |   {0x0900, 0x09FF, "NDS Videoguard (900..9FF)" }, // 6 | ||||||
|  |   {0x0B00, 0x0BFF, "Conax (B00..BFF)"          }, // 7 | ||||||
|  |   {0x0D00, 0x0DFF, "CryptoWorks (D00..DFF)"    }, // 8 | ||||||
|  |   {0x0E00, 0x0EFF, "PowerVu (E00..EFF)"        }, // 9 | ||||||
|  |   {0x1000, 0x10FF, "RAS (1000..10FF)"          }, // 10 | ||||||
|  |   {0x1200, 0x12FF, "NagraVision (1200..12FF)"  }, // 11 | ||||||
|  |   {0x1700, 0x17FF, "VCAS (1700..17FF)"         }, // 12 | ||||||
|  |   {0x1800, 0x18FF, "NagraVision (1800..18FF)"  }, // 13 | ||||||
|  |   {0x22F0, 0x22F0, "Codicrypt (22F0)"          }, // 14 | ||||||
|  |   {0x2600, 0x2600, "BISS (2600)"               }, // 15 | ||||||
|  |   {0x2719, 0x2719, "VanyaCas (2719)"           }, // 16 | ||||||
|  |   {0x4347, 0x4347, "CryptOn (4347)"            }, // 17 | ||||||
|  |   {0x4800, 0x4800, "Accessgate (4800)"         }, // 18 | ||||||
|  |   {0x4900, 0x4900, "China Crypt (4900)"        }, // 19 | ||||||
|  |   {0x4A02, 0x4A02, "Tongfang (4A02)"           }, // 20 | ||||||
|  |   {0x4A10, 0x4A10, "EasyCas (4A10)"            }, // 21 | ||||||
|  |   {0x4A20, 0x4A20, "AlphaCrypt (4A20)"         }, // 22 | ||||||
|  |   {0x4A60, 0x4A60, "SkyCrypt (4A60)"           }, // 23 | ||||||
|  |   {0x4A61, 0x4A61, "Neotioncrypt (4A61)"       }, // 24 | ||||||
|  |   {0x4A62, 0x4A62, "SkyCrypt (4A62)"           }, // 25 | ||||||
|  |   {0x4A63, 0x4A63, "Neotion SHL (4A63)"        }, // 26 | ||||||
|  |   {0x4A64, 0x4A6F, "SkyCrypt (4A64)"           }, // 27 | ||||||
|  |   {0x4A70, 0x4A70, "DreamCrypt (4A70)"         }, // 28 | ||||||
|  |   {0x4A80, 0x4A80, "ThalesCrypt (4A80)"        }, // 29 | ||||||
|  |   {0x4AA1, 0x4AA1, "KeyFly (4AA1)"             }, // 30 | ||||||
|  |   {0x4ABF, 0x4ABF, "CTI-CAS (4ABF)"            }, // 31 | ||||||
|  |   {0x4AC1, 0x4AC1, "Latens (4AC1)"             }, // 32 | ||||||
|  |   {0x4AD0, 0x4AD1, "X-Crypt (4AD0)"            }, // 33 | ||||||
|  |   {0x4AD4, 0x4AD4, "OmniCrypt (4AD4)"          }, // 34 | ||||||
|  |   {0x4AE0, 0x4AE1, "Z-Crypt (4AE0)"            }, // 35 | ||||||
|  |   {0x4AE4, 0x4AE4, "CoreCrypt (4AE4)"          }, // 36 | ||||||
|  |   {0x4AE5, 0x4AE5, "PRO-Crypt (4AE5)"          }, // 37 | ||||||
|  |   {0x4AEA, 0x4AEA, "Cryptoguard (4AEA)"        }, // 38 | ||||||
|  |   {0x4AEB, 0x4AEB, "Abel Quintic (4AEB)"       }, // 39 | ||||||
|  |   {0x4AF0, 0x4AF0, "ABV (4AF0)"                }, // 40 | ||||||
|  |   {0x5500, 0x5500, "Z-Crypt (5500)"            }, // 41 | ||||||
|  |   {0x5501, 0x5501, "Griffin (5501)"            }, // 42 | ||||||
|  |   {0x5581, 0x5581, "Bulcrypt (5581)"           }, // 43 | ||||||
|  |   {0x7BE1, 0x7BE1, "DRE-Crypt (7BE1)"          }, // 44 | ||||||
|  |   {0xA101, 0xA101, "RosCrypt-M (A101)"         }, // 45 | ||||||
|  |   {0xEAD0, 0xEAD0, "VanyaCas (EAD0)"           }, // 46 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | bool checkCASystem(unsigned int cicamP, int caidP) | ||||||
|  | { | ||||||
|  |   // always skip the first row | ||||||
|  |   if ((cicamP > 0) && (cicamP < ELEMENTS(ca_systems_table))) | ||||||
|  |      return ((caidP >= ca_systems_table[cicamP].start) && (caidP <= ca_systems_table[cicamP].end)); | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										86
									
								
								common.h
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								common.h
									
									
									
									
									
								
							| @@ -13,11 +13,11 @@ | |||||||
| #include <vdr/config.h> | #include <vdr/config.h> | ||||||
| #include <vdr/i18n.h> | #include <vdr/i18n.h> | ||||||
|  |  | ||||||
| #define ELEMENTS(x)                      (sizeof(x) / sizeof(x[0])) | #define SATIP_DEFAULT_RTSP_PORT          554 | ||||||
|  |  | ||||||
| #define SATIP_MAX_DEVICES                MAXDEVICES | #define SATIP_MAX_DEVICES                MAXDEVICES | ||||||
|  |  | ||||||
| #define SATIP_BUFFER_SIZE                KILOBYTE(1024) | #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 | ||||||
| @@ -29,12 +29,15 @@ | |||||||
| #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       5 | #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) \ | ||||||
| @@ -47,15 +50,15 @@ | |||||||
|      esyslog("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];                                          \ | ||||||
|         esyslog("[%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) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -81,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); | ||||||
| @@ -100,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 | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								config.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								config.c
									
									
									
									
									
								
							| @@ -14,56 +14,69 @@ cSatipConfig SatipConfig; | |||||||
| cSatipConfig::cSatipConfig(void) | cSatipConfig::cSatipConfig(void) | ||||||
| : operatingModeM(eOperatingModeLow), | : operatingModeM(eOperatingModeLow), | ||||||
|   traceModeM(eTraceModeNormal), |   traceModeM(eTraceModeNormal), | ||||||
|  |   ciExtensionM(0), | ||||||
|   eitScanM(1), |   eitScanM(1), | ||||||
|   useBytesM(1) |   useBytesM(1), | ||||||
|  |   portRangeStartM(0), | ||||||
|  |   portRangeStopM(0), | ||||||
|  |   transportModeM(eTransportModeUnicast), | ||||||
|  |   detachedModeM(false), | ||||||
|  |   disableServerQuirksM(false), | ||||||
|  |   useSingleModelServersM(false) | ||||||
| { | { | ||||||
|   for (unsigned int i = 0; i < ARRAY_SIZE(disabledSourcesM); ++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; |       disabledSourcesM[i] = cSource::stNone; | ||||||
|   for (unsigned int i = 0; i < ARRAY_SIZE(disabledFiltersM); ++i) |   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 cSatipConfig::GetDisabledSourcesCount(void) const | ||||||
| { | { | ||||||
|   unsigned int n = 0; |   unsigned int n = 0; | ||||||
|   while ((n < ARRAY_SIZE(disabledSourcesM) && (disabledSourcesM[n] != cSource::stNone))) |   while ((n < ELEMENTS(disabledSourcesM) && (disabledSourcesM[n] != cSource::stNone))) | ||||||
|         n++; |         n++; | ||||||
|   return n; |   return n; | ||||||
| } | } | ||||||
|  |  | ||||||
| int cSatipConfig::GetDisabledSources(unsigned int indexP) const | int cSatipConfig::GetDisabledSources(unsigned int indexP) const | ||||||
| { | { | ||||||
|   return (indexP < ARRAY_SIZE(disabledSourcesM)) ? disabledSourcesM[indexP] : cSource::stNone; |   return (indexP < ELEMENTS(disabledSourcesM)) ? disabledSourcesM[indexP] : cSource::stNone; | ||||||
| } | } | ||||||
|  |  | ||||||
| void cSatipConfig::SetDisabledSources(unsigned int indexP, int sourceP) | void cSatipConfig::SetDisabledSources(unsigned int indexP, int sourceP) | ||||||
| { | { | ||||||
|   if (indexP < ARRAY_SIZE(disabledSourcesM)) |   if (indexP < ELEMENTS(disabledSourcesM)) | ||||||
|      disabledSourcesM[indexP] = sourceP; |      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) |  | ||||||
| { |  | ||||||
|   debug1("%s (%s)", __PRETTY_FUNCTION__, directoryP); |  | ||||||
|   ERROR_IF(!realpath(directoryP, configDirectoryM), "Cannot canonicalize configuration directory"); |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								config.h
									
									
									
									
									
								
							| @@ -16,11 +16,18 @@ class cSatipConfig | |||||||
| private: | private: | ||||||
|   unsigned int operatingModeM; |   unsigned int operatingModeM; | ||||||
|   unsigned int traceModeM; |   unsigned int traceModeM; | ||||||
|  |   unsigned int ciExtensionM; | ||||||
|   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 disabledSourcesM[MAX_DISABLED_SOURCES_COUNT]; | ||||||
|   int disabledFiltersM[SECTION_FILTER_TABLE_SIZE]; |   int disabledFiltersM[SECTION_FILTER_TABLE_SIZE]; | ||||||
|   char configDirectoryM[PATH_MAX]; |  | ||||||
|  |  | ||||||
| public: | public: | ||||||
|   enum eOperatingMode { |   enum eOperatingMode { | ||||||
| @@ -30,25 +37,31 @@ public: | |||||||
|     eOperatingModeHigh, |     eOperatingModeHigh, | ||||||
|     eOperatingModeCount |     eOperatingModeCount | ||||||
|   }; |   }; | ||||||
|  |   enum eTransportMode { | ||||||
|  |     eTransportModeUnicast = 0, | ||||||
|  |     eTransportModeMulticast, | ||||||
|  |     eTransportModeRtpOverTcp, | ||||||
|  |     eTransportModeCount | ||||||
|  |   }; | ||||||
|   enum eTraceMode { |   enum eTraceMode { | ||||||
|    eTraceModeNormal  = 0x0000, |     eTraceModeNormal  = 0x0000, | ||||||
|    eTraceModeDebug1  = 0x0001, |     eTraceModeDebug1  = 0x0001, | ||||||
|    eTraceModeDebug2  = 0x0002, |     eTraceModeDebug2  = 0x0002, | ||||||
|    eTraceModeDebug3  = 0x0004, |     eTraceModeDebug3  = 0x0004, | ||||||
|    eTraceModeDebug4  = 0x0008, |     eTraceModeDebug4  = 0x0008, | ||||||
|    eTraceModeDebug5  = 0x0010, |     eTraceModeDebug5  = 0x0010, | ||||||
|    eTraceModeDebug6  = 0x0020, |     eTraceModeDebug6  = 0x0020, | ||||||
|    eTraceModeDebug7  = 0x0040, |     eTraceModeDebug7  = 0x0040, | ||||||
|    eTraceModeDebug8  = 0x0080, |     eTraceModeDebug8  = 0x0080, | ||||||
|    eTraceModeDebug9  = 0x0100, |     eTraceModeDebug9  = 0x0100, | ||||||
|    eTraceModeDebug10 = 0x0200, |     eTraceModeDebug10 = 0x0200, | ||||||
|    eTraceModeDebug11 = 0x0400, |     eTraceModeDebug11 = 0x0400, | ||||||
|    eTraceModeDebug12 = 0x0800, |     eTraceModeDebug12 = 0x0800, | ||||||
|    eTraceModeDebug13 = 0x1000, |     eTraceModeDebug13 = 0x1000, | ||||||
|    eTraceModeDebug14 = 0x2000, |     eTraceModeDebug14 = 0x2000, | ||||||
|    eTraceModeDebug15 = 0x4000, |     eTraceModeDebug15 = 0x4000, | ||||||
|    eTraceModeDebug16 = 0x8000, |     eTraceModeDebug16 = 0x8000, | ||||||
|    eTraceModeMask    = 0xFFFF |     eTraceModeMask    = 0xFFFF | ||||||
|   }; |   }; | ||||||
|   cSatipConfig(); |   cSatipConfig(); | ||||||
|   unsigned int GetOperatingMode(void) const { return operatingModeM; } |   unsigned int GetOperatingMode(void) const { return operatingModeM; } | ||||||
| @@ -59,21 +72,38 @@ public: | |||||||
|   void ToggleOperatingMode(void) { operatingModeM = (operatingModeM + 1) % eOperatingModeCount; } |   void ToggleOperatingMode(void) { operatingModeM = (operatingModeM + 1) % eOperatingModeCount; } | ||||||
|   unsigned int GetTraceMode(void) const { return traceModeM; } |   unsigned int GetTraceMode(void) const { return traceModeM; } | ||||||
|   bool IsTraceMode(eTraceMode modeP) const { return (traceModeM & modeP); } |   bool IsTraceMode(eTraceMode modeP) const { return (traceModeM & modeP); } | ||||||
|  |   unsigned int GetCIExtension(void) const { return ciExtensionM; } | ||||||
|  |   int GetCICAM(unsigned int indexP) const; | ||||||
|   unsigned int GetEITScan(void) const { return eitScanM; } |   unsigned int GetEITScan(void) const { return eitScanM; } | ||||||
|   unsigned int GetUseBytes(void) const { return useBytesM; } |   unsigned int GetUseBytes(void) const { return useBytesM; } | ||||||
|   const char *GetConfigDirectory(void) const { return configDirectoryM; } |   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; |   unsigned int GetDisabledSourcesCount(void) const; | ||||||
|   int GetDisabledSources(unsigned int indexP) 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; } | ||||||
|  |  | ||||||
|   void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; } |   void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; } | ||||||
|   void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); } |   void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); } | ||||||
|  |   void SetCIExtension(unsigned int onOffP) { ciExtensionM = onOffP; } | ||||||
|  |   void SetCICAM(unsigned int indexP, int cicamP); | ||||||
|   void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; } |   void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; } | ||||||
|   void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; } |   void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; } | ||||||
|   void SetConfigDirectory(const char *directoryP); |   void 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 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; } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| extern cSatipConfig SatipConfig; | extern cSatipConfig SatipConfig; | ||||||
|   | |||||||
							
								
								
									
										91
									
								
								device.c
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								device.c
									
									
									
									
									
								
							| @@ -103,7 +103,8 @@ cString cSatipDevice::GetSatipStatus(void) | |||||||
|          bool live = (device == cDevice::ActualDevice()); |          bool live = (device == cDevice::ActualDevice()); | ||||||
|          bool lock = device->HasLock(); |          bool lock = device->HasLock(); | ||||||
|          const cChannel *channel = device->GetCurrentlyTunedTransponder(); |          const cChannel *channel = device->GetCurrentlyTunedTransponder(); | ||||||
|          for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { |          LOCK_TIMERS_READ; | ||||||
|  |          for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer)) { | ||||||
|              if (timer->Recording()) { |              if (timer->Recording()) { | ||||||
|                 cRecordControl *control = cRecordControls::GetRecordControl(timer); |                 cRecordControl *control = cRecordControls::GetRecordControl(timer); | ||||||
|                 if (control && control->Device() == device) |                 if (control && control->Device() == device) | ||||||
| @@ -115,8 +116,12 @@ cString cSatipDevice::GetSatipStatus(void) | |||||||
|             info = cString::sprintf("%sCardIndex: %d  HasLock: yes  Strength: %d  Quality: %d%s\n", *info, device->CardIndex(), device->SignalStrength(), device->SignalQuality(), live ? "  Live: yes" : ""); |             info = cString::sprintf("%sCardIndex: %d  HasLock: yes  Strength: %d  Quality: %d%s\n", *info, device->CardIndex(), device->SignalStrength(), device->SignalQuality(), live ? "  Live: yes" : ""); | ||||||
|          else |          else | ||||||
|             info = cString::sprintf("%sCardIndex: %d  HasLock: no\n", *info, device->CardIndex()); |             info = cString::sprintf("%sCardIndex: %d  HasLock: no\n", *info, device->CardIndex()); | ||||||
|          if (channel && channel->Number() > 0) |          if (channel) { | ||||||
|             info = cString::sprintf("%sTransponder: %d  Channel: %s\n", *info, (channel && channel->Number() > 0) ? channel->Transponder() : 0, (channel && channel->Number() > 0) ? channel->Name() : "---"); |             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) |          if (timers) | ||||||
|             info = cString::sprintf("%sRecording: %d timer%s\n", *info, timers, (timers > 1) ? "s" : ""); |             info = cString::sprintf("%sRecording: %d timer%s\n", *info, timers, (timers > 1) ? "s" : ""); | ||||||
|          info = cString::sprintf("%s\n", *info); |          info = cString::sprintf("%s\n", *info); | ||||||
| @@ -128,13 +133,14 @@ cString cSatipDevice::GetSatipStatus(void) | |||||||
| cString cSatipDevice::GetGeneralInformation(void) | cString cSatipDevice::GetGeneralInformation(void) | ||||||
| { | { | ||||||
|   debug16("%s [device %u]", __PRETTY_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) | ||||||
| @@ -194,6 +200,8 @@ cString cSatipDevice::DeviceType(void) const | |||||||
| cString cSatipDevice::DeviceName(void) const | cString cSatipDevice::DeviceName(void) const | ||||||
| { | { | ||||||
|   debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); |   debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); | ||||||
|  |   if (!Receiving()) | ||||||
|  |      return cString::sprintf("%s %d", *DeviceType(), deviceIndexM); | ||||||
|   return deviceNameM; |   return deviceNameM; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -217,7 +225,13 @@ int cSatipDevice::SignalQuality(void) const | |||||||
|  |  | ||||||
| bool cSatipDevice::ProvidesSource(int sourceP) const | bool cSatipDevice::ProvidesSource(int sourceP) const | ||||||
| { | { | ||||||
|   debug9("%s (%c) [device %u]", __PRETTY_FUNCTION__, cSource::ToChar(sourceP), deviceIndexM); |   cSource *s = Sources.Get(sourceP); | ||||||
|  |   debug9("%s (%c) desc='%s' [device %u]", __PRETTY_FUNCTION__, cSource::ToChar(sourceP), s ? s->Description() : "", deviceIndexM); | ||||||
|  |   if (SatipConfig.GetDetachedMode()) | ||||||
|  |      return false; | ||||||
|  |   // source descriptions starting with '0' are disabled | ||||||
|  |   if (s && s->Description() && (*(s->Description()) == '0')) | ||||||
|  |      return false; | ||||||
|   if (!SatipConfig.IsOperatingModeOff() && !!cSatipDiscover::GetInstance()->GetServer(sourceP)) { |   if (!SatipConfig.IsOperatingModeOff() && !!cSatipDiscover::GetInstance()->GetServer(sourceP)) { | ||||||
|      int numDisabledSourcesM = SatipConfig.GetDisabledSourcesCount(); |      int numDisabledSourcesM = SatipConfig.GetDisabledSourcesCount(); | ||||||
|      for (int i = 0; i < numDisabledSourcesM; ++i) { |      for (int i = 0; i < numDisabledSourcesM; ++i) { | ||||||
| @@ -324,20 +338,20 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) | |||||||
|         return false; |         return false; | ||||||
|         } |         } | ||||||
|      cString address; |      cString address; | ||||||
|      cSatipServer *server = cSatipDiscover::GetInstance()->GetServer(channelP->Source(), channelP->Transponder(), dtp.System()); |      cSatipServer *server = cSatipDiscover::GetInstance()->AssignServer(deviceIndexM, channelP->Source(), channelP->Transponder(), dtp.System()); | ||||||
|      if (!server) { |      if (!server) { | ||||||
|         debug1("%s No suitable server found [device %u]", __PRETTY_FUNCTION__, deviceIndexM); |         debug9("%s No suitable server found [device %u]", __PRETTY_FUNCTION__, deviceIndexM); | ||||||
|         return false; |         return false; | ||||||
|         } |         } | ||||||
|      cSatipDiscover::GetInstance()->SetTransponder(server, channelP->Transponder()); |      if (pTunerM && pTunerM->SetSource(server, channelP->Transponder(), *params, deviceIndexM)) { | ||||||
|      if (pTunerM && pTunerM->SetSource(server, *params, deviceIndexM)) { |  | ||||||
|         deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server)); |  | ||||||
|         channelM = *channelP; |         channelM = *channelP; | ||||||
|  |         deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server)); | ||||||
|         return true; |         return true; | ||||||
|         } |         } | ||||||
|      } |      } | ||||||
|   else if (pTunerM) { |   else if (pTunerM) { | ||||||
|      pTunerM->SetSource(NULL, NULL, deviceIndexM); |      pTunerM->SetSource(NULL, 0, NULL, deviceIndexM); | ||||||
|  |      deviceNameM = cString::sprintf("%s %d", *DeviceType(), deviceIndexM); | ||||||
|      return true; |      return true; | ||||||
|      } |      } | ||||||
|   return false; |   return false; | ||||||
| @@ -345,11 +359,11 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) | |||||||
|  |  | ||||||
| bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP) | bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP) | ||||||
| { | { | ||||||
|   debug9("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP->pid, typeP, onP, deviceIndexM); |   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) { | ||||||
|      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; | ||||||
| @@ -357,7 +371,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) | ||||||
| { | { | ||||||
|   debug9("%s (%d, %02X, %02X) [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, deviceIndexM); |   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)) | ||||||
| @@ -371,7 +385,7 @@ void cSatipDevice::CloseFilter(int handleP) | |||||||
| { | { | ||||||
|   if (pSectionFilterHandlerM) { |   if (pSectionFilterHandlerM) { | ||||||
|      int pid = pSectionFilterHandlerM->GetPid(handleP); |      int pid = pSectionFilterHandlerM->GetPid(handleP); | ||||||
|      debug9("%s (%d) [device %u]", __PRETTY_FUNCTION__, pid, deviceIndexM); |      debug12("%s (%d) [device %u]", __PRETTY_FUNCTION__, pid, deviceIndexM); | ||||||
|      if (pTunerM) |      if (pTunerM) | ||||||
|         pTunerM->SetPid(pid, ptOther, false); |         pTunerM->SetPid(pid, ptOther, false); | ||||||
|      pSectionFilterHandlerM->Close(handleP); |      pSectionFilterHandlerM->Close(handleP); | ||||||
| @@ -406,7 +420,7 @@ bool cSatipDevice::HasLock(int timeoutMsP) const | |||||||
| bool cSatipDevice::HasInternalCam(void) | bool cSatipDevice::HasInternalCam(void) | ||||||
| { | { | ||||||
|   debug16("%s [device %u]", __PRETTY_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) | ||||||
| @@ -428,6 +442,45 @@ int cSatipDevice::GetId(void) | |||||||
|   return deviceIndexM; |   return deviceIndexM; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int cSatipDevice::GetPmtPid(void) | ||||||
|  | { | ||||||
|  |   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) | uchar *cSatipDevice::GetData(int *availableP) | ||||||
| { | { | ||||||
|   debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); |   debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); | ||||||
| @@ -471,8 +524,9 @@ void cSatipDevice::SkipData(int countP) | |||||||
| bool cSatipDevice::GetTSPacket(uchar *&dataP) | bool cSatipDevice::GetTSPacket(uchar *&dataP) | ||||||
| { | { | ||||||
|   debug16("%s [device %u]", __PRETTY_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; | ||||||
| @@ -484,7 +538,6 @@ bool cSatipDevice::GetTSPacket(uchar *&dataP) | |||||||
|            return true; |            return true; | ||||||
|            } |            } | ||||||
|         } |         } | ||||||
| #endif |  | ||||||
|      dataP = GetData(); |      dataP = GetData(); | ||||||
|      return true; |      return true; | ||||||
|      } |      } | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								device.h
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								device.h
									
									
									
									
									
								
							| @@ -43,7 +43,7 @@ private: | |||||||
|  |  | ||||||
|   // 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); | ||||||
|  |  | ||||||
| @@ -108,6 +108,10 @@ public: | |||||||
| public: | public: | ||||||
|   virtual void WriteData(u_char *bufferP, int lengthP); |   virtual void WriteData(u_char *bufferP, int lengthP); | ||||||
|   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 | ||||||
|   | |||||||
| @@ -14,9 +14,13 @@ public: | |||||||
|   virtual ~cSatipDeviceIf() {} |   virtual ~cSatipDeviceIf() {} | ||||||
|   virtual void WriteData(u_char *bufferP, int lengthP) = 0; |   virtual void WriteData(u_char *bufferP, int lengthP) = 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&); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										224
									
								
								discover.c
									
									
									
									
									
								
							
							
						
						
									
										224
									
								
								discover.c
									
									
									
									
									
								
							| @@ -32,7 +32,7 @@ bool cSatipDiscover::Initialize(cSatipDiscoverServers *serversP) | |||||||
|   if (instanceS) { |   if (instanceS) { | ||||||
|        if (serversP) { |        if (serversP) { | ||||||
|           for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s)) |           for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s)) | ||||||
|               instanceS->AddServer(s->IpAddress(), s->Model(), s->Description()); |               instanceS->AddServer(s->IpAddress(), s->IpPort(), s->Model(), s->Filters(), s->Description(), s->Quirk()); | ||||||
|           } |           } | ||||||
|      else |      else | ||||||
|         instanceS->Activate(); |         instanceS->Activate(); | ||||||
| @@ -47,43 +47,26 @@ void cSatipDiscover::Destroy(void) | |||||||
|      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; | ||||||
|   debug16("%s len=%zu", __PRETTY_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 |   return len; | ||||||
|      TiXmlDocument doc; | } | ||||||
|      char *xml = MALLOC(char, len + 1); |  | ||||||
|      memcpy(xml, ptrP, len); | size_t cSatipDiscover::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP) | ||||||
|      *(xml + len + 1) = 0; | { | ||||||
|      doc.Parse((const char *)xml); |   cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP); | ||||||
|      TiXmlHandle docHandle(&doc); |   size_t len = sizeP * nmembP; | ||||||
|      TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement(); |   debug16("%s len=%zu", __PRETTY_FUNCTION__, len); | ||||||
|      if (descElement) |  | ||||||
|         desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware"; |   if (obj && (len > 0)) | ||||||
|      TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement(); |      obj->dataBufferM.Add(ptrP, len); | ||||||
|      if (modelElement) |  | ||||||
|         model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1"; |  | ||||||
| #else |  | ||||||
|      pugi::xml_document doc; |  | ||||||
|      pugi::xml_parse_result result = doc.load_buffer(ptrP, len); |  | ||||||
|      if (result) { |  | ||||||
|         pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName"); |  | ||||||
|         if (descNode) |  | ||||||
|            desc = descNode.text().as_string("MyBrokenHardware"); |  | ||||||
|         pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP"); |  | ||||||
|         if (modelNode) |  | ||||||
|            model = modelNode.text().as_string("DVBS2-1"); |  | ||||||
|         } |  | ||||||
| #endif |  | ||||||
|      SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr); |  | ||||||
|      obj->AddServer(addr, model, desc); |  | ||||||
|      } |  | ||||||
|  |  | ||||||
|   return len; |   return len; | ||||||
| } | } | ||||||
| @@ -120,6 +103,8 @@ int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *data | |||||||
| cSatipDiscover::cSatipDiscover() | cSatipDiscover::cSatipDiscover() | ||||||
| : cThread("SATIP discover"), | : cThread("SATIP discover"), | ||||||
|   mutexM(), |   mutexM(), | ||||||
|  |   headerBufferM(), | ||||||
|  |   dataBufferM(), | ||||||
|   msearchM(*this), |   msearchM(*this), | ||||||
|   probeUrlListM(), |   probeUrlListM(), | ||||||
|   handleM(curl_easy_init()), |   handleM(curl_easy_init()), | ||||||
| @@ -170,7 +155,7 @@ void cSatipDiscover::Action(void) | |||||||
|            probeIntervalM.Set(eProbeIntervalMs); |            probeIntervalM.Set(eProbeIntervalMs); | ||||||
|            msearchM.Probe(); |            msearchM.Probe(); | ||||||
|            mutexM.Lock(); |            mutexM.Lock(); | ||||||
|            serversM.Cleanup(eProbeIntervalMs * 2); |            serversM.Cleanup(eCleanupTimeoutMs); | ||||||
|            mutexM.Unlock(); |            mutexM.Unlock(); | ||||||
|            } |            } | ||||||
|         mutexM.Lock(); |         mutexM.Lock(); | ||||||
| @@ -195,6 +180,7 @@ void cSatipDiscover::Fetch(const char *urlP) | |||||||
| { | { | ||||||
|   debug1("%s (%s)", __PRETTY_FUNCTION__, urlP); |   debug1("%s (%s)", __PRETTY_FUNCTION__, urlP); | ||||||
|   if (handleM && !isempty(urlP)) { |   if (handleM && !isempty(urlP)) { | ||||||
|  |      const char *addr = NULL; | ||||||
|      long rc = 0; |      long rc = 0; | ||||||
|      CURLcode res = CURLE_OK; |      CURLcode res = CURLE_OK; | ||||||
|  |  | ||||||
| @@ -203,8 +189,10 @@ void cSatipDiscover::Fetch(const char *urlP) | |||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGFUNCTION, cSatipDiscover::DebugCallback); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_DEBUGDATA, this); | ||||||
|  |  | ||||||
|      // Set callback |      // Set header and data callbacks | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipDiscover::HeaderCallback); | ||||||
|  |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this); | ||||||
|  |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::DataCallback); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); | ||||||
|  |  | ||||||
|      // No progress meter and no signaling |      // No progress meter and no signaling | ||||||
| @@ -224,23 +212,99 @@ void cSatipDiscover::Fetch(const char *urlP) | |||||||
|      // Fetch the data |      // Fetch the data | ||||||
|      SATIP_CURL_EASY_PERFORM(handleM); |      SATIP_CURL_EASY_PERFORM(handleM); | ||||||
|      SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc); |      SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc); | ||||||
|      if (rc != 200) |      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); |         error("Discovery detected invalid status code: %ld", rc); | ||||||
|      } |      } | ||||||
| } | } | ||||||
|  |  | ||||||
| void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char * descP) | int cSatipDiscover::ParseRtspPort(void) | ||||||
| { | { | ||||||
|   debug1("%s (%s, %s, %s)", __PRETTY_FUNCTION__, addrP, modelP, descP); |   debug1("%s", __PRETTY_FUNCTION__); | ||||||
|   cMutexLock MutexLock(&mutexM); |   char *s, *p = headerBufferM.Data(); | ||||||
|   cSatipServer *tmp = new cSatipServer(addrP, modelP, descP); |   char *r = strtok_r(p, "\r\n", &s); | ||||||
|   // Validate against existing servers |   int port = SATIP_DEFAULT_RTSP_PORT; | ||||||
|   if (!serversM.Update(tmp)) { |  | ||||||
|      info("Adding server '%s|%s|%s'",  tmp->Address(), tmp->Model(), tmp->Description()); |   while (r) { | ||||||
|      serversM.Add(tmp); |         debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r); | ||||||
|  |         r = skipspace(r); | ||||||
|  |         if (strstr(r, "X-SATIP-RTSP-Port")) { | ||||||
|  |            int tmp = -1; | ||||||
|  |            if (sscanf(r, "X-SATIP-RTSP-Port:%11d", &tmp) == 1) { | ||||||
|  |               port = tmp; | ||||||
|  |               break; | ||||||
|  |               } | ||||||
|  |            } | ||||||
|  |         r = strtok_r(NULL, "\r\n", &s); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |   return port; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cSatipDiscover::ParseDeviceInfo(const char *addrP, const int portP) | ||||||
|  | { | ||||||
|  |   debug1("%s (%s, %d)", __PRETTY_FUNCTION__, addrP, portP); | ||||||
|  |   const char *desc = NULL, *model = NULL; | ||||||
|  | #ifdef USE_TINYXML | ||||||
|  |   TiXmlDocument doc; | ||||||
|  |   doc.Parse(dataBufferM.Data()); | ||||||
|  |   TiXmlHandle docHandle(&doc); | ||||||
|  |   TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement(); | ||||||
|  |   if (descElement) | ||||||
|  |      desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware"; | ||||||
|  |   TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement(); | ||||||
|  |   if (modelElement) | ||||||
|  |      model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1"; | ||||||
|  | #else | ||||||
|  |   pugi::xml_document doc; | ||||||
|  |   if (doc.load_buffer(dataBufferM.Data(), dataBufferM.Size())) { | ||||||
|  |      pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName"); | ||||||
|  |      if (descNode) | ||||||
|  |         desc = descNode.text().as_string("MyBrokenHardware"); | ||||||
|  |      pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP"); | ||||||
|  |      if (modelNode) | ||||||
|  |         model = modelNode.text().as_string("DVBS2-1"); | ||||||
|  |      } | ||||||
|  | #endif | ||||||
|  |   AddServer(addrP, portP, model, NULL, desc, cSatipServer::eSatipQuirkNone); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cSatipDiscover::AddServer(const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP) | ||||||
|  | { | ||||||
|  |   debug1("%s (%s, %d, %s, %s, %s, %d)", __PRETTY_FUNCTION__, addrP, portP, modelP, filtersP, descP, quirkP); | ||||||
|  |   cMutexLock MutexLock(&mutexM); | ||||||
|  |   if (SatipConfig.GetUseSingleModelServers() && modelP && !isempty(modelP)) { | ||||||
|  |      int n = 0; | ||||||
|  |      char *s, *p = strdup(modelP); | ||||||
|  |      char *r = strtok_r(p, ",", &s); | ||||||
|  |      while (r) { | ||||||
|  |            r = skipspace(r); | ||||||
|  |            cString desc = cString::sprintf("%s #%d", !isempty(descP) ? descP : "MyBrokenHardware", n++); | ||||||
|  |            cSatipServer *tmp = new cSatipServer(addrP, portP, r, filtersP, desc, quirkP); | ||||||
|  |            if (!serversM.Update(tmp)) { | ||||||
|  |               info("Adding server '%s|%s|%s' Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !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(addrP, portP, modelP, filtersP, descP, quirkP); | ||||||
|  |      if (!serversM.Update(tmp)) { | ||||||
|  |         info("Adding server '%s|%s|%s' Filters: %s CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), !isempty(tmp->Filters()) ? tmp->Filters() : "none", tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none"); | ||||||
|  |         serversM.Add(tmp); | ||||||
|  |         } | ||||||
|  |      else | ||||||
|  |         DELETENULL(tmp); | ||||||
|      } |      } | ||||||
|   else |  | ||||||
|      DELETENULL(tmp); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| int cSatipDiscover::GetServerCount(void) | int cSatipDiscover::GetServerCount(void) | ||||||
| @@ -250,11 +314,18 @@ int cSatipDiscover::GetServerCount(void) | |||||||
|   return serversM.Count(); |   return serversM.Count(); | ||||||
| } | } | ||||||
|  |  | ||||||
| cSatipServer *cSatipDiscover::GetServer(int sourceP, int transponderP, int systemP) | cSatipServer *cSatipDiscover::AssignServer(int deviceIdP, int sourceP, int transponderP, int systemP) | ||||||
| { | { | ||||||
|   debug16("%s (%d, %d, %d)", __PRETTY_FUNCTION__, sourceP, transponderP, systemP); |   debug16("%s (%d, %d, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, sourceP, transponderP, systemP); | ||||||
|   cMutexLock MutexLock(&mutexM); |   cMutexLock MutexLock(&mutexM); | ||||||
|   return serversM.Find(sourceP, transponderP, systemP); |   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) | ||||||
| @@ -285,18 +356,53 @@ cString cSatipDiscover::GetServerList(void) | |||||||
|   return serversM.List(); |   return serversM.List(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void cSatipDiscover::SetTransponder(cSatipServer *serverP, int transponderP) | void cSatipDiscover::ActivateServer(cSatipServer *serverP, bool onOffP) | ||||||
| { |  | ||||||
|   debug16("%s (, %d)", __PRETTY_FUNCTION__, transponderP); |  | ||||||
|   cMutexLock MutexLock(&mutexM); |  | ||||||
|   serversM.SetTransponder(serverP, transponderP); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void cSatipDiscover::UseServer(cSatipServer *serverP, bool onOffP) |  | ||||||
| { | { | ||||||
|   debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP); |   debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP); | ||||||
|   cMutexLock MutexLock(&mutexM); |   cMutexLock MutexLock(&mutexM); | ||||||
|   serversM.Use(serverP, onOffP); |   serversM.Activate(serverP, onOffP); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cSatipDiscover::AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP) | ||||||
|  | { | ||||||
|  |   debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP); | ||||||
|  |   cMutexLock MutexLock(&mutexM); | ||||||
|  |   serversM.Attach(serverP, deviceIdP, transponderP); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cSatipDiscover::DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP) | ||||||
|  | { | ||||||
|  |   debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP); | ||||||
|  |   cMutexLock MutexLock(&mutexM); | ||||||
|  |   serversM.Detach(serverP, deviceIdP, transponderP); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool cSatipDiscover::IsServerQuirk(cSatipServer *serverP, int quirkP) | ||||||
|  | { | ||||||
|  |   debug16("%s (, %d)", __PRETTY_FUNCTION__, quirkP); | ||||||
|  |   cMutexLock MutexLock(&mutexM); | ||||||
|  |   return serversM.IsQuirk(serverP, quirkP); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool cSatipDiscover::HasServerCI(cSatipServer *serverP) | ||||||
|  | { | ||||||
|  |   debug16("%s", __PRETTY_FUNCTION__); | ||||||
|  |   cMutexLock MutexLock(&mutexM); | ||||||
|  |   return serversM.HasCI(serverP); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | cString cSatipDiscover::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) | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								discover.h
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								discover.h
									
									
									
									
									
								
							| @@ -13,6 +13,7 @@ | |||||||
| #include <vdr/thread.h> | #include <vdr/thread.h> | ||||||
| #include <vdr/tools.h> | #include <vdr/tools.h> | ||||||
|  |  | ||||||
|  | #include "common.h" | ||||||
| #include "discoverif.h" | #include "discoverif.h" | ||||||
| #include "msearch.h" | #include "msearch.h" | ||||||
| #include "server.h" | #include "server.h" | ||||||
| @@ -20,16 +21,22 @@ | |||||||
|  |  | ||||||
| class cSatipDiscoverServer : public cListObject { | class cSatipDiscoverServer : public cListObject { | ||||||
| private: | private: | ||||||
|  |   int ipPortM; | ||||||
|  |   int quirkM; | ||||||
|   cString ipAddressM; |   cString ipAddressM; | ||||||
|   cString descriptionM; |   cString descriptionM; | ||||||
|   cString modelM; |   cString modelM; | ||||||
|  |   cString filtersM; | ||||||
| public: | public: | ||||||
|   cSatipDiscoverServer(const char *ipAddressP, const char *modelP, const char *descriptionP) |   cSatipDiscoverServer(const char *ipAddressP, const int ipPortP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP) | ||||||
|   { |   { | ||||||
|     ipAddressM = ipAddressP; modelM = modelP; descriptionM = descriptionP; |     ipAddressM = ipAddressP; ipPortM = ipPortP; modelM = modelP; filtersM = filtersP; descriptionM = descriptionP; quirkM = quirkP; | ||||||
|   } |   } | ||||||
|  |   int IpPort(void)              { return ipPortM; } | ||||||
|  |   int Quirk(void)               { return quirkM; } | ||||||
|   const char *IpAddress(void)   { return *ipAddressM; } |   const char *IpAddress(void)   { return *ipAddressM; } | ||||||
|   const char *Model(void)       { return *modelM; } |   const char *Model(void)       { return *modelM; } | ||||||
|  |   const char *Filters(void)     { return *filtersM; } | ||||||
|   const char *Description(void) { return *descriptionM; } |   const char *Description(void) { return *descriptionM; } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -39,15 +46,19 @@ class cSatipDiscoverServers : public cList<cSatipDiscoverServer> { | |||||||
| class cSatipDiscover : public cThread, public cSatipDiscoverIf { | class cSatipDiscover : public cThread, public cSatipDiscoverIf { | ||||||
| private: | private: | ||||||
|   enum { |   enum { | ||||||
|     eSleepTimeoutMs   = 500,  // in milliseconds |     eSleepTimeoutMs   = 500,   // in milliseconds | ||||||
|     eConnectTimeoutMs = 1500, // in milliseconds |     eConnectTimeoutMs = 1500,  // in milliseconds | ||||||
|     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 size_t WriteCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); |   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 int    DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP); |   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; |   cSatipMsearch msearchM; | ||||||
|   cStringList probeUrlListM; |   cStringList probeUrlListM; | ||||||
|   CURL *handleM; |   CURL *handleM; | ||||||
| @@ -56,7 +67,9 @@ private: | |||||||
|   cSatipServers serversM; |   cSatipServers serversM; | ||||||
|   void Activate(void); |   void Activate(void); | ||||||
|   void Deactivate(void); |   void Deactivate(void); | ||||||
|   void AddServer(const char *addrP, const char *modelP, const char *descP); |   int ParseRtspPort(void); | ||||||
|  |   void ParseDeviceInfo(const char *addrP, const int portP); | ||||||
|  |   void AddServer(const char *addrP, const int portP, const char *modelP, const char *filtersP, const char *descP, const int quirkP); | ||||||
|   void Fetch(const char *urlP); |   void Fetch(const char *urlP); | ||||||
|   // constructor |   // constructor | ||||||
|   cSatipDiscover(); |   cSatipDiscover(); | ||||||
| @@ -74,12 +87,18 @@ public: | |||||||
|   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 transponderP = 0, 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 SetTransponder(cSatipServer *serverP, int transponderP); |   void ActivateServer(cSatipServer *serverP, bool onOffP); | ||||||
|   void UseServer(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); | ||||||
|  |   int GetServerPort(cSatipServer *serverP); | ||||||
|   cString GetServerList(void); |   cString GetServerList(void); | ||||||
|   int NumProvidedSystems(void); |   int NumProvidedSystems(void); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ public: | |||||||
|   virtual void SetUrl(const char *urlP) = 0; |   virtual void SetUrl(const char *urlP) = 0; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|   cSatipDiscoverIf(const cSatipDiscoverIf&); |   explicit cSatipDiscoverIf(const cSatipDiscoverIf&); | ||||||
|   cSatipDiscoverIf& operator=(const cSatipDiscoverIf&); |   cSatipDiscoverIf& operator=(const cSatipDiscoverIf&); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								log.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								log.h
									
									
									
									
									
								
							| @@ -32,11 +32,11 @@ | |||||||
| #define debug9(x...)  void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug9)  ? dsyslog("SATIP9: " x)  : void() ) | #define debug9(x...)  void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug9)  ? dsyslog("SATIP9: " x)  : void() ) | ||||||
| // 0x0200: RTCP packets | // 0x0200: RTCP packets | ||||||
| #define debug10(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug10) ? dsyslog("SATIP10: " x) : void() ) | #define debug10(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug10) ? dsyslog("SATIP10: " x) : void() ) | ||||||
| // 0x0400: TBD | // 0x0400: CI | ||||||
| #define debug11(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug11) ? dsyslog("SATIP11: " x) : void() ) | #define debug11(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug11) ? dsyslog("SATIP11: " x) : void() ) | ||||||
| // 0x0800: TBD | // 0x0800: Pids | ||||||
| #define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() ) | #define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() ) | ||||||
| // 0x1000: TBD | // 0x1000: Discovery | ||||||
| #define debug13(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug13) ? dsyslog("SATIP13: " x) : void() ) | #define debug13(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug13) ? dsyslog("SATIP13: " x) : void() ) | ||||||
| // 0x2000: TBD | // 0x2000: TBD | ||||||
| #define debug14(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug14) ? dsyslog("SATIP14: " x) : void() ) | #define debug14(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug14) ? dsyslog("SATIP14: " x) : void() ) | ||||||
| @@ -46,4 +46,3 @@ | |||||||
| #define debug16(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug16) ? dsyslog("SATIP16: " x) : void() ) | #define debug16(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug16) ? dsyslog("SATIP16: " x) : void() ) | ||||||
|  |  | ||||||
| #endif // __SATIP_LOG_H | #endif // __SATIP_LOG_H | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								msearch.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								msearch.c
									
									
									
									
									
								
							| @@ -29,12 +29,13 @@ cSatipMsearch::cSatipMsearch(cSatipDiscoverIf &discoverP) | |||||||
|      memset(bufferM, 0, bufferLenM); |      memset(bufferM, 0, bufferLenM); | ||||||
|   else |   else | ||||||
|      error("Cannot create Msearch buffer!"); |      error("Cannot create Msearch buffer!"); | ||||||
|   if (!Open(eDiscoveryPort)) |   if (!Open(eDiscoveryPort, true)) | ||||||
|      error("Cannot open Msearch port!"); |      error("Cannot open Msearch port!"); | ||||||
| } | } | ||||||
|  |  | ||||||
| cSatipMsearch::~cSatipMsearch() | cSatipMsearch::~cSatipMsearch() | ||||||
| { | { | ||||||
|  |   FREE_POINTER(bufferM); | ||||||
| } | } | ||||||
|  |  | ||||||
| void cSatipMsearch::Probe(void) | void cSatipMsearch::Probe(void) | ||||||
| @@ -44,6 +45,9 @@ void cSatipMsearch::Probe(void) | |||||||
|      cSatipPoller::GetInstance()->Register(*this); |      cSatipPoller::GetInstance()->Register(*this); | ||||||
|      registeredM = true; |      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)); |   Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS)); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -59,12 +63,12 @@ void cSatipMsearch::Process(void) | |||||||
|      int length; |      int length; | ||||||
|      while ((length = Read(bufferM, bufferLenM)) > 0) { |      while ((length = Read(bufferM, bufferLenM)) > 0) { | ||||||
|            bufferM[min(length, int(bufferLenM - 1))] = 0; |            bufferM[min(length, int(bufferLenM - 1))] = 0; | ||||||
|            debug3("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM); |            debug13("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM); | ||||||
|            bool status = false, valid = false; |            bool status = false, valid = false; | ||||||
|            char *s, *p = reinterpret_cast<char *>(bufferM), *location = NULL; |            char *s, *p = reinterpret_cast<char *>(bufferM), *location = NULL; | ||||||
|            char *r = strtok_r(p, "\r\n", &s); |            char *r = strtok_r(p, "\r\n", &s); | ||||||
|            while (r) { |            while (r) { | ||||||
|                  debug3("%s r=%s", __PRETTY_FUNCTION__, r); |                  debug13("%s r=%s", __PRETTY_FUNCTION__, r); | ||||||
|                  // Check the status code |                  // Check the status code | ||||||
|                  // HTTP/1.1 200 OK |                  // HTTP/1.1 200 OK | ||||||
|                  if (!status && startswith(r, "HTTP/1.1 200 OK")) |                  if (!status && startswith(r, "HTTP/1.1 200 OK")) | ||||||
| @@ -93,11 +97,14 @@ void cSatipMsearch::Process(void) | |||||||
|                  r = strtok_r(NULL, "\r\n", &s); |                  r = strtok_r(NULL, "\r\n", &s); | ||||||
|                  } |                  } | ||||||
|            } |            } | ||||||
|      if (errno != EAGAIN && errno != EWOULDBLOCK) |  | ||||||
|         error("Error %d reading in %s", errno, *ToString()); |  | ||||||
|      } |      } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void cSatipMsearch::Process(unsigned char *dataP, int lengthP) | ||||||
|  | { | ||||||
|  |   debug16("%s", __PRETTY_FUNCTION__); | ||||||
|  | } | ||||||
|  |  | ||||||
| cString cSatipMsearch::ToString(void) const | cString cSatipMsearch::ToString(void) const | ||||||
| { | { | ||||||
|   return "MSearch"; |   return "MSearch"; | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ private: | |||||||
|   bool registeredM; |   bool registeredM; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|   cSatipMsearch(cSatipDiscoverIf &discoverP); |   explicit cSatipMsearch(cSatipDiscoverIf &discoverP); | ||||||
|   virtual ~cSatipMsearch(); |   virtual ~cSatipMsearch(); | ||||||
|   void Probe(void); |   void Probe(void); | ||||||
|  |  | ||||||
| @@ -34,6 +34,7 @@ public: | |||||||
| public: | public: | ||||||
|   virtual int GetFd(void); |   virtual int GetFd(void); | ||||||
|   virtual void Process(void); |   virtual void Process(void); | ||||||
|  |   virtual void Process(unsigned char *dataP, int lengthP); | ||||||
|   virtual cString ToString(void) const; |   virtual cString ToString(void) const; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										358
									
								
								param.c
									
									
									
									
									
								
							
							
						
						
									
										358
									
								
								param.c
									
									
									
									
									
								
							| @@ -147,15 +147,6 @@ cString GetTransponderUrlParameters(const cChannel *channelP) | |||||||
|      cDvbTransponderParameters dtp(channelP->Parameters()); |      cDvbTransponderParameters dtp(channelP->Parameters()); | ||||||
|      int DataSlice = 0; |      int DataSlice = 0; | ||||||
|      int C2TuningFrequencyType = 0; |      int C2TuningFrequencyType = 0; | ||||||
| #if defined(APIVERSNUM) && APIVERSNUM < 20106 |  | ||||||
|      int Pilot = PILOT_AUTO; |  | ||||||
|      int T2SystemId = 0; |  | ||||||
|      int SisoMiso = 0; |  | ||||||
| #else |  | ||||||
|      int Pilot = dtp.Pilot(); |  | ||||||
|      int T2SystemId = dtp.T2SystemId(); |  | ||||||
|      int SisoMiso = dtp.SisoMiso(); |  | ||||||
| #endif |  | ||||||
|      float freq = channelP->Frequency(); |      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()); | ||||||
| @@ -167,34 +158,349 @@ 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)) | ||||||
|  |      ST(" S 1") { // to comply with SAT>IP protocol specification 1.2.2 | ||||||
|  |        dtp.SetPilot(PILOT_OFF); | ||||||
|  |        dtp.SetModulation(QPSK); | ||||||
|  |        dtp.SetRollOff(ROLLOFF_35); | ||||||
|  |        } | ||||||
|  |      if ((channelP->Rid() % 100) > 0) | ||||||
|  |                 q += snprintf(q,       STBUFLEFT, "&fe=%d",           channelP->Rid() % 100); | ||||||
|  |      ST(" S *") q += snprintf(q,       STBUFLEFT, "src=%d&",          ((src > 0) && (src <= 255)) ? src : 1); | ||||||
|                 q += snprintf(q,       STBUFLEFT, "freq=%s",          *dtoa(freq, "%lg")); |                 q += snprintf(q,       STBUFLEFT, "freq=%s",          *dtoa(freq, "%lg")); | ||||||
|      ST(" S *") q += snprintf(q,       STBUFLEFT, "&src=%d",          ((src > 0) && (src <= 255)) ? src : 1); |  | ||||||
|      ST(" S *") q += snprintf(q,       STBUFLEFT, "&sr=%d",           channelP->Srate()); |  | ||||||
|      ST("C  1") q += snprintf(q,       STBUFLEFT, "&sr=%d",           channelP->Srate()); |  | ||||||
|      ST(" S *") q += snprintf(q,       STBUFLEFT, "&pol=%c",          tolower(dtp.Polarization())); |      ST(" S *") q += snprintf(q,       STBUFLEFT, "&pol=%c",          tolower(dtp.Polarization())); | ||||||
|      ST("C T2") q += snprintf(q,       STBUFLEFT, "&plp=%d",          dtp.StreamId()); |      ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(),      SatipRollOffValues); | ||||||
|      ST("  T2") q += snprintf(q,       STBUFLEFT, "&t2id=%d",         T2SystemId); |  | ||||||
|      ST("C  2") q += snprintf(q,       STBUFLEFT, "&c2tft=%d",        C2TuningFrequencyType); |      ST("C  2") q += snprintf(q,       STBUFLEFT, "&c2tft=%d",        C2TuningFrequencyType); | ||||||
|      ST("C  2") q += snprintf(q,       STBUFLEFT, "&ds=%d",           DataSlice); |  | ||||||
|      ST("C  1") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(),    SatipInversionValues); |  | ||||||
|      ST("  T2") q += PrintUrlString(q, STBUFLEFT, SisoMiso,           SatipSisoMisoValues); |  | ||||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(),    SatipBandwidthValues); |      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(),    SatipBandwidthValues); | ||||||
|      ST("C  2") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(),    SatipBandwidthValues); |      ST("C  2") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(),    SatipBandwidthValues); | ||||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(),        SatipGuardValues); |  | ||||||
|      ST("CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(),    SatipCodeRateValues); |  | ||||||
|      ST(" S 2") q += PrintUrlString(q, STBUFLEFT, Pilot,              SatipPilotValues); |  | ||||||
|      ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); |  | ||||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); |  | ||||||
|      ST("C  1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); |  | ||||||
|      ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(),      SatipRollOffValues); |  | ||||||
|      ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesSat); |      ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesSat); | ||||||
|      ST("C  *") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesCable); |      ST("C  *") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesCable); | ||||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesTerrestrial); |      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesTerrestrial); | ||||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues); |      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues); | ||||||
|      if (channelP->Rid() > 0) |      ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); | ||||||
|                 q += snprintf(q,       STBUFLEFT, "&fe=%d",           channelP->Rid()); |      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); | ||||||
|  |      ST("C  1") 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); | ||||||
| #undef ST | #undef ST | ||||||
|      return buffer; |      return buffer; | ||||||
|      } |      } | ||||||
|   return NULL; |   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; | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								param.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								param.h
									
									
									
									
									
								
							| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								po/ca_ES.po
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								po/ca_ES.po
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | |||||||
| # VDR plugin language source file. | # VDR plugin language source file. | ||||||
| # Copyright (C) 2007-2014 Rolf Ahrenberg | # Copyright (C) 2007-2016 Rolf Ahrenberg | ||||||
| # This file is distributed under the same license as the satip package. | # This file is distributed under the same license as the satip package. | ||||||
| # Gabriel Bonich, 2014 | # Gabriel Bonich, 2014-2015 | ||||||
| # | # | ||||||
| msgid "" | msgid "" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: vdr-satip 1.0.0\n" | "Project-Id-Version: vdr-satip 2.3.0\n" | ||||||
| "Report-Msgid-Bugs-To: <see README>\n" | "Report-Msgid-Bugs-To: <see README>\n" | ||||||
| "POT-Creation-Date: 2014-12-24 12:24+0200\n" | "POT-Creation-Date: 2016-12-18 12:18+0200\n" | ||||||
| "PO-Revision-Date: 2014-12-24 12:24+0200\n" | "PO-Revision-Date: 2016-12-18 12:18+0200\n" | ||||||
| "Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n" | "Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n" | ||||||
| "Language-Team: Catalan <vdr@linuxtv.org>\n" | "Language-Team: Catalan <vdr@linuxtv.org>\n" | ||||||
| "Language: ca\n" | "Language: ca\n" | ||||||
| @@ -38,7 +38,7 @@ msgid "SAT>IP Devices" | |||||||
| msgstr "SAT>IP Dispositius" | msgstr "SAT>IP Dispositius" | ||||||
|  |  | ||||||
| msgid "SAT>IP Server" | msgid "SAT>IP Server" | ||||||
| msgstr "" | msgstr "SAT>IP Server" | ||||||
|  |  | ||||||
| msgid "Address" | msgid "Address" | ||||||
| msgstr "Adressa" | msgstr "Adressa" | ||||||
| @@ -49,11 +49,14 @@ 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" | msgid "SAT>IP Device Status" | ||||||
| msgstr "" | msgstr "SAT>IP Estat Dispositiu" | ||||||
|  |  | ||||||
| msgid "SAT>IP Information" | msgid "SAT>IP Information" | ||||||
| msgstr "SAT>IP Informació" | msgstr "SAT>IP Informació" | ||||||
| @@ -82,9 +85,18 @@ msgstr "Normal" | |||||||
| msgid "high" | msgid "high" | ||||||
| msgstr "Alt" | msgstr "Alt" | ||||||
|  |  | ||||||
| msgid "Button$Devices" | msgid "Unicast" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Multicast" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "RTP-over-TCP" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Button$Devices" | ||||||
|  | msgstr "Dispositius" | ||||||
|  |  | ||||||
| msgid "Operating mode" | msgid "Operating mode" | ||||||
| msgstr "Mode de operació" | msgstr "Mode de operació" | ||||||
|  |  | ||||||
| @@ -96,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" | ||||||
|  |  | ||||||
| @@ -116,7 +152,7 @@ msgstr "" | |||||||
| "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 sources" | msgid "Disabled sources" | ||||||
| msgstr "" | msgstr "Desactiva entrades" | ||||||
|  |  | ||||||
| msgid "none" | msgid "none" | ||||||
| msgstr "no" | msgstr "no" | ||||||
| @@ -126,9 +162,12 @@ msgid "" | |||||||
| "\n" | "\n" | ||||||
| "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." | "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." | ||||||
| msgstr "" | 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." | msgid "Define a source to be blacklisted." | ||||||
| msgstr "" | msgstr "Definir una entrada a la llista negra" | ||||||
|  |  | ||||||
| msgid "Disabled filters" | msgid "Disabled filters" | ||||||
| msgstr "Desactiva filtres" | msgstr "Desactiva filtres" | ||||||
| @@ -148,8 +187,17 @@ 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 servers:" | msgid "Transport mode" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "" | ||||||
|  | "Define which transport mode shall be used.\n" | ||||||
|  | "\n" | ||||||
|  | "Unicast, Multicast, RTP-over-TCP" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Active SAT>IP servers:" | ||||||
|  | msgstr "Activa SAT>IP servers:" | ||||||
|  |  | ||||||
| msgid "Help" | msgid "Help" | ||||||
| msgstr "Ajuda" | msgstr "Ajuda" | ||||||
|   | |||||||
							
								
								
									
										74
									
								
								po/de_DE.po
									
									
									
									
									
								
							
							
						
						
									
										74
									
								
								po/de_DE.po
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | |||||||
| # VDR plugin language source file. | # VDR plugin language source file. | ||||||
| # Copyright (C) 2007-2014 Rolf Ahrenberg | # Copyright (C) 2007-2016 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-2016 | ||||||
| # | # | ||||||
| msgid "" | msgid "" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: vdr-satip 1.0.0\n" | "Project-Id-Version: vdr-satip 2.3.0\n" | ||||||
| "Report-Msgid-Bugs-To: <see README>\n" | "Report-Msgid-Bugs-To: <see README>\n" | ||||||
| "POT-Creation-Date: 2014-12-24 12:24+0200\n" | "POT-Creation-Date: 2016-12-18 12:18+0200\n" | ||||||
| "PO-Revision-Date: 2014-12-24 12:24+0200\n" | "PO-Revision-Date: 2016-12-18 12:18+0200\n" | ||||||
| "Last-Translator: Frank Neumann <fnu@yavdr.org>\n" | "Last-Translator: Frank Neumann <fnu@yavdr.org>\n" | ||||||
| "Language-Team: German <vdr@linuxtv.org>\n" | "Language-Team: German <vdr@linuxtv.org>\n" | ||||||
| "Language: de\n" | "Language: de\n" | ||||||
| @@ -49,6 +49,9 @@ 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" | ||||||
|  |  | ||||||
| @@ -82,11 +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" | msgid "Button$Devices" | ||||||
| msgstr "" | 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" | ||||||
| @@ -96,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 "" | ||||||
| "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 abgeschaltet\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öchste Priorität" | ||||||
|  |  | ||||||
|  | msgid "Enable CI extension" | ||||||
|  | msgstr "Aktiviere CI Erweiterung" | ||||||
|  |  | ||||||
|  | msgid "" | ||||||
|  | "Define whether a CI extension shall be used.\n" | ||||||
|  | "\n" | ||||||
|  | "This setting enables integrated CI/CAM handling found in some SAT>IP hardware (e.g. Digital Devices OctopusNet)." | ||||||
|  | msgstr "" | ||||||
|  | "Legt fest ob eine CI Erweiterung genutzt werden soll.\n" | ||||||
|  | "\n" | ||||||
|  | "Diese Einstellung aktiviert die Nutzung des integrierten CI/CAM einiger SAT>IP Geräte (z.B. Digital Devices OctopusNet)." | ||||||
|  |  | ||||||
|  | msgid "CI/CAM" | ||||||
|  | msgstr "CI/CAM" | ||||||
|  |  | ||||||
|  | msgid "" | ||||||
|  | "Define a desired CAM type for the CI slot.\n" | ||||||
|  | "\n" | ||||||
|  | "The '---' option lets SAT>IP hardware do the auto-selection." | ||||||
|  | msgstr "" | ||||||
|  | "Bestimmt welcher CI Einschub für ein CAM genutzt werden soll.\n" | ||||||
|  | "\n" | ||||||
|  | "Die Option '---' überlässt der SAT>IP Hardware die automatische Auswahl." | ||||||
|  |  | ||||||
| msgid "Enable EPG scanning" | msgid "Enable EPG scanning" | ||||||
| msgstr "Aktiviere EPG Aktualisierung" | msgstr "Aktiviere EPG Aktualisierung" | ||||||
|  |  | ||||||
| @@ -111,7 +147,7 @@ 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." | ||||||
|  |  | ||||||
| @@ -126,7 +162,7 @@ msgid "" | |||||||
| "\n" | "\n" | ||||||
| "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." | "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." | ||||||
| msgstr "" | msgstr "" | ||||||
| "Definiert die Anzahl der deaktivierten Quellen.\n" | "Legt die Anzahl der deaktivierten Quellen fest.\n" | ||||||
| "\n" | "\n" | ||||||
| "Für einige SAT>IP server sind nicht alle Satellitenpositionen verfügbar, nicht verfügbare Quellen können hier ausgeblendet werden" | "Für einige SAT>IP server sind nicht alle Satellitenpositionen verfügbar, nicht verfügbare Quellen können hier ausgeblendet werden" | ||||||
|  |  | ||||||
| @@ -143,16 +179,28 @@ msgid "" | |||||||
| 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 "Transport mode" | ||||||
|  | msgstr "Übertragungsart" | ||||||
|  |  | ||||||
|  | msgid "" | ||||||
|  | "Define which transport mode shall be used.\n" | ||||||
|  | "\n" | ||||||
|  | "Unicast, Multicast, RTP-over-TCP" | ||||||
|  | msgstr "" | ||||||
|  | "Lege die gewünschte Übertragungsart fest.\n" | ||||||
|  | "\n" | ||||||
|  | "Unicast, Multicast, RTP-over-TCP" | ||||||
|  |  | ||||||
| msgid "Active SAT>IP servers:" | msgid "Active SAT>IP servers:" | ||||||
| msgstr "Aktive SAT>IP Server" | msgstr "Aktive SAT>IP Server:" | ||||||
|  |  | ||||||
| msgid "Help" | msgid "Help" | ||||||
| msgstr "Hilfe" | msgstr "Hilfe" | ||||||
|   | |||||||
							
								
								
									
										70
									
								
								po/es_ES.po
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								po/es_ES.po
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | |||||||
| # VDR plugin language source file. | # VDR plugin language source file. | ||||||
| # Copyright (C) 2007-2014 Rolf Ahrenberg | # Copyright (C) 2007-2016 Rolf Ahrenberg | ||||||
| # This file is distributed under the same license as the satip package. | # This file is distributed under the same license as the satip package. | ||||||
| # Gabriel Bonich, 2014 | # Gabriel Bonich, 2014-2015 | ||||||
| # | # | ||||||
| msgid "" | msgid "" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: vdr-satip 1.0.0\n" | "Project-Id-Version: vdr-satip 2.3.0\n" | ||||||
| "Report-Msgid-Bugs-To: <see README>\n" | "Report-Msgid-Bugs-To: <see README>\n" | ||||||
| "POT-Creation-Date: 2014-12-24 12:24+0200\n" | "POT-Creation-Date: 2016-12-18 12:18+0200\n" | ||||||
| "PO-Revision-Date: 2014-12-24 12:24+0200\n" | "PO-Revision-Date: 2016-12-18 12:18+0200\n" | ||||||
| "Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n" | "Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n" | ||||||
| "Language-Team: Spanish <vdr@linuxtv.org>\n" | "Language-Team: Spanish <vdr@linuxtv.org>\n" | ||||||
| "Language: es\n" | "Language: es\n" | ||||||
| @@ -38,7 +38,7 @@ msgid "SAT>IP Devices" | |||||||
| msgstr "SAT>IP Dispositivos" | msgstr "SAT>IP Dispositivos" | ||||||
|  |  | ||||||
| msgid "SAT>IP Server" | msgid "SAT>IP Server" | ||||||
| msgstr "" | msgstr "SAT>IP Server" | ||||||
|  |  | ||||||
| msgid "Address" | msgid "Address" | ||||||
| msgstr "Dirección" | msgstr "Dirección" | ||||||
| @@ -49,11 +49,14 @@ 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" | msgid "SAT>IP Device Status" | ||||||
| msgstr "" | msgstr "SAT>IP Estado del Dispositivo" | ||||||
|  |  | ||||||
| msgid "SAT>IP Information" | msgid "SAT>IP Information" | ||||||
| msgstr "SAT>IP Información" | msgstr "SAT>IP Información" | ||||||
| @@ -82,9 +85,18 @@ msgstr "Normal" | |||||||
| msgid "high" | msgid "high" | ||||||
| msgstr "Alto" | msgstr "Alto" | ||||||
|  |  | ||||||
| msgid "Button$Devices" | msgid "Unicast" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Multicast" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "RTP-over-TCP" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Button$Devices" | ||||||
|  | msgstr "Dispositivos" | ||||||
|  |  | ||||||
| msgid "Operating mode" | msgid "Operating mode" | ||||||
| msgstr "Modo de operación" | msgstr "Modo de operación" | ||||||
|  |  | ||||||
| @@ -103,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" | ||||||
|  |  | ||||||
| @@ -116,7 +152,7 @@ msgstr "" | |||||||
| "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 sources" | msgid "Disabled sources" | ||||||
| msgstr "" | msgstr "Desactiva fuentes" | ||||||
|  |  | ||||||
| msgid "none" | msgid "none" | ||||||
| msgstr "no" | msgstr "no" | ||||||
| @@ -126,9 +162,12 @@ msgid "" | |||||||
| "\n" | "\n" | ||||||
| "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." | "SAT>IP servers might not have all satellite positions available and such sources can be blacklisted here." | ||||||
| msgstr "" | 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." | msgid "Define a source to be blacklisted." | ||||||
| msgstr "" | msgstr "Define fuentes de la lista negra" | ||||||
|  |  | ||||||
| msgid "Disabled filters" | msgid "Disabled filters" | ||||||
| msgstr "Desactiva filtros" | msgstr "Desactiva filtros" | ||||||
| @@ -148,8 +187,17 @@ 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 servers:" | msgid "Transport mode" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "" | ||||||
|  | "Define which transport mode shall be used.\n" | ||||||
|  | "\n" | ||||||
|  | "Unicast, Multicast, RTP-over-TCP" | ||||||
|  | msgstr "" | ||||||
|  |  | ||||||
|  | msgid "Active SAT>IP servers:" | ||||||
|  | msgstr "Activa SAT>IP servers:" | ||||||
|  |  | ||||||
| msgid "Help" | msgid "Help" | ||||||
| msgstr "Ayuda" | msgstr "Ayuda" | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								po/fi_FI.po
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								po/fi_FI.po
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | |||||||
| # VDR plugin language source file. | # VDR plugin language source file. | ||||||
| # Copyright (C) 2007-2014 Rolf Ahrenberg | # Copyright (C) 2007-2016 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-2016 | ||||||
| # | # | ||||||
| msgid "" | msgid "" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: vdr-satip 1.0.0\n" | "Project-Id-Version: vdr-satip 2.3.0\n" | ||||||
| "Report-Msgid-Bugs-To: <see README>\n" | "Report-Msgid-Bugs-To: <see README>\n" | ||||||
| "POT-Creation-Date: 2014-12-24 12:24+0200\n" | "POT-Creation-Date: 2016-12-18 12:18+0200\n" | ||||||
| "PO-Revision-Date: 2014-12-24 12:24+0200\n" | "PO-Revision-Date: 2016-12-18 12:18+0200\n" | ||||||
| "Last-Translator: Rolf Ahrenberg\n" | "Last-Translator: Rolf Ahrenberg\n" | ||||||
| "Language-Team: Finnish <vdr@linuxtv.org>\n" | "Language-Team: Finnish <vdr@linuxtv.org>\n" | ||||||
| "Language: fi\n" | "Language: fi\n" | ||||||
| @@ -49,6 +49,9 @@ 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" | ||||||
|  |  | ||||||
| @@ -82,6 +85,15 @@ 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" | msgid "Button$Devices" | ||||||
| msgstr "Laitteet" | msgstr "Laitteet" | ||||||
|  |  | ||||||
| @@ -102,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ä" | ||||||
|  |  | ||||||
| @@ -150,6 +186,18 @@ 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 "Transport mode" | ||||||
|  | msgstr "Siirtoyhteystapa" | ||||||
|  |  | ||||||
|  | msgid "" | ||||||
|  | "Define which transport mode shall be used.\n" | ||||||
|  | "\n" | ||||||
|  | "Unicast, Multicast, RTP-over-TCP" | ||||||
|  | msgstr "" | ||||||
|  | "Määrittele käytettävä siirtoyhteystapa.\n" | ||||||
|  | "\n" | ||||||
|  | "Unicast, Multicast, RTP-over-TCP" | ||||||
|  |  | ||||||
| msgid "Active SAT>IP servers:" | msgid "Active SAT>IP servers:" | ||||||
| msgstr "Aktiiviset SAT>IP-palvelimet:" | msgstr "Aktiiviset SAT>IP-palvelimet:" | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								poller.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								poller.c
									
									
									
									
									
								
							| @@ -79,7 +79,7 @@ void cSatipPoller::Action(void) | |||||||
|   // Do the thread loop |   // Do the thread loop | ||||||
|   while (Running()) { |   while (Running()) { | ||||||
|         int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, -1); |         int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, -1); | ||||||
|         ERROR_IF_FUNC((nfds == -1), "epoll_wait() failed", break, ;); |         ERROR_IF_FUNC((nfds == -1 && errno != EINTR), "epoll_wait() failed", break, ;); | ||||||
|         for (int i = 0; i < nfds; ++i) { |         for (int i = 0; i < nfds; ++i) { | ||||||
|             cSatipPollerIf* poll = reinterpret_cast<cSatipPollerIf *>(events[i].data.ptr); |             cSatipPollerIf* poll = reinterpret_cast<cSatipPollerIf *>(events[i].data.ptr); | ||||||
|             if (poll) { |             if (poll) { | ||||||
|   | |||||||
| @@ -14,10 +14,11 @@ public: | |||||||
|   virtual ~cSatipPollerIf() {} |   virtual ~cSatipPollerIf() {} | ||||||
|   virtual int GetFd(void) = 0; |   virtual int GetFd(void) = 0; | ||||||
|   virtual void Process(void) = 0; |   virtual void Process(void) = 0; | ||||||
|  |   virtual void Process(unsigned char *dataP, int lengthP) = 0; | ||||||
|   virtual cString ToString(void) const = 0; |   virtual cString ToString(void) const = 0; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|   cSatipPollerIf(const cSatipPollerIf&); |   explicit cSatipPollerIf(const cSatipPollerIf&); | ||||||
|   cSatipPollerIf& operator=(const cSatipPollerIf&); |   cSatipPollerIf& operator=(const cSatipPollerIf&); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								rtcp.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								rtcp.c
									
									
									
									
									
								
							| @@ -25,7 +25,7 @@ cSatipRtcp::cSatipRtcp(cSatipTunerIf &tunerP) | |||||||
| cSatipRtcp::~cSatipRtcp() | cSatipRtcp::~cSatipRtcp() | ||||||
| { | { | ||||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); |   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); | ||||||
|   DELETE_POINTER(bufferM); |   FREE_POINTER(bufferM); | ||||||
| } | } | ||||||
|  |  | ||||||
| int cSatipRtcp::GetFd(void) | int cSatipRtcp::GetFd(void) | ||||||
| @@ -36,7 +36,7 @@ int cSatipRtcp::GetFd(void) | |||||||
|  |  | ||||||
| int cSatipRtcp::GetApplicationOffset(int *lengthP) | int cSatipRtcp::GetApplicationOffset(int *lengthP) | ||||||
| { | { | ||||||
|   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, *lengthP, tunerM.GetId()); |   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP ? *lengthP : -1, tunerM.GetId()); | ||||||
|   if (!lengthP) |   if (!lengthP) | ||||||
|      return -1; |      return -1; | ||||||
|   int offset = 0; |   int offset = 0; | ||||||
| @@ -50,7 +50,7 @@ int cSatipRtcp::GetApplicationOffset(int *lengthP) | |||||||
|         //unsigned int st = bufferM[offset] & 0x1F; |         //unsigned int st = bufferM[offset] & 0x1F; | ||||||
|         // Payload type |         // Payload type | ||||||
|         unsigned int pt = bufferM[offset + 1] & 0xFF; |         unsigned int pt = bufferM[offset + 1] & 0xFF; | ||||||
|         // Lenght |         // Length | ||||||
|         unsigned int length = ((bufferM[offset + 2] & 0xFF) << 8) | (bufferM[offset + 3] & 0xFF); |         unsigned int length = ((bufferM[offset + 2] & 0xFF) << 8) | (bufferM[offset + 3] & 0xFF); | ||||||
|         // Convert it to bytes |         // Convert it to bytes | ||||||
|         length = (length + 1) * 4; |         length = (length + 1) * 4; | ||||||
| @@ -89,8 +89,16 @@ void cSatipRtcp::Process(void) | |||||||
|            if (offset >= 0) |            if (offset >= 0) | ||||||
|               tunerM.ProcessApplicationData(bufferM + offset, length); |               tunerM.ProcessApplicationData(bufferM + offset, length); | ||||||
|            } |            } | ||||||
|      if (errno != EAGAIN && errno != EWOULDBLOCK) |      } | ||||||
|         error("Error %d reading in %s", errno, *ToString()); | } | ||||||
|  |  | ||||||
|  | void cSatipRtcp::Process(unsigned char *dataP, int lengthP) | ||||||
|  | { | ||||||
|  |   debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); | ||||||
|  |   if (dataP && lengthP > 0) { | ||||||
|  |      int offset = GetApplicationOffset(&lengthP); | ||||||
|  |      if (offset >= 0) | ||||||
|  |         tunerM.ProcessApplicationData(dataP + offset, lengthP); | ||||||
|      } |      } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								rtcp.h
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								rtcp.h
									
									
									
									
									
								
							| @@ -20,16 +20,17 @@ private: | |||||||
|   cSatipTunerIf &tunerM; |   cSatipTunerIf &tunerM; | ||||||
|   unsigned int bufferLenM; |   unsigned int bufferLenM; | ||||||
|   unsigned char *bufferM; |   unsigned char *bufferM; | ||||||
|   int GetApplicationOffset(int *lenghtP); |   int GetApplicationOffset(int *lengthP); | ||||||
|  |  | ||||||
| public: | public: | ||||||
|   cSatipRtcp(cSatipTunerIf &tunerP); |   explicit cSatipRtcp(cSatipTunerIf &tunerP); | ||||||
|   virtual ~cSatipRtcp(); |   virtual ~cSatipRtcp(); | ||||||
|  |  | ||||||
|   // for internal poller interface |   // for internal poller interface | ||||||
| public: | public: | ||||||
|   virtual int GetFd(void); |   virtual int GetFd(void); | ||||||
|   virtual void Process(void); |   virtual void Process(void); | ||||||
|  |   virtual void Process(unsigned char *dataP, int lengthP); | ||||||
|   virtual cString ToString(void) const; |   virtual cString ToString(void) const; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								rtp.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								rtp.c
									
									
									
									
									
								
							| @@ -29,7 +29,7 @@ cSatipRtp::cSatipRtp(cSatipTunerIf &tunerP) | |||||||
| cSatipRtp::~cSatipRtp() | cSatipRtp::~cSatipRtp() | ||||||
| { | { | ||||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); |   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); | ||||||
|   DELETE_POINTER(bufferM); |   FREE_POINTER(bufferM); | ||||||
| } | } | ||||||
|  |  | ||||||
| int cSatipRtp::GetFd(void) | int cSatipRtp::GetFd(void) | ||||||
| @@ -51,7 +51,7 @@ void cSatipRtp::Close(void) | |||||||
|      } |      } | ||||||
| } | } | ||||||
|  |  | ||||||
| int cSatipRtp::GetHeaderLenght(unsigned char *bufferP, unsigned int lengthP) | int cSatipRtp::GetHeaderLength(unsigned char *bufferP, unsigned int lengthP) | ||||||
| { | { | ||||||
|   debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, tunerM.GetId()); |   debug16("%s (, %d) [device %d]", __PRETTY_FUNCTION__, lengthP, tunerM.GetId()); | ||||||
|   unsigned int headerlen = 0; |   unsigned int headerlen = 0; | ||||||
| @@ -88,7 +88,7 @@ int cSatipRtp::GetHeaderLenght(unsigned char *bufferP, unsigned int lengthP) | |||||||
|            } |            } | ||||||
|         else |         else | ||||||
|            sequenceNumberM = seq; |            sequenceNumberM = seq; | ||||||
|         // Header lenght |         // Header length | ||||||
|         headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t); |         headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t); | ||||||
|         // Check if extension |         // Check if extension | ||||||
|         if (x) { |         if (x) { | ||||||
| @@ -130,21 +130,34 @@ void cSatipRtp::Process(void) | |||||||
|        count = ReadMulti(bufferM, lenMsg, eRtpPacketReadCount, eMaxUdpPacketSizeB); |        count = ReadMulti(bufferM, lenMsg, eRtpPacketReadCount, eMaxUdpPacketSizeB); | ||||||
|        for (int i = 0; i < count; ++i) { |        for (int i = 0; i < count; ++i) { | ||||||
|            unsigned char *p = &bufferM[i * eMaxUdpPacketSizeB]; |            unsigned char *p = &bufferM[i * eMaxUdpPacketSizeB]; | ||||||
|            int headerlen = GetHeaderLenght(p, lenMsg[i]); |            int headerlen = GetHeaderLength(p, lenMsg[i]); | ||||||
|            if ((headerlen >= 0) && (headerlen < (int)lenMsg[i])) |            if ((headerlen >= 0) && (headerlen < (int)lenMsg[i])) | ||||||
|               tunerM.ProcessVideoData(p + headerlen, lenMsg[i] - headerlen); |               tunerM.ProcessVideoData(p + headerlen, lenMsg[i] - headerlen); | ||||||
|            } |            } | ||||||
|        } while (count >= eRtpPacketReadCount); |        } while (count >= eRtpPacketReadCount); | ||||||
|  |  | ||||||
|      if (errno != EAGAIN && errno != EWOULDBLOCK) |  | ||||||
|         error("Error %d reading in %s [device %d]", errno, *ToString(), tunerM.GetId()); |  | ||||||
|  |  | ||||||
|      elapsed = processing.Elapsed(); |      elapsed = processing.Elapsed(); | ||||||
|      if (elapsed > 1) |      if (elapsed > 1) | ||||||
|         debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, count, elapsed, tunerM.GetId()); |         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 | cString cSatipRtp::ToString(void) const | ||||||
| { | { | ||||||
|   return cString::sprintf("RTP [device %d]", tunerM.GetId()); |   return cString::sprintf("RTP [device %d]", tunerM.GetId()); | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								rtp.h
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								rtp.h
									
									
									
									
									
								
							| @@ -25,10 +25,10 @@ private: | |||||||
|   time_t lastErrorReportM; |   time_t lastErrorReportM; | ||||||
|   int packetErrorsM; |   int packetErrorsM; | ||||||
|   int sequenceNumberM; |   int sequenceNumberM; | ||||||
|   int GetHeaderLenght(unsigned char *bufferP, unsigned int lengthP); |   int GetHeaderLength(unsigned char *bufferP, unsigned int lengthP); | ||||||
|  |  | ||||||
| public: | public: | ||||||
|   cSatipRtp(cSatipTunerIf &tunerP); |   explicit cSatipRtp(cSatipTunerIf &tunerP); | ||||||
|   virtual ~cSatipRtp(); |   virtual ~cSatipRtp(); | ||||||
|   virtual void Close(void); |   virtual void Close(void); | ||||||
|  |  | ||||||
| @@ -36,6 +36,7 @@ public: | |||||||
| public: | public: | ||||||
|   virtual int GetFd(void); |   virtual int GetFd(void); | ||||||
|   virtual void Process(void); |   virtual void Process(void); | ||||||
|  |   virtual void Process(unsigned char *dataP, int lengthP); | ||||||
|   virtual cString ToString(void) const; |   virtual cString ToString(void) const; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										302
									
								
								rtsp.c
									
									
									
									
									
								
							
							
						
						
									
										302
									
								
								rtsp.c
									
									
									
									
									
								
							| @@ -15,9 +15,16 @@ | |||||||
|  |  | ||||||
| cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP) | cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP) | ||||||
| : tunerM(tunerP), | : tunerM(tunerP), | ||||||
|   modeM(cmUnicast), |   headerBufferM(), | ||||||
|  |   dataBufferM(), | ||||||
|   handleM(NULL), |   handleM(NULL), | ||||||
|   headerListM(NULL) |   headerListM(NULL), | ||||||
|  |   errorNoMoreM(""), | ||||||
|  |   errorOutOfRangeM(""), | ||||||
|  |   errorCheckSyntaxM(""), | ||||||
|  |   modeM(cSatipConfig::eTransportModeUnicast), | ||||||
|  |   interleavedRtpIdM(0), | ||||||
|  |   interleavedRtcpIdM(1) | ||||||
| { | { | ||||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); |   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); | ||||||
|   Create(); |   Create(); | ||||||
| @@ -29,46 +36,50 @@ cSatipRtsp::~cSatipRtsp() | |||||||
|   Destroy(); |   Destroy(); | ||||||
| } | } | ||||||
|  |  | ||||||
| size_t cSatipRtsp::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP) | 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); |  | ||||||
|  |  | ||||||
|   char *s, *p = (char *)ptrP; |  | ||||||
|   char *r = strtok_r(p, "\r\n", &s); |  | ||||||
|  |  | ||||||
|   while (obj && r) { |  | ||||||
|         debug16("%s (%zu): %s", __PRETTY_FUNCTION__, len, r); |  | ||||||
|         r = skipspace(r); |  | ||||||
|         if (strstr(r, "com.ses.streamID")) { |  | ||||||
|            int streamid = -1; |  | ||||||
|            if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1) |  | ||||||
|               obj->tunerM.SetStreamId(streamid); |  | ||||||
|            } |  | ||||||
|         else if (strstr(r, "Session:")) { |  | ||||||
|            int timeout = -1; |  | ||||||
|            char *session = NULL; |  | ||||||
|            if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2) |  | ||||||
|               obj->tunerM.SetSessionTimeout(skipspace(session), timeout * 1000); |  | ||||||
|            else if (sscanf(r, "Session:%m[^;]", &session) == 1) |  | ||||||
|               obj->tunerM.SetSessionTimeout(skipspace(session), -1); |  | ||||||
|            FREE_POINTER(session); |  | ||||||
|            } |  | ||||||
|         r = strtok_r(NULL, "\r\n", &s); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|   return len; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| size_t cSatipRtsp::WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP) |  | ||||||
| { | { | ||||||
|   cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP); |   cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP); | ||||||
|   size_t len = sizeP * nmembP; |   size_t len = sizeP * nmembP; | ||||||
|   debug16("%s len=%zu", __PRETTY_FUNCTION__, len); |   debug16("%s len=%zu", __PRETTY_FUNCTION__, len); | ||||||
|  |  | ||||||
|   if (obj && (len > 0)) |   if (obj && (len > 0)) | ||||||
|      obj->tunerM.ProcessApplicationData((u_char*)ptrP, len); |      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; |   return len; | ||||||
| } | } | ||||||
| @@ -102,6 +113,21 @@ int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, s | |||||||
|   return 0; |   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) | cString cSatipRtsp::RtspUnescapeString(const char *strP) | ||||||
| { | { | ||||||
|   debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId()); |   debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId()); | ||||||
| @@ -138,6 +164,9 @@ void cSatipRtsp::Create(void) | |||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_MS, (long)eConnectTimeoutMs); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs); | ||||||
|  |  | ||||||
|  |      // Limit download speed (bytes/s) | ||||||
|  |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_MAX_RECV_SPEED_LARGE, eMaxDownloadSpeedMBits * 131072L); | ||||||
|  |  | ||||||
|      // Set user-agent |      // Set user-agent | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, tunerM.GetId())); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, tunerM.GetId())); | ||||||
|      } |      } | ||||||
| @@ -186,9 +215,9 @@ bool cSatipRtsp::Options(const char *uriP) | |||||||
|   return result; |   return result; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP) | bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTcpP) | ||||||
| { | { | ||||||
|   debug1("%s (%s, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, tunerM.GetId()); |   debug1("%s (%s, %d, %d, %d) [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, useTcpP, tunerM.GetId()); | ||||||
|   bool result = false; |   bool result = false; | ||||||
|  |  | ||||||
|   if (handleM && !isempty(uriP)) { |   if (handleM && !isempty(uriP)) { | ||||||
| @@ -197,15 +226,18 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP) | |||||||
|      cTimeMs processing(0); |      cTimeMs processing(0); | ||||||
|      CURLcode res = CURLE_OK; |      CURLcode res = CURLE_OK; | ||||||
|  |  | ||||||
|      switch (modeM) { |      switch (SatipConfig.GetTransportMode()) { | ||||||
|        case cmMulticast: |        case cSatipConfig::eTransportModeMulticast: | ||||||
|             // RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl> |             // RTP/AVP;multicast;destination=<multicast group address>;port=<RTP port>-<RTCP port>;ttl=<ttl>[;source=<multicast source address>] | ||||||
|             transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP); |             transport = cString::sprintf("RTP/AVP;multicast"); | ||||||
|             break; |             break; | ||||||
|        default: |        default: | ||||||
|        case cmUnicast: |  | ||||||
|             // RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port> |             // RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port> | ||||||
|             transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP); |             // 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; |             break; | ||||||
|        } |        } | ||||||
|  |  | ||||||
| @@ -216,10 +248,25 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP) | |||||||
|      // Set header callback for catching the session and timeout |      // Set header callback for catching the session and timeout | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipRtsp::HeaderCallback); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipRtsp::HeaderCallback); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this); |      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); |      SATIP_CURL_EASY_PERFORM(handleM); | ||||||
|      // Session id is now known - disable header parsing |      // Session id is now known - disable header parsing | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, 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); |      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()); |      debug5("%s (%s, %d, %d) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, rc, processing.Elapsed(), tunerM.GetId()); | ||||||
| @@ -253,11 +300,15 @@ bool cSatipRtsp::Describe(const char *uriP) | |||||||
|  |  | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_DESCRIBE); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::WriteCallback); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); | ||||||
|      SATIP_CURL_EASY_PERFORM(handleM); |      SATIP_CURL_EASY_PERFORM(handleM); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, 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); |      result = ValidateLatestResponse(&rc); | ||||||
|      debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId()); |      debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId()); | ||||||
| @@ -278,7 +329,15 @@ bool cSatipRtsp::Play(const char *uriP) | |||||||
|  |  | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_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_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); |      result = ValidateLatestResponse(&rc); | ||||||
|      debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId()); |      debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId()); | ||||||
| @@ -299,7 +358,17 @@ bool cSatipRtsp::Teardown(const char *uriP) | |||||||
|  |  | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, uriP); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_TEARDOWN); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_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_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_CLIENT_CSEQ, 1L); | ||||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL); |      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL); | ||||||
| @@ -311,24 +380,153 @@ bool cSatipRtsp::Teardown(const char *uriP) | |||||||
|   return result; |   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 cSatipRtsp::ValidateLatestResponse(long *rcP) | ||||||
| { | { | ||||||
|   bool result = false; |   bool result = false; | ||||||
|  |  | ||||||
|   if (handleM) { |   if (handleM) { | ||||||
|  |      char *url = NULL; | ||||||
|      long rc = 0; |      long rc = 0; | ||||||
|      CURLcode res = CURLE_OK; |      CURLcode res = CURLE_OK; | ||||||
|      SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc); |      SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc); | ||||||
|      if (rc == 200) |      switch (rc) { | ||||||
|         result = true; |        case 200: | ||||||
|      else if (rc != 0) { |             result = true; | ||||||
|         char *url = NULL; |             break; | ||||||
|         SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url); |        case 400: | ||||||
|         error("Detected invalid status code %ld: %s [device %d]", rc, url, tunerM.GetId()); |             // 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) |      if (rcP) | ||||||
|         *rcP = rc; |         *rcP = rc; | ||||||
|      } |      } | ||||||
|  |   errorNoMoreM = ""; | ||||||
|  |   errorOutOfRangeM = ""; | ||||||
|  |   errorCheckSyntaxM = ""; | ||||||
|   debug1("%s result=%s [device %d]", __PRETTY_FUNCTION__, result ? "ok" : "failed", tunerM.GetId()); |   debug1("%s result=%s [device %d]", __PRETTY_FUNCTION__, result ? "ok" : "failed", tunerM.GetId()); | ||||||
|  |  | ||||||
|   return result; |   return result; | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								rtsp.h
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								rtsp.h
									
									
									
									
									
								
							| @@ -15,26 +15,37 @@ | |||||||
| #error "libcurl is missing required RTSP support" | #error "libcurl is missing required RTSP support" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #include "common.h" | ||||||
| #include "tunerif.h" | #include "tunerif.h" | ||||||
|  |  | ||||||
| class cSatipRtsp { | class cSatipRtsp { | ||||||
| private: | private: | ||||||
|   static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP); |   static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); | ||||||
|   static size_t WriteCallback(void *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); |   static int    DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP); | ||||||
|  |  | ||||||
|   enum { |   enum { | ||||||
|     eConnectTimeoutMs = 1500,  // in milliseconds |     eConnectTimeoutMs      = 1500,  // in milliseconds | ||||||
|  |     eMaxDownloadSpeedMBits = 20,    // in megabits per second | ||||||
|   }; |   }; | ||||||
|   enum eCommunicationMode { cmUnicast, cmMulticast }; |  | ||||||
|  |  | ||||||
|   cSatipTunerIf &tunerM; |   cSatipTunerIf &tunerM; | ||||||
|   eCommunicationMode modeM; |   cSatipMemoryBuffer headerBufferM; | ||||||
|  |   cSatipMemoryBuffer dataBufferM; | ||||||
|   CURL *handleM; |   CURL *handleM; | ||||||
|   struct curl_slist *headerListM; |   struct curl_slist *headerListM; | ||||||
|  |   cString errorNoMoreM; | ||||||
|  |   cString errorOutOfRangeM; | ||||||
|  |   cString errorCheckSyntaxM; | ||||||
|  |   int modeM; | ||||||
|  |   unsigned int interleavedRtpIdM; | ||||||
|  |   unsigned int interleavedRtcpIdM; | ||||||
|  |  | ||||||
|   void Create(void); |   void Create(void); | ||||||
|   void Destroy(void); |   void Destroy(void); | ||||||
|  |   void ParseHeader(void); | ||||||
|  |   void ParseData(void); | ||||||
|   bool ValidateLatestResponse(long *rcP); |   bool ValidateLatestResponse(long *rcP); | ||||||
|  |  | ||||||
|   // to prevent copy constructor and assignment |   // to prevent copy constructor and assignment | ||||||
| @@ -42,13 +53,14 @@ private: | |||||||
|   cSatipRtsp& operator=(const cSatipRtsp&); |   cSatipRtsp& operator=(const cSatipRtsp&); | ||||||
|  |  | ||||||
| public: | public: | ||||||
|   cSatipRtsp(cSatipTunerIf &tunerP); |   explicit cSatipRtsp(cSatipTunerIf &tunerP); | ||||||
|   virtual ~cSatipRtsp(); |   virtual ~cSatipRtsp(); | ||||||
|  |  | ||||||
|  |   cString GetActiveMode(void); | ||||||
|   cString RtspUnescapeString(const char *strP); |   cString RtspUnescapeString(const char *strP); | ||||||
|   void Reset(void); |   void Reset(void); | ||||||
|   bool Options(const char *uriP); |   bool Options(const char *uriP); | ||||||
|   bool Setup(const char *uriP, int rtpPortP, int rtcpPortP); |   bool Setup(const char *uriP, int rtpPortP, int rtcpPortP, bool useTcpP); | ||||||
|   bool SetSession(const char *sessionP); |   bool SetSession(const char *sessionP); | ||||||
|   bool Describe(const char *uriP); |   bool Describe(const char *uriP); | ||||||
|   bool Play(const char *uriP); |   bool Play(const char *uriP); | ||||||
|   | |||||||
							
								
								
									
										193
									
								
								satip.c
									
									
									
									
									
								
							
							
						
						
									
										193
									
								
								satip.c
									
									
									
									
									
								
							| @@ -19,15 +19,15 @@ | |||||||
| #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 < 20301 | ||||||
| #error "VDR-2.0.0 API version or greater is required!" | #error "VDR-2.3.1 API version or greater is required!" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifndef GITVERSION | #ifndef GITVERSION | ||||||
| #define GITVERSION "" | #define GITVERSION "" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|        const char VERSION[]     = "1.0.0" GITVERSION; |        const char VERSION[]     = "2.3.0" 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 { | ||||||
| @@ -35,6 +35,8 @@ private: | |||||||
|   unsigned int deviceCountM; |   unsigned int deviceCountM; | ||||||
|   cSatipDiscoverServers *serversM; |   cSatipDiscoverServers *serversM; | ||||||
|   void ParseServer(const char *paramP); |   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 ParseSources(const char *valueP, int *sourcesP); | ||||||
|   int ParseFilters(const char *valueP, int *filtersP); |   int ParseFilters(const char *valueP, int *filtersP); | ||||||
| public: | public: | ||||||
| @@ -61,7 +63,7 @@ public: | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
| cPluginSatip::cPluginSatip(void) | cPluginSatip::cPluginSatip(void) | ||||||
| : deviceCountM(1), | : deviceCountM(2), | ||||||
|   serversM(NULL) |   serversM(NULL) | ||||||
| { | { | ||||||
|   debug16("%s", __PRETTY_FUNCTION__); |   debug16("%s", __PRETTY_FUNCTION__); | ||||||
| @@ -81,8 +83,14 @@ const char *cPluginSatip::CommandLineHelp(void) | |||||||
|   debug1("%s", __PRETTY_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>  set number of devices to be created\n" |   return "  -d <num>, --devices=<number>  set number of devices to be created\n" | ||||||
|          "  -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>|<model2>|<desc2>\n" |          "  -t <mode>, --trace=<mode>     set the tracing mode\n" | ||||||
|          "                                define hard-coded SAT>IP server(s)\n"; |          "  -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>:<port>|<model2>:<filter>|<desc2>:<quirk>\n" | ||||||
|  |          "                                define hard-coded SAT>IP server(s)\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"; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool cPluginSatip::ProcessArgs(int argc, char *argv[]) | bool cPluginSatip::ProcessArgs(int argc, char *argv[]) | ||||||
| @@ -90,14 +98,20 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[]) | |||||||
|   debug1("%s", __PRETTY_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' }, | ||||||
|     { "trace",   required_argument, NULL, 't' }, |     { "trace",    required_argument, NULL, 't' }, | ||||||
|     { "server",  required_argument, NULL, 's' }, |     { "server",   required_argument, NULL, 's' }, | ||||||
|     { NULL,      no_argument,       NULL,  0  } |     { "portrange",required_argument, NULL, 'p' }, | ||||||
|  |     { "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:t:s:", long_options, NULL)) != -1) { |   while ((c = getopt_long(argc, argv, "d:t:s:p:DSn", long_options, NULL)) != -1) { | ||||||
|     switch (c) { |     switch (c) { | ||||||
|       case 'd': |       case 'd': | ||||||
|            deviceCountM = strtol(optarg, NULL, 0); |            deviceCountM = strtol(optarg, NULL, 0); | ||||||
| @@ -106,12 +120,29 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[]) | |||||||
|            SatipConfig.SetTraceMode(strtol(optarg, NULL, 0)); |            SatipConfig.SetTraceMode(strtol(optarg, NULL, 0)); | ||||||
|            break; |            break; | ||||||
|       case 's': |       case 's': | ||||||
|            ParseServer(optarg); |            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; |            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; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -121,7 +152,6 @@ bool cPluginSatip::Initialize(void) | |||||||
|   // 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(); |   cSatipPoller::GetInstance()->Initialize(); | ||||||
|   cSatipDiscover::GetInstance()->Initialize(serversM); |   cSatipDiscover::GetInstance()->Initialize(serversM); | ||||||
|   return cSatipDevice::Initialize(deviceCountM); |   return cSatipDevice::Initialize(deviceCountM); | ||||||
| @@ -197,12 +227,14 @@ void cPluginSatip::ParseServer(const char *paramP) | |||||||
| { | { | ||||||
|   debug1("%s (%s)", __PRETTY_FUNCTION__, paramP); |   debug1("%s (%s)", __PRETTY_FUNCTION__, paramP); | ||||||
|   int n = 0; |   int n = 0; | ||||||
|   char *s, *p = (char *)paramP; |   char *s, *p = strdup(paramP); | ||||||
|   char *r = strtok_r(p, ";", &s); |   char *r = strtok_r(p, ";", &s); | ||||||
|   while (r) { |   while (r) { | ||||||
|         r = skipspace(r); |         r = skipspace(r); | ||||||
|         debug3("%s server[%d]=%s", __PRETTY_FUNCTION__, n, r); |         debug3("%s server[%d]=%s", __PRETTY_FUNCTION__, n, r); | ||||||
|         cString serverAddr, serverModel, serverDescription; |         cString serverAddr, serverModel, serverFilters, serverDescription; | ||||||
|  |         int serverQuirk = cSatipServer::eSatipQuirkNone; | ||||||
|  |         int serverPort = SATIP_DEFAULT_RTSP_PORT; | ||||||
|         int n2 = 0; |         int n2 = 0; | ||||||
|         char *s2, *p2 = r; |         char *s2, *p2 = r; | ||||||
|         char *r2 = strtok_r(p2, "|", &s2); |         char *r2 = strtok_r(p2, "|", &s2); | ||||||
| @@ -210,13 +242,34 @@ void cPluginSatip::ParseServer(const char *paramP) | |||||||
|               debug3("%s param[%d]=%s", __PRETTY_FUNCTION__, n2, r2); |               debug3("%s param[%d]=%s", __PRETTY_FUNCTION__, n2, r2); | ||||||
|               switch (n2++) { |               switch (n2++) { | ||||||
|                      case 0: |                      case 0: | ||||||
|  |                           { | ||||||
|                           serverAddr = r2; |                           serverAddr = r2; | ||||||
|  |                           char *r3 = strchr(r2, ':'); | ||||||
|  |                           if (r3) { | ||||||
|  |                              serverPort = strtol(r3 + 1, NULL, 0); | ||||||
|  |                              serverAddr = serverAddr.Truncate(r3 - r2); | ||||||
|  |                              } | ||||||
|  |                           } | ||||||
|                           break; |                           break; | ||||||
|                      case 1: |                      case 1: | ||||||
|  |                           { | ||||||
|                           serverModel = r2; |                           serverModel = r2; | ||||||
|  |                           char *r3 = strchr(r2, ':'); | ||||||
|  |                           if (r3) { | ||||||
|  |                              serverFilters = r3 + 1; | ||||||
|  |                              serverModel = serverModel.Truncate(r3 - r2); | ||||||
|  |                              } | ||||||
|  |                           } | ||||||
|                           break; |                           break; | ||||||
|                      case 2: |                      case 2: | ||||||
|  |                           { | ||||||
|                           serverDescription = r2; |                           serverDescription = r2; | ||||||
|  |                           char *r3 = strchr(r2, ':'); | ||||||
|  |                           if (r3) { | ||||||
|  |                              serverQuirk = strtol(r3 + 1, NULL, 0); | ||||||
|  |                              serverDescription = serverDescription.Truncate(r3 - r2); | ||||||
|  |                              } | ||||||
|  |                           } | ||||||
|                           break; |                           break; | ||||||
|                      default: |                      default: | ||||||
|                           break; |                           break; | ||||||
| @@ -224,21 +277,71 @@ void cPluginSatip::ParseServer(const char *paramP) | |||||||
|               r2 = strtok_r(NULL, "|", &s2); |               r2 = strtok_r(NULL, "|", &s2); | ||||||
|               } |               } | ||||||
|         if (*serverAddr && *serverModel && *serverDescription) { |         if (*serverAddr && *serverModel && *serverDescription) { | ||||||
|            debug1("%s ipaddr=%s model=%s desc=%s", __PRETTY_FUNCTION__, *serverAddr, *serverModel, *serverDescription); |            debug1("%s ipaddr=%s port=%d model=%s (%s) desc=%s (%d)", __PRETTY_FUNCTION__, *serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk); | ||||||
|            if (!serversM) |            if (!serversM) | ||||||
|               serversM = new cSatipDiscoverServers(); |               serversM = new cSatipDiscoverServers(); | ||||||
|            serversM->Add(new cSatipDiscoverServer(*serverAddr, *serverModel, *serverDescription)); |            serversM->Add(new cSatipDiscoverServer(*serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk)); | ||||||
|            } |            } | ||||||
|         ++n; |         ++n; | ||||||
|         r = strtok_r(NULL, ";", &s); |         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) | int cPluginSatip::ParseSources(const char *valueP, int *sourcesP) | ||||||
| { | { | ||||||
|   debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP); |   debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP); | ||||||
|   int n = 0; |   int n = 0; | ||||||
|   char *s, *p = (char *)valueP; |   char *s, *p = strdup(valueP); | ||||||
|   char *r = strtok_r(p, " ", &s); |   char *r = strtok_r(p, " ", &s); | ||||||
|   while (r) { |   while (r) { | ||||||
|         r = skipspace(r); |         r = skipspace(r); | ||||||
| @@ -246,8 +349,9 @@ int cPluginSatip::ParseSources(const char *valueP, int *sourcesP) | |||||||
|         if (n < MAX_DISABLED_SOURCES_COUNT) { |         if (n < MAX_DISABLED_SOURCES_COUNT) { | ||||||
|            sourcesP[n++] = cSource::FromString(r); |            sourcesP[n++] = cSource::FromString(r); | ||||||
|            } |            } | ||||||
|         r = strtok_r(NULL, " \n", &s); |         r = strtok_r(NULL, " ", &s); | ||||||
|         } |         } | ||||||
|  |   FREE_POINTER(p); | ||||||
|   return n; |   return n; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -259,7 +363,7 @@ int cPluginSatip::ParseFilters(const char *valueP, int *filtersP) | |||||||
|   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); | ||||||
|     debug3(":%s filters[%d]=%d", __PRETTY_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) | ||||||
| @@ -274,11 +378,21 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP) | |||||||
|   // Parse your own setup parameters and store their values. |   // Parse your own setup parameters and store their values. | ||||||
|   if (!strcasecmp(nameP, "OperatingMode")) |   if (!strcasecmp(nameP, "OperatingMode")) | ||||||
|      SatipConfig.SetOperatingMode(atoi(valueP)); |      SatipConfig.SetOperatingMode(atoi(valueP)); | ||||||
|  |   else if (!strcasecmp(nameP, "EnableCIExtension")) | ||||||
|  |      SatipConfig.SetCIExtension(atoi(valueP)); | ||||||
|  |   else if (!strcasecmp(nameP, "CICAM")) { | ||||||
|  |      int Cicams[MAX_CICAM_COUNT]; | ||||||
|  |      for (unsigned int i = 0; i < ELEMENTS(Cicams); ++i) | ||||||
|  |          Cicams[i] = 0; | ||||||
|  |      unsigned int CicamsCount = ParseCicams(valueP, Cicams); | ||||||
|  |      for (unsigned int i = 0; i < CicamsCount; ++i) | ||||||
|  |          SatipConfig.SetCICAM(i, Cicams[i]); | ||||||
|  |      } | ||||||
|   else if (!strcasecmp(nameP, "EnableEITScan")) |   else if (!strcasecmp(nameP, "EnableEITScan")) | ||||||
|      SatipConfig.SetEITScan(atoi(valueP)); |      SatipConfig.SetEITScan(atoi(valueP)); | ||||||
|   else if (!strcasecmp(nameP, "DisabledSources")) { |   else if (!strcasecmp(nameP, "DisabledSources")) { | ||||||
|      int DisabledSources[MAX_DISABLED_SOURCES_COUNT]; |      int DisabledSources[MAX_DISABLED_SOURCES_COUNT]; | ||||||
|      for (unsigned int i = 0; i < ARRAY_SIZE(DisabledSources); ++i) |      for (unsigned int i = 0; i < ELEMENTS(DisabledSources); ++i) | ||||||
|          DisabledSources[i] = cSource::stNone; |          DisabledSources[i] = cSource::stNone; | ||||||
|      unsigned int DisabledSourcesCount = ParseSources(valueP, DisabledSources); |      unsigned int DisabledSourcesCount = ParseSources(valueP, DisabledSources); | ||||||
|      for (unsigned int i = 0; i < DisabledSourcesCount; ++i) |      for (unsigned int i = 0; i < DisabledSourcesCount; ++i) | ||||||
| @@ -286,12 +400,14 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP) | |||||||
|      } |      } | ||||||
|   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; | ||||||
| @@ -321,8 +437,12 @@ const char **cPluginSatip::SVDRPHelpPages(void) | |||||||
|     "    Lists status information of SAT>IP devices.\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" |     "TRAC [ <mode> ]\n" | ||||||
|     "    Gets and/or sets used tracing mode.\n", |     "    Gets and/or sets used tracing mode.\n", | ||||||
|     NULL |     NULL | ||||||
| @@ -389,8 +509,19 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in | |||||||
|      } |      } | ||||||
|   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; | ||||||
| @@ -409,6 +540,16 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in | |||||||
|        } |        } | ||||||
|      return cString::sprintf("SATIP 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) { |   else if (strcasecmp(commandP, "TRAC") == 0) { | ||||||
|      if (optionP && *optionP) |      if (optionP && *optionP) | ||||||
|         SatipConfig.SetTraceMode(strtol(optionP, NULL, 0)); |         SatipConfig.SetTraceMode(strtol(optionP, NULL, 0)); | ||||||
|   | |||||||
| @@ -338,6 +338,19 @@ 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) | ||||||
| { | { | ||||||
|   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM); |   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM); | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
							
								
								
									
										472
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										472
									
								
								server.c
									
									
									
									
									
								
							| @@ -12,23 +12,107 @@ | |||||||
| #include "log.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 unused one | ||||||
|  |   for (cSatipFrontend *f = First(); f; f = Next(f)) { | ||||||
|  |       if (!f->Attached() || (f->DeviceId() == deviceIdP)) { | ||||||
|  |          tmp = f; | ||||||
|  |          break; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |   if (tmp) { | ||||||
|  |      tmp->SetTransponder(transponderP); | ||||||
|  |      return true; | ||||||
|  |      } | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool cSatipFrontends::Attach(int deviceIdP, int transponderP) | ||||||
|  | { | ||||||
|  |   for (cSatipFrontend *f = First(); f; f = Next(f)) { | ||||||
|  |       if (f->Transponder() == transponderP) { | ||||||
|  |          f->Attach(deviceIdP); | ||||||
|  |          debug9("%s (%d, %d) %s/#%d", __PRETTY_FUNCTION__, deviceIdP, transponderP, *f->Description(), f->Index()); | ||||||
|  |          return true; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |   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 (%d, %d) %s/#%d", __PRETTY_FUNCTION__, deviceIdP, transponderP, *f->Description(), f->Index()); | ||||||
|  |          return true; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  |  | ||||||
| // --- cSatipServer ----------------------------------------------------------- | // --- cSatipServer ----------------------------------------------------------- | ||||||
|  |  | ||||||
| cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char *descriptionP) | cSatipServer::cSatipServer(const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP) | ||||||
| : addressM(addressP), | : addressM((addressP && *addressP) ? addressP : "0.0.0.0"), | ||||||
|   modelM(modelP), |   modelM((modelP && *modelP) ? modelP : "DVBS-1"), | ||||||
|   descriptionM(descriptionP), |   filtersM((filtersP && *filtersP) ? filtersP : ""), | ||||||
|   modelTypeM(eSatipModelTypeNone), |   descriptionM(!isempty(descriptionP) ? descriptionP : "MyBrokenHardware"), | ||||||
|   quirkM(eSatipQuirkNone), |   quirksM(""), | ||||||
|   useCountM(0), |   portM(portP), | ||||||
|   transponderM(0), |   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); | ||||||
|   if (!isempty(*descriptionM)) { |      char *r = strtok_r(p, ",", &s); | ||||||
|  |      unsigned int i = 0; | ||||||
|  |      while (r) { | ||||||
|  |            int t = cSource::FromString(skipspace(r)); | ||||||
|  |            if (t && i < ELEMENTS(sourceFiltersM)) | ||||||
|  |               sourceFiltersM[i++] = t; | ||||||
|  |            r = strtok_r(NULL, ",", &s); | ||||||
|  |            } | ||||||
|  |      if (i) { | ||||||
|  |         filtersM = ""; | ||||||
|  |         for (unsigned int j = 0; j < i; ++j) | ||||||
|  |             filtersM = cString::sprintf("%s%s%s", *filtersM, isempty(*filtersM) ? "" : ",", *cSource::ToString(sourceFiltersM[j])); | ||||||
|  |         debug3("%s filters=%s", __PRETTY_FUNCTION__, *filtersM); | ||||||
|  |         } | ||||||
|  |      FREE_POINTER(p); | ||||||
|  |      } | ||||||
|  |   if (!SatipConfig.GetDisableServerQuirks()) { | ||||||
|      // These devices contain a session id bug: |      // These devices contain a session id bug: | ||||||
|      // Inverto Airscreen Server IDL 400 ? |      // Inverto Airscreen Server IDL 400 ? | ||||||
|      // Elgato EyeTV Netstream 4Sat ? |      // Elgato EyeTV Netstream 4Sat ? | ||||||
| @@ -37,56 +121,94 @@ cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char | |||||||
|          strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400 |          strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400 | ||||||
|         ) |         ) | ||||||
|         quirkM |= eSatipQuirkSessionId; |         quirkM |= eSatipQuirkSessionId; | ||||||
|  |      // These devices contain support for RTP over TCP: | ||||||
|  |      if (strstr(*descriptionM, "minisatip") ||          // minisatip server | ||||||
|  |          strstr(*descriptionM, "DVBViewer") ||          // DVBViewer Media Server | ||||||
|  |          strstr(*descriptionM, "GSSBOX") ||             // Grundig Sat Systems GSS.box DSI 400 | ||||||
|  |          strstr(*descriptionM, "DIGIBIT") ||            // Telestar Digibit R1 | ||||||
|  |          strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400 | ||||||
|  |         ) | ||||||
|  |         quirkM |= eSatipQuirkRtpOverTcp; | ||||||
|      // These devices contain a play (add/delpids) parameter bug: |      // These devices contain a play (add/delpids) parameter bug: | ||||||
|      if (strstr(*descriptionM, "fritzdvbc"))            // Fritz!WLAN Repeater DVB-C |      if (strstr(*descriptionM, "fritzdvbc")             // Fritz!WLAN Repeater DVB-C | ||||||
|  |         ) | ||||||
|         quirkM |= eSatipQuirkPlayPids; |         quirkM |= eSatipQuirkPlayPids; | ||||||
|      // These devices contain a frontend locking bug: |      // These devices contain a frontend locking bug: | ||||||
|      if (strstr(*descriptionM, "fritzdvbc"))            // Fritz!WLAN Repeater DVB-C |      if (strstr(*descriptionM, "fritzdvbc") ||            // Fritz!WLAN Repeater DVB-C | ||||||
|  |          strstr(*descriptionM, "Schwaiger Sat>IP Server") // Schwaiger MS41IP | ||||||
|  |         ) | ||||||
|         quirkM |= eSatipQuirkForceLock; |         quirkM |= eSatipQuirkForceLock; | ||||||
|      if (quirkM != eSatipQuirkNone) |      // These devices support the X_PMT protocol extension | ||||||
|         info("Malfunctioning '%s' server detected! Please, fix the firmware.", *descriptionM); |      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, "Triax SatIP Converter") // Triax TSS 400 | ||||||
|  |                                                         // Kathrein ExIP 414/E | ||||||
|  |         ) | ||||||
|  |         quirkM |= eSatipQuirkForcePilot; | ||||||
|  |      } | ||||||
|  |   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::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; |  | ||||||
|            } |            } | ||||||
|         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; |  | ||||||
|            } |            } | ||||||
|         if (strstr(r, "DVBC2")) { |         else if (c = strstr(r, "DVBC-")) { | ||||||
|            modelTypeM |= cSatipServer::eSatipModelTypeDVBC2; |            int count = atoi(c + 5); | ||||||
|            if (char *c = strstr(r, "-")) |            for (int i = 1; i <= count; ++i) | ||||||
|               modelCountM[eSatipModuleDVBC2] = atoi(++c); |                frontendsM[eSatipFrontendDVBC].Add(new cSatipFrontend(i, "DVB-C")); | ||||||
|            else |  | ||||||
|               modelCountM[eSatipModuleDVBC2] = 1; |  | ||||||
|            } |            } | ||||||
|         if (strstr(r, "DVBC")) { |         else if (c = strstr(r, "DVBC2-")) { | ||||||
|            modelTypeM |= cSatipServer::eSatipModelTypeDVBC; |            int count = atoi(c + 6); | ||||||
|            if (char *c = strstr(r, "-")) |            for (int i = 1; i <= count; ++i) | ||||||
|               modelCountM[eSatipModuleDVBC] = atoi(++c); |                frontendsM[eSatipFrontendDVBC2].Add(new cSatipFrontend(i, "DVB-C2")); | ||||||
|            else |  | ||||||
|               modelCountM[eSatipModuleDVBC] = 1; |  | ||||||
|            } |            } | ||||||
|         r = strtok_r(NULL, ",", &s); |         r = strtok_r(NULL, ",", &s); | ||||||
|         } |         } | ||||||
|   free(p); |   FREE_POINTER(p); | ||||||
| } | } | ||||||
|  |  | ||||||
| cSatipServer::~cSatipServer() | cSatipServer::~cSatipServer() | ||||||
| @@ -96,15 +218,124 @@ 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); | ||||||
|  |         } | ||||||
|  |      } | ||||||
|  |   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(); | ||||||
|  |      } | ||||||
|  |   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); | ||||||
|  |         } | ||||||
|  |      } | ||||||
|  |   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(); | ||||||
| } | } | ||||||
|  |  | ||||||
| // --- cSatipServers ---------------------------------------------------------- | // --- cSatipServers ---------------------------------------------------------- | ||||||
| @@ -112,49 +343,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 transponderP, 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) && s->Used() && (s->Transponder() == transponderP)) |       if (s->Matches(sourceP)) | ||||||
|  |          return s; | ||||||
|  |       } | ||||||
|  |   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; |          return s; | ||||||
|       } |       } | ||||||
|   for (cSatipServer *s = First(); s; s = Next(s)) { |   for (cSatipServer *s = First(); s; s = Next(s)) { | ||||||
|       if (s->Match(model)) { |       if (s->IsActive() && s->Assign(deviceIdP, sourceP, systemP, transponderP)) | ||||||
|          result = s; |          return s; | ||||||
|          if (!s->Used()) { |  | ||||||
|             break; |  | ||||||
|             } |  | ||||||
|          } |  | ||||||
|       } |  | ||||||
|   return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void cSatipServers::SetTransponder(cSatipServer *serverP, bool transponderP) |  | ||||||
| { |  | ||||||
|   for (cSatipServer *s = First(); s; s = Next(s)) { |  | ||||||
|       if (s == serverP) { |  | ||||||
|          s->SetTransponder(transponderP); |  | ||||||
|          break; |  | ||||||
|          } |  | ||||||
|       } |       } | ||||||
|  |   return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| cSatipServer *cSatipServers::Update(cSatipServer *serverP) | cSatipServer *cSatipServers::Update(cSatipServer *serverP) | ||||||
| @@ -168,16 +382,60 @@ 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)) { | ||||||
| @@ -188,6 +446,30 @@ void cSatipServers::Cleanup(uint64_t intervalMsP) | |||||||
|       } |       } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | 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 = ""; | ||||||
| @@ -204,7 +486,7 @@ 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()); |       list = cString::sprintf("%s%c %s|%s|%s\n", *list, s->IsActive() ? '+' : '-', s->Address(), s->Model(), s->Description()); | ||||||
|   return list; |   return list; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -213,13 +495,15 @@ 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-S2: qpsk, 8psk, 16apsk, 32apsk |       // DVB-S2: qpsk, 8psk, 16apsk, 32apsk | ||||||
|       count += s->Satellite() * 4; |       count += s->GetModulesDVBS2() * 4; | ||||||
|       // DVB-T2: qpsk, qam16, qam64, qam256 |  | ||||||
|       // DVB-T: qpsk, qam16, qam64 |       // DVB-T: qpsk, qam16, qam64 | ||||||
|       count += s->Terrestrial2() ? s->Terrestrial2() * 4 : s->Terrestrial() * 3; |       count += s->GetModulesDVBT() * 3; | ||||||
|       // DVB-C2: qam16, qam32, qam64, qam128, qam256 |       // DVB-T2: qpsk, qam16, qam64, qam256 | ||||||
|  |       count += s->GetModulesDVBT2() * 4; | ||||||
|       // DVB-C: qam64, qam128, qam256 |       // DVB-C: qam64, qam128, qam256 | ||||||
|       count += s->Cable2() ? s->Cable2() * 5 : s->Cable() * 3; |       count += s->GetModulesDVBC() * 3; | ||||||
|  |       // DVB-C2: qam16, qam32, qam64, qam128, qam256 | ||||||
|  |       count += s->GetModulesDVBC2() * 5; | ||||||
|       } |       } | ||||||
|   return count; |   return count; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										142
									
								
								server.h
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								server.h
									
									
									
									
									
								
							| @@ -8,67 +8,109 @@ | |||||||
| #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, | ||||||
|     eSatipModuleDVBC, |     eSatipFrontendDVBC, | ||||||
|     eSatipModuleDVBC2, |     eSatipFrontendDVBC2, | ||||||
|     eSatipModuleCount |     eSatipFrontendCount | ||||||
|  |   }; | ||||||
|  |   enum { | ||||||
|  |     eSatipMaxSourceFilters = 16 | ||||||
|   }; |   }; | ||||||
|   cString addressM; |   cString addressM; | ||||||
|   cString modelM; |   cString modelM; | ||||||
|  |   cString filtersM; | ||||||
|   cString descriptionM; |   cString descriptionM; | ||||||
|   int modelCountM[eSatipModuleCount]; |   cString quirksM; | ||||||
|   int modelTypeM; |   cSatipFrontends frontendsM[eSatipFrontendCount]; | ||||||
|  |   int sourceFiltersM[eSatipMaxSourceFilters]; | ||||||
|  |   int portM; | ||||||
|   int quirkM; |   int quirkM; | ||||||
|   int useCountM; |   bool hasCiM; | ||||||
|   int transponderM; |   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, | ||||||
|     eSatipQuirkPlayPids  = 0x02, |     eSatipQuirkPlayPids   = 0x02, | ||||||
|     eSatipQuirkForceLock = 0x04, |     eSatipQuirkForceLock  = 0x04, | ||||||
|     eSatipQuirkMask      = 0x0F |     eSatipQuirkRtpOverTcp = 0x08, | ||||||
|  |     eSatipQuirkCiXpmt     = 0x10, | ||||||
|  |     eSatipQuirkCiTnr      = 0x20, | ||||||
|  |     eSatipQuirkForcePilot = 0x40, | ||||||
|  |     eSatipQuirkMask       = 0xFF | ||||||
|   }; |   }; | ||||||
|   enum eSatipModelType { |   cSatipServer(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, |  | ||||||
|     eSatipModelTypeDVBC2 = 0x10, |  | ||||||
|     eSatipModelTypeMask  = 0xFF |  | ||||||
|   }; |  | ||||||
|   cSatipServer(const char *addressP, const char *modelP, const char *descriptionP); |  | ||||||
|   virtual ~cSatipServer(); |   virtual ~cSatipServer(); | ||||||
|   virtual int Compare(const cListObject &listObjectP) const; |   virtual int Compare(const cListObject &listObjectP) const; | ||||||
|   void Use(bool onOffP); |   bool Assign(int deviceIdP, int sourceP, int systemP, int transponderP); | ||||||
|   void SetTransponder(const int transponderP) { transponderM = transponderP; } |   bool Matches(int sourceP); | ||||||
|   int Transponder(void)     { return transponderM; } |   bool Matches(int deviceIdP, int sourceP, int systemP, int transponderP); | ||||||
|   bool Used(void)           { return !!useCountM; } |   void Attach(int deviceIdP, int transponderP); | ||||||
|   const char *Address()     { return *addressM; } |   void Detach(int deviceIdP, int transponderP); | ||||||
|   const char *Model(void)   { return *modelM; } |   int GetModulesDVBS2(void); | ||||||
|   const char *Description() { return *descriptionM; } |   int GetModulesDVBT(void); | ||||||
|   bool Quirk(int quirkP)    { return ((quirkP & eSatipQuirkMask) & quirkM); } |   int GetModulesDVBT2(void); | ||||||
|   int ModelType(void)       { return modelTypeM; } |   int GetModulesDVBC(void); | ||||||
|   bool Match(int modelP)    { return ((modelP & eSatipModelTypeMask) & modelTypeM); } |   int GetModulesDVBC2(void); | ||||||
|   int Cable()               { return Match(eSatipModelTypeDVBC)  ? modelCountM[eSatipModuleDVBC]  : 0; } |   void Activate(bool onOffP)    { activeM = onOffP; } | ||||||
|   int Cable2()              { return Match(eSatipModelTypeDVBC2) ? modelCountM[eSatipModuleDVBC2] : 0; } |   const char *Address(void)     { return *addressM; } | ||||||
|   int Satellite()           { return Match(eSatipModelTypeDVBS2) ? modelCountM[eSatipModuleDVBS2] : 0; } |   const char *Model(void)       { return *modelM; } | ||||||
|   int Terrestrial()         { return Match(eSatipModelTypeDVBT)  ? modelCountM[eSatipModuleDVBT]  : 0; } |   const char *Filters(void)     { return *filtersM; } | ||||||
|   int Terrestrial2()        { return Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : 0; } |   const char *Description(void) { return *descriptionM; } | ||||||
|   void Update(void)         { lastSeenM.Set(); } |   const char *Quirks(void)      { return *quirksM; } | ||||||
|   uint64_t LastSeen(void)   { return lastSeenM.Elapsed(); } |   int Port(void)                { return portM; } | ||||||
|   time_t Created(void)      { return createdM; } |   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 ---------------------------------------------------------- | ||||||
| @@ -76,12 +118,18 @@ 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 transponderP, int systemP); |   cSatipServer *Find(int sourceP); | ||||||
|   void SetTransponder(cSatipServer *serverP, bool transponderP); |   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 GetString(cSatipServer *serverP); |   cString GetString(cSatipServer *serverP); | ||||||
|  |   int GetPort(cSatipServer *serverP); | ||||||
|   cString List(void); |   cString List(void); | ||||||
|   int NumProvidedSystems(void); |   int NumProvidedSystems(void); | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										94
									
								
								setup.c
									
									
									
									
									
								
							
							
						
						
									
										94
									
								
								setup.c
									
									
									
									
									
								
							| @@ -86,23 +86,29 @@ eOSState cSatipEditSrcItem::ProcessKey(eKeys Key) | |||||||
| 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 Server"), 20), | : cOsdMenu(tr("SAT>IP Server"), 20), | ||||||
|  |   serverM(serverP), | ||||||
|  |   activeM(serverP && serverP->IsActive()), | ||||||
|   addressM(serverP ? serverP->Address() : "---"), |   addressM(serverP ? serverP->Address() : "---"), | ||||||
|   modelM(serverP ? serverP->Model() : "---"), |   modelM(serverP ? serverP->Model() : "---"), | ||||||
|   descriptionM(serverP ? serverP->Description() : "---"), |   descriptionM(serverP ? serverP->Description() : "---"), | ||||||
|  |   ciExtensionM(serverP && serverP->HasCI() ? trVDR("yes") : trVDR("no")), | ||||||
|   createdM(serverP ? serverP->Created() : 0) |   createdM(serverP ? serverP->Created() : 0) | ||||||
| { | { | ||||||
|   SetMenuCategory(mcSetupPlugins); |   SetMenuCategory(mcSetupPlugins); | ||||||
| @@ -116,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) { | ||||||
| @@ -132,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; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -142,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); | ||||||
|   }; |   }; | ||||||
| @@ -152,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() ? "+" : "-", 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) | ||||||
| @@ -327,8 +342,11 @@ 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()), | ||||||
|   eitScanM(SatipConfig.GetEITScan()), |   eitScanM(SatipConfig.GetEITScan()), | ||||||
|   numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()), |   numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()), | ||||||
|   numDisabledFiltersM(SatipConfig.GetDisabledFiltersCount()) |   numDisabledFiltersM(SatipConfig.GetDisabledFiltersCount()) | ||||||
| @@ -338,6 +356,13 @@ cSatipPluginSetup::cSatipPluginSetup() | |||||||
|   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) |   if (numDisabledSourcesM > MAX_DISABLED_SOURCES_COUNT) | ||||||
|      numDisabledSourcesM = MAX_DISABLED_SOURCES_COUNT; |      numDisabledSourcesM = MAX_DISABLED_SOURCES_COUNT; | ||||||
|   for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i) |   for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i) | ||||||
| @@ -364,6 +389,14 @@ 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.")); | ||||||
|  |  | ||||||
| @@ -383,15 +416,20 @@ void cSatipPluginSetup::Setup(void) | |||||||
|          helpM.Append(tr("Define an ill-behaving filter to be blacklisted.")); |          helpM.Append(tr("Define an ill-behaving filter to be blacklisted.")); | ||||||
|          } |          } | ||||||
|      } |      } | ||||||
|  |   Add(new cMenuEditStraItem(tr("Transport mode"), &transportModeM, ELEMENTS(transportModeTextsM), transportModeTextsM)); | ||||||
|  |   helpM.Append(tr("Define which transport mode shall be used.\n\nUnicast, Multicast, RTP-over-TCP")); | ||||||
|   Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false)); |   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(); | ||||||
| @@ -440,14 +478,17 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP) | |||||||
| { | { | ||||||
|   bool hadSubMenu = HasSubMenu(); |   bool hadSubMenu = HasSubMenu(); | ||||||
|   int oldOperatingMode = operatingModeM; |   int oldOperatingMode = operatingModeM; | ||||||
|  |   int oldCiExtension = ciExtensionM; | ||||||
|   int oldNumDisabledSources = numDisabledSourcesM; |   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) { | ||||||
| @@ -463,7 +504,7 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP) | |||||||
|   if ((keyP == kNone) && (cSatipDiscover::GetInstance()->GetServers()->Count() != deviceCountM)) |   if ((keyP == kNone) && (cSatipDiscover::GetInstance()->GetServers()->Count() != deviceCountM)) | ||||||
|      Setup(); |      Setup(); | ||||||
|  |  | ||||||
|   if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode))) { |   if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode) || (ciExtensionM != oldCiExtension) || (detachedModeM != SatipConfig.GetDetachedMode()))) { | ||||||
|      while ((numDisabledSourcesM < oldNumDisabledSources) && (oldNumDisabledSources > 0)) |      while ((numDisabledSourcesM < oldNumDisabledSources) && (oldNumDisabledSources > 0)) | ||||||
|            disabledSourcesM[--oldNumDisabledSources] = cSource::stNone; |            disabledSourcesM[--oldNumDisabledSources] = cSource::stNone; | ||||||
|      while ((numDisabledFiltersM < oldNumDisabledFilters) && (oldNumDisabledFilters > 0)) |      while ((numDisabledFiltersM < oldNumDisabledFilters) && (oldNumDisabledFilters > 0)) | ||||||
| @@ -474,6 +515,22 @@ 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) | void cSatipPluginSetup::StoreSources(const char *nameP, int *sourcesP) | ||||||
| { | { | ||||||
|   cString buffer = ""; |   cString buffer = ""; | ||||||
| @@ -486,7 +543,7 @@ void cSatipPluginSetup::StoreSources(const char *nameP, int *sourcesP) | |||||||
|       else |       else | ||||||
|          buffer = cString::sprintf("%s", *cSource::ToString(sourcesP[i])); |          buffer = cString::sprintf("%s", *cSource::ToString(sourcesP[i])); | ||||||
|       } |       } | ||||||
|   debug1("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer); |   debug3("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer); | ||||||
|   SetupStore(nameP, *buffer); |   SetupStore(nameP, *buffer); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -502,7 +559,7 @@ void cSatipPluginSetup::StoreFilters(const char *nameP, int *valuesP) | |||||||
|       else |       else | ||||||
|          buffer = cString::sprintf("%d", valuesP[i]); |          buffer = cString::sprintf("%d", valuesP[i]); | ||||||
|       } |       } | ||||||
|   debug1("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer); |   debug3("%s (%s, %s)", __PRETTY_FUNCTION__, nameP, *buffer); | ||||||
|   SetupStore(nameP, *buffer); |   SetupStore(nameP, *buffer); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -510,12 +567,19 @@ 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("EnableEITScan", eitScanM); |   SetupStore("EnableEITScan", eitScanM); | ||||||
|  |   StoreCicams("CICAM", cicamsM); | ||||||
|   StoreSources("DisabledSources", disabledSourcesM); |   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) |   for (int i = 0; i < MAX_DISABLED_SOURCES_COUNT; ++i) | ||||||
|       SatipConfig.SetDisabledSources(i, disabledSourcesM[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) | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								setup.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								setup.h
									
									
									
									
									
								
							| @@ -15,9 +15,15 @@ | |||||||
| 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 cicamsM[MAX_CICAM_COUNT]; | ||||||
|  |   const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE]; | ||||||
|   int eitScanM; |   int eitScanM; | ||||||
|   int numDisabledSourcesM; |   int numDisabledSourcesM; | ||||||
|   int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT]; |   int disabledSourcesM[MAX_DISABLED_SOURCES_COUNT]; | ||||||
| @@ -31,6 +37,7 @@ private: | |||||||
|   eOSState ShowDeviceStatus(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 StoreSources(const char *nameP, int *sourcesP); | ||||||
|   void StoreFilters(const char *nameP, int *valuesP); |   void StoreFilters(const char *nameP, int *valuesP); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										178
									
								
								socket.c
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								socket.c
									
									
									
									
									
								
							| @@ -21,7 +21,11 @@ | |||||||
|  |  | ||||||
| cSatipSocket::cSatipSocket() | cSatipSocket::cSatipSocket() | ||||||
| : socketPortM(0), | : socketPortM(0), | ||||||
|   socketDescM(-1) |   socketDescM(-1), | ||||||
|  |   isMulticastM(false), | ||||||
|  |   useSsmM(false), | ||||||
|  |   streamAddrM(htonl(INADDR_ANY)), | ||||||
|  |   sourceAddrM(htonl(INADDR_ANY)) | ||||||
| { | { | ||||||
|   debug1("%s", __PRETTY_FUNCTION__); |   debug1("%s", __PRETTY_FUNCTION__); | ||||||
|   memset(&sockAddrM, 0, sizeof(sockAddrM)); |   memset(&sockAddrM, 0, sizeof(sockAddrM)); | ||||||
| @@ -34,10 +38,17 @@ cSatipSocket::~cSatipSocket() | |||||||
|   Close(); |   Close(); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool cSatipSocket::Open(const int portP) | bool cSatipSocket::Open(const int portP, const bool reuseP) | ||||||
| { | { | ||||||
|  |   // 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); | ||||||
| @@ -46,9 +57,19 @@ 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__ | ||||||
|      // Bind socket |      // Bind socket | ||||||
|      memset(&sockAddrM, 0, sizeof(sockAddrM)); |      memset(&sockAddrM, 0, sizeof(sockAddrM)); | ||||||
|      sockAddrM.sin_family = AF_INET; |      sockAddrM.sin_family = AF_INET; | ||||||
| @@ -57,23 +78,41 @@ 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); |   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) | ||||||
| { | { | ||||||
|   debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM); |   debug1("%s sockerPort=%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; | ||||||
|      memset(&sockAddrM, 0, sizeof(sockAddrM)); |      memset(&sockAddrM, 0, sizeof(sockAddrM)); | ||||||
|  |      streamAddrM = htonl(INADDR_ANY); | ||||||
|  |      sourceAddrM = htonl(INADDR_ANY); | ||||||
|  |      isMulticastM = false; | ||||||
|  |      useSsmM = false; | ||||||
|      } |      } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -96,6 +135,96 @@ 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) | ||||||
| { | { | ||||||
|   debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP); |   debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP); | ||||||
| @@ -126,21 +255,41 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP) | |||||||
|  |  | ||||||
|     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__ | ||||||
|  |        if (isMulticastM) { | ||||||
|  |           // Process auxiliary received data and validate source address | ||||||
|  |           for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { | ||||||
|  |               if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { | ||||||
|  |                  struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg); | ||||||
|  |                  if ((i->ipi_addr.s_addr == streamAddrM) || (htonl(INADDR_ANY) == streamAddrM)) | ||||||
|  |                     return len; | ||||||
|  |                  } | ||||||
|  |               } | ||||||
|  |           } | ||||||
|  |        else | ||||||
|  | #endif // __FreeBSD__ | ||||||
|  |           return len; | ||||||
|  |        } | ||||||
|     } while (len > 0); |     } while (len > 0); | ||||||
|   ERROR_IF_RET(len < 0 && errno != EAGAIN, "recvmsg()", return -1); |   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) | int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRecvSizeP, unsigned int elementCountP, unsigned int elementBufferSizeP) | ||||||
| { | { | ||||||
|   debug16("%s (, , %d, %d)", __PRETTY_FUNCTION__, elementCountP, elementBufferSizeP); |   debug16("%s (, , %d, %d)", __PRETTY_FUNCTION__, elementCountP, elementBufferSizeP); | ||||||
|  |   int count = -1; | ||||||
|   // Error out if socket not initialized |   // Error out if socket not initialized | ||||||
|   if (socketDescM <= 0) { |   if (socketDescM <= 0) { | ||||||
|      error("%s Invalid socket", __PRETTY_FUNCTION__); |      error("%s Invalid socket", __PRETTY_FUNCTION__); | ||||||
|      return -1; |      return -1; | ||||||
|      } |      } | ||||||
|  |   if (!bufferAddrP || !elementRecvSizeP || !elementCountP || !elementBufferSizeP) { | ||||||
|  |      error("%s Invalid parameter(s)", __PRETTY_FUNCTION__); | ||||||
|  |      return -1; | ||||||
|  |      } | ||||||
|  | #if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,12) | ||||||
|   // Initialize iov and msgh structures |   // Initialize iov and msgh structures | ||||||
|   struct mmsghdr mmsgh[elementCountP]; |   struct mmsghdr mmsgh[elementCountP]; | ||||||
|   struct iovec iov[elementCountP]; |   struct iovec iov[elementCountP]; | ||||||
| @@ -153,12 +302,21 @@ int cSatipSocket::ReadMulti(unsigned char *bufferAddrP, unsigned int *elementRec | |||||||
|       } |       } | ||||||
|  |  | ||||||
|   // Read data from socket as a set |   // Read data from socket as a set | ||||||
|   int count = -1; |   count = (int)recvmmsg(socketDescM, mmsgh, elementCountP, MSG_DONTWAIT, NULL); | ||||||
|   if (socketDescM && bufferAddrP && elementRecvSizeP && (elementCountP > 0) && (elementBufferSizeP > 0)) |  | ||||||
|      count = (int)recvmmsg(socketDescM, mmsgh, elementCountP, MSG_DONTWAIT, NULL); |  | ||||||
|   ERROR_IF_RET(count < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmmsg()", return -1); |   ERROR_IF_RET(count < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmmsg()", return -1); | ||||||
|   for (int i = 0; i < count; ++i) |   for (int i = 0; i < count; ++i) | ||||||
|       elementRecvSizeP[i] = mmsgh[i].msg_len; |       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]); |   debug16("%s Received %d packets size[0]=%d", __PRETTY_FUNCTION__, count, elementRecvSizeP[0]); | ||||||
|  |  | ||||||
|   return count; |   return count; | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								socket.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								socket.h
									
									
									
									
									
								
							| @@ -15,14 +15,23 @@ private: | |||||||
|   int socketPortM; |   int socketPortM; | ||||||
|   int socketDescM; |   int socketDescM; | ||||||
|   struct sockaddr_in sockAddrM; |   struct sockaddr_in sockAddrM; | ||||||
|  |   bool isMulticastM; | ||||||
|  |   bool useSsmM; | ||||||
|  |   in_addr_t streamAddrM; | ||||||
|  |   in_addr_t sourceAddrM; | ||||||
|  |   bool CheckAddress(const char *addrP, in_addr_t *inAddrP); | ||||||
|  |   bool Join(void); | ||||||
|  |   bool Leave(void); | ||||||
|  |  | ||||||
| public: | public: | ||||||
|   cSatipSocket(); |   cSatipSocket(); | ||||||
|   virtual ~cSatipSocket(); |   virtual ~cSatipSocket(); | ||||||
|   bool Open(const int portP = 0); |   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); |   virtual void Close(void); | ||||||
|   int Fd(void) { return socketDescM; } |   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); | ||||||
|   | |||||||
							
								
								
									
										192
									
								
								tuner.c
									
									
									
									
									
								
							
							
						
						
									
										192
									
								
								tuner.c
									
									
									
									
									
								
							| @@ -25,8 +25,10 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP) | |||||||
|   rtcpM(*this), |   rtcpM(*this), | ||||||
|   streamAddrM(""), |   streamAddrM(""), | ||||||
|   streamParamM(""), |   streamParamM(""), | ||||||
|   currentServerM(NULL), |   tnrParamM(""), | ||||||
|   nextServerM(NULL), |   streamPortM(SATIP_DEFAULT_RTSP_PORT), | ||||||
|  |   currentServerM(NULL, deviceP.GetId(), 0), | ||||||
|  |   nextServerM(NULL, deviceP.GetId(), 0), | ||||||
|   mutexM(), |   mutexM(), | ||||||
|   reConnectM(), |   reConnectM(), | ||||||
|   keepAliveM(), |   keepAliveM(), | ||||||
| @@ -40,7 +42,9 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP) | |||||||
|   hasLockM(false), |   hasLockM(false), | ||||||
|   signalStrengthM(-1), |   signalStrengthM(-1), | ||||||
|   signalQualityM(-1), |   signalQualityM(-1), | ||||||
|  |   frontendIdM(-1), | ||||||
|   streamIdM(-1), |   streamIdM(-1), | ||||||
|  |   pmtPidM(-1), | ||||||
|   addPidsM(), |   addPidsM(), | ||||||
|   delPidsM(), |   delPidsM(), | ||||||
|   pidsM() |   pidsM() | ||||||
| @@ -48,12 +52,16 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP) | |||||||
|   debug1("%s (, %d) [device %d]", __PRETTY_FUNCTION__, packetLenP, deviceIdM); |   debug1("%s (, %d) [device %d]", __PRETTY_FUNCTION__, packetLenP, deviceIdM); | ||||||
|  |  | ||||||
|   // Open sockets |   // Open sockets | ||||||
|   int i = 100; |   int i = SatipConfig.GetPortRangeStart() ? SatipConfig.GetPortRangeStop() - SatipConfig.GetPortRangeStart() - 1 : 100; | ||||||
|  |   int port = SatipConfig.GetPortRangeStart(); | ||||||
|   while (i-- > 0) { |   while (i-- > 0) { | ||||||
|         if (rtpM.Open(0) && rtcpM.Open(rtpM.Port() + 1)) |         // RTP must use an even port number | ||||||
|  |         if (rtpM.Open(port) && (rtpM.Port() % 2 == 0) && rtcpM.Open(rtpM.Port() + 1)) | ||||||
|            break; |            break; | ||||||
|         rtpM.Close(); |         rtpM.Close(); | ||||||
|         rtcpM.Close(); |         rtcpM.Close(); | ||||||
|  |         if (SatipConfig.GetPortRangeStart()) | ||||||
|  |            port += 2; | ||||||
|         } |         } | ||||||
|   if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) { |   if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) { | ||||||
|      error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM); |      error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM); | ||||||
| @@ -89,6 +97,10 @@ cSatipTuner::~cSatipTuner() | |||||||
| void cSatipTuner::Action(void) | void cSatipTuner::Action(void) | ||||||
| { | { | ||||||
|   debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIdM); |   debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|  |  | ||||||
|  |   bool lastIdleStatus = false; | ||||||
|  |   cTimeMs idleCheck(eIdleCheckTimeoutMs); | ||||||
|  |   cTimeMs tuning(eTuningTimeoutMs); | ||||||
|   reConnectM.Set(eConnectTimeoutMs); |   reConnectM.Set(eConnectTimeoutMs); | ||||||
|   // Do the thread loop |   // Do the thread loop | ||||||
|   while (Running()) { |   while (Running()) { | ||||||
| @@ -105,6 +117,7 @@ void cSatipTuner::Action(void) | |||||||
|           case tsSet: |           case tsSet: | ||||||
|                debug4("%s: tsSet [device %d]", __PRETTY_FUNCTION__, deviceIdM); |                debug4("%s: tsSet [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|                if (Connect()) { |                if (Connect()) { | ||||||
|  |                   tuning.Set(eTuningTimeoutMs); | ||||||
|                   RequestState(tsTuned, smInternal); |                   RequestState(tsTuned, smInternal); | ||||||
|                   UpdatePids(true); |                   UpdatePids(true); | ||||||
|                   } |                   } | ||||||
| @@ -114,10 +127,12 @@ void cSatipTuner::Action(void) | |||||||
|           case tsTuned: |           case tsTuned: | ||||||
|                debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM); |                debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|                reConnectM.Set(eConnectTimeoutMs); |                reConnectM.Set(eConnectTimeoutMs); | ||||||
|  |                idleCheck.Set(eIdleCheckTimeoutMs); | ||||||
|  |                lastIdleStatus = false; | ||||||
|                // Read reception statistics via DESCRIBE and RTCP |                // Read reception statistics via DESCRIBE and RTCP | ||||||
|                if (hasLockM || ReadReceptionStatus()) { |                if (hasLockM || ReadReceptionStatus()) { | ||||||
|                   // Quirk for devices without valid reception data |                   // Quirk for devices without valid reception data | ||||||
|                   if (currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkForceLock)) { |                   if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkForceLock)) { | ||||||
|                      hasLockM = true; |                      hasLockM = true; | ||||||
|                      signalStrengthM = eDefaultSignalStrength; |                      signalStrengthM = eDefaultSignalStrength; | ||||||
|                      signalQualityM = eDefaultSignalQuality; |                      signalQualityM = eDefaultSignalQuality; | ||||||
| @@ -125,6 +140,10 @@ void cSatipTuner::Action(void) | |||||||
|                   if (hasLockM) |                   if (hasLockM) | ||||||
|                      RequestState(tsLocked, smInternal); |                      RequestState(tsLocked, smInternal); | ||||||
|                   } |                   } | ||||||
|  |                else if (tuning.TimedOut()) { | ||||||
|  |                   error("Tuning timeout - retuning [device %d]", deviceIdM); | ||||||
|  |                   RequestState(tsSet, smInternal); | ||||||
|  |                   } | ||||||
|                break; |                break; | ||||||
|           case tsLocked: |           case tsLocked: | ||||||
|                debug4("%s: tsLocked [device %d]", __PRETTY_FUNCTION__, deviceIdM); |                debug4("%s: tsLocked [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
| @@ -143,6 +162,16 @@ void cSatipTuner::Action(void) | |||||||
|                   RequestState(tsSet, smInternal); |                   RequestState(tsSet, smInternal); | ||||||
|                   break; |                   break; | ||||||
|                   } |                   } | ||||||
|  |                if (idleCheck.TimedOut()) { | ||||||
|  |                   bool currentIdleStatus = deviceM->IsIdle(); | ||||||
|  |                   if (lastIdleStatus && currentIdleStatus) { | ||||||
|  |                      info("Idle timeout - releasing [device %d]", deviceIdM); | ||||||
|  |                      RequestState(tsRelease, smInternal); | ||||||
|  |                      } | ||||||
|  |                   lastIdleStatus = currentIdleStatus; | ||||||
|  |                   idleCheck.Set(eIdleCheckTimeoutMs); | ||||||
|  |                   break; | ||||||
|  |                   } | ||||||
|                break; |                break; | ||||||
|           default: |           default: | ||||||
|                error("Unknown tuner status %d [device %d]", currentStateM, deviceIdM); |                error("Unknown tuner status %d [device %d]", currentStateM, deviceIdM); | ||||||
| @@ -182,12 +211,11 @@ bool cSatipTuner::Connect(void) | |||||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); |   debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|  |  | ||||||
|   if (!isempty(*streamAddrM)) { |   if (!isempty(*streamAddrM)) { | ||||||
|      cString connectionUri = cString::sprintf("rtsp://%s/", *streamAddrM); |      cString connectionUri = GetBaseUrl(*streamAddrM, streamPortM); | ||||||
|  |      tnrParamM = ""; | ||||||
|      // Just retune |      // Just retune | ||||||
|      if (streamIdM >= 0) { |      if (streamIdM >= 0) { | ||||||
|         cString uri = cString::sprintf("%sstream=%d?%s", *connectionUri, streamIdM, *streamParamM); |         cString uri = cString::sprintf("%sstream=%d?%s", *connectionUri, streamIdM, *streamParamM); | ||||||
|         //if (pidsM.Size()) |  | ||||||
|         //   uri = cString::sprintf("%s&pids=%s", *uri, *pidsM.ListPids()); |  | ||||||
|         debug1("%s Retuning [device %d]", __PRETTY_FUNCTION__, deviceIdM); |         debug1("%s Retuning [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|         if (rtspM.Play(*uri)) { |         if (rtspM.Play(*uri)) { | ||||||
|            keepAliveM.Set(timeoutM); |            keepAliveM.Set(timeoutM); | ||||||
| @@ -196,21 +224,21 @@ bool cSatipTuner::Connect(void) | |||||||
|         } |         } | ||||||
|      else if (rtspM.Options(*connectionUri)) { |      else if (rtspM.Options(*connectionUri)) { | ||||||
|         cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM); |         cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM); | ||||||
|  |         bool useTcp = SatipConfig.IsTransportModeRtpOverTcp() && nextServerM.IsValid() && nextServerM.IsQuirk(cSatipServer::eSatipQuirkRtpOverTcp); | ||||||
|         // Flush any old content |         // Flush any old content | ||||||
|         rtpM.Flush(); |         //rtpM.Flush(); | ||||||
|         rtcpM.Flush(); |         //rtcpM.Flush(); | ||||||
|         if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port())) { |         if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port(), useTcp)) { | ||||||
|            keepAliveM.Set(timeoutM); |            keepAliveM.Set(timeoutM); | ||||||
|            if (nextServerM) { |            if (nextServerM.IsValid()) { | ||||||
|               cSatipDiscover::GetInstance()->UseServer(nextServerM, true); |  | ||||||
|               currentServerM = nextServerM; |               currentServerM = nextServerM; | ||||||
|               nextServerM = NULL; |               nextServerM.Reset(); | ||||||
|               } |               } | ||||||
|  |            currentServerM.Attach(); | ||||||
|            return true; |            return true; | ||||||
|            } |            } | ||||||
|         } |         } | ||||||
|      else |      rtspM.Reset(); | ||||||
|         rtspM.Reset(); |  | ||||||
|      streamIdM = -1; |      streamIdM = -1; | ||||||
|      error("Connect failed [device %d]", deviceIdM); |      error("Connect failed [device %d]", deviceIdM); | ||||||
|      } |      } | ||||||
| @@ -224,8 +252,10 @@ bool cSatipTuner::Disconnect(void) | |||||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); |   debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|  |  | ||||||
|   if (!isempty(*streamAddrM) && (streamIdM >= 0)) { |   if (!isempty(*streamAddrM) && (streamIdM >= 0)) { | ||||||
|      cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); |      cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM); | ||||||
|      rtspM.Teardown(*uri); |      rtspM.Teardown(*uri); | ||||||
|  |      // some devices requires a teardown for TCP connection also | ||||||
|  |      rtspM.Reset(); | ||||||
|      streamIdM = -1; |      streamIdM = -1; | ||||||
|      } |      } | ||||||
|  |  | ||||||
| @@ -233,11 +263,12 @@ bool cSatipTuner::Disconnect(void) | |||||||
|   hasLockM = false; |   hasLockM = false; | ||||||
|   signalStrengthM = -1; |   signalStrengthM = -1; | ||||||
|   signalQualityM = -1; |   signalQualityM = -1; | ||||||
|  |   frontendIdM = -1; | ||||||
|  |  | ||||||
|   if (currentServerM) |   currentServerM.Detach(); | ||||||
|      cSatipDiscover::GetInstance()->UseServer(currentServerM, false); |  | ||||||
|   statusUpdateM.Set(0); |   statusUpdateM.Set(0); | ||||||
|   timeoutM = eMinKeepAliveIntervalMs; |   timeoutM = eMinKeepAliveIntervalMs; | ||||||
|  |   pmtPidM = -1; | ||||||
|   addPidsM.Clear(); |   addPidsM.Clear(); | ||||||
|   delPidsM.Clear(); |   delPidsM.Clear(); | ||||||
|  |  | ||||||
| @@ -266,6 +297,11 @@ void cSatipTuner::ProcessVideoData(u_char *bufferP, int lengthP) | |||||||
|   reConnectM.Set(eConnectTimeoutMs); |   reConnectM.Set(eConnectTimeoutMs); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void cSatipTuner::ProcessRtpData(u_char *bufferP, int lengthP) | ||||||
|  | { | ||||||
|  |   rtpM.Process(bufferP, lengthP); | ||||||
|  | } | ||||||
|  |  | ||||||
| void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) | void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) | ||||||
| { | { | ||||||
|   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM); |   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM); | ||||||
| @@ -283,6 +319,9 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) | |||||||
|      if (c)  { |      if (c)  { | ||||||
|         int value; |         int value; | ||||||
|  |  | ||||||
|  |         // feID: | ||||||
|  |         frontendIdM = atoi(c + 7); | ||||||
|  |  | ||||||
|         // level: |         // level: | ||||||
|         // Numerical value between 0 and 255 |         // Numerical value between 0 and 255 | ||||||
|         // An incoming L-band satellite signal of |         // An incoming L-band satellite signal of | ||||||
| @@ -290,7 +329,7 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) | |||||||
|         // -65dBm corresponds to 32 |         // -65dBm corresponds to 32 | ||||||
|         // No signal corresponds to 0 |         // No signal corresponds to 0 | ||||||
|         c = strstr(c, ","); |         c = strstr(c, ","); | ||||||
|         value = atoi(++c); |         value = min(atoi(++c), 255); | ||||||
|         // Scale value to 0-100 |         // Scale value to 0-100 | ||||||
|         signalStrengthM = (value >= 0) ? (value * 100 / 255) : -1; |         signalStrengthM = (value >= 0) ? (value * 100 / 255) : -1; | ||||||
|  |  | ||||||
| @@ -308,7 +347,7 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) | |||||||
|         // -a BER lower than 2x10-4 after Viterbi for DVB-S |         // -a BER lower than 2x10-4 after Viterbi for DVB-S | ||||||
|         // -a PER lower than 10-7 for DVB-S2 |         // -a PER lower than 10-7 for DVB-S2 | ||||||
|         c = strstr(c, ","); |         c = strstr(c, ","); | ||||||
|         value = atoi(++c); |         value = min(atoi(++c), 15); | ||||||
|         // Scale value to 0-100 |         // Scale value to 0-100 | ||||||
|         signalQualityM = (hasLockM && (value >= 0)) ? (value * 100 / 15) : 0; |         signalQualityM = (hasLockM && (value >= 0)) ? (value * 100 / 15) : 0; | ||||||
|         } |         } | ||||||
| @@ -316,6 +355,11 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) | |||||||
|   reConnectM.Set(eConnectTimeoutMs); |   reConnectM.Set(eConnectTimeoutMs); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void cSatipTuner::ProcessRtcpData(u_char *bufferP, int lengthP) | ||||||
|  | { | ||||||
|  |   rtcpM.Process(bufferP, lengthP); | ||||||
|  | } | ||||||
|  |  | ||||||
| void cSatipTuner::SetStreamId(int streamIdP) | void cSatipTuner::SetStreamId(int streamIdP) | ||||||
| { | { | ||||||
|   cMutexLock MutexLock(&mutexM); |   cMutexLock MutexLock(&mutexM); | ||||||
| @@ -328,27 +372,72 @@ void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP) | |||||||
|   cMutexLock MutexLock(&mutexM); |   cMutexLock MutexLock(&mutexM); | ||||||
|   debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, sessionP, timeoutP, deviceIdM); |   debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, sessionP, timeoutP, deviceIdM); | ||||||
|   sessionM = sessionP; |   sessionM = sessionP; | ||||||
|   if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0")) |   if (nextServerM.IsQuirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0")) | ||||||
|      rtspM.SetSession(SkipZeroes(*sessionM)); |      rtspM.SetSession(SkipZeroes(*sessionM)); | ||||||
|   timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs; |   timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void cSatipTuner::SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP) | ||||||
|  | { | ||||||
|  |   cMutexLock MutexLock(&mutexM); | ||||||
|  |   debug1("%s (%d, %d, %s, %s) [device %d]", __PRETTY_FUNCTION__, rtpPortP, rtcpPortP, streamAddrP, sourceAddrP, deviceIdM); | ||||||
|  |   bool multicast = !isempty(streamAddrP); | ||||||
|  |   // Adapt RTP to any transport media change | ||||||
|  |   if (multicast != rtpM.IsMulticast() || rtpPortP != rtpM.Port()) { | ||||||
|  |      cSatipPoller::GetInstance()->Unregister(rtpM); | ||||||
|  |      rtpM.Close(); | ||||||
|  |      if (rtpPortP >= 0) { | ||||||
|  |         if (multicast) | ||||||
|  |            rtpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP); | ||||||
|  |         else | ||||||
|  |            rtpM.Open(rtpPortP); | ||||||
|  |         cSatipPoller::GetInstance()->Register(rtpM); | ||||||
|  |         } | ||||||
|  |      } | ||||||
|  |   // Adapt RTCP to any transport media change | ||||||
|  |   if (multicast != rtcpM.IsMulticast() || rtcpPortP != rtcpM.Port()) { | ||||||
|  |      cSatipPoller::GetInstance()->Unregister(rtcpM); | ||||||
|  |      rtcpM.Close(); | ||||||
|  |      if (rtcpPortP >= 0) { | ||||||
|  |         if (multicast) | ||||||
|  |            rtcpM.OpenMulticast(rtpPortP, streamAddrP, sourceAddrP); | ||||||
|  |         else | ||||||
|  |            rtcpM.Open(rtpPortP); | ||||||
|  |         cSatipPoller::GetInstance()->Register(rtcpM); | ||||||
|  |         } | ||||||
|  |      } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | cString cSatipTuner::GetBaseUrl(const char *addressP, const int portP) | ||||||
|  | { | ||||||
|  |   debug16("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, addressP, portP, deviceIdM); | ||||||
|  |  | ||||||
|  |   if (portP != SATIP_DEFAULT_RTSP_PORT) | ||||||
|  |      return cString::sprintf("rtsp://%s:%d/", addressP, portP); | ||||||
|  |  | ||||||
|  |   return cString::sprintf("rtsp://%s/", addressP); | ||||||
|  | } | ||||||
|  |  | ||||||
| int cSatipTuner::GetId(void) | int cSatipTuner::GetId(void) | ||||||
| { | { | ||||||
|   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); |   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|   return deviceIdM; |   return deviceIdM; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const int indexP) | bool cSatipTuner::SetSource(cSatipServer *serverP, const int transponderP, const char *parameterP, const int indexP) | ||||||
| { | { | ||||||
|   debug1("%s (%s, %d) [device %d]", __PRETTY_FUNCTION__, parameterP, indexP, deviceIdM); |   debug1("%s (%d, %s, %d) [device %d]", __PRETTY_FUNCTION__, transponderP, parameterP, indexP, deviceIdM); | ||||||
|   cMutexLock MutexLock(&mutexM); |   cMutexLock MutexLock(&mutexM); | ||||||
|   if (serverP) { |   if (serverP) { | ||||||
|      nextServerM = cSatipDiscover::GetInstance()->GetServer(serverP); |      nextServerM.Set(serverP, transponderP); | ||||||
|      if (nextServerM && !isempty(nextServerM->Address()) && !isempty(parameterP)) { |      if (!isempty(*nextServerM.GetAddress()) && !isempty(parameterP)) { | ||||||
|         // Update stream address and parameter |         // Update stream address and parameter | ||||||
|         streamAddrM = rtspM.RtspUnescapeString(nextServerM->Address()); |         streamAddrM = rtspM.RtspUnescapeString(*nextServerM.GetAddress()); | ||||||
|         streamParamM = rtspM.RtspUnescapeString(parameterP); |         streamParamM = rtspM.RtspUnescapeString(parameterP); | ||||||
|  |         streamPortM = nextServerM.GetPort(); | ||||||
|  |         // Modify parameter if required | ||||||
|  |         if (nextServerM.IsQuirk(cSatipServer::eSatipQuirkForcePilot) && strstr(parameterP, "msys=dvbs2") && !strstr(parameterP, "plts=")) | ||||||
|  |            streamParamM = rtspM.RtspUnescapeString(*cString::sprintf("%s&plts=on", parameterP)); | ||||||
|         // Reconnect |         // Reconnect | ||||||
|         RequestState(tsSet, smExternal); |         RequestState(tsSet, smExternal); | ||||||
|         } |         } | ||||||
| @@ -375,8 +464,7 @@ bool cSatipTuner::SetPid(int pidP, int typeP, bool onP) | |||||||
|      delPidsM.AddPid(pidP); |      delPidsM.AddPid(pidP); | ||||||
|      addPidsM.RemovePid(pidP); |      addPidsM.RemovePid(pidP); | ||||||
|      } |      } | ||||||
|   debug9("%s (%d, %d, %d) pids=%s [device %d]", __PRETTY_FUNCTION__, pidP, typeP, onP, *pidsM.ListPids(), deviceIdM); |   debug12("%s (%d, %d, %d) pids=%s [device %d]", __PRETTY_FUNCTION__, pidP, typeP, onP, *pidsM.ListPids(), deviceIdM); | ||||||
|   pidUpdateCacheM.Set(ePidUpdateIntervalMs); |  | ||||||
|   sleepM.Signal(); |   sleepM.Signal(); | ||||||
|  |  | ||||||
|   return true; |   return true; | ||||||
| @@ -388,8 +476,9 @@ bool cSatipTuner::UpdatePids(bool forceP) | |||||||
|   cMutexLock MutexLock(&mutexM); |   cMutexLock MutexLock(&mutexM); | ||||||
|   if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) && |   if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) && | ||||||
|       !isempty(*streamAddrM) && (streamIdM > 0)) { |       !isempty(*streamAddrM) && (streamIdM > 0)) { | ||||||
|      cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); |      cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM); | ||||||
|      bool usedummy = !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkPlayPids)); |      bool useci = (SatipConfig.GetCIExtension() && currentServerM.HasCI()); | ||||||
|  |      bool usedummy = currentServerM.IsQuirk(cSatipServer::eSatipQuirkPlayPids); | ||||||
|      if (forceP || usedummy) { |      if (forceP || usedummy) { | ||||||
|         if (pidsM.Size()) |         if (pidsM.Size()) | ||||||
|            uri = cString::sprintf("%s?pids=%s", *uri, *pidsM.ListPids()); |            uri = cString::sprintf("%s?pids=%s", *uri, *pidsM.ListPids()); | ||||||
| @@ -402,6 +491,33 @@ bool cSatipTuner::UpdatePids(bool forceP) | |||||||
|         if (delPidsM.Size()) |         if (delPidsM.Size()) | ||||||
|            uri = cString::sprintf("%s%sdelpids=%s", *uri, addPidsM.Size() ? "&" : "?", *delPidsM.ListPids()); |            uri = cString::sprintf("%s%sdelpids=%s", *uri, addPidsM.Size() ? "&" : "?", *delPidsM.ListPids()); | ||||||
|         } |         } | ||||||
|  |      if (useci) { | ||||||
|  |         if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkCiXpmt)) { | ||||||
|  |            // CI extension parameters: | ||||||
|  |            // - x_pmt : specifies the PMT of the service you want the CI to decode | ||||||
|  |            // - x_ci  : specfies which CI slot (1..n) to use | ||||||
|  |            //           value 0 releases the CI slot | ||||||
|  |            //           CI slot released automatically if the stream is released, | ||||||
|  |            //           but not when used retuning to another channel | ||||||
|  |            int pid = deviceM->GetPmtPid(); | ||||||
|  |            if ((pid > 0) && (pid != pmtPidM)) { | ||||||
|  |               int slot = deviceM->GetCISlot(); | ||||||
|  |               uri = cString::sprintf("%s&x_pmt=%d", *uri, pid); | ||||||
|  |               if (slot > 0) | ||||||
|  |                  uri = cString::sprintf("%s&x_ci=%d", *uri, slot); | ||||||
|  |               } | ||||||
|  |            pmtPidM = pid; | ||||||
|  |            } | ||||||
|  |         else if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkCiTnr)) { | ||||||
|  |            // CI extension parameters: | ||||||
|  |            // - tnr : specifies a channel config entry | ||||||
|  |            cString param = deviceM->GetTnrParameterString(); | ||||||
|  |            if (!isempty(*param) && strcmp(*tnrParamM, *param) != 0) | ||||||
|  |               uri = cString::sprintf("%s&tnr=%s", *uri, *param); | ||||||
|  |            tnrParamM = param; | ||||||
|  |            } | ||||||
|  |         } | ||||||
|  |      pidUpdateCacheM.Set(ePidUpdateIntervalMs); | ||||||
|      if (!rtspM.Play(*uri)) |      if (!rtspM.Play(*uri)) | ||||||
|         return false; |         return false; | ||||||
|      addPidsM.Clear(); |      addPidsM.Clear(); | ||||||
| @@ -420,7 +536,7 @@ bool cSatipTuner::KeepAlive(bool forceP) | |||||||
|      forceP = true; |      forceP = true; | ||||||
|      } |      } | ||||||
|   if (forceP && !isempty(*streamAddrM)) { |   if (forceP && !isempty(*streamAddrM)) { | ||||||
|      cString uri = cString::sprintf("rtsp://%s/", *streamAddrM); |      cString uri = GetBaseUrl(*streamAddrM, streamPortM); | ||||||
|      if (!rtspM.Options(*uri)) |      if (!rtspM.Options(*uri)) | ||||||
|         return false; |         return false; | ||||||
|      } |      } | ||||||
| @@ -437,7 +553,7 @@ bool cSatipTuner::ReadReceptionStatus(bool forceP) | |||||||
|      forceP = true; |      forceP = true; | ||||||
|      } |      } | ||||||
|   if (forceP && !isempty(*streamAddrM) && (streamIdM > 0)) { |   if (forceP && !isempty(*streamAddrM) && (streamIdM > 0)) { | ||||||
|      cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); |      cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM); | ||||||
|      if (rtspM.Describe(*uri)) |      if (rtspM.Describe(*uri)) | ||||||
|         return true; |         return true; | ||||||
|      } |      } | ||||||
| @@ -539,6 +655,12 @@ const char *cSatipTuner::TunerStateString(eTunerState stateP) | |||||||
|   return "---"; |   return "---"; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int cSatipTuner::FrontendId(void) | ||||||
|  | { | ||||||
|  |   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|  |   return frontendIdM; | ||||||
|  | } | ||||||
|  |  | ||||||
| int cSatipTuner::SignalStrength(void) | int cSatipTuner::SignalStrength(void) | ||||||
| { | { | ||||||
|   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); |   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
| @@ -560,11 +682,11 @@ bool cSatipTuner::HasLock(void) | |||||||
| cString cSatipTuner::GetSignalStatus(void) | cString cSatipTuner::GetSignalStatus(void) | ||||||
| { | { | ||||||
|   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); |   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|   return cString::sprintf("lock=%d strength=%d quality=%d", HasLock(), SignalStrength(), SignalQuality()); |   return cString::sprintf("lock=%d strength=%d quality=%d frontend=%d", HasLock(), SignalStrength(), SignalQuality(), FrontendId()); | ||||||
| } | } | ||||||
|  |  | ||||||
| cString cSatipTuner::GetInformation(void) | cString cSatipTuner::GetInformation(void) | ||||||
| { | { | ||||||
|   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); |   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||||
|   return (currentStateM >= tsTuned) ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed"; |   return (currentStateM >= tsTuned) ? cString::sprintf("%s?%s (%s) [stream=%d]", *GetBaseUrl(*streamAddrM, streamPortM), *streamParamM, *rtspM.GetActiveMode(), streamIdM) : "connection failed"; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										61
									
								
								tuner.h
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								tuner.h
									
									
									
									
									
								
							| @@ -12,6 +12,7 @@ | |||||||
| #include <vdr/tools.h> | #include <vdr/tools.h> | ||||||
|  |  | ||||||
| #include "deviceif.h" | #include "deviceif.h" | ||||||
|  | #include "discover.h" | ||||||
| #include "rtp.h" | #include "rtp.h" | ||||||
| #include "rtcp.h" | #include "rtcp.h" | ||||||
| #include "rtsp.h" | #include "rtsp.h" | ||||||
| @@ -20,14 +21,6 @@ | |||||||
|  |  | ||||||
| class cSatipPid : public cVector<int> { | class cSatipPid : public cVector<int> { | ||||||
| private: | private: | ||||||
|   int PidIndex(const int &pidP) |  | ||||||
|   { |  | ||||||
|     for (int i = 0; i < Size(); ++i) { |  | ||||||
|         if (pidP == At(i)) |  | ||||||
|            return i; |  | ||||||
|         } |  | ||||||
|     return -1; |  | ||||||
|   } |  | ||||||
|   static int PidCompare(const void *aPidP, const void *bPidP) |   static int PidCompare(const void *aPidP, const void *bPidP) | ||||||
|   { |   { | ||||||
|     return (*(int*)aPidP - *(int*)bPidP); |     return (*(int*)aPidP - *(int*)bPidP); | ||||||
| @@ -36,18 +29,13 @@ private: | |||||||
| public: | public: | ||||||
|   void RemovePid(const int &pidP) |   void RemovePid(const int &pidP) | ||||||
|   { |   { | ||||||
|     int i = PidIndex(pidP); |     if (RemoveElement(pidP)) | ||||||
|     if (i >= 0) { |  | ||||||
|        Remove(i); |  | ||||||
|        Sort(PidCompare); |        Sort(PidCompare); | ||||||
|        } |  | ||||||
|   } |   } | ||||||
|   void AddPid(int pidP) |   void AddPid(int pidP) | ||||||
|   { |   { | ||||||
|     if (PidIndex(pidP) < 0) { |     if (AppendUnique(pidP)) | ||||||
|        Append(pidP); |  | ||||||
|        Sort(PidCompare); |        Sort(PidCompare); | ||||||
|        } |  | ||||||
|   } |   } | ||||||
|   cString ListPids(void) |   cString ListPids(void) | ||||||
|   { |   { | ||||||
| @@ -61,6 +49,30 @@ public: | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | class cSatipTunerServer | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |   cSatipServer *serverM; | ||||||
|  |   int deviceIdM; | ||||||
|  |   int transponderM; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   cSatipTunerServer(cSatipServer *serverP, const int deviceIdP, const int transponderP) : serverM(serverP), deviceIdM(deviceIdP), transponderM(transponderP) {} | ||||||
|  |   ~cSatipTunerServer() {} | ||||||
|  |   cSatipTunerServer(const cSatipTunerServer &objP) { serverM = NULL; deviceIdM = -1; transponderM = 0; } | ||||||
|  |   cSatipTunerServer& operator= (const cSatipTunerServer &objP) { serverM = objP.serverM; deviceIdM = objP.deviceIdM; transponderM = objP.transponderM; return *this; } | ||||||
|  |   bool IsValid(void) { return !!serverM; } | ||||||
|  |   bool IsQuirk(int quirkP) { return (serverM && cSatipDiscover::GetInstance()->IsServerQuirk(serverM, quirkP)); } | ||||||
|  |   bool HasCI(void) { return (serverM && cSatipDiscover::GetInstance()->HasServerCI(serverM)); } | ||||||
|  |   void Attach(void) { if (serverM) cSatipDiscover::GetInstance()->AttachServer(serverM, deviceIdM, transponderM); } | ||||||
|  |   void Detach(void) { if (serverM) cSatipDiscover::GetInstance()->DetachServer(serverM, deviceIdM, transponderM); } | ||||||
|  |   void Set(cSatipServer *serverP, const int transponderP) { serverM = serverP; transponderM = transponderP; } | ||||||
|  |   void Reset(void) { serverM = NULL; transponderM = 0; } | ||||||
|  |   cString GetAddress(void) { return serverM ? cSatipDiscover::GetInstance()->GetServerAddress(serverM) : ""; } | ||||||
|  |   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 | class cSatipTuner : public cThread, public cSatipTunerStatistics, public cSatipTunerIf | ||||||
| { | { | ||||||
| private: | private: | ||||||
| @@ -68,10 +80,12 @@ private: | |||||||
|     eDummyPid               = 100, |     eDummyPid               = 100, | ||||||
|     eDefaultSignalStrength  = 15, |     eDefaultSignalStrength  = 15, | ||||||
|     eDefaultSignalQuality   = 224, |     eDefaultSignalQuality   = 224, | ||||||
|     eSleepTimeoutMs         = 1000,  // in milliseconds |     eSleepTimeoutMs         = 250,   // in milliseconds | ||||||
|     eStatusUpdateTimeoutMs  = 1000,  // in milliseconds |     eStatusUpdateTimeoutMs  = 1000,  // in milliseconds | ||||||
|     ePidUpdateIntervalMs    = 250,   // in milliseconds |     ePidUpdateIntervalMs    = 250,   // in milliseconds | ||||||
|     eConnectTimeoutMs       = 5000,  // in milliseconds |     eConnectTimeoutMs       = 5000,  // in milliseconds | ||||||
|  |     eIdleCheckTimeoutMs     = 15000, // in milliseconds | ||||||
|  |     eTuningTimeoutMs        = 20000, // in milliseconds | ||||||
|     eMinKeepAliveIntervalMs = 30000  // in milliseconds |     eMinKeepAliveIntervalMs = 30000  // in milliseconds | ||||||
|   }; |   }; | ||||||
|   enum eTunerState { tsIdle, tsRelease, tsSet, tsTuned, tsLocked }; |   enum eTunerState { tsIdle, tsRelease, tsSet, tsTuned, tsLocked }; | ||||||
| @@ -85,8 +99,10 @@ private: | |||||||
|   cSatipRtcp rtcpM; |   cSatipRtcp rtcpM; | ||||||
|   cString streamAddrM; |   cString streamAddrM; | ||||||
|   cString streamParamM; |   cString streamParamM; | ||||||
|   cSatipServer *currentServerM; |   cString tnrParamM; | ||||||
|   cSatipServer *nextServerM; |   int streamPortM; | ||||||
|  |   cSatipTunerServer currentServerM; | ||||||
|  |   cSatipTunerServer nextServerM; | ||||||
|   cMutex mutexM; |   cMutex mutexM; | ||||||
|   cTimeMs reConnectM; |   cTimeMs reConnectM; | ||||||
|   cTimeMs keepAliveM; |   cTimeMs keepAliveM; | ||||||
| @@ -100,7 +116,9 @@ private: | |||||||
|   bool hasLockM; |   bool hasLockM; | ||||||
|   int signalStrengthM; |   int signalStrengthM; | ||||||
|   int signalQualityM; |   int signalQualityM; | ||||||
|  |   int frontendIdM; | ||||||
|   int streamIdM; |   int streamIdM; | ||||||
|  |   int pmtPidM; | ||||||
|   cSatipPid addPidsM; |   cSatipPid addPidsM; | ||||||
|   cSatipPid delPidsM; |   cSatipPid delPidsM; | ||||||
|   cSatipPid pidsM; |   cSatipPid pidsM; | ||||||
| @@ -115,6 +133,7 @@ private: | |||||||
|   bool RequestState(eTunerState stateP, eStateMode modeP); |   bool RequestState(eTunerState stateP, eStateMode modeP); | ||||||
|   const char *StateModeString(eStateMode modeP); |   const char *StateModeString(eStateMode modeP); | ||||||
|   const char *TunerStateString(eTunerState stateP); |   const char *TunerStateString(eTunerState stateP); | ||||||
|  |   cString GetBaseUrl(const char *addressP, const int portP); | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|   virtual void Action(void); |   virtual void Action(void); | ||||||
| @@ -123,10 +142,11 @@ public: | |||||||
|   cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP); |   cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP); | ||||||
|   virtual ~cSatipTuner(); |   virtual ~cSatipTuner(); | ||||||
|   bool IsTuned(void) const { return (currentStateM >= tsTuned); } |   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); | ||||||
|   int SignalQuality(void); |   int SignalQuality(void); | ||||||
|   bool HasLock(void); |   bool HasLock(void); | ||||||
| @@ -137,8 +157,11 @@ public: | |||||||
| public: | public: | ||||||
|   virtual void ProcessVideoData(u_char *bufferP, int lengthP); |   virtual void ProcessVideoData(u_char *bufferP, int lengthP); | ||||||
|   virtual void ProcessApplicationData(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 SetStreamId(int streamIdP); | ||||||
|   virtual void SetSessionTimeout(const char *sessionP, int timeoutP); |   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); |   virtual int GetId(void); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,14 +12,17 @@ class cSatipTunerIf { | |||||||
| public: | public: | ||||||
|   cSatipTunerIf() {} |   cSatipTunerIf() {} | ||||||
|   virtual ~cSatipTunerIf() {} |   virtual ~cSatipTunerIf() {} | ||||||
|   virtual void ProcessVideoData(u_char *bufferP, int lenghtP) = 0; |   virtual void ProcessVideoData(u_char *bufferP, int lengthP) = 0; | ||||||
|   virtual void ProcessApplicationData(u_char *bufferP, int lenghtP) = 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 SetStreamId(int streamIdP) = 0; | ||||||
|   virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 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; |   virtual int GetId(void) = 0; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|   cSatipTunerIf(const cSatipTunerIf&); |   explicit cSatipTunerIf(const cSatipTunerIf&); | ||||||
|   cSatipTunerIf& operator=(const cSatipTunerIf&); |   cSatipTunerIf& operator=(const cSatipTunerIf&); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user