mirror of
				https://github.com/rofafor/vdr-plugin-satip.git
				synced 2023-10-10 11:37:42 +00:00 
			
		
		
		
	Compare commits
	
		
			56 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 6573c38fb6 | ||
|  | 581ac4966d | ||
|  | 99e366b261 | ||
|  | 3b89dd4b01 | ||
|  | ee6ac0d48a | ||
|  | e6c9776ec9 | ||
|  | 7aef2a3dff | ||
|  | 61b56db909 | ||
|  | 4c45787541 | ||
|  | f65dca2910 | ||
|  | db0c18ba33 | ||
|  | 0f9e0014df | ||
|  | 6bb7fb511b | ||
|  | 7815821824 | ||
|  | bc481bcc4d | ||
|  | 7289da9f41 | ||
|  | d5e0106d8e | ||
|  | fe532e2248 | ||
|  | b5483b9d77 | ||
|  | fd23b0483a | ||
|  | 18c9b79533 | ||
|  | e4f560c66e | ||
|  | 57ea119d03 | ||
|  | ae8298d19a | ||
|  | b755dbf318 | ||
|  | 8f12ce6f55 | ||
|  | 9d5f7cc703 | ||
|  | c1a881ba94 | ||
|  | 165fd5b14a | ||
|  | 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 | 
							
								
								
									
										36
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								HISTORY
									
									
									
									
									
								
							| @@ -120,3 +120,39 @@ VDR Plugin 'satip' Revision History | ||||
| - 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. | ||||
|   | ||||
							
								
								
									
										17
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								Makefile
									
									
									
									
									
								
							| @@ -2,18 +2,10 @@ | ||||
| # Makefile for SAT>IP plugin | ||||
| # | ||||
|  | ||||
| # Debugging on/off | ||||
|  | ||||
| #SATIP_DEBUG = 1 | ||||
|  | ||||
| # Use TinyXML instead of PugiXML | ||||
|  | ||||
| #SATIP_USE_TINYXML = 1 | ||||
|  | ||||
| # Strip debug symbols?  Set eg. to /bin/true if not | ||||
|  | ||||
| STRIP = strip | ||||
|  | ||||
| # The official name of this plugin. | ||||
| # This name will be used in the '-P...' option of VDR to load the plugin. | ||||
| # By default the main source file also carries this name. | ||||
| @@ -40,6 +32,7 @@ TMPDIR ?= /tmp | ||||
|  | ||||
| export CFLAGS   = $(call PKGCFG,cflags) | ||||
| export CXXFLAGS = $(call PKGCFG,cxxflags) | ||||
| STRIP           ?= /bin/true | ||||
|  | ||||
| ### The version number of VDR's plugin API: | ||||
|  | ||||
| @@ -75,12 +68,6 @@ else | ||||
| LIBS += -lpugixml | ||||
| endif | ||||
|  | ||||
| ifdef SATIP_DEBUG | ||||
| ifeq ($(SATIP_DEBUG),1) | ||||
| DEFINES += -DDEBUG | ||||
| endif | ||||
| endif | ||||
|  | ||||
| ifneq ($(strip $(GITTAG)),) | ||||
| DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"' | ||||
| endif | ||||
| @@ -142,9 +129,7 @@ install-i18n: $(I18Nmsgs) | ||||
|  | ||||
| $(SOFILE): $(OBJS) | ||||
| 	$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@ | ||||
| ifndef SATIP_DEBUG | ||||
| 	@$(STRIP) $@ | ||||
| endif | ||||
|  | ||||
| install-lib: $(SOFILE) | ||||
| 	install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) | ||||
|   | ||||
							
								
								
									
										22
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								README
									
									
									
									
									
								
							| @@ -42,7 +42,7 @@ make -C satip-X.Y.Z install | ||||
| Configuration: | ||||
|  | ||||
| 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. | ||||
|  | ||||
| The plugin accepts also a "--server" (-s) command-line parameter, that | ||||
| @@ -52,9 +52,15 @@ separated list of "<ipaddress>|<model>|<description>" entries. The model | ||||
| consists of a DVB system (DVBS2,DVBT2,DVBT,DVBC) and number of available | ||||
| frontends separated by a hyphen: | ||||
|  | ||||
| vdr -P 'satip -s <ipaddress>|<model>|<description>;...' | ||||
| vdr -P 'satip -s 192.168.0.1|DVBS2-2,DVBT2-2|Octo1' | ||||
| vdr -P 'satip -s 192.168.0.1|DVBS2-4|Octo1;192.168.0.2|DVBT2-4|Octo2' | ||||
| 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 | ||||
| sources.conf. If the source description begins with a number, it's used | ||||
| @@ -110,6 +116,11 @@ Setup menu: | ||||
|                              "Disable filter" options which allow you | ||||
|                              to disable the individual section filters. | ||||
|                              Valid range: "none" = 0 ... 7 | ||||
| - Transport mode = unicast   If you want to use the non-standard | ||||
|                    multicast RTP-over-TCP transport mode, set this option | ||||
|                    rtp-o-tcp accordingly. Otherwise, the transport | ||||
|                              mode will be RTP-over-UDP via unicast or | ||||
|                              multicast. | ||||
| - [Red:Scan]                 Forces network scanning of SAT>IP hardware. | ||||
| - [Yellow:Devices]           Opens SAT>IP device status menu. | ||||
| - [Blue:Info]                Opens SAT>IP information/statistics menu. | ||||
| @@ -125,6 +136,9 @@ Information menu: | ||||
|  | ||||
| Notes: | ||||
|  | ||||
| - If you are having problems receiving DVB-S2 channels, make sure your | ||||
|   channels.conf entry contains correct pilot tone setting. | ||||
|  | ||||
| - The stream id "-1" states about unsuccessful tuning. This might be a | ||||
|   result of invalid channel parameters or lack of free SAT>IP tuners. | ||||
|  | ||||
|   | ||||
							
								
								
									
										52
									
								
								common.h
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								common.h
									
									
									
									
									
								
							| @@ -13,9 +13,11 @@ | ||||
| #include <vdr/config.h> | ||||
| #include <vdr/i18n.h> | ||||
|  | ||||
| #define SATIP_DEFAULT_RTSP_PORT          554 | ||||
|  | ||||
| #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_GENERAL        1 | ||||
| @@ -35,7 +37,7 @@ | ||||
|  | ||||
| #define SATIP_CURL_EASY_GETINFO(X, Y, Z) \ | ||||
|   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) \ | ||||
| @@ -84,6 +86,52 @@ | ||||
|  | ||||
| #define ELEMENTS(x) (sizeof(x) / sizeof(x[0])) | ||||
|  | ||||
| class cSatipMemoryBuffer { | ||||
| private: | ||||
|   enum { | ||||
|     eMaxDataSize = MEGABYTE(2) | ||||
|   }; | ||||
|   char *dataM; | ||||
|   size_t sizeM; | ||||
|   void *AllocBuffer(void *ptrP, size_t sizeP) | ||||
|   { | ||||
|     // There might be a realloc() out there that doesn't like reallocing NULL pointers, so we take care of it here | ||||
|     if (ptrP) | ||||
|        return realloc(ptrP, sizeP); | ||||
|     else | ||||
|        return malloc(sizeP); | ||||
|   } | ||||
|   // to prevent copy constructor and assignment | ||||
|   cSatipMemoryBuffer(const cSatipMemoryBuffer&); | ||||
|   cSatipMemoryBuffer& operator=(const cSatipMemoryBuffer&); | ||||
| public: | ||||
|   cSatipMemoryBuffer() : dataM(NULL), sizeM(0) {} | ||||
|   ~cSatipMemoryBuffer() { Reset(); } | ||||
|   size_t Add(char *dataP, size_t sizeP) | ||||
|   { | ||||
|      if (sizeP > 0) { | ||||
|         size_t len = sizeM + sizeP + 1; | ||||
|         if (len < eMaxDataSize) { | ||||
|            dataM = (char *)AllocBuffer(dataM, len); | ||||
|            if (dataM) { | ||||
|               memcpy(&(dataM[sizeM]), dataP, sizeP); | ||||
|               sizeM += sizeP; | ||||
|               dataM[sizeM] = 0; | ||||
|               return sizeP; | ||||
|               } | ||||
|            else | ||||
|               esyslog("[%s,%d]: Failed to allocate memory", __FILE__, __LINE__); | ||||
|           } | ||||
|        else | ||||
|           esyslog("[%s,%d]: Buffer overflow", __FILE__, __LINE__); | ||||
|        } | ||||
|      return 0; | ||||
|   }; | ||||
|   char *Data(void) { return dataM; } | ||||
|   size_t Size(void) { return sizeM; } | ||||
|   void Reset(void) { FREE_POINTER(dataM); sizeM = 0; }; | ||||
| }; | ||||
|  | ||||
| uint16_t ts_pid(const uint8_t *bufP); | ||||
| uint8_t payload(const uint8_t *bufP); | ||||
| const char *id_pid(const u_short pidP); | ||||
|   | ||||
							
								
								
									
										4
									
								
								config.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								config.c
									
									
									
									
									
								
							| @@ -17,6 +17,10 @@ cSatipConfig::cSatipConfig(void) | ||||
|   ciExtensionM(0), | ||||
|   eitScanM(1), | ||||
|   useBytesM(1), | ||||
|   portRangeStartM(0), | ||||
|   portRangeStopM(0), | ||||
|   transportModeM(eTransportModeUnicast), | ||||
|   detachedModeM(false), | ||||
|   disableServerQuirksM(false), | ||||
|   useSingleModelServersM(false) | ||||
| { | ||||
|   | ||||
							
								
								
									
										21
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								config.h
									
									
									
									
									
								
							| @@ -19,6 +19,10 @@ private: | ||||
|   unsigned int ciExtensionM; | ||||
|   unsigned int eitScanM; | ||||
|   unsigned int useBytesM; | ||||
|   unsigned int portRangeStartM; | ||||
|   unsigned int portRangeStopM; | ||||
|   unsigned int transportModeM; | ||||
|   bool detachedModeM; | ||||
|   bool disableServerQuirksM; | ||||
|   bool useSingleModelServersM; | ||||
|   int cicamsM[MAX_CICAM_COUNT]; | ||||
| @@ -33,6 +37,12 @@ public: | ||||
|     eOperatingModeHigh, | ||||
|     eOperatingModeCount | ||||
|   }; | ||||
|   enum eTransportMode { | ||||
|     eTransportModeUnicast = 0, | ||||
|     eTransportModeMulticast, | ||||
|     eTransportModeRtpOverTcp, | ||||
|     eTransportModeCount | ||||
|   }; | ||||
|   enum eTraceMode { | ||||
|     eTraceModeNormal  = 0x0000, | ||||
|     eTraceModeDebug1  = 0x0001, | ||||
| @@ -66,12 +76,19 @@ public: | ||||
|   int GetCICAM(unsigned int indexP) const; | ||||
|   unsigned int GetEITScan(void) const { return eitScanM; } | ||||
|   unsigned int GetUseBytes(void) const { return useBytesM; } | ||||
|   unsigned int GetTransportMode(void) const { return transportModeM; } | ||||
|   bool IsTransportModeUnicast(void) const { return (transportModeM == eTransportModeUnicast); } | ||||
|   bool IsTransportModeRtpOverTcp(void) const { return (transportModeM == eTransportModeRtpOverTcp); } | ||||
|   bool IsTransportModeMulticast(void) const { return (transportModeM == eTransportModeMulticast); } | ||||
|   bool GetDetachedMode(void) const { return detachedModeM; } | ||||
|   bool GetDisableServerQuirks(void) const { return disableServerQuirksM; } | ||||
|   bool GetUseSingleModelServers(void) const { return useSingleModelServersM; } | ||||
|   unsigned int GetDisabledSourcesCount(void) const; | ||||
|   int GetDisabledSources(unsigned int indexP) const; | ||||
|   unsigned int GetDisabledFiltersCount(void) const; | ||||
|   int GetDisabledFilters(unsigned int indexP) const; | ||||
|   unsigned int GetPortRangeStart(void) const { return portRangeStartM; } | ||||
|   unsigned int GetPortRangeStop(void) const { return portRangeStopM; } | ||||
|  | ||||
|   void SetOperatingMode(unsigned int operatingModeP) { operatingModeM = operatingModeP; } | ||||
|   void SetTraceMode(unsigned int modeP) { traceModeM = (modeP & eTraceModeMask); } | ||||
| @@ -79,10 +96,14 @@ public: | ||||
|   void SetCICAM(unsigned int indexP, int cicamP); | ||||
|   void SetEITScan(unsigned int onOffP) { eitScanM = onOffP; } | ||||
|   void SetUseBytes(unsigned int onOffP) { useBytesM = onOffP; } | ||||
|   void SetTransportMode(unsigned int transportModeP) { transportModeM = transportModeP; } | ||||
|   void SetDetachedMode(bool onOffP) { detachedModeM = onOffP; } | ||||
|   void SetDisableServerQuirks(bool onOffP) { disableServerQuirksM = onOffP; } | ||||
|   void SetUseSingleModelServers(bool onOffP) { useSingleModelServersM = onOffP; } | ||||
|   void SetDisabledSources(unsigned int indexP, int sourceP); | ||||
|   void SetDisabledFilters(unsigned int indexP, int numberP); | ||||
|   void SetPortRangeStart(unsigned int rangeStartP) { portRangeStartM = rangeStartP; } | ||||
|   void SetPortRangeStop(unsigned int rangeStopP) { portRangeStopM = rangeStopP; } | ||||
| }; | ||||
|  | ||||
| extern cSatipConfig SatipConfig; | ||||
|   | ||||
							
								
								
									
										45
									
								
								device.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								device.c
									
									
									
									
									
								
							| @@ -103,7 +103,12 @@ cString cSatipDevice::GetSatipStatus(void) | ||||
|          bool live = (device == cDevice::ActualDevice()); | ||||
|          bool lock = device->HasLock(); | ||||
|          const cChannel *channel = device->GetCurrentlyTunedTransponder(); | ||||
| #if defined(APIVERSNUM) && APIVERSNUM >= 20301 | ||||
|          LOCK_TIMERS_READ; | ||||
|          for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer)) { | ||||
| #else | ||||
|          for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { | ||||
| #endif | ||||
|              if (timer->Recording()) { | ||||
|                 cRecordControl *control = cRecordControls::GetRecordControl(timer); | ||||
|                 if (control && control->Device() == device) | ||||
| @@ -115,8 +120,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" : ""); | ||||
|          else | ||||
|             info = cString::sprintf("%sCardIndex: %d  HasLock: no\n", *info, device->CardIndex()); | ||||
|          if (channel && channel->Number() > 0) | ||||
|             info = cString::sprintf("%sTransponder: %d  Channel: %s\n", *info, (channel && channel->Number() > 0) ? channel->Transponder() : 0, (channel && channel->Number() > 0) ? channel->Name() : "---"); | ||||
|          if (channel) { | ||||
|             if (channel->Number() > 0 && device->Receiving()) | ||||
|                info = cString::sprintf("%sTransponder: %d  Channel: %s\n", *info, channel->Transponder(), channel->Name()); | ||||
|             else | ||||
|                info = cString::sprintf("%sTransponder: %d\n", *info, channel->Transponder()); | ||||
|             } | ||||
|          if (timers) | ||||
|             info = cString::sprintf("%sRecording: %d timer%s\n", *info, timers, (timers > 1) ? "s" : ""); | ||||
|          info = cString::sprintf("%s\n", *info); | ||||
| @@ -128,13 +137,20 @@ cString cSatipDevice::GetSatipStatus(void) | ||||
| cString cSatipDevice::GetGeneralInformation(void) | ||||
| { | ||||
|   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", | ||||
| #if defined(APIVERSNUM) && APIVERSNUM >= 20301 | ||||
|   LOCK_CHANNELS_READ; | ||||
| #endif | ||||
|   return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s\n", | ||||
|                           deviceIndexM, CardIndex(), | ||||
|                           pTunerM ? *pTunerM->GetInformation() : "", | ||||
|                           pTunerM ? *pTunerM->GetSignalStatus() : "", | ||||
|                           pTunerM ? *pTunerM->GetTunerStatistic() : "", | ||||
|                           *GetBufferStatistic(), | ||||
| #if defined(APIVERSNUM) && APIVERSNUM >= 20301 | ||||
|                           *Channels->GetByNumber(cDevice::CurrentChannel())->ToText()); | ||||
| #else | ||||
|                           *Channels.GetByNumber(cDevice::CurrentChannel())->ToText()); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| cString cSatipDevice::GetPidsInformation(void) | ||||
| @@ -194,6 +210,8 @@ cString cSatipDevice::DeviceType(void) const | ||||
| cString cSatipDevice::DeviceName(void) const | ||||
| { | ||||
|   debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); | ||||
|   if (!Receiving()) | ||||
|      return cString::sprintf("%s %d", *DeviceType(), deviceIndexM); | ||||
|   return deviceNameM; | ||||
| } | ||||
|  | ||||
| @@ -219,6 +237,8 @@ bool cSatipDevice::ProvidesSource(int sourceP) const | ||||
| { | ||||
|   cSource *s = Sources.Get(sourceP); | ||||
|   debug9("%s (%c) desc='%s' [device %u]", __PRETTY_FUNCTION__, cSource::ToChar(sourceP), s ? s->Description() : "", deviceIndexM); | ||||
|   if (SatipConfig.GetDetachedMode()) | ||||
|      return false; | ||||
|   // source descriptions starting with '0' are disabled | ||||
|   if (s && s->Description() && (*(s->Description()) == '0')) | ||||
|      return false; | ||||
| @@ -341,6 +361,7 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) | ||||
|      } | ||||
|   else if (pTunerM) { | ||||
|      pTunerM->SetSource(NULL, 0, NULL, deviceIndexM); | ||||
|      deviceNameM = cString::sprintf("%s %d", *DeviceType(), deviceIndexM); | ||||
|      return true; | ||||
|      } | ||||
|   return false; | ||||
| @@ -348,11 +369,11 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) | ||||
|  | ||||
| bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP) | ||||
| { | ||||
|   debug12("%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 (onP) | ||||
|         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 true; | ||||
| @@ -458,6 +479,18 @@ int cSatipDevice::GetCISlot(void) | ||||
|   return slot; | ||||
| } | ||||
|  | ||||
| cString cSatipDevice::GetTnrParameterString(void) | ||||
| { | ||||
|    if (channelM.Ca()) | ||||
|       return GetTnrUrlParameters(&channelM); | ||||
|    return NULL; | ||||
| } | ||||
|  | ||||
| bool cSatipDevice::IsIdle(void) | ||||
| { | ||||
|   return !Receiving(); | ||||
| } | ||||
|  | ||||
| uchar *cSatipDevice::GetData(int *availableP) | ||||
| { | ||||
|   debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); | ||||
| @@ -501,6 +534,8 @@ void cSatipDevice::SkipData(int countP) | ||||
| bool cSatipDevice::GetTSPacket(uchar *&dataP) | ||||
| { | ||||
|   debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); | ||||
|   if (SatipConfig.GetDetachedMode()) | ||||
|      return false; | ||||
|   if (tsBufferM) { | ||||
|      if (cCamSlot *cs = CamSlot()) { | ||||
|         if (cs->WantsTsData()) { | ||||
|   | ||||
							
								
								
									
										4
									
								
								device.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								device.h
									
									
									
									
									
								
							| @@ -43,7 +43,7 @@ private: | ||||
|  | ||||
|   // constructor & destructor | ||||
| public: | ||||
|   cSatipDevice(unsigned int deviceIndexP); | ||||
|   explicit cSatipDevice(unsigned int deviceIndexP); | ||||
|   virtual ~cSatipDevice(); | ||||
|   cString GetInformation(unsigned int pageP = SATIP_DEVICE_INFO_ALL); | ||||
|  | ||||
| @@ -110,6 +110,8 @@ public: | ||||
|   virtual int GetId(void); | ||||
|   virtual int GetPmtPid(void); | ||||
|   virtual int GetCISlot(void); | ||||
|   virtual cString GetTnrParameterString(void); | ||||
|   virtual bool IsIdle(void); | ||||
| }; | ||||
|  | ||||
| #endif // __SATIP_DEVICE_H | ||||
|   | ||||
| @@ -16,9 +16,11 @@ public: | ||||
|   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: | ||||
|   cSatipDeviceIf(const cSatipDeviceIf&); | ||||
|   explicit cSatipDeviceIf(const cSatipDeviceIf&); | ||||
|   cSatipDeviceIf& operator=(const cSatipDeviceIf&); | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										143
									
								
								discover.c
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								discover.c
									
									
									
									
									
								
							| @@ -32,7 +32,7 @@ bool cSatipDiscover::Initialize(cSatipDiscoverServers *serversP) | ||||
|   if (instanceS) { | ||||
|        if (serversP) { | ||||
|           for (cSatipDiscoverServer *s = serversP->First(); s; s = serversP->Next(s)) | ||||
|               instanceS->AddServer(s->IpAddress(), s->Model(), s->Description()); | ||||
|               instanceS->AddServer(s->IpAddress(), s->IpPort(), s->Model(), s->Filters(), s->Description(), s->Quirk()); | ||||
|           } | ||||
|      else | ||||
|         instanceS->Activate(); | ||||
| @@ -47,44 +47,27 @@ void cSatipDiscover::Destroy(void) | ||||
|      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); | ||||
|   size_t len = sizeP * nmembP; | ||||
|   debug16("%s len=%zu", __PRETTY_FUNCTION__, len); | ||||
|  | ||||
|   if (obj) { | ||||
|      CURLcode res = CURLE_OK; | ||||
|      const char *desc = NULL, *model = NULL, *addr = NULL; | ||||
| #ifdef USE_TINYXML | ||||
|      TiXmlDocument doc; | ||||
|      char *xml = MALLOC(char, len + 1); | ||||
|      memcpy(xml, ptrP, len); | ||||
|      *(xml + len + 1) = 0; | ||||
|      doc.Parse((const char *)xml); | ||||
|      TiXmlHandle docHandle(&doc); | ||||
|      TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement(); | ||||
|      if (descElement) | ||||
|         desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware"; | ||||
|      TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement(); | ||||
|      if (modelElement) | ||||
|         model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1"; | ||||
| #else | ||||
|      pugi::xml_document doc; | ||||
|      pugi::xml_parse_result result = doc.load_buffer(ptrP, len); | ||||
|      if (result) { | ||||
|         pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName"); | ||||
|         if (descNode) | ||||
|            desc = descNode.text().as_string("MyBrokenHardware"); | ||||
|         pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP"); | ||||
|         if (modelNode) | ||||
|            model = modelNode.text().as_string("DVBS2-1"); | ||||
|         } | ||||
| #endif | ||||
|      SATIP_CURL_EASY_GETINFO(obj->handleM, CURLINFO_PRIMARY_IP, &addr); | ||||
|      obj->AddServer(addr, model, desc); | ||||
|   if (obj && (len > 0)) | ||||
|      obj->headerBufferM.Add(ptrP, len); | ||||
|  | ||||
|   return len; | ||||
| } | ||||
|  | ||||
| size_t cSatipDiscover::DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP) | ||||
| { | ||||
|   cSatipDiscover *obj = reinterpret_cast<cSatipDiscover *>(dataP); | ||||
|   size_t len = sizeP * nmembP; | ||||
|   debug16("%s len=%zu", __PRETTY_FUNCTION__, len); | ||||
|  | ||||
|   if (obj && (len > 0)) | ||||
|      obj->dataBufferM.Add(ptrP, len); | ||||
|  | ||||
|   return len; | ||||
| } | ||||
|  | ||||
| @@ -120,6 +103,8 @@ int cSatipDiscover::DebugCallback(CURL *handleP, curl_infotype typeP, char *data | ||||
| cSatipDiscover::cSatipDiscover() | ||||
| : cThread("SATIP discover"), | ||||
|   mutexM(), | ||||
|   headerBufferM(), | ||||
|   dataBufferM(), | ||||
|   msearchM(*this), | ||||
|   probeUrlListM(), | ||||
|   handleM(curl_easy_init()), | ||||
| @@ -170,7 +155,7 @@ void cSatipDiscover::Action(void) | ||||
|            probeIntervalM.Set(eProbeIntervalMs); | ||||
|            msearchM.Probe(); | ||||
|            mutexM.Lock(); | ||||
|            serversM.Cleanup(eProbeIntervalMs * 2); | ||||
|            serversM.Cleanup(eCleanupTimeoutMs); | ||||
|            mutexM.Unlock(); | ||||
|            } | ||||
|         mutexM.Lock(); | ||||
| @@ -195,6 +180,7 @@ void cSatipDiscover::Fetch(const char *urlP) | ||||
| { | ||||
|   debug1("%s (%s)", __PRETTY_FUNCTION__, urlP); | ||||
|   if (handleM && !isempty(urlP)) { | ||||
|      const char *addr = NULL; | ||||
|      long rc = 0; | ||||
|      CURLcode res = CURLE_OK; | ||||
|  | ||||
| @@ -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_DEBUGDATA, this); | ||||
|  | ||||
|      // Set callback | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::WriteCallback); | ||||
|      // Set header and data callbacks | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipDiscover::HeaderCallback); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipDiscover::DataCallback); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); | ||||
|  | ||||
|      // No progress meter and no signaling | ||||
| @@ -224,14 +212,71 @@ void cSatipDiscover::Fetch(const char *urlP) | ||||
|      // Fetch the data | ||||
|      SATIP_CURL_EASY_PERFORM(handleM); | ||||
|      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); | ||||
|      } | ||||
| } | ||||
|  | ||||
| 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__); | ||||
|   char *s, *p = headerBufferM.Data(); | ||||
|   char *r = strtok_r(p, "\r\n", &s); | ||||
|   int port = SATIP_DEFAULT_RTSP_PORT; | ||||
|  | ||||
|   while (r) { | ||||
|         debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r); | ||||
|         r = skipspace(r); | ||||
|         if (strstr(r, "X-SATIP-RTSP-Port")) { | ||||
|            int tmp = -1; | ||||
|            if (sscanf(r, "X-SATIP-RTSP-Port:%11d", &tmp) == 1) { | ||||
|               port = tmp; | ||||
|               break; | ||||
|               } | ||||
|            } | ||||
|         r = strtok_r(NULL, "\r\n", &s); | ||||
|         } | ||||
|  | ||||
|   return port; | ||||
| } | ||||
|  | ||||
| void cSatipDiscover::ParseDeviceInfo(const char *addrP, const int portP) | ||||
| { | ||||
|   debug1("%s (%s, %d)", __PRETTY_FUNCTION__, addrP, portP); | ||||
|   const char *desc = NULL, *model = NULL; | ||||
| #ifdef USE_TINYXML | ||||
|   TiXmlDocument doc; | ||||
|   doc.Parse(dataBufferM.Data()); | ||||
|   TiXmlHandle docHandle(&doc); | ||||
|   TiXmlElement *descElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("friendlyName").ToElement(); | ||||
|   if (descElement) | ||||
|      desc = descElement->GetText() ? descElement->GetText() : "MyBrokenHardware"; | ||||
|   TiXmlElement *modelElement = docHandle.FirstChild("root").FirstChild("device").FirstChild("satip:X_SATIPCAP").ToElement(); | ||||
|   if (modelElement) | ||||
|      model = modelElement->GetText() ? modelElement->GetText() : "DVBS2-1"; | ||||
| #else | ||||
|   pugi::xml_document doc; | ||||
|   if (doc.load_buffer(dataBufferM.Data(), dataBufferM.Size())) { | ||||
|      pugi::xml_node descNode = doc.first_element_by_path("root/device/friendlyName"); | ||||
|      if (descNode) | ||||
|         desc = descNode.text().as_string("MyBrokenHardware"); | ||||
|      pugi::xml_node modelNode = doc.first_element_by_path("root/device/satip:X_SATIPCAP"); | ||||
|      if (modelNode) | ||||
|         model = modelNode.text().as_string("DVBS2-1"); | ||||
|      } | ||||
| #endif | ||||
|   AddServer(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; | ||||
| @@ -240,9 +285,9 @@ void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char | ||||
|      while (r) { | ||||
|            r = skipspace(r); | ||||
|            cString desc = cString::sprintf("%s #%d", !isempty(descP) ? descP : "MyBrokenHardware", n++); | ||||
|            cSatipServer *tmp = new cSatipServer(addrP, r, desc); | ||||
|            cSatipServer *tmp = new cSatipServer(addrP, portP, r, filtersP, desc, quirkP); | ||||
|            if (!serversM.Update(tmp)) { | ||||
|               info("Adding server '%s|%s|%s' CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none"); | ||||
|               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 | ||||
| @@ -252,9 +297,9 @@ void cSatipDiscover::AddServer(const char *addrP, const char *modelP, const char | ||||
|      FREE_POINTER(p); | ||||
|      } | ||||
|   else { | ||||
|      cSatipServer *tmp = new cSatipServer(addrP, modelP, descP); | ||||
|      cSatipServer *tmp = new cSatipServer(addrP, portP, modelP, filtersP, descP, quirkP); | ||||
|      if (!serversM.Update(tmp)) { | ||||
|         info("Adding server '%s|%s|%s' CI: %s Quirks: %s", tmp->Address(), tmp->Model(), tmp->Description(), tmp->HasCI() ? "yes" : "no", tmp->HasQuirk() ? tmp->Quirks() : "none"); | ||||
|         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 | ||||
| @@ -311,6 +356,13 @@ cString cSatipDiscover::GetServerList(void) | ||||
|   return serversM.List(); | ||||
| } | ||||
|  | ||||
| void cSatipDiscover::ActivateServer(cSatipServer *serverP, bool onOffP) | ||||
| { | ||||
|   debug16("%s (, %d)", __PRETTY_FUNCTION__, onOffP); | ||||
|   cMutexLock MutexLock(&mutexM); | ||||
|   serversM.Activate(serverP, onOffP); | ||||
| } | ||||
|  | ||||
| void cSatipDiscover::AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP) | ||||
| { | ||||
|   debug16("%s (, %d, %d)", __PRETTY_FUNCTION__, deviceIdP, transponderP); | ||||
| @@ -346,6 +398,13 @@ cString cSatipDiscover::GetServerAddress(cSatipServer *serverP) | ||||
|   return serversM.GetAddress(serverP); | ||||
| } | ||||
|  | ||||
| int cSatipDiscover::GetServerPort(cSatipServer *serverP) | ||||
| { | ||||
|   debug16("%s", __PRETTY_FUNCTION__); | ||||
|   cMutexLock MutexLock(&mutexM); | ||||
|   return serversM.GetPort(serverP); | ||||
| } | ||||
|  | ||||
| int cSatipDiscover::NumProvidedSystems(void) | ||||
| { | ||||
|   debug16("%s", __PRETTY_FUNCTION__); | ||||
|   | ||||
							
								
								
									
										25
									
								
								discover.h
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								discover.h
									
									
									
									
									
								
							| @@ -13,6 +13,7 @@ | ||||
| #include <vdr/thread.h> | ||||
| #include <vdr/tools.h> | ||||
|  | ||||
| #include "common.h" | ||||
| #include "discoverif.h" | ||||
| #include "msearch.h" | ||||
| #include "server.h" | ||||
| @@ -20,16 +21,22 @@ | ||||
|  | ||||
| class cSatipDiscoverServer : public cListObject { | ||||
| private: | ||||
|   int ipPortM; | ||||
|   int quirkM; | ||||
|   cString ipAddressM; | ||||
|   cString descriptionM; | ||||
|   cString modelM; | ||||
|   cString filtersM; | ||||
| 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 *Model(void)       { return *modelM; } | ||||
|   const char *Filters(void)     { return *filtersM; } | ||||
|   const char *Description(void) { return *descriptionM; } | ||||
| }; | ||||
|  | ||||
| @@ -42,12 +49,16 @@ private: | ||||
|     eSleepTimeoutMs   = 500,   // in milliseconds | ||||
|     eConnectTimeoutMs = 1500,  // in milliseconds | ||||
|     eProbeTimeoutMs   = 2000,  // in milliseconds | ||||
|     eProbeIntervalMs  = 60000 // in milliseconds | ||||
|     eProbeIntervalMs  = 60000, // in milliseconds | ||||
|     eCleanupTimeoutMs = 124000 // in milliseoonds | ||||
|   }; | ||||
|   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); | ||||
|   cMutex mutexM; | ||||
|   cSatipMemoryBuffer headerBufferM; | ||||
|   cSatipMemoryBuffer dataBufferM; | ||||
|   cSatipMsearch msearchM; | ||||
|   cStringList probeUrlListM; | ||||
|   CURL *handleM; | ||||
| @@ -56,7 +67,9 @@ private: | ||||
|   cSatipServers serversM; | ||||
|   void Activate(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); | ||||
|   // constructor | ||||
|   cSatipDiscover(); | ||||
| @@ -79,11 +92,13 @@ public: | ||||
|   cSatipServer *GetServer(cSatipServer *serverP); | ||||
|   cSatipServers *GetServers(void); | ||||
|   cString GetServerString(cSatipServer *serverP); | ||||
|   void ActivateServer(cSatipServer *serverP, bool onOffP); | ||||
|   void AttachServer(cSatipServer *serverP, int deviceIdP, int transponderP); | ||||
|   void DetachServer(cSatipServer *serverP, int deviceIdP, int transponderP); | ||||
|   bool IsServerQuirk(cSatipServer *serverP, int quirkP); | ||||
|   bool HasServerCI(cSatipServer *serverP); | ||||
|   cString GetServerAddress(cSatipServer *serverP); | ||||
|   int GetServerPort(cSatipServer *serverP); | ||||
|   cString GetServerList(void); | ||||
|   int NumProvidedSystems(void); | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,7 @@ public: | ||||
|   virtual void SetUrl(const char *urlP) = 0; | ||||
|  | ||||
| private: | ||||
|   cSatipDiscoverIf(const cSatipDiscoverIf&); | ||||
|   explicit cSatipDiscoverIf(const cSatipDiscoverIf&); | ||||
|   cSatipDiscoverIf& operator=(const cSatipDiscoverIf&); | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										5
									
								
								log.h
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								log.h
									
									
									
									
									
								
							| @@ -34,9 +34,9 @@ | ||||
| #define debug10(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug10) ? dsyslog("SATIP10: " x) : void() ) | ||||
| // 0x0400: CI | ||||
| #define debug11(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug11) ? dsyslog("SATIP11: " x) : void() ) | ||||
| // 0x0800: Discovery | ||||
| // 0x0800: Pids | ||||
| #define debug12(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug12) ? dsyslog("SATIP12: " x) : void() ) | ||||
| // 0x1000: Pids | ||||
| // 0x1000: Discovery | ||||
| #define debug13(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug13) ? dsyslog("SATIP13: " x) : void() ) | ||||
| // 0x2000: TBD | ||||
| #define debug14(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug14) ? dsyslog("SATIP14: " x) : void() ) | ||||
| @@ -46,4 +46,3 @@ | ||||
| #define debug16(x...) void( SatipConfig.IsTraceMode(cSatipConfig::eTraceModeDebug16) ? dsyslog("SATIP16: " x) : void() ) | ||||
|  | ||||
| #endif // __SATIP_LOG_H | ||||
|  | ||||
|   | ||||
							
								
								
									
										14
									
								
								msearch.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								msearch.c
									
									
									
									
									
								
							| @@ -29,7 +29,7 @@ cSatipMsearch::cSatipMsearch(cSatipDiscoverIf &discoverP) | ||||
|      memset(bufferM, 0, bufferLenM); | ||||
|   else | ||||
|      error("Cannot create Msearch buffer!"); | ||||
|   if (!Open(eDiscoveryPort)) | ||||
|   if (!Open(eDiscoveryPort, true)) | ||||
|      error("Cannot open Msearch port!"); | ||||
| } | ||||
|  | ||||
| @@ -45,6 +45,9 @@ void cSatipMsearch::Probe(void) | ||||
|      cSatipPoller::GetInstance()->Register(*this); | ||||
|      registeredM = true; | ||||
|      } | ||||
|   // Send two queries with one second interval | ||||
|   Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS)); | ||||
|   cCondWait::SleepMs(1000); | ||||
|   Write(bcastAddressS, reinterpret_cast<const unsigned char *>(bcastMessageS), strlen(bcastMessageS)); | ||||
| } | ||||
|  | ||||
| @@ -60,12 +63,12 @@ void cSatipMsearch::Process(void) | ||||
|      int length; | ||||
|      while ((length = Read(bufferM, bufferLenM)) > 0) { | ||||
|            bufferM[min(length, int(bufferLenM - 1))] = 0; | ||||
|            debug12("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM); | ||||
|            debug13("%s len=%d buf=%s", __PRETTY_FUNCTION__, length, bufferM); | ||||
|            bool status = false, valid = false; | ||||
|            char *s, *p = reinterpret_cast<char *>(bufferM), *location = NULL; | ||||
|            char *r = strtok_r(p, "\r\n", &s); | ||||
|            while (r) { | ||||
|                  debug12("%s r=%s", __PRETTY_FUNCTION__, r); | ||||
|                  debug13("%s r=%s", __PRETTY_FUNCTION__, r); | ||||
|                  // Check the status code | ||||
|                  // HTTP/1.1 200 OK | ||||
|                  if (!status && startswith(r, "HTTP/1.1 200 OK")) | ||||
| @@ -97,6 +100,11 @@ void cSatipMsearch::Process(void) | ||||
|      } | ||||
| } | ||||
|  | ||||
| void cSatipMsearch::Process(unsigned char *dataP, int lengthP) | ||||
| { | ||||
|   debug16("%s", __PRETTY_FUNCTION__); | ||||
| } | ||||
|  | ||||
| cString cSatipMsearch::ToString(void) const | ||||
| { | ||||
|   return "MSearch"; | ||||
|   | ||||
| @@ -26,7 +26,7 @@ private: | ||||
|   bool registeredM; | ||||
|  | ||||
| public: | ||||
|   cSatipMsearch(cSatipDiscoverIf &discoverP); | ||||
|   explicit cSatipMsearch(cSatipDiscoverIf &discoverP); | ||||
|   virtual ~cSatipMsearch(); | ||||
|   void Probe(void); | ||||
|  | ||||
| @@ -34,6 +34,7 @@ public: | ||||
| public: | ||||
|   virtual int GetFd(void); | ||||
|   virtual void Process(void); | ||||
|   virtual void Process(unsigned char *dataP, int lengthP); | ||||
|   virtual cString ToString(void) const; | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										352
									
								
								param.c
									
									
									
									
									
								
							
							
						
						
									
										352
									
								
								param.c
									
									
									
									
									
								
							| @@ -147,9 +147,6 @@ cString GetTransponderUrlParameters(const cChannel *channelP) | ||||
|      cDvbTransponderParameters dtp(channelP->Parameters()); | ||||
|      int DataSlice = 0; | ||||
|      int C2TuningFrequencyType = 0; | ||||
|      int Pilot = dtp.Pilot(); | ||||
|      int T2SystemId = dtp.T2SystemId(); | ||||
|      int SisoMiso = dtp.SisoMiso(); | ||||
|      float freq = channelP->Frequency(); | ||||
|      char type = cSource::ToChar(channelP->Source()); | ||||
|      cSource *source = Sources.Get(channelP->Source()); | ||||
| @@ -161,34 +158,349 @@ cString GetTransponderUrlParameters(const cChannel *channelP) | ||||
|            freq /= 1000L; | ||||
| #define ST(s) if (strchr(s, type) && (strchr(s, '0' + dtp.System() + 1) || strchr(s, '*'))) | ||||
| #define STBUFLEFT (sizeof(buffer) - (q - buffer)) | ||||
|      ST(" S 1") { // to comply with SAT>IP protocol specification 1.2.2 | ||||
|        dtp.SetPilot(PILOT_OFF); | ||||
|        dtp.SetModulation(QPSK); | ||||
|        dtp.SetRollOff(ROLLOFF_35); | ||||
|        } | ||||
|      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")); | ||||
|      ST(" S *") q += snprintf(q,       STBUFLEFT, "&src=%d",          ((src > 0) && (src <= 255)) ? src : 1); | ||||
|      ST(" S *") q += snprintf(q,       STBUFLEFT, "&sr=%d",           channelP->Srate()); | ||||
|      ST("C  1") q += snprintf(q,       STBUFLEFT, "&sr=%d",           channelP->Srate()); | ||||
|      ST(" S *") q += snprintf(q,       STBUFLEFT, "&pol=%c",          tolower(dtp.Polarization())); | ||||
|      ST("C T2") q += snprintf(q,       STBUFLEFT, "&plp=%d",          dtp.StreamId()); | ||||
|      ST("  T2") q += snprintf(q,       STBUFLEFT, "&t2id=%d",         T2SystemId); | ||||
|      ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(),      SatipRollOffValues); | ||||
|      ST("C  2") q += snprintf(q,       STBUFLEFT, "&c2tft=%d",        C2TuningFrequencyType); | ||||
|      ST("C  2") q += snprintf(q,       STBUFLEFT, "&ds=%d",           DataSlice); | ||||
|      ST("C  1") q += PrintUrlString(q, STBUFLEFT, dtp.Inversion(),    SatipInversionValues); | ||||
|      ST("  T2") q += PrintUrlString(q, STBUFLEFT, SisoMiso,           SatipSisoMisoValues); | ||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(),    SatipBandwidthValues); | ||||
|      ST("C  2") q += PrintUrlString(q, STBUFLEFT, dtp.Bandwidth(),    SatipBandwidthValues); | ||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Guard(),        SatipGuardValues); | ||||
|      ST("CST*") q += PrintUrlString(q, STBUFLEFT, dtp.CoderateH(),    SatipCodeRateValues); | ||||
|      ST(" S 2") q += PrintUrlString(q, STBUFLEFT, Pilot,              SatipPilotValues); | ||||
|      ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); | ||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); | ||||
|      ST("C  1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); | ||||
|      ST(" S 2") q += PrintUrlString(q, STBUFLEFT, dtp.RollOff(),      SatipRollOffValues); | ||||
|      ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesSat); | ||||
|      ST("C  *") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesCable); | ||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.System(),       SatipSystemValuesTerrestrial); | ||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Transmission(), SatipTransmissionValues); | ||||
|      if ((channelP->Rid() % 100) > 0) | ||||
|                 snprintf(q,            STBUFLEFT, "&fe=%d",           channelP->Rid() % 100); | ||||
|      ST(" S *") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); | ||||
|      ST("  T*") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); | ||||
|      ST("C  1") q += PrintUrlString(q, STBUFLEFT, dtp.Modulation(),   SatipModulationValues); | ||||
|      ST(" 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 | ||||
|      return buffer; | ||||
|      } | ||||
|   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" | ||||
|  | ||||
| cString GetTransponderUrlParameters(const cChannel *channelP); | ||||
| cString GetTnrUrlParameters(const cChannel *channelP); | ||||
|  | ||||
| #endif // __SATIP_PARAM_H | ||||
|   | ||||
							
								
								
									
										26
									
								
								po/ca_ES.po
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								po/ca_ES.po
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | ||||
| # VDR plugin language source file. | ||||
| # Copyright (C) 2007-2015 Rolf Ahrenberg | ||||
| # Copyright (C) 2007-2016 Rolf Ahrenberg | ||||
| # This file is distributed under the same license as the satip package. | ||||
| # Gabriel Bonich, 2014-2015 | ||||
| # | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: vdr-satip 2.2.0\n" | ||||
| "Project-Id-Version: vdr-satip 2.2.4\n" | ||||
| "Report-Msgid-Bugs-To: <see README>\n" | ||||
| "POT-Creation-Date: 2015-02-19 02:19+0200\n" | ||||
| "PO-Revision-Date: 2015-02-19 02:19+0200\n" | ||||
| "POT-Creation-Date: 2016-12-18 12:18+0200\n" | ||||
| "PO-Revision-Date: 2016-12-18 12:18+0200\n" | ||||
| "Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n" | ||||
| "Language-Team: Catalan <vdr@linuxtv.org>\n" | ||||
| "Language: ca\n" | ||||
| @@ -85,6 +85,15 @@ msgstr "Normal" | ||||
| msgid "high" | ||||
| msgstr "Alt" | ||||
|  | ||||
| msgid "Unicast" | ||||
| msgstr "" | ||||
|  | ||||
| msgid "Multicast" | ||||
| msgstr "" | ||||
|  | ||||
| msgid "RTP-over-TCP" | ||||
| msgstr "" | ||||
|  | ||||
| msgid "Button$Devices" | ||||
| msgstr "Dispositius" | ||||
|  | ||||
| @@ -178,6 +187,15 @@ msgstr "Filtra" | ||||
| msgid "Define an ill-behaving filter to be blacklisted." | ||||
| msgstr "Definir un filtre mal comportar a la llista negra." | ||||
|  | ||||
| msgid "Transport mode" | ||||
| msgstr "" | ||||
|  | ||||
| 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:" | ||||
|  | ||||
|   | ||||
							
								
								
									
										39
									
								
								po/de_DE.po
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								po/de_DE.po
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | ||||
| # VDR plugin language source file. | ||||
| # Copyright (C) 2007-2015 Rolf Ahrenberg | ||||
| # Copyright (C) 2007-2016 Rolf Ahrenberg | ||||
| # This file is distributed under the same license as the satip package. | ||||
| # Frank Neumann, 2014-2015 | ||||
| # Frank Neumann, 2014-2016 | ||||
| # | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: vdr-satip 2.2.0\n" | ||||
| "Project-Id-Version: vdr-satip 2.2.4\n" | ||||
| "Report-Msgid-Bugs-To: <see README>\n" | ||||
| "POT-Creation-Date: 2015-02-19 02:19+0200\n" | ||||
| "PO-Revision-Date: 2015-02-19 02:19+0200\n" | ||||
| "POT-Creation-Date: 2016-12-18 12:18+0200\n" | ||||
| "PO-Revision-Date: 2016-12-18 12:18+0200\n" | ||||
| "Last-Translator: Frank Neumann <fnu@yavdr.org>\n" | ||||
| "Language-Team: German <vdr@linuxtv.org>\n" | ||||
| "Language: de\n" | ||||
| @@ -85,11 +85,20 @@ msgstr "normal" | ||||
| msgid "high" | ||||
| msgstr "hoch" | ||||
|  | ||||
| msgid "Unicast" | ||||
| msgstr "Unicast" | ||||
|  | ||||
| msgid "Multicast" | ||||
| msgstr "Multicast" | ||||
|  | ||||
| msgid "RTP-over-TCP" | ||||
| msgstr "RTP-over-TCP" | ||||
|  | ||||
| msgid "Button$Devices" | ||||
| msgstr "Geräte" | ||||
|  | ||||
| msgid "Operating mode" | ||||
| msgstr "Betriebsmodus" | ||||
| msgstr "Betriebsart" | ||||
|  | ||||
| msgid "" | ||||
| "Define the used operating mode for all SAT>IP devices:\n" | ||||
| @@ -99,7 +108,7 @@ msgid "" | ||||
| "normal - devices are working within normal parameters\n" | ||||
| "high - devices are working at the highest priority" | ||||
| msgstr "" | ||||
| "Bestimme den Betriebsmodus für alle SAT>IP Geräte:\n" | ||||
| "Bestimme die Betriebsart für alle SAT>IP Geräte:\n" | ||||
| "\n" | ||||
| "aus - Geräte sind abgeschaltet\n" | ||||
| "niedrig - Geräte arbeiten mit geringster Priorität\n" | ||||
| @@ -170,13 +179,25 @@ msgid "" | ||||
| msgstr "" | ||||
| "Bestimme die Anzahl der Abschnittsfilter die deaktiviert werden sollen.\n" | ||||
| "\n" | ||||
| "Bestimmte Abschnittsfilter können unerwünschtes Verhalten mit VDR, z.B. falsche Zeit-Synchronisation, verursachen. Durch das Ausblenden einzelner Filter können nützliche Daten dieser Abschnitte für den VDR erhalten 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" | ||||
| msgstr "Filter" | ||||
|  | ||||
| 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:" | ||||
| msgstr "Aktive SAT>IP Server:" | ||||
|   | ||||
							
								
								
									
										26
									
								
								po/es_ES.po
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								po/es_ES.po
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | ||||
| # VDR plugin language source file. | ||||
| # Copyright (C) 2007-2015 Rolf Ahrenberg | ||||
| # Copyright (C) 2007-2016 Rolf Ahrenberg | ||||
| # This file is distributed under the same license as the satip package. | ||||
| # Gabriel Bonich, 2014-2015 | ||||
| # | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: vdr-satip 2.2.0\n" | ||||
| "Project-Id-Version: vdr-satip 2.2.4\n" | ||||
| "Report-Msgid-Bugs-To: <see README>\n" | ||||
| "POT-Creation-Date: 2015-02-19 02:19+0200\n" | ||||
| "PO-Revision-Date: 2015-02-19 02:19+0200\n" | ||||
| "POT-Creation-Date: 2016-12-18 12:18+0200\n" | ||||
| "PO-Revision-Date: 2016-12-18 12:18+0200\n" | ||||
| "Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n" | ||||
| "Language-Team: Spanish <vdr@linuxtv.org>\n" | ||||
| "Language: es\n" | ||||
| @@ -85,6 +85,15 @@ msgstr "Normal" | ||||
| msgid "high" | ||||
| msgstr "Alto" | ||||
|  | ||||
| msgid "Unicast" | ||||
| msgstr "" | ||||
|  | ||||
| msgid "Multicast" | ||||
| msgstr "" | ||||
|  | ||||
| msgid "RTP-over-TCP" | ||||
| msgstr "" | ||||
|  | ||||
| msgid "Button$Devices" | ||||
| msgstr "Dispositivos" | ||||
|  | ||||
| @@ -178,6 +187,15 @@ msgstr "Filtra" | ||||
| msgid "Define an ill-behaving filter to be blacklisted." | ||||
| msgstr "Define un filtro para poner en la lista negra." | ||||
|  | ||||
| msgid "Transport mode" | ||||
| msgstr "" | ||||
|  | ||||
| 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:" | ||||
|  | ||||
|   | ||||
							
								
								
									
										31
									
								
								po/fi_FI.po
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								po/fi_FI.po
									
									
									
									
									
								
							| @@ -1,14 +1,14 @@ | ||||
| # VDR plugin language source file. | ||||
| # Copyright (C) 2007-2015 Rolf Ahrenberg | ||||
| # Copyright (C) 2007-2016 Rolf Ahrenberg | ||||
| # This file is distributed under the same license as the satip package. | ||||
| # Rolf Ahrenberg, 2015 | ||||
| # Rolf Ahrenberg, 2015-2016 | ||||
| # | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: vdr-satip 2.2.0\n" | ||||
| "Project-Id-Version: vdr-satip 2.2.4\n" | ||||
| "Report-Msgid-Bugs-To: <see README>\n" | ||||
| "POT-Creation-Date: 2015-02-19 02:19+0200\n" | ||||
| "PO-Revision-Date: 2015-02-19 02:19+0200\n" | ||||
| "POT-Creation-Date: 2016-12-18 12:18+0200\n" | ||||
| "PO-Revision-Date: 2016-12-18 12:18+0200\n" | ||||
| "Last-Translator: Rolf Ahrenberg\n" | ||||
| "Language-Team: Finnish <vdr@linuxtv.org>\n" | ||||
| "Language: fi\n" | ||||
| @@ -85,6 +85,15 @@ msgstr "normaali" | ||||
| msgid "high" | ||||
| msgstr "korkea" | ||||
|  | ||||
| msgid "Unicast" | ||||
| msgstr "Unicast" | ||||
|  | ||||
| msgid "Multicast" | ||||
| msgstr "Multicast" | ||||
|  | ||||
| msgid "RTP-over-TCP" | ||||
| msgstr "RTP-over-TCP" | ||||
|  | ||||
| msgid "Button$Devices" | ||||
| msgstr "Laitteet" | ||||
|  | ||||
| @@ -177,6 +186,18 @@ msgstr "Suodatin" | ||||
| msgid "Define an ill-behaving filter to be blacklisted." | ||||
| msgstr "Määrittele käytöstä poistettava suodatin, joka lisätään mustalle listalle." | ||||
|  | ||||
| msgid "Transport mode" | ||||
| msgstr "Siirtoyhteystapa" | ||||
|  | ||||
| msgid "" | ||||
| "Define which transport mode shall be used.\n" | ||||
| "\n" | ||||
| "Unicast, Multicast, RTP-over-TCP" | ||||
| msgstr "" | ||||
| "Määrittele käytettävä siirtoyhteystapa.\n" | ||||
| "\n" | ||||
| "Unicast, Multicast, RTP-over-TCP" | ||||
|  | ||||
| msgid "Active SAT>IP servers:" | ||||
| msgstr "Aktiiviset SAT>IP-palvelimet:" | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								poller.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								poller.c
									
									
									
									
									
								
							| @@ -79,7 +79,7 @@ void cSatipPoller::Action(void) | ||||
|   // Do the thread loop | ||||
|   while (Running()) { | ||||
|         int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, -1); | ||||
|         ERROR_IF_FUNC((nfds == -1), "epoll_wait() failed", break, ;); | ||||
|         ERROR_IF_FUNC((nfds == -1 && errno != EINTR), "epoll_wait() failed", break, ;); | ||||
|         for (int i = 0; i < nfds; ++i) { | ||||
|             cSatipPollerIf* poll = reinterpret_cast<cSatipPollerIf *>(events[i].data.ptr); | ||||
|             if (poll) { | ||||
|   | ||||
| @@ -14,10 +14,11 @@ public: | ||||
|   virtual ~cSatipPollerIf() {} | ||||
|   virtual int GetFd(void) = 0; | ||||
|   virtual void Process(void) = 0; | ||||
|   virtual void Process(unsigned char *dataP, int lengthP) = 0; | ||||
|   virtual cString ToString(void) const = 0; | ||||
|  | ||||
| private: | ||||
|   cSatipPollerIf(const cSatipPollerIf&); | ||||
|   explicit cSatipPollerIf(const cSatipPollerIf&); | ||||
|   cSatipPollerIf& operator=(const cSatipPollerIf&); | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										12
									
								
								rtcp.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								rtcp.c
									
									
									
									
									
								
							| @@ -36,7 +36,7 @@ int cSatipRtcp::GetFd(void) | ||||
|  | ||||
| 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) | ||||
|      return -1; | ||||
|   int offset = 0; | ||||
| @@ -92,6 +92,16 @@ void cSatipRtcp::Process(void) | ||||
|      } | ||||
| } | ||||
|  | ||||
| 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); | ||||
|      } | ||||
| } | ||||
|  | ||||
| cString cSatipRtcp::ToString(void) const | ||||
| { | ||||
|   return cString::sprintf("RTCP [device %d]", tunerM.GetId()); | ||||
|   | ||||
							
								
								
									
										3
									
								
								rtcp.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								rtcp.h
									
									
									
									
									
								
							| @@ -23,13 +23,14 @@ private: | ||||
|   int GetApplicationOffset(int *lengthP); | ||||
|  | ||||
| public: | ||||
|   cSatipRtcp(cSatipTunerIf &tunerP); | ||||
|   explicit cSatipRtcp(cSatipTunerIf &tunerP); | ||||
|   virtual ~cSatipRtcp(); | ||||
|  | ||||
|   // for internal poller interface | ||||
| public: | ||||
|   virtual int GetFd(void); | ||||
|   virtual void Process(void); | ||||
|   virtual void Process(unsigned char *dataP, int lengthP); | ||||
|   virtual cString ToString(void) const; | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										16
									
								
								rtp.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								rtp.c
									
									
									
									
									
								
							| @@ -142,6 +142,22 @@ void cSatipRtp::Process(void) | ||||
|      } | ||||
| } | ||||
|  | ||||
| void cSatipRtp::Process(unsigned char *dataP, int lengthP) | ||||
| { | ||||
|   debug16("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); | ||||
|   if (dataP && lengthP > 0) { | ||||
|      uint64_t elapsed; | ||||
|      cTimeMs processing(0); | ||||
|      int headerlen = GetHeaderLength(dataP, lengthP); | ||||
|      if ((headerlen >= 0) && (headerlen < lengthP)) | ||||
|         tunerM.ProcessVideoData(dataP + headerlen, lengthP - headerlen); | ||||
|  | ||||
|      elapsed = processing.Elapsed(); | ||||
|      if (elapsed > 1) | ||||
|         debug6("%s %d read(s) took %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, lengthP, elapsed, tunerM.GetId()); | ||||
|      } | ||||
| } | ||||
|  | ||||
| cString cSatipRtp::ToString(void) const | ||||
| { | ||||
|   return cString::sprintf("RTP [device %d]", tunerM.GetId()); | ||||
|   | ||||
							
								
								
									
										3
									
								
								rtp.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								rtp.h
									
									
									
									
									
								
							| @@ -28,7 +28,7 @@ private: | ||||
|   int GetHeaderLength(unsigned char *bufferP, unsigned int lengthP); | ||||
|  | ||||
| public: | ||||
|   cSatipRtp(cSatipTunerIf &tunerP); | ||||
|   explicit cSatipRtp(cSatipTunerIf &tunerP); | ||||
|   virtual ~cSatipRtp(); | ||||
|   virtual void Close(void); | ||||
|  | ||||
| @@ -36,6 +36,7 @@ public: | ||||
| public: | ||||
|   virtual int GetFd(void); | ||||
|   virtual void Process(void); | ||||
|   virtual void Process(unsigned char *dataP, int lengthP); | ||||
|   virtual cString ToString(void) const; | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										292
									
								
								rtsp.c
									
									
									
									
									
								
							
							
						
						
									
										292
									
								
								rtsp.c
									
									
									
									
									
								
							| @@ -15,9 +15,16 @@ | ||||
|  | ||||
| cSatipRtsp::cSatipRtsp(cSatipTunerIf &tunerP) | ||||
| : tunerM(tunerP), | ||||
|   modeM(cmUnicast), | ||||
|   headerBufferM(), | ||||
|   dataBufferM(), | ||||
|   handleM(NULL), | ||||
|   headerListM(NULL) | ||||
|   headerListM(NULL), | ||||
|   errorNoMoreM(""), | ||||
|   errorOutOfRangeM(""), | ||||
|   errorCheckSyntaxM(""), | ||||
|   modeM(cSatipConfig::eTransportModeUnicast), | ||||
|   interleavedRtpIdM(0), | ||||
|   interleavedRtcpIdM(1) | ||||
| { | ||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); | ||||
|   Create(); | ||||
| @@ -29,46 +36,50 @@ cSatipRtsp::~cSatipRtsp() | ||||
|   Destroy(); | ||||
| } | ||||
|  | ||||
| size_t cSatipRtsp::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP) | ||||
| { | ||||
|   cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP); | ||||
|   size_t len = sizeP * nmembP; | ||||
|   debug16("%s len=%zu", __PRETTY_FUNCTION__, len); | ||||
|  | ||||
|   char *s, *p = (char *)ptrP; | ||||
|   char *r = strtok_r(p, "\r\n", &s); | ||||
|  | ||||
|   while (obj && r) { | ||||
|         debug16("%s (%zu): %s", __PRETTY_FUNCTION__, len, r); | ||||
|         r = skipspace(r); | ||||
|         if (strstr(r, "com.ses.streamID")) { | ||||
|            int streamid = -1; | ||||
|            if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1) | ||||
|               obj->tunerM.SetStreamId(streamid); | ||||
|            } | ||||
|         else if (strstr(r, "Session:")) { | ||||
|            int timeout = -1; | ||||
|            char *session = NULL; | ||||
|            if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2) | ||||
|               obj->tunerM.SetSessionTimeout(skipspace(session), timeout * 1000); | ||||
|            else if (sscanf(r, "Session:%m[^;]", &session) == 1) | ||||
|               obj->tunerM.SetSessionTimeout(skipspace(session), -1); | ||||
|            FREE_POINTER(session); | ||||
|            } | ||||
|         r = strtok_r(NULL, "\r\n", &s); | ||||
|         } | ||||
|  | ||||
|   return len; | ||||
| } | ||||
|  | ||||
| size_t cSatipRtsp::WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP) | ||||
| size_t cSatipRtsp::HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP) | ||||
| { | ||||
|   cSatipRtsp *obj = reinterpret_cast<cSatipRtsp *>(dataP); | ||||
|   size_t len = sizeP * nmembP; | ||||
|   debug16("%s len=%zu", __PRETTY_FUNCTION__, len); | ||||
|  | ||||
|   if (obj && (len > 0)) | ||||
|      obj->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; | ||||
| } | ||||
| @@ -102,6 +113,21 @@ int cSatipRtsp::DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, s | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| cString cSatipRtsp::GetActiveMode(void) | ||||
| { | ||||
|   switch (modeM) { | ||||
|     case cSatipConfig::eTransportModeUnicast: | ||||
|          return "Unicast"; | ||||
|     case cSatipConfig::eTransportModeMulticast: | ||||
|          return "Multicast"; | ||||
|     case cSatipConfig::eTransportModeRtpOverTcp: | ||||
|          return "RTP-over-TCP"; | ||||
|     default: | ||||
|          break; | ||||
|     } | ||||
|   return ""; | ||||
| } | ||||
|  | ||||
| cString cSatipRtsp::RtspUnescapeString(const char *strP) | ||||
| { | ||||
|   debug1("%s (%s) [device %d]", __PRETTY_FUNCTION__, strP, tunerM.GetId()); | ||||
| @@ -138,6 +164,9 @@ void cSatipRtsp::Create(void) | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_TIMEOUT_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 | ||||
|      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; | ||||
| } | ||||
|  | ||||
| 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; | ||||
|  | ||||
|   if (handleM && !isempty(uriP)) { | ||||
| @@ -197,14 +226,17 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP) | ||||
|      cTimeMs processing(0); | ||||
|      CURLcode res = CURLE_OK; | ||||
|  | ||||
|      switch (modeM) { | ||||
|        case cmMulticast: | ||||
|             // RTP/AVP;multicast;destination=<IP multicast address>;port=<RTP port>-<RTCP port>;ttl=<ttl> | ||||
|             transport = cString::sprintf("RTP/AVP;multicast;port=%d-%d", rtpPortP, rtcpPortP); | ||||
|      switch (SatipConfig.GetTransportMode()) { | ||||
|        case cSatipConfig::eTransportModeMulticast: | ||||
|             // RTP/AVP;multicast;destination=<multicast group address>;port=<RTP port>-<RTCP port>;ttl=<ttl>[;source=<multicast source address>] | ||||
|             transport = cString::sprintf("RTP/AVP;multicast"); | ||||
|             break; | ||||
|        default: | ||||
|        case cmUnicast: | ||||
|             // RTP/AVP;unicast;client_port=<client RTP port>-<client RTCP port> | ||||
|             // RTP/AVP/TCP;unicast;client_port=<client RTP port>-<client RTCP port> | ||||
|             if (useTcpP) | ||||
|                transport = cString::sprintf("RTP/AVP/TCP;unicast;interleaved=%u-%u", interleavedRtpIdM, interleavedRtcpIdM); | ||||
|             else | ||||
|                transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpPortP, rtcpPortP); | ||||
|             break; | ||||
|        } | ||||
| @@ -216,10 +248,25 @@ bool cSatipRtsp::Setup(const char *uriP, int rtpPortP, int rtcpPortP) | ||||
|      // Set header callback for catching the session and timeout | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipRtsp::HeaderCallback); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL); | ||||
|  | ||||
|      SATIP_CURL_EASY_PERFORM(handleM); | ||||
|      // Session id is now known - disable header parsing | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL); | ||||
|      if (headerBufferM.Size() > 0) { | ||||
|         ParseHeader(); | ||||
|         headerBufferM.Reset(); | ||||
|         } | ||||
|      if (dataBufferM.Size() > 0) { | ||||
|         ParseData(); | ||||
|         dataBufferM.Reset(); | ||||
|         } | ||||
|  | ||||
|      result = ValidateLatestResponse(&rc); | ||||
|      debug5("%s (%s, %d, %d) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rtpPortP, rtcpPortP, rc, processing.Elapsed(), tunerM.GetId()); | ||||
| @@ -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_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_PERFORM(handleM); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL); | ||||
|      if (dataBufferM.Size() > 0) { | ||||
|         tunerM.ProcessApplicationData((u_char *)dataBufferM.Data(), dataBufferM.Size()); | ||||
|         dataBufferM.Reset(); | ||||
|         } | ||||
|  | ||||
|      result = ValidateLatestResponse(&rc); | ||||
|      debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId()); | ||||
| @@ -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_REQUEST, (long)CURL_RTSPREQ_PLAY); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); | ||||
|      SATIP_CURL_EASY_PERFORM(handleM); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL); | ||||
|      if (dataBufferM.Size() > 0) { | ||||
|         ParseData(); | ||||
|         dataBufferM.Reset(); | ||||
|         } | ||||
|  | ||||
|      result = ValidateLatestResponse(&rc); | ||||
|      debug5("%s (%s) Response %ld in %" PRIu64 " ms [device %d]", __PRETTY_FUNCTION__, uriP, rc, processing.Elapsed(), tunerM.GetId()); | ||||
| @@ -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_REQUEST, (long)CURL_RTSPREQ_TEARDOWN); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, cSatipRtsp::DataCallback); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL); | ||||
|      SATIP_CURL_EASY_PERFORM(handleM); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEFUNCTION, NULL); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, NULL); | ||||
|      if (dataBufferM.Size() > 0) { | ||||
|         ParseData(); | ||||
|         dataBufferM.Reset(); | ||||
|         } | ||||
|  | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_CLIENT_CSEQ, 1L); | ||||
|      SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, NULL); | ||||
| @@ -311,24 +380,153 @@ bool cSatipRtsp::Teardown(const char *uriP) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| void cSatipRtsp::ParseHeader(void) | ||||
| { | ||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); | ||||
|   char *s, *p = headerBufferM.Data(); | ||||
|   char *r = strtok_r(p, "\r\n", &s); | ||||
|  | ||||
|   while (r) { | ||||
|         debug16("%s (%zu): %s", __PRETTY_FUNCTION__, headerBufferM.Size(), r); | ||||
|         r = skipspace(r); | ||||
|         if (strstr(r, "com.ses.streamID")) { | ||||
|            int streamid = -1; | ||||
|            if (sscanf(r, "com.ses.streamID:%11d", &streamid) == 1) | ||||
|               tunerM.SetStreamId(streamid); | ||||
|            } | ||||
|         else if (strstr(r, "Session:")) { | ||||
|            int timeout = -1; | ||||
|            char *session = NULL; | ||||
|            if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2) | ||||
|               tunerM.SetSessionTimeout(skipspace(session), timeout * 1000); | ||||
|            else if (sscanf(r, "Session:%m[^;]", &session) == 1) | ||||
|               tunerM.SetSessionTimeout(skipspace(session), -1); | ||||
|            FREE_POINTER(session); | ||||
|            } | ||||
|         else if (strstr(r, "Transport:")) { | ||||
|            CURLcode res = CURLE_OK; | ||||
|            int rtp = -1, rtcp = -1, ttl = -1; | ||||
|            char *tmp = NULL, *destination = NULL, *source = NULL; | ||||
|            interleavedRtpIdM = 0; | ||||
|            interleavedRtcpIdM = 1; | ||||
|            SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, NULL); | ||||
|            SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, NULL); | ||||
|            if (sscanf(r, "Transport:%m[^;];unicast;client_port=%11d-%11d", &tmp, &rtp, &rtcp) == 3) { | ||||
|               modeM = cSatipConfig::eTransportModeUnicast; | ||||
|               tunerM.SetupTransport(rtp, rtcp, NULL, NULL); | ||||
|               } | ||||
|            else if (sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d;source=%m[^;]", &tmp, &destination, &rtp, &rtcp, &ttl, &source) == 6 || | ||||
|                     sscanf(r, "Transport:%m[^;];multicast;destination=%m[^;];port=%11d-%11d;ttl=%11d", &tmp, &destination, &rtp, &rtcp, &ttl) == 5) { | ||||
|               modeM = cSatipConfig::eTransportModeMulticast; | ||||
|               tunerM.SetupTransport(rtp, rtcp, destination, source); | ||||
|               } | ||||
|            else if (sscanf(r, "Transport:%m[^;];interleaved=%11d-%11d", &tmp, &rtp, &rtcp) == 3) { | ||||
|               interleavedRtpIdM = rtp; | ||||
|               interleavedRtcpIdM = rtcp; | ||||
|               SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEFUNCTION, cSatipRtsp::InterleaveCallback); | ||||
|               SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_INTERLEAVEDATA, this); | ||||
|               modeM = cSatipConfig::eTransportModeRtpOverTcp; | ||||
|               tunerM.SetupTransport(-1, -1, NULL, NULL); | ||||
|               } | ||||
|            FREE_POINTER(tmp); | ||||
|            FREE_POINTER(destination); | ||||
|            FREE_POINTER(source); | ||||
|            } | ||||
|         r = strtok_r(NULL, "\r\n", &s); | ||||
|         } | ||||
| } | ||||
|  | ||||
| void cSatipRtsp::ParseData(void) | ||||
| { | ||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, tunerM.GetId()); | ||||
|   char *s, *p = dataBufferM.Data(); | ||||
|   char *r = strtok_r(p, "\r\n", &s); | ||||
|  | ||||
|   while (r) { | ||||
|         debug16("%s (%zu): %s", __PRETTY_FUNCTION__, dataBufferM.Size(), r); | ||||
|         r = skipspace(r); | ||||
|         if (strstr(r, "No-More:")) { | ||||
|            char *tmp = NULL; | ||||
|            if (sscanf(r, "No-More:%m[^;]", &tmp) == 1) { | ||||
|               errorNoMoreM = skipspace(tmp); | ||||
|               debug3("%s No-More: %s [device %d]", __PRETTY_FUNCTION__, *errorNoMoreM, tunerM.GetId()); | ||||
|               } | ||||
|            FREE_POINTER(tmp); | ||||
|            } | ||||
|         else if (strstr(r, "Out-of-Range:")) { | ||||
|            char *tmp = NULL; | ||||
|            if (sscanf(r, "Out-of-Range:%m[^;]", &tmp) == 1) { | ||||
|               errorOutOfRangeM = skipspace(tmp); | ||||
|               debug3("%s Out-of-Range: %s [device %d]", __PRETTY_FUNCTION__, *errorOutOfRangeM, tunerM.GetId()); | ||||
|               } | ||||
|            FREE_POINTER(tmp); | ||||
|            } | ||||
|         else if (strstr(r, "Check-Syntax:")) { | ||||
|            char *tmp = NULL; | ||||
|            if (sscanf(r, "Check-Syntax:%m[^;]", &tmp) == 1) { | ||||
|               errorCheckSyntaxM = skipspace(tmp); | ||||
|               debug3("%s Check-Syntax: %s [device %d]", __PRETTY_FUNCTION__, *errorCheckSyntaxM, tunerM.GetId()); | ||||
|               } | ||||
|            FREE_POINTER(tmp); | ||||
|            } | ||||
|         r = strtok_r(NULL, "\r\n", &s); | ||||
|         } | ||||
| } | ||||
|  | ||||
| bool cSatipRtsp::ValidateLatestResponse(long *rcP) | ||||
| { | ||||
|   bool result = false; | ||||
|  | ||||
|   if (handleM) { | ||||
|      char *url = NULL; | ||||
|      long rc = 0; | ||||
|      CURLcode res = CURLE_OK; | ||||
|      SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc); | ||||
|      if (rc == 200) | ||||
|      switch (rc) { | ||||
|        case 200: | ||||
|             result = true; | ||||
|      else if (rc != 0) { | ||||
|         char *url = NULL; | ||||
|             break; | ||||
|        case 400: | ||||
|             // SETUP PLAY TEARDOWN | ||||
|             // The message body of the response may contain the "Check-Syntax:" parameter followed | ||||
|             // by the malformed syntax | ||||
|             if (!isempty(*errorCheckSyntaxM)) { | ||||
|                SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url); | ||||
|                error("Check syntax: %s (error code %ld: %s) [device %d]", *errorCheckSyntaxM, rc, url, tunerM.GetId()); | ||||
|                break; | ||||
|                } | ||||
|        case 403: | ||||
|             // SETUP PLAY TEARDOWN | ||||
|             // The message body of the response may contain the "Out-of-Range:" parameter followed | ||||
|             // by a space-separated list of the attribute names that are not understood: | ||||
|             // "src" "fe" "freq" "pol" "msys" "mtype" "plts" "ro" "sr" "fec" "pids" "addpids" "delpids" "mcast" | ||||
|             if (!isempty(*errorOutOfRangeM)) { | ||||
|                SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url); | ||||
|                error("Out of range: %s (error code %ld: %s) [device %d]", *errorOutOfRangeM, rc, url, tunerM.GetId()); | ||||
|                // Reseting the connection wouldn't help anything due to invalid channel configuration, so let it be successful | ||||
|                result = true; | ||||
|                break; | ||||
|                } | ||||
|        case 503: | ||||
|             // SETUP PLAY | ||||
|             // The message body of the response may contain the "No-More:" parameter followed | ||||
|             // by a space-separated list of the missing ressources: “sessions” "frontends" "pids | ||||
|             if (!isempty(*errorNoMoreM)) { | ||||
|                SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url); | ||||
|                error("No more: %s (error code %ld: %s) [device %d]", *errorNoMoreM, rc, url, tunerM.GetId()); | ||||
|                break; | ||||
|                } | ||||
|        default: | ||||
|             SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_EFFECTIVE_URL, &url); | ||||
|             error("Detected invalid status code %ld: %s [device %d]", rc, url, tunerM.GetId()); | ||||
|             break; | ||||
|        } | ||||
|      if (rcP) | ||||
|         *rcP = rc; | ||||
|      } | ||||
|   errorNoMoreM = ""; | ||||
|   errorOutOfRangeM = ""; | ||||
|   errorCheckSyntaxM = ""; | ||||
|   debug1("%s result=%s [device %d]", __PRETTY_FUNCTION__, result ? "ok" : "failed", tunerM.GetId()); | ||||
|  | ||||
|   return result; | ||||
|   | ||||
							
								
								
									
										24
									
								
								rtsp.h
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								rtsp.h
									
									
									
									
									
								
							| @@ -15,26 +15,37 @@ | ||||
| #error "libcurl is missing required RTSP support" | ||||
| #endif | ||||
|  | ||||
| #include "common.h" | ||||
| #include "tunerif.h" | ||||
|  | ||||
| class cSatipRtsp { | ||||
| private: | ||||
|   static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP); | ||||
|   static size_t WriteCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP); | ||||
|   static size_t HeaderCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); | ||||
|   static size_t DataCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); | ||||
|   static size_t InterleaveCallback(char *ptrP, size_t sizeP, size_t nmembP, void *dataP); | ||||
|   static int    DebugCallback(CURL *handleP, curl_infotype typeP, char *dataP, size_t sizeP, void *userPtrP); | ||||
|  | ||||
|   enum { | ||||
|     eConnectTimeoutMs      = 1500,  // in milliseconds | ||||
|     eMaxDownloadSpeedMBits = 20,    // in megabits per second | ||||
|   }; | ||||
|   enum eCommunicationMode { cmUnicast, cmMulticast }; | ||||
|  | ||||
|   cSatipTunerIf &tunerM; | ||||
|   eCommunicationMode modeM; | ||||
|   cSatipMemoryBuffer headerBufferM; | ||||
|   cSatipMemoryBuffer dataBufferM; | ||||
|   CURL *handleM; | ||||
|   struct curl_slist *headerListM; | ||||
|   cString errorNoMoreM; | ||||
|   cString errorOutOfRangeM; | ||||
|   cString errorCheckSyntaxM; | ||||
|   int modeM; | ||||
|   unsigned int interleavedRtpIdM; | ||||
|   unsigned int interleavedRtcpIdM; | ||||
|  | ||||
|   void Create(void); | ||||
|   void Destroy(void); | ||||
|   void ParseHeader(void); | ||||
|   void ParseData(void); | ||||
|   bool ValidateLatestResponse(long *rcP); | ||||
|  | ||||
|   // to prevent copy constructor and assignment | ||||
| @@ -42,13 +53,14 @@ private: | ||||
|   cSatipRtsp& operator=(const cSatipRtsp&); | ||||
|  | ||||
| public: | ||||
|   cSatipRtsp(cSatipTunerIf &tunerP); | ||||
|   explicit cSatipRtsp(cSatipTunerIf &tunerP); | ||||
|   virtual ~cSatipRtsp(); | ||||
|  | ||||
|   cString GetActiveMode(void); | ||||
|   cString RtspUnescapeString(const char *strP); | ||||
|   void Reset(void); | ||||
|   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 Describe(const char *uriP); | ||||
|   bool Play(const char *uriP); | ||||
|   | ||||
							
								
								
									
										120
									
								
								satip.c
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								satip.c
									
									
									
									
									
								
							| @@ -27,7 +27,7 @@ | ||||
| #define GITVERSION "" | ||||
| #endif | ||||
|  | ||||
|        const char VERSION[]     = "2.2.0" GITVERSION; | ||||
|        const char VERSION[]     = "2.2.4" GITVERSION; | ||||
| static const char DESCRIPTION[] = trNOOP("SAT>IP Devices"); | ||||
|  | ||||
| class cPluginSatip : public cPlugin { | ||||
| @@ -35,6 +35,7 @@ private: | ||||
|   unsigned int deviceCountM; | ||||
|   cSatipDiscoverServers *serversM; | ||||
|   void ParseServer(const char *paramP); | ||||
|   void ParsePortRange(const char *paramP); | ||||
|   int ParseCicams(const char *valueP, int *cicamsP); | ||||
|   int ParseSources(const char *valueP, int *sourcesP); | ||||
|   int ParseFilters(const char *valueP, int *filtersP); | ||||
| @@ -62,7 +63,7 @@ public: | ||||
|   }; | ||||
|  | ||||
| cPluginSatip::cPluginSatip(void) | ||||
| : deviceCountM(1), | ||||
| : deviceCountM(2), | ||||
|   serversM(NULL) | ||||
| { | ||||
|   debug16("%s", __PRETTY_FUNCTION__); | ||||
| @@ -83,10 +84,13 @@ const char *cPluginSatip::CommandLineHelp(void) | ||||
|   // Return a string that describes all known command line options. | ||||
|   return "  -d <num>, --devices=<number>  set number of devices to be created\n" | ||||
|          "  -t <mode>, --trace=<mode>     set the tracing mode\n" | ||||
|          "  -s <ipaddr>|<model>|<desc>, --server=<ipaddr1>|<model1>|<desc1>;<ipaddr2>|<model2>|<desc2>\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 all the server quirks\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[]) | ||||
| @@ -97,14 +101,17 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[]) | ||||
|     { "devices",  required_argument, NULL, 'd' }, | ||||
|     { "trace",    required_argument, NULL, 't' }, | ||||
|     { "server",   required_argument, NULL, 's' }, | ||||
|     { "portrange",required_argument, NULL, 'p' }, | ||||
|     { "detach",   no_argument,       NULL, 'D' }, | ||||
|     { "single",   no_argument,       NULL, 'S' }, | ||||
|     { "noquirks", no_argument,       NULL, 'n' }, | ||||
|     { NULL,       no_argument,       NULL,  0  } | ||||
|     }; | ||||
|  | ||||
|   cString server; | ||||
|   cString portrange; | ||||
|   int c; | ||||
|   while ((c = getopt_long(argc, argv, "d:t:s:Sn", long_options, NULL)) != -1) { | ||||
|   while ((c = getopt_long(argc, argv, "d:t:s:p:DSn", long_options, NULL)) != -1) { | ||||
|     switch (c) { | ||||
|       case 'd': | ||||
|            deviceCountM = strtol(optarg, NULL, 0); | ||||
| @@ -115,16 +122,24 @@ bool cPluginSatip::ProcessArgs(int argc, char *argv[]) | ||||
|       case 's': | ||||
|            server = optarg; | ||||
|            break; | ||||
|       case 'D': | ||||
|            SatipConfig.SetDetachedMode(true); | ||||
|            break; | ||||
|       case 'S': | ||||
|            SatipConfig.SetUseSingleModelServers(true); | ||||
|            break; | ||||
|       case 'n': | ||||
|            SatipConfig.SetDisableServerQuirks(true); | ||||
|            break; | ||||
|       case 'p': | ||||
|            portrange = optarg; | ||||
|            break; | ||||
|       default: | ||||
|            return false; | ||||
|       } | ||||
|     } | ||||
|   if (!isempty(*portrange)) | ||||
|      ParsePortRange(portrange); | ||||
|   // this must be done after all parameters are parsed | ||||
|   if (!isempty(*server)) | ||||
|      ParseServer(*server); | ||||
| @@ -217,7 +232,9 @@ void cPluginSatip::ParseServer(const char *paramP) | ||||
|   while (r) { | ||||
|         r = skipspace(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; | ||||
|         char *s2, *p2 = r; | ||||
|         char *r2 = strtok_r(p2, "|", &s2); | ||||
| @@ -225,13 +242,34 @@ void cPluginSatip::ParseServer(const char *paramP) | ||||
|               debug3("%s param[%d]=%s", __PRETTY_FUNCTION__, n2, r2); | ||||
|               switch (n2++) { | ||||
|                      case 0: | ||||
|                           { | ||||
|                           serverAddr = r2; | ||||
|                           char *r3 = strchr(r2, ':'); | ||||
|                           if (r3) { | ||||
|                              serverPort = strtol(r3 + 1, NULL, 0); | ||||
|                              serverAddr = serverAddr.Truncate(r3 - r2); | ||||
|                              } | ||||
|                           } | ||||
|                           break; | ||||
|                      case 1: | ||||
|                           { | ||||
|                           serverModel = r2; | ||||
|                           char *r3 = strchr(r2, ':'); | ||||
|                           if (r3) { | ||||
|                              serverFilters = r3 + 1; | ||||
|                              serverModel = serverModel.Truncate(r3 - r2); | ||||
|                              } | ||||
|                           } | ||||
|                           break; | ||||
|                      case 2: | ||||
|                           { | ||||
|                           serverDescription = r2; | ||||
|                           char *r3 = strchr(r2, ':'); | ||||
|                           if (r3) { | ||||
|                              serverQuirk = strtol(r3 + 1, NULL, 0); | ||||
|                              serverDescription = serverDescription.Truncate(r3 - r2); | ||||
|                              } | ||||
|                           } | ||||
|                           break; | ||||
|                      default: | ||||
|                           break; | ||||
| @@ -239,10 +277,10 @@ void cPluginSatip::ParseServer(const char *paramP) | ||||
|               r2 = strtok_r(NULL, "|", &s2); | ||||
|               } | ||||
|         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) | ||||
|               serversM = new cSatipDiscoverServers(); | ||||
|            serversM->Add(new cSatipDiscoverServer(*serverAddr, *serverModel, *serverDescription)); | ||||
|            serversM->Add(new cSatipDiscoverServer(*serverAddr, serverPort, *serverModel, *serverFilters, *serverDescription, serverQuirk)); | ||||
|            } | ||||
|         ++n; | ||||
|         r = strtok_r(NULL, ";", &s); | ||||
| @@ -250,6 +288,37 @@ void cPluginSatip::ParseServer(const char *paramP) | ||||
|   FREE_POINTER(p); | ||||
| } | ||||
|  | ||||
| void cPluginSatip::ParsePortRange(const char *paramP) | ||||
| { | ||||
|   char *s, *p = skipspace(paramP); | ||||
|   char *r = strtok_r(p, "-", &s); | ||||
|   unsigned int rangeStart = 0; | ||||
|   unsigned int rangeStop = 0; | ||||
|   if (r) { | ||||
|      rangeStart = strtol(r, NULL, 0); | ||||
|      r = strtok_r(NULL, "-", &s); | ||||
|      } | ||||
|   if (r) | ||||
|      rangeStop = strtol(r, NULL, 0); | ||||
|   else { | ||||
|      error("Port range argument not valid '%s'", paramP); | ||||
|      rangeStart = 0; | ||||
|      rangeStop = 0; | ||||
|      } | ||||
|   if (rangeStart % 2) { | ||||
|      error("The given range start port must be even!"); | ||||
|      rangeStart = 0; | ||||
|      rangeStop = 0; | ||||
|      } | ||||
|   else if (rangeStop - rangeStart + 1 < deviceCountM * 2) { | ||||
|      error("The given port range is to small: %d < %d!", rangeStop - rangeStart + 1, deviceCountM * 2); | ||||
|      rangeStart = 0; | ||||
|      rangeStop = 0; | ||||
|      } | ||||
|   SatipConfig.SetPortRangeStart(rangeStart); | ||||
|   SatipConfig.SetPortRangeStop(rangeStop); | ||||
| } | ||||
|  | ||||
| int cPluginSatip::ParseCicams(const char *valueP, int *cicamsP) | ||||
| { | ||||
|   debug1("%s (%s,)", __PRETTY_FUNCTION__, valueP); | ||||
| @@ -337,6 +406,8 @@ bool cPluginSatip::SetupParse(const char *nameP, const char *valueP) | ||||
|      for (unsigned int i = 0; i < DisabledFiltersCount; ++i) | ||||
|          SatipConfig.SetDisabledFilters(i, DisabledFilters[i]); | ||||
|      } | ||||
|   else if (!strcasecmp(nameP, "TransportMode")) | ||||
|      SatipConfig.SetTransportMode(atoi(valueP)); | ||||
|   else | ||||
|      return false; | ||||
|   return true; | ||||
| @@ -366,8 +437,12 @@ const char **cPluginSatip::SVDRPHelpPages(void) | ||||
|     "    Lists status information of SAT>IP devices.\n", | ||||
|     "CONT\n" | ||||
|     "    Shows SAT>IP device count.\n", | ||||
|     "OPER\n" | ||||
|     "    Toggles operating mode of SAT>IP devices.\n", | ||||
|     "OPER [ off | low | normal | high ]\n" | ||||
|     "    Gets and(or sets operating mode of SAT>IP devices.\n", | ||||
|     "ATTA\n" | ||||
|     "    Attach active SAT>IP servers.\n", | ||||
|     "DETA\n" | ||||
|     "    Detachs active SAT>IP servers.\n", | ||||
|     "TRAC [ <mode> ]\n" | ||||
|     "    Gets and/or sets used tracing mode.\n", | ||||
|     NULL | ||||
| @@ -434,8 +509,19 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in | ||||
|      } | ||||
|   else if (strcasecmp(commandP, "OPER") == 0) { | ||||
|      cString mode; | ||||
|      SatipConfig.ToggleOperatingMode(); | ||||
|      switch (SatipConfig.GetOperatingMode()) { | ||||
|      unsigned int oper = SatipConfig.GetOperatingMode(); | ||||
|      if (optionP && *optionP) { | ||||
|         if (strcasecmp(optionP, "off") == 0) | ||||
|            oper = cSatipConfig::eOperatingModeOff; | ||||
|         else if (strcasecmp(optionP, "low") == 0) | ||||
|            oper = cSatipConfig::eOperatingModeLow; | ||||
|         else if (strcasecmp(optionP, "normal") == 0) | ||||
|            oper = cSatipConfig::eOperatingModeNormal; | ||||
|         else if (strcasecmp(optionP, "high") == 0) | ||||
|            oper = cSatipConfig::eOperatingModeHigh; | ||||
|         SatipConfig.SetOperatingMode(oper); | ||||
|      } | ||||
|      switch (oper) { | ||||
|        case cSatipConfig::eOperatingModeOff: | ||||
|             mode = "off"; | ||||
|             break; | ||||
| @@ -454,6 +540,16 @@ cString cPluginSatip::SVDRPCommand(const char *commandP, const char *optionP, in | ||||
|        } | ||||
|      return cString::sprintf("SATIP operating mode: %s\n", *mode); | ||||
|      } | ||||
|   else if (strcasecmp(commandP, "ATTA") == 0) { | ||||
|      SatipConfig.SetDetachedMode(false); | ||||
|      info("SATIP servers attached"); | ||||
|      return cString("SATIP servers attached"); | ||||
|      } | ||||
|   else if (strcasecmp(commandP, "DETA") == 0) { | ||||
|      SatipConfig.SetDetachedMode(true); | ||||
|      info("SATIP servers detached"); | ||||
|      return cString("SATIP servers detached"); | ||||
|      } | ||||
|   else if (strcasecmp(commandP, "TRAC") == 0) { | ||||
|      if (optionP && *optionP) | ||||
|         SatipConfig.SetTraceMode(strtol(optionP, NULL, 0)); | ||||
|   | ||||
| @@ -338,6 +338,19 @@ cString cSatipSectionFilterHandler::GetInformation(void) | ||||
|   return s; | ||||
| } | ||||
|  | ||||
| bool cSatipSectionFilterHandler::Exists(u_short pidP) | ||||
| { | ||||
|   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM); | ||||
|   cMutexLock MutexLock(&mutexM); | ||||
|   for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) { | ||||
|       if (filtersM[i] && (pidP == filtersM[i]->GetPid())) { | ||||
|          debug12("%s (%d) Found [device %d]", __PRETTY_FUNCTION__, pidP, deviceIndexM); | ||||
|          return true; | ||||
|          } | ||||
|       } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cSatipSectionFilterHandler::Delete(unsigned int indexP) | ||||
| { | ||||
|   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, indexP, deviceIndexM); | ||||
|   | ||||
| @@ -80,6 +80,7 @@ public: | ||||
|   cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP); | ||||
|   virtual ~cSatipSectionFilterHandler(); | ||||
|   cString GetInformation(void); | ||||
|   bool Exists(u_short pidP); | ||||
|   int Open(u_short pidP, u_char tidP, u_char maskP); | ||||
|   void Close(int handleP); | ||||
|   int GetPid(int handleP); | ||||
|   | ||||
							
								
								
									
										138
									
								
								server.c
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								server.c
									
									
									
									
									
								
							| @@ -80,16 +80,38 @@ bool cSatipFrontends::Detach(int deviceIdP, int transponderP) | ||||
|  | ||||
| // --- 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 && *addressP) ? addressP : "0.0.0.0"), | ||||
|   modelM((modelP && *modelP) ? modelP : "DVBS-1"), | ||||
|   filtersM((filtersP && *filtersP) ? filtersP : ""), | ||||
|   descriptionM(!isempty(descriptionP) ? descriptionP : "MyBrokenHardware"), | ||||
|   quirksM(""), | ||||
|   quirkM(eSatipQuirkNone), | ||||
|   portM(portP), | ||||
|   quirkM(quirkP), | ||||
|   hasCiM(false), | ||||
|   activeM(true), | ||||
|   createdM(time(NULL)), | ||||
|   lastSeenM(0) | ||||
| { | ||||
|   memset(sourceFiltersM, 0, sizeof(sourceFiltersM)); | ||||
|   if (!isempty(*filtersM)) { | ||||
|      char *s, *p = strdup(*filtersM); | ||||
|      char *r = strtok_r(p, ",", &s); | ||||
|      unsigned int i = 0; | ||||
|      while (r) { | ||||
|            int t = cSource::FromString(skipspace(r)); | ||||
|            if (t && i < ELEMENTS(sourceFiltersM)) | ||||
|               sourceFiltersM[i++] = t; | ||||
|            r = strtok_r(NULL, ",", &s); | ||||
|            } | ||||
|      if (i) { | ||||
|         filtersM = ""; | ||||
|         for (unsigned int j = 0; j < i; ++j) | ||||
|             filtersM = cString::sprintf("%s%s%s", *filtersM, isempty(*filtersM) ? "" : ",", *cSource::ToString(sourceFiltersM[j])); | ||||
|         debug3("%s filters=%s", __PRETTY_FUNCTION__, *filtersM); | ||||
|         } | ||||
|      FREE_POINTER(p); | ||||
|      } | ||||
|   if (!SatipConfig.GetDisableServerQuirks()) { | ||||
|      // These devices contain a session id bug: | ||||
|      // Inverto Airscreen Server IDL 400 ? | ||||
| @@ -97,27 +119,64 @@ cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char | ||||
|      if (strstr(*descriptionM, "GSSBOX") ||             // Grundig Sat Systems GSS.box DSI 400 | ||||
|          strstr(*descriptionM, "DIGIBIT") ||            // Telestar Digibit R1 | ||||
|          strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400 | ||||
|         ) { | ||||
|         ) | ||||
|         quirkM |= eSatipQuirkSessionId; | ||||
|         quirksM = cString::sprintf("%s%sSessionId", *quirksM, isempty(*quirksM) ? "" : ","); | ||||
|         } | ||||
|      // 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: | ||||
|      if (strstr(*descriptionM, "fritzdvbc")             // Fritz!WLAN Repeater DVB-C | ||||
|         ) { | ||||
|         ) | ||||
|         quirkM |= eSatipQuirkPlayPids; | ||||
|         quirksM = cString::sprintf("%s%sPlayPids", *quirksM, isempty(*quirksM) ? "" : ","); | ||||
|         } | ||||
|      // 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; | ||||
|         quirksM = cString::sprintf("%s%sForceLock", *quirksM, isempty(*quirksM) ? "" : ","); | ||||
|         } | ||||
|      debug3("%s description=%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM, *quirksM); | ||||
|      } | ||||
|      // These devices support the X_PMT protocol extension | ||||
|   if (strstr(*descriptionM, "OctopusNet"))              // Digital Devices OctopusNet | ||||
|      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 *r = strtok_r(p, ",", &s); | ||||
|   while (r) { | ||||
| @@ -149,7 +208,7 @@ cSatipServer::cSatipServer(const char *addressP, const char *modelP, const char | ||||
|            } | ||||
|         r = strtok_r(NULL, ",", &s); | ||||
|         } | ||||
|   free(p); | ||||
|   FREE_POINTER(p); | ||||
| } | ||||
|  | ||||
| cSatipServer::~cSatipServer() | ||||
| @@ -168,9 +227,23 @@ int cSatipServer::Compare(const cListObject &listObjectP) const | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| bool cSatipServer::IsValidSource(int sourceP) | ||||
| { | ||||
|   if (sourceFiltersM[0]) { | ||||
|      for (unsigned int i = 0; i < ELEMENTS(sourceFiltersM); ++i) { | ||||
|          if (sourceP == sourceFiltersM[i]) { | ||||
|             return true; | ||||
|             } | ||||
|          } | ||||
|      return false; | ||||
|      } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool cSatipServer::Assign(int deviceIdP, int sourceP, int systemP, int transponderP) | ||||
| { | ||||
|   bool result = false; | ||||
|   if (IsValidSource(sourceP)) { | ||||
|      if (cSource::IsType(sourceP, 'S')) | ||||
|         result = frontendsM[eSatipFrontendDVBS2].Assign(deviceIdP, transponderP); | ||||
|      else if (cSource::IsType(sourceP, 'T')) { | ||||
| @@ -185,23 +258,27 @@ bool cSatipServer::Assign(int deviceIdP, int sourceP, int systemP, int transpond | ||||
|         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')) { | ||||
| @@ -216,6 +293,7 @@ bool cSatipServer::Matches(int deviceIdP, int sourceP, int systemP, int transpon | ||||
|         else | ||||
|            result = frontendsM[eSatipFrontendDVBC].Matches(deviceIdP, transponderP) || frontendsM[eSatipFrontendDVBC2].Matches(deviceIdP, transponderP); | ||||
|         } | ||||
|      } | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| @@ -283,11 +361,11 @@ cSatipServer *cSatipServers::Find(int sourceP) | ||||
| cSatipServer *cSatipServers::Assign(int deviceIdP, int sourceP, int transponderP, int systemP) | ||||
| { | ||||
|   for (cSatipServer *s = First(); s; s = Next(s)) { | ||||
|       if (s->Matches(deviceIdP, sourceP, systemP, transponderP)) | ||||
|       if (s->IsActive() && s->Matches(deviceIdP, sourceP, systemP, transponderP)) | ||||
|          return s; | ||||
|       } | ||||
|   for (cSatipServer *s = First(); s; s = Next(s)) { | ||||
|       if (s->Assign(deviceIdP, sourceP, systemP, transponderP)) | ||||
|       if (s->IsActive() && s->Assign(deviceIdP, sourceP, systemP, transponderP)) | ||||
|          return s; | ||||
|       } | ||||
|   return NULL; | ||||
| @@ -304,6 +382,16 @@ cSatipServer *cSatipServers::Update(cSatipServer *serverP) | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| void cSatipServers::Activate(cSatipServer *serverP, bool onOffP) | ||||
| { | ||||
|   for (cSatipServer *s = First(); s; s = Next(s)) { | ||||
|       if (s == serverP) { | ||||
|          s->Activate(onOffP); | ||||
|          break; | ||||
|          } | ||||
|       } | ||||
| } | ||||
|  | ||||
| void cSatipServers::Attach(cSatipServer *serverP, int deviceIdP, int transponderP) | ||||
| { | ||||
|   for (cSatipServer *s = First(); s; s = Next(s)) { | ||||
| @@ -370,6 +458,18 @@ cString cSatipServers::GetAddress(cSatipServer *serverP) | ||||
|   return address; | ||||
| } | ||||
|  | ||||
| int cSatipServers::GetPort(cSatipServer *serverP) | ||||
| { | ||||
|   int port = SATIP_DEFAULT_RTSP_PORT; | ||||
|   for (cSatipServer *s = First(); s; s = Next(s)) { | ||||
|       if (s == serverP) { | ||||
|          port = s->Port(); | ||||
|          break; | ||||
|          } | ||||
|       } | ||||
|   return port; | ||||
| } | ||||
|  | ||||
| cString cSatipServers::GetString(cSatipServer *serverP) | ||||
| { | ||||
|   cString list = ""; | ||||
| @@ -386,7 +486,7 @@ cString cSatipServers::List(void) | ||||
| { | ||||
|   cString list = ""; | ||||
|   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; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										22
									
								
								server.h
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								server.h
									
									
									
									
									
								
							| @@ -54,15 +54,23 @@ private: | ||||
|     eSatipFrontendDVBC2, | ||||
|     eSatipFrontendCount | ||||
|   }; | ||||
|   enum { | ||||
|     eSatipMaxSourceFilters = 16 | ||||
|   }; | ||||
|   cString addressM; | ||||
|   cString modelM; | ||||
|   cString filtersM; | ||||
|   cString descriptionM; | ||||
|   cString quirksM; | ||||
|   cSatipFrontends frontendsM[eSatipFrontendCount]; | ||||
|   int sourceFiltersM[eSatipMaxSourceFilters]; | ||||
|   int portM; | ||||
|   int quirkM; | ||||
|   bool hasCiM; | ||||
|   bool activeM; | ||||
|   time_t createdM; | ||||
|   cTimeMs lastSeenM; | ||||
|   bool IsValidSource(int sourceP); | ||||
|  | ||||
| public: | ||||
|   enum eSatipQuirk { | ||||
| @@ -70,9 +78,13 @@ public: | ||||
|     eSatipQuirkSessionId  = 0x01, | ||||
|     eSatipQuirkPlayPids   = 0x02, | ||||
|     eSatipQuirkForceLock  = 0x04, | ||||
|     eSatipQuirkMask      = 0x0F | ||||
|     eSatipQuirkRtpOverTcp = 0x08, | ||||
|     eSatipQuirkCiXpmt     = 0x10, | ||||
|     eSatipQuirkCiTnr      = 0x20, | ||||
|     eSatipQuirkForcePilot = 0x40, | ||||
|     eSatipQuirkMask       = 0xFF | ||||
|   }; | ||||
|   cSatipServer(const char *addressP, const char *modelP, const char *descriptionP); | ||||
|   cSatipServer(const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP, const int quirkP); | ||||
|   virtual ~cSatipServer(); | ||||
|   virtual int Compare(const cListObject &listObjectP) const; | ||||
|   bool Assign(int deviceIdP, int sourceP, int systemP, int transponderP); | ||||
| @@ -85,13 +97,17 @@ public: | ||||
|   int GetModulesDVBT2(void); | ||||
|   int GetModulesDVBC(void); | ||||
|   int GetModulesDVBC2(void); | ||||
|   void Activate(bool onOffP)    { activeM = onOffP; } | ||||
|   const char *Address(void)     { return *addressM; } | ||||
|   const char *Model(void)       { return *modelM; } | ||||
|   const char *Filters(void)     { return *filtersM; } | ||||
|   const char *Description(void) { return *descriptionM; } | ||||
|   const char *Quirks(void)      { return *quirksM; } | ||||
|   int Port(void)                { return portM; } | ||||
|   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; } | ||||
| @@ -105,6 +121,7 @@ public: | ||||
|   cSatipServer *Find(int sourceP); | ||||
|   cSatipServer *Assign(int deviceIdP, int sourceP, int transponderP, int systemP); | ||||
|   cSatipServer *Update(cSatipServer *serverP); | ||||
|   void Activate(cSatipServer *serverP, bool onOffP); | ||||
|   void Attach(cSatipServer *serverP, int deviceIdP, int transponderP); | ||||
|   void Detach(cSatipServer *serverP, int deviceIdP, int transponderP); | ||||
|   bool IsQuirk(cSatipServer *serverP, int quirkP); | ||||
| @@ -112,6 +129,7 @@ public: | ||||
|   void Cleanup(uint64_t intervalMsP = 0); | ||||
|   cString GetAddress(cSatipServer *serverP); | ||||
|   cString GetString(cSatipServer *serverP); | ||||
|   int GetPort(cSatipServer *serverP); | ||||
|   cString List(void); | ||||
|   int NumProvidedSystems(void); | ||||
| }; | ||||
|   | ||||
							
								
								
									
										40
									
								
								setup.c
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								setup.c
									
									
									
									
									
								
							| @@ -86,6 +86,8 @@ eOSState cSatipEditSrcItem::ProcessKey(eKeys Key) | ||||
| class cSatipServerInfo : public cOsdMenu | ||||
| { | ||||
| private: | ||||
|   cSatipServer *serverM; | ||||
|   int activeM; | ||||
|   cString addressM; | ||||
|   cString modelM; | ||||
|   cString descriptionM; | ||||
| @@ -94,13 +96,15 @@ private: | ||||
|   void Setup(void); | ||||
|  | ||||
| public: | ||||
|   cSatipServerInfo(cSatipServer *serverP); | ||||
|   explicit cSatipServerInfo(cSatipServer *serverP); | ||||
|   virtual ~cSatipServerInfo(); | ||||
|   virtual eOSState ProcessKey(eKeys keyP); | ||||
| }; | ||||
|  | ||||
| cSatipServerInfo::cSatipServerInfo(cSatipServer *serverP) | ||||
| : cOsdMenu(tr("SAT>IP Server"), 20), | ||||
|   serverM(serverP), | ||||
|   activeM(serverP && serverP->IsActive()), | ||||
|   addressM(serverP ? serverP->Address() : "---"), | ||||
|   modelM(serverP ? serverP->Model() : "---"), | ||||
|   descriptionM(serverP ? serverP->Description() : "---"), | ||||
| @@ -118,6 +122,7 @@ cSatipServerInfo::~cSatipServerInfo() | ||||
|  | ||||
| void cSatipServerInfo::Setup(void) | ||||
| { | ||||
|   Add(new cMenuEditBoolItem(trVDR("Active"), &activeM)); | ||||
|   Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Address"),       *addressM),              osUnknown, false)); | ||||
|   Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Model"),         *modelM),                osUnknown, false)); | ||||
|   Add(new cOsdItem(cString::sprintf("%s:\t%s", tr("Description"),   *descriptionM),          osUnknown, false)); | ||||
| @@ -127,6 +132,7 @@ void cSatipServerInfo::Setup(void) | ||||
|  | ||||
| eOSState cSatipServerInfo::ProcessKey(eKeys keyP) | ||||
| { | ||||
|   int oldActive = activeM; | ||||
|   eOSState state = cOsdMenu::ProcessKey(keyP); | ||||
|  | ||||
|   if (state == osUnknown) { | ||||
| @@ -135,6 +141,12 @@ eOSState cSatipServerInfo::ProcessKey(eKeys keyP) | ||||
|        default:  state = osContinue; break; | ||||
|        } | ||||
|      } | ||||
|  | ||||
|   if (keyP != kNone && oldActive != activeM) { | ||||
|      cSatipDiscover::GetInstance()->ActivateServer(serverM, activeM); | ||||
|      Setup(); | ||||
|      } | ||||
|  | ||||
|   return state; | ||||
| } | ||||
|  | ||||
| @@ -145,7 +157,7 @@ private: | ||||
|   cSatipServer *serverM; | ||||
|  | ||||
| public: | ||||
|   cSatipServerItem(cSatipServer *serverP); | ||||
|   explicit cSatipServerItem(cSatipServer *serverP); | ||||
|   cSatipServer *Server(void) { return serverM; } | ||||
|   virtual void SetMenuItem(cSkinDisplayMenu *displayMenuP, int indexP, bool currentP, bool selectableP); | ||||
|   }; | ||||
| @@ -155,7 +167,7 @@ cSatipServerItem::cSatipServerItem(cSatipServer *serverP) | ||||
| { | ||||
|   SetSelectable(true); | ||||
|   // 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) | ||||
| @@ -330,8 +342,10 @@ eOSState cSatipMenuInfo::ProcessKey(eKeys keyP) | ||||
| // --- cSatipPluginSetup ------------------------------------------------------ | ||||
|  | ||||
| cSatipPluginSetup::cSatipPluginSetup() | ||||
| : deviceCountM(0), | ||||
| : detachedModeM(SatipConfig.GetDetachedMode()), | ||||
|   deviceCountM(0), | ||||
|   operatingModeM(SatipConfig.GetOperatingMode()), | ||||
|   transportModeM(SatipConfig.GetTransportMode()), | ||||
|   ciExtensionM(SatipConfig.GetCIExtension()), | ||||
|   eitScanM(SatipConfig.GetEITScan()), | ||||
|   numDisabledSourcesM(SatipConfig.GetDisabledSourcesCount()), | ||||
| @@ -342,6 +356,9 @@ cSatipPluginSetup::cSatipPluginSetup() | ||||
|   operatingModeTextsM[cSatipConfig::eOperatingModeLow]    = tr("low"); | ||||
|   operatingModeTextsM[cSatipConfig::eOperatingModeNormal] = tr("normal"); | ||||
|   operatingModeTextsM[cSatipConfig::eOperatingModeHigh]   = tr("high"); | ||||
|   transportModeTextsM[cSatipConfig::eTransportModeUnicast]    = tr("Unicast"); | ||||
|   transportModeTextsM[cSatipConfig::eTransportModeMulticast]  = tr("Multicast"); | ||||
|   transportModeTextsM[cSatipConfig::eTransportModeRtpOverTcp] = tr("RTP-over-TCP"); | ||||
|   for (unsigned int i = 0; i < ELEMENTS(cicamsM); ++i) | ||||
|       cicamsM[i] = SatipConfig.GetCICAM(i); | ||||
|   for (unsigned int i = 0; i < ELEMENTS(ca_systems_table); ++i) | ||||
| @@ -399,15 +416,20 @@ void cSatipPluginSetup::Setup(void) | ||||
|          helpM.Append(tr("Define an ill-behaving filter to be blacklisted.")); | ||||
|          } | ||||
|      } | ||||
|   Add(new cMenuEditStraItem(tr("Transport mode"), &transportModeM, ELEMENTS(transportModeTextsM), transportModeTextsM)); | ||||
|   helpM.Append(tr("Define which transport mode shall be used.\n\nUnicast, Multicast, RTP-over-TCP")); | ||||
|   Add(new cOsdItem(tr("Active SAT>IP servers:"), osUnknown, false)); | ||||
|   helpM.Append(""); | ||||
|  | ||||
|   detachedModeM = SatipConfig.GetDetachedMode(); | ||||
|   if (!detachedModeM) { | ||||
|      cSatipServers *servers = cSatipDiscover::GetInstance()->GetServers(); | ||||
|      deviceCountM = servers->Count(); | ||||
|      for (cSatipServer *s = servers->First(); s; s = servers->Next(s)) { | ||||
|          Add(new cSatipServerItem(s)); | ||||
|          helpM.Append(""); | ||||
|          } | ||||
|      } | ||||
|  | ||||
|   SetCurrent(Get(current)); | ||||
|   Display(); | ||||
| @@ -461,10 +483,12 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP) | ||||
|   int oldNumDisabledFilters = numDisabledFiltersM; | ||||
|   eOSState state = cMenuSetupPage::ProcessKey(keyP); | ||||
|  | ||||
|   // Ugly hack with hardcoded '#' character :( | ||||
|   // Ugly hack with hardcoded '+/-' characters :( | ||||
|   const char *p = Get(Current())->Text(); | ||||
|   if (!hadSubMenu && !HasSubMenu() && (*p == '#') && (keyP == kOk)) | ||||
|   if (!hadSubMenu && !HasSubMenu() && p && (*p == '+' || *p == '-') && (keyP == kOk)) | ||||
|      return DeviceInfo(); | ||||
|   if (hadSubMenu && !HasSubMenu()) | ||||
|      Setup(); | ||||
|  | ||||
|   if (state == osUnknown) { | ||||
|      switch (keyP) { | ||||
| @@ -480,7 +504,7 @@ eOSState cSatipPluginSetup::ProcessKey(eKeys keyP) | ||||
|   if ((keyP == kNone) && (cSatipDiscover::GetInstance()->GetServers()->Count() != deviceCountM)) | ||||
|      Setup(); | ||||
|  | ||||
|   if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode) || (ciExtensionM != oldCiExtension))) { | ||||
|   if ((keyP != kNone) && ((numDisabledSourcesM != oldNumDisabledSources) || (numDisabledFiltersM != oldNumDisabledFilters) || (operatingModeM != oldOperatingMode) || (ciExtensionM != oldCiExtension) || (detachedModeM != SatipConfig.GetDetachedMode()))) { | ||||
|      while ((numDisabledSourcesM < oldNumDisabledSources) && (oldNumDisabledSources > 0)) | ||||
|            disabledSourcesM[--oldNumDisabledSources] = cSource::stNone; | ||||
|      while ((numDisabledFiltersM < oldNumDisabledFilters) && (oldNumDisabledFilters > 0)) | ||||
| @@ -543,6 +567,7 @@ void cSatipPluginSetup::Store(void) | ||||
| { | ||||
|   // Store values into setup.conf | ||||
|   SetupStore("OperatingMode", operatingModeM); | ||||
|   SetupStore("TransportMode", transportModeM); | ||||
|   SetupStore("EnableCIExtension", ciExtensionM); | ||||
|   SetupStore("EnableEITScan", eitScanM); | ||||
|   StoreCicams("CICAM", cicamsM); | ||||
| @@ -550,6 +575,7 @@ void cSatipPluginSetup::Store(void) | ||||
|   StoreFilters("DisabledFilters", disabledFilterIndexesM); | ||||
|   // Update global config | ||||
|   SatipConfig.SetOperatingMode(operatingModeM); | ||||
|   SatipConfig.SetTransportMode(transportModeM); | ||||
|   SatipConfig.SetCIExtension(ciExtensionM); | ||||
|   SatipConfig.SetEITScan(eitScanM); | ||||
|   for (int i = 0; i < MAX_CICAM_COUNT; ++i) | ||||
|   | ||||
							
								
								
									
										3
									
								
								setup.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								setup.h
									
									
									
									
									
								
							| @@ -15,9 +15,12 @@ | ||||
| class cSatipPluginSetup : public cMenuSetupPage | ||||
| { | ||||
| private: | ||||
|   bool detachedModeM; | ||||
|   int deviceCountM; | ||||
|   int operatingModeM; | ||||
|   int transportModeM; | ||||
|   const char *operatingModeTextsM[cSatipConfig::eOperatingModeCount]; | ||||
|   const char *transportModeTextsM[cSatipConfig::eTransportModeCount]; | ||||
|   int ciExtensionM; | ||||
|   int cicamsM[MAX_CICAM_COUNT]; | ||||
|   const char *cicamTextsM[CA_SYSTEMS_TABLE_SIZE]; | ||||
|   | ||||
							
								
								
									
										151
									
								
								socket.c
									
									
									
									
									
								
							
							
						
						
									
										151
									
								
								socket.c
									
									
									
									
									
								
							| @@ -21,7 +21,11 @@ | ||||
|  | ||||
| cSatipSocket::cSatipSocket() | ||||
| : socketPortM(0), | ||||
|   socketDescM(-1) | ||||
|   socketDescM(-1), | ||||
|   isMulticastM(false), | ||||
|   useSsmM(false), | ||||
|   streamAddrM(htonl(INADDR_ANY)), | ||||
|   sourceAddrM(htonl(INADDR_ANY)) | ||||
| { | ||||
|   debug1("%s", __PRETTY_FUNCTION__); | ||||
|   memset(&sockAddrM, 0, sizeof(sockAddrM)); | ||||
| @@ -34,10 +38,17 @@ cSatipSocket::~cSatipSocket() | ||||
|   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 | ||||
|   if (socketDescM < 0) { | ||||
|      int yes; | ||||
|      socklen_t len = sizeof(sockAddrM); | ||||
|      // Create socket | ||||
|      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)", | ||||
|                    Close(), return false); | ||||
|      // 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, | ||||
|                    "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 | ||||
|      memset(&sockAddrM, 0, sizeof(sockAddrM)); | ||||
|      sockAddrM.sin_family = AF_INET; | ||||
| @@ -60,20 +81,38 @@ bool cSatipSocket::Open(const int portP) | ||||
|      ERROR_IF_FUNC(getsockname(socketDescM, (struct sockaddr*)&sockAddrM, &len) < 0, | ||||
|                    "getsockname()", Close(), return false); | ||||
|      socketPortM = ntohs(sockAddrM.sin_port); | ||||
|      isMulticastM = false; | ||||
|      } | ||||
|   debug1("%s (%d) socketPort=%d", __PRETTY_FUNCTION__, portP, socketPortM); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool cSatipSocket::OpenMulticast(const int portP, const char *streamAddrP, const char *sourceAddrP) | ||||
| { | ||||
|   debug1("%s (%d, %s, %s)", __PRETTY_FUNCTION__, portP, streamAddrP, sourceAddrP); | ||||
|   if (Open(portP)) { | ||||
|      CheckAddress(streamAddrP, &streamAddrM); | ||||
|      if (!isempty(sourceAddrP)) | ||||
|         useSsmM = CheckAddress(sourceAddrP, &sourceAddrM); | ||||
|      return Join(); | ||||
|      } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| void cSatipSocket::Close(void) | ||||
| { | ||||
|   debug1("%s sockerPort=%d", __PRETTY_FUNCTION__, socketPortM); | ||||
|   // Check if socket exists | ||||
|   if (socketDescM >= 0) { | ||||
|      Leave(); | ||||
|      close(socketDescM); | ||||
|      socketDescM = -1; | ||||
|      socketPortM = 0; | ||||
|      memset(&sockAddrM, 0, sizeof(sockAddrM)); | ||||
|      streamAddrM = htonl(INADDR_ANY); | ||||
|      sourceAddrM = htonl(INADDR_ANY); | ||||
|      isMulticastM = false; | ||||
|      useSsmM = false; | ||||
|      } | ||||
| } | ||||
|  | ||||
| @@ -96,6 +135,96 @@ bool cSatipSocket::Flush(void) | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cSatipSocket::CheckAddress(const char *addrP, in_addr_t *inAddrP) | ||||
| { | ||||
|   if (inAddrP) { | ||||
|      // First try only the IP address | ||||
|      *inAddrP = inet_addr(addrP); | ||||
|      if (*inAddrP == htonl(INADDR_NONE)) { | ||||
|         debug1("%s (%s, ) Cannot convert to address", __PRETTY_FUNCTION__, addrP); | ||||
|         // It may be a host name, get the name | ||||
|         struct hostent *host = gethostbyname(addrP); | ||||
|         if (!host) { | ||||
|            char tmp[64]; | ||||
|            error("gethostbyname() failed: %s is not valid address: %s", addrP, | ||||
|                  strerror_r(h_errno, tmp, sizeof(tmp))); | ||||
|            return false; | ||||
|            } | ||||
|         *inAddrP = inet_addr(*host->h_addr_list); | ||||
|         } | ||||
|      return true; | ||||
|      } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cSatipSocket::Join(void) | ||||
| { | ||||
|   debug1("%s", __PRETTY_FUNCTION__); | ||||
|   // Check if socket exists | ||||
|   if (socketDescM >= 0 && !isMulticastM) { | ||||
|      // Join a new multicast group | ||||
|      if (useSsmM) { | ||||
|         // Source-specific multicast (SSM) is used | ||||
|         struct group_source_req gsr; | ||||
|         struct sockaddr_in *grp; | ||||
|         struct sockaddr_in *src; | ||||
|         gsr.gsr_interface = 0; // if_nametoindex("any") ? | ||||
|         grp = (struct sockaddr_in*)&gsr.gsr_group; | ||||
|         grp->sin_family = AF_INET; | ||||
|         grp->sin_addr.s_addr = streamAddrM; | ||||
|         grp->sin_port = 0; | ||||
|         src = (struct sockaddr_in*)&gsr.gsr_source; | ||||
|         src->sin_family = AF_INET; | ||||
|         src->sin_addr.s_addr = sourceAddrM; | ||||
|         src->sin_port = 0; | ||||
|         ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_JOIN_SOURCE_GROUP)", return false); | ||||
|         } | ||||
|      else { | ||||
|         struct ip_mreq mreq; | ||||
|         mreq.imr_multiaddr.s_addr = streamAddrM; | ||||
|         mreq.imr_interface.s_addr = htonl(INADDR_ANY); | ||||
|         ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false); | ||||
|         } | ||||
|      // Update multicasting flag | ||||
|      isMulticastM = true; | ||||
|      } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool cSatipSocket::Leave(void) | ||||
| { | ||||
|   debug1("%s", __PRETTY_FUNCTION__); | ||||
|   // Check if socket exists | ||||
|   if (socketDescM >= 0 && isMulticastM) { | ||||
|      // Leave the existing multicast group | ||||
|      if (useSsmM) { | ||||
|         // Source-specific multicast (SSM) is used | ||||
|         struct group_source_req gsr; | ||||
|         struct sockaddr_in *grp; | ||||
|         struct sockaddr_in *src; | ||||
|         gsr.gsr_interface = 0; // if_nametoindex("any") ? | ||||
|         grp = (struct sockaddr_in*)&gsr.gsr_group; | ||||
|         grp->sin_family = AF_INET; | ||||
|         grp->sin_addr.s_addr = streamAddrM; | ||||
|         grp->sin_port = 0; | ||||
|         src = (struct sockaddr_in*)&gsr.gsr_source; | ||||
|         src->sin_family = AF_INET; | ||||
|         src->sin_addr.s_addr = sourceAddrM; | ||||
|         src->sin_port = 0; | ||||
|         ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, MCAST_LEAVE_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_LEAVE_SOURCE_GROUP)", return false); | ||||
|         } | ||||
|      else { | ||||
|         struct ip_mreq mreq; | ||||
|         mreq.imr_multiaddr.s_addr = streamAddrM; | ||||
|         mreq.imr_interface.s_addr = htonl(INADDR_ANY); | ||||
|         ERROR_IF_RET(setsockopt(socketDescM, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false); | ||||
|         } | ||||
|      // Update multicasting flag | ||||
|      isMulticastM = false; | ||||
|      } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP) | ||||
| { | ||||
|   debug16("%s (, %d)", __PRETTY_FUNCTION__, bufferLenP); | ||||
| @@ -126,8 +255,22 @@ int cSatipSocket::Read(unsigned char *bufferAddrP, unsigned int bufferLenP) | ||||
|  | ||||
|     if (socketDescM && bufferAddrP && (bufferLenP > 0)) | ||||
|        len = (int)recvmsg(socketDescM, &msgh, MSG_DONTWAIT); | ||||
|     if (len > 0) | ||||
|     if (len > 0) { | ||||
| #ifndef __FreeBSD__ | ||||
|        if (isMulticastM) { | ||||
|           // Process auxiliary received data and validate source address | ||||
|           for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { | ||||
|               if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { | ||||
|                  struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg); | ||||
|                  if ((i->ipi_addr.s_addr == streamAddrM) || (htonl(INADDR_ANY) == streamAddrM)) | ||||
|                     return len; | ||||
|                  } | ||||
|               } | ||||
|           } | ||||
|        else | ||||
| #endif // __FreeBSD__ | ||||
|           return len; | ||||
|        } | ||||
|     } while (len > 0); | ||||
|   ERROR_IF_RET(len < 0 && errno != EAGAIN && errno != EWOULDBLOCK, "recvmsg()", return -1); | ||||
|   return 0; | ||||
|   | ||||
							
								
								
									
										11
									
								
								socket.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								socket.h
									
									
									
									
									
								
							| @@ -15,14 +15,23 @@ private: | ||||
|   int socketPortM; | ||||
|   int socketDescM; | ||||
|   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: | ||||
|   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); | ||||
|   int Fd(void) { return socketDescM; } | ||||
|   int Port(void) { return socketPortM; } | ||||
|   bool IsMulticast(void) { return isMulticastM; } | ||||
|   bool IsOpen(void) { return (socketDescM >= 0); } | ||||
|   bool Flush(void); | ||||
|   int Read(unsigned char *bufferAddrP, unsigned int bufferLenP); | ||||
|   | ||||
							
								
								
									
										113
									
								
								tuner.c
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								tuner.c
									
									
									
									
									
								
							| @@ -25,6 +25,8 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP) | ||||
|   rtcpM(*this), | ||||
|   streamAddrM(""), | ||||
|   streamParamM(""), | ||||
|   tnrParamM(""), | ||||
|   streamPortM(SATIP_DEFAULT_RTSP_PORT), | ||||
|   currentServerM(NULL, deviceP.GetId(), 0), | ||||
|   nextServerM(NULL, deviceP.GetId(), 0), | ||||
|   mutexM(), | ||||
| @@ -50,12 +52,16 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP) | ||||
|   debug1("%s (, %d) [device %d]", __PRETTY_FUNCTION__, packetLenP, deviceIdM); | ||||
|  | ||||
|   // Open sockets | ||||
|   int i = 100; | ||||
|   int i = SatipConfig.GetPortRangeStart() ? SatipConfig.GetPortRangeStop() - SatipConfig.GetPortRangeStart() - 1 : 100; | ||||
|   int port = SatipConfig.GetPortRangeStart(); | ||||
|   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; | ||||
|         rtpM.Close(); | ||||
|         rtcpM.Close(); | ||||
|         if (SatipConfig.GetPortRangeStart()) | ||||
|            port += 2; | ||||
|         } | ||||
|   if ((rtpM.Port() <= 0) || (rtcpM.Port() <= 0)) { | ||||
|      error("Cannot open required RTP/RTCP ports [device %d]", deviceIdM); | ||||
| @@ -91,6 +97,10 @@ cSatipTuner::~cSatipTuner() | ||||
| void cSatipTuner::Action(void) | ||||
| { | ||||
|   debug1("%s Entering [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||
|  | ||||
|   bool lastIdleStatus = false; | ||||
|   cTimeMs idleCheck(eIdleCheckTimeoutMs); | ||||
|   cTimeMs tuning(eTuningTimeoutMs); | ||||
|   reConnectM.Set(eConnectTimeoutMs); | ||||
|   // Do the thread loop | ||||
|   while (Running()) { | ||||
| @@ -107,6 +117,7 @@ void cSatipTuner::Action(void) | ||||
|           case tsSet: | ||||
|                debug4("%s: tsSet [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||
|                if (Connect()) { | ||||
|                   tuning.Set(eTuningTimeoutMs); | ||||
|                   RequestState(tsTuned, smInternal); | ||||
|                   UpdatePids(true); | ||||
|                   } | ||||
| @@ -116,6 +127,8 @@ void cSatipTuner::Action(void) | ||||
|           case tsTuned: | ||||
|                debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||
|                reConnectM.Set(eConnectTimeoutMs); | ||||
|                idleCheck.Set(eIdleCheckTimeoutMs); | ||||
|                lastIdleStatus = false; | ||||
|                // Read reception statistics via DESCRIBE and RTCP | ||||
|                if (hasLockM || ReadReceptionStatus()) { | ||||
|                   // Quirk for devices without valid reception data | ||||
| @@ -127,6 +140,10 @@ void cSatipTuner::Action(void) | ||||
|                   if (hasLockM) | ||||
|                      RequestState(tsLocked, smInternal); | ||||
|                   } | ||||
|                else if (tuning.TimedOut()) { | ||||
|                   error("Tuning timeout - retuning [device %d]", deviceIdM); | ||||
|                   RequestState(tsSet, smInternal); | ||||
|                   } | ||||
|                break; | ||||
|           case tsLocked: | ||||
|                debug4("%s: tsLocked [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||
| @@ -145,6 +162,16 @@ void cSatipTuner::Action(void) | ||||
|                   RequestState(tsSet, smInternal); | ||||
|                   break; | ||||
|                   } | ||||
|                if (idleCheck.TimedOut()) { | ||||
|                   bool currentIdleStatus = deviceM->IsIdle(); | ||||
|                   if (lastIdleStatus && currentIdleStatus) { | ||||
|                      info("Idle timeout - releasing [device %d]", deviceIdM); | ||||
|                      RequestState(tsRelease, smInternal); | ||||
|                      } | ||||
|                   lastIdleStatus = currentIdleStatus; | ||||
|                   idleCheck.Set(eIdleCheckTimeoutMs); | ||||
|                   break; | ||||
|                   } | ||||
|                break; | ||||
|           default: | ||||
|                error("Unknown tuner status %d [device %d]", currentStateM, deviceIdM); | ||||
| @@ -184,7 +211,8 @@ bool cSatipTuner::Connect(void) | ||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||
|  | ||||
|   if (!isempty(*streamAddrM)) { | ||||
|      cString connectionUri = cString::sprintf("rtsp://%s/", *streamAddrM); | ||||
|      cString connectionUri = GetBaseUrl(*streamAddrM, streamPortM); | ||||
|      tnrParamM = ""; | ||||
|      // Just retune | ||||
|      if (streamIdM >= 0) { | ||||
|         cString uri = cString::sprintf("%sstream=%d?%s", *connectionUri, streamIdM, *streamParamM); | ||||
| @@ -196,10 +224,11 @@ bool cSatipTuner::Connect(void) | ||||
|         } | ||||
|      else if (rtspM.Options(*connectionUri)) { | ||||
|         cString uri = cString::sprintf("%s?%s", *connectionUri, *streamParamM); | ||||
|         bool useTcp = SatipConfig.IsTransportModeRtpOverTcp() && nextServerM.IsValid() && nextServerM.IsQuirk(cSatipServer::eSatipQuirkRtpOverTcp); | ||||
|         // Flush any old content | ||||
|         //rtpM.Flush(); | ||||
|         //rtcpM.Flush(); | ||||
|         if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port())) { | ||||
|         if (rtspM.Setup(*uri, rtpM.Port(), rtcpM.Port(), useTcp)) { | ||||
|            keepAliveM.Set(timeoutM); | ||||
|            if (nextServerM.IsValid()) { | ||||
|               currentServerM = nextServerM; | ||||
| @@ -209,7 +238,6 @@ bool cSatipTuner::Connect(void) | ||||
|            return true; | ||||
|            } | ||||
|         } | ||||
|      else | ||||
|      rtspM.Reset(); | ||||
|      streamIdM = -1; | ||||
|      error("Connect failed [device %d]", deviceIdM); | ||||
| @@ -224,7 +252,7 @@ bool cSatipTuner::Disconnect(void) | ||||
|   debug1("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||
|  | ||||
|   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); | ||||
|      // some devices requires a teardown for TCP connection also | ||||
|      rtspM.Reset(); | ||||
| @@ -269,6 +297,11 @@ void cSatipTuner::ProcessVideoData(u_char *bufferP, int lengthP) | ||||
|   reConnectM.Set(eConnectTimeoutMs); | ||||
| } | ||||
|  | ||||
| void cSatipTuner::ProcessRtpData(u_char *bufferP, int lengthP) | ||||
| { | ||||
|   rtpM.Process(bufferP, lengthP); | ||||
| } | ||||
|  | ||||
| void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) | ||||
| { | ||||
|   debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, lengthP, deviceIdM); | ||||
| @@ -322,6 +355,11 @@ void cSatipTuner::ProcessApplicationData(u_char *bufferP, int lengthP) | ||||
|   reConnectM.Set(eConnectTimeoutMs); | ||||
| } | ||||
|  | ||||
| void cSatipTuner::ProcessRtcpData(u_char *bufferP, int lengthP) | ||||
| { | ||||
|   rtcpM.Process(bufferP, lengthP); | ||||
| } | ||||
|  | ||||
| void cSatipTuner::SetStreamId(int streamIdP) | ||||
| { | ||||
|   cMutexLock MutexLock(&mutexM); | ||||
| @@ -339,6 +377,47 @@ void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP) | ||||
|   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) | ||||
| { | ||||
|   debug16("%s [device %d]", __PRETTY_FUNCTION__, deviceIdM); | ||||
| @@ -355,6 +434,10 @@ bool cSatipTuner::SetSource(cSatipServer *serverP, const int transponderP, const | ||||
|         // Update stream address and parameter | ||||
|         streamAddrM = rtspM.RtspUnescapeString(*nextServerM.GetAddress()); | ||||
|         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 | ||||
|         RequestState(tsSet, smExternal); | ||||
|         } | ||||
| @@ -393,7 +476,7 @@ bool cSatipTuner::UpdatePids(bool forceP) | ||||
|   cMutexLock MutexLock(&mutexM); | ||||
|   if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) && | ||||
|       !isempty(*streamAddrM) && (streamIdM > 0)) { | ||||
|      cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); | ||||
|      cString uri = cString::sprintf("%sstream=%d", *GetBaseUrl(*streamAddrM, streamPortM), streamIdM); | ||||
|      bool useci = (SatipConfig.GetCIExtension() && currentServerM.HasCI()); | ||||
|      bool usedummy = currentServerM.IsQuirk(cSatipServer::eSatipQuirkPlayPids); | ||||
|      if (forceP || usedummy) { | ||||
| @@ -409,6 +492,7 @@ bool cSatipTuner::UpdatePids(bool forceP) | ||||
|            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 | ||||
| @@ -424,6 +508,15 @@ bool cSatipTuner::UpdatePids(bool forceP) | ||||
|               } | ||||
|            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)) | ||||
|         return false; | ||||
| @@ -443,7 +536,7 @@ bool cSatipTuner::KeepAlive(bool forceP) | ||||
|      forceP = true; | ||||
|      } | ||||
|   if (forceP && !isempty(*streamAddrM)) { | ||||
|      cString uri = cString::sprintf("rtsp://%s/", *streamAddrM); | ||||
|      cString uri = GetBaseUrl(*streamAddrM, streamPortM); | ||||
|      if (!rtspM.Options(*uri)) | ||||
|         return false; | ||||
|      } | ||||
| @@ -460,7 +553,7 @@ bool cSatipTuner::ReadReceptionStatus(bool forceP) | ||||
|      forceP = true; | ||||
|      } | ||||
|   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)) | ||||
|         return true; | ||||
|      } | ||||
| @@ -595,5 +688,5 @@ cString cSatipTuner::GetSignalStatus(void) | ||||
| cString cSatipTuner::GetInformation(void) | ||||
| { | ||||
|   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"; | ||||
| } | ||||
|   | ||||
							
								
								
									
										9
									
								
								tuner.h
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								tuner.h
									
									
									
									
									
								
							| @@ -69,6 +69,7 @@ public: | ||||
|   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); } | ||||
| }; | ||||
|  | ||||
| @@ -83,6 +84,8 @@ private: | ||||
|     eStatusUpdateTimeoutMs  = 1000,  // in milliseconds | ||||
|     ePidUpdateIntervalMs    = 250,   // in milliseconds | ||||
|     eConnectTimeoutMs       = 5000,  // in milliseconds | ||||
|     eIdleCheckTimeoutMs     = 15000, // in milliseconds | ||||
|     eTuningTimeoutMs        = 20000, // in milliseconds | ||||
|     eMinKeepAliveIntervalMs = 30000  // in milliseconds | ||||
|   }; | ||||
|   enum eTunerState { tsIdle, tsRelease, tsSet, tsTuned, tsLocked }; | ||||
| @@ -96,6 +99,8 @@ private: | ||||
|   cSatipRtcp rtcpM; | ||||
|   cString streamAddrM; | ||||
|   cString streamParamM; | ||||
|   cString tnrParamM; | ||||
|   int streamPortM; | ||||
|   cSatipTunerServer currentServerM; | ||||
|   cSatipTunerServer nextServerM; | ||||
|   cMutex mutexM; | ||||
| @@ -128,6 +133,7 @@ private: | ||||
|   bool RequestState(eTunerState stateP, eStateMode modeP); | ||||
|   const char *StateModeString(eStateMode modeP); | ||||
|   const char *TunerStateString(eTunerState stateP); | ||||
|   cString GetBaseUrl(const char *addressP, const int portP); | ||||
|  | ||||
| protected: | ||||
|   virtual void Action(void); | ||||
| @@ -151,8 +157,11 @@ public: | ||||
| public: | ||||
|   virtual void ProcessVideoData(u_char *bufferP, int lengthP); | ||||
|   virtual void ProcessApplicationData(u_char *bufferP, int lengthP); | ||||
|   virtual void ProcessRtpData(u_char *bufferP, int lengthP); | ||||
|   virtual void ProcessRtcpData(u_char *bufferP, int lengthP); | ||||
|   virtual void SetStreamId(int streamIdP); | ||||
|   virtual void SetSessionTimeout(const char *sessionP, int timeoutP); | ||||
|   virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP); | ||||
|   virtual int GetId(void); | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -14,12 +14,15 @@ public: | ||||
|   virtual ~cSatipTunerIf() {} | ||||
|   virtual void ProcessVideoData(u_char *bufferP, int lengthP) = 0; | ||||
|   virtual void ProcessApplicationData(u_char *bufferP, int lengthP) = 0; | ||||
|   virtual void ProcessRtpData(u_char *bufferP, int lengthP) = 0; | ||||
|   virtual void ProcessRtcpData(u_char *bufferP, int lengthP) = 0; | ||||
|   virtual void SetStreamId(int streamIdP) = 0; | ||||
|   virtual void SetSessionTimeout(const char *sessionP, int timeoutP) = 0; | ||||
|   virtual void SetupTransport(int rtpPortP, int rtcpPortP, const char *streamAddrP, const char *sourceAddrP) = 0; | ||||
|   virtual int GetId(void) = 0; | ||||
|  | ||||
| private: | ||||
|   cSatipTunerIf(const cSatipTunerIf&); | ||||
|   explicit cSatipTunerIf(const cSatipTunerIf&); | ||||
|   cSatipTunerIf& operator=(const cSatipTunerIf&); | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user