[StreamServerSeek] Reverse-Proxy + Player
[enigma2-plugins.git] / streamserverseek / src / StreamServerSeek.py
1 from enigma import eStreamServer, eServiceReference, iPlayableService, eTimer
2 from Components.config import config
3 from Components.PerServiceDisplay import PerServiceBase
4
5 import os.path
6
7 if os.path.isfile("/usr/lib/enigma2/python/Plugins/SystemPlugins/GstRtspServer/StreamServerControl.py"):
8         from Plugins.SystemPlugins.GstRtspServer.StreamServerControl import streamServerControl
9 else:
10         from Components.StreamServerControl import streamServerControl
11
12 from subprocess import call
13
14 class StreamServerSeekNoSessionException(BaseException):
15         pass
16
17 class StreamServerSeekAlreadyInitializedException(BaseException):
18         pass
19
20 class StreamServerSeek(PerServiceBase):
21         __instance = None
22         _session = None
23         _seekToMin = 0
24         _isTemporaryLiveMode = False
25         _isTemporaryLiveModeActive = False
26         _temporaryLiveModeService = False
27         _tvLastService = False
28         _origCec = False
29
30         def __new__(cls, *p, **k):
31                 if StreamServerSeek.__instance is None:
32                         if not 'session' in k:
33                                 raise StreamServerSeekNoSessionException
34                         StreamServerSeek._session = k["session"]
35                         StreamServerSeek.__instance = PerServiceBase.__new__(cls)
36                 elif 'session' in k:
37                         raise StreamServerSeekAlreadyInitializedException
38
39                 return StreamServerSeek.__instance
40         
41         def __init__(self, *p, **k):
42                 if not 'session' in k:
43                         return
44
45                 print "[StreamServerSeek] init"
46                 
47                 config.misc.standbyCounter.addNotifier(self._onStandby, initial_call = False)
48
49                 PerServiceBase.__init__(self, self._session.nav,
50                         { 
51                                 iPlayableService.evServiceChanged: self._onServiceChanged,
52                                 iPlayableService.evEOF: self._onEOF,
53                                 iPlayableService.evPlay: self._onPlaying
54                         }, with_event=False)
55                 
56                 
57                 self._timer = eTimer()
58                 self._timer_conn = self._timer.timeout.connect(self.endTemporaryLiveMode)
59
60                 streamServerControl.onSourceStateChanged.append(self._onSourceStateChanged)
61                 
62         def _onStandby(self, element):
63                 if self._isTemporaryLiveMode:
64                         print "[StreamserverSeek] onStandBy: Ending temporary Live-Mode"
65                         self.endTemporaryLiveMode(False)
66
67                 if self._origCec:
68                         print "[StreamserverSeek] Re-enable CEC"
69                         config.cec.enabled.value = True
70                         config.cec.enabled.save()
71
72         def _onServiceChanged(self):
73                 if self._isTemporaryLiveModeActive and self._temporaryLiveModeService and eServiceReference(self._temporaryLiveModeService).toCompareString() != self.navcore.getCurrentServiceReference().toCompareString():
74                         print "[StreamserverSeek] onServiceChanged: Ending temporary Live-Mode"
75                         self.endTemporaryLiveMode(False)
76
77         def _onEOF(self):
78                 if self._isTemporaryLiveModeActive:
79                         print "[StreamserverSeek] onEOF: Ending temporary Live-Mode"
80                         self.endTemporaryLiveMode()
81
82         def _onPlaying(self):
83                 if self._isTemporaryLiveModeActive:
84                         self.doSeek()
85         
86         def _onSourceStateChanged(self, state):
87                 if self._isTemporaryLiveMode and (state == False or state == 2):
88                         print "[StreamserverSeek] Temporary Live-Mode active, but all clients disconnected. End it in 15 seconds"
89                         self._timer.start(15000, True)
90                 elif self._isTemporaryLiveMode and self._timer.isActive():
91                         print "[StreamserverSeek] Reset end-timer"
92                         self._timer.stop()
93                 
94                 if state == True or state == 4:
95                         self.doSeek()
96
97         def doSeek(self):
98                 if not self._seekToMin:
99                         return
100
101                 print "[StreamserverSeek] doSeek()"
102
103                 seek = False
104                 if self._isTemporaryLiveModeActive:
105                         seek = self._session.nav.getCurrentService().seek()
106                 elif streamServerControl._encoderService:
107                         seek = streamServerControl._encoderService.seek()
108
109                 if seek:
110                         print "[StreamserverSeek] Seeking to %d minutes" % self._seekToMin
111                         seek.seekTo(self._seekToMin * 60 * 90000)
112
113                 self._seekToMin = 0
114
115         def changeIdleMode(self, idle):
116                 from Screens.Standby import inStandby
117                 if (inStandby is None and not idle) or (not inStandby is None and idle):
118                         return
119
120                 if not idle:
121                         self._origCec = config.cec.enabled.value
122                         if self._origCec:
123                                 print "[StreamserverSeek] Disable CEC"
124                                 config.cec.enabled.value = False
125                                 config.cec.enabled.save()
126                         inStandby.Power()
127                 else:
128                         from Screens.Standby import Standby
129                         self._session.open(Standby)
130
131         def forceInputMode(self, inputMode):
132                 if os.path.isfile("/usr/lib/enigma2/python/Plugins/SystemPlugins/GstRtspServer/StreamServerControl.py"):
133                         from Plugins.SystemPlugins.GstRtspServer.StreamServerConfig import applyConfig
134                         config.streamserver.source.value = str(inputMode)
135                         applyConfig(streamServerControl, False, True)
136                         return
137
138                 # This *should* work like done below the "return". However this leads to EncoderTimeout and hanging daemon sometimes
139                 # Therefor just kill it...
140                 call(["systemctl", "disable", "dreamliveserver.socket"])
141                 call(["killall", "-9", "dreamliveserver"])
142                 streamServerControl.config.streamserver.source.value = str(inputMode)
143                 streamServerControl.setInputMode(inputMode)
144                 call(["systemctl", "enable", "dreamliveserver.socket"])
145                 streamServerControl.config.streamserver.source.save()
146                 return
147
148                 # doesn't work reliably if a client is still connected:
149                 isMediatorEnabled = streamServerControl.config.streamserver.mediator.enabled.value
150
151                 rtsp_enabled = streamServerControl.config.streamserver.rtsp.enabled.value
152                 rtsp_path = streamServerControl.config.streamserver.rtsp.path.value
153                 rtsp_user = streamServerControl.config.streamserver.rtsp.user.value
154                 rtsp_password = streamServerControl.config.streamserver.rtsp.password.value
155                 #rtsp_port = streamServerControl.config.streamserver.rtsp.port.value
156                 hls_enabled = streamServerControl.config.streamserver.hls.enabled.value
157                 hls_path = streamServerControl.config.streamserver.hls.path.value
158                 #hls_port = streamServerControl.config.streamserver.hls.port.value
159                 hls_user = streamServerControl.config.streamserver.hls.user.value
160                 hls_password = streamServerControl.config.streamserver.hls.password.value
161
162                 streamServerControl.enableRTSP(False, rtsp_path, 554, rtsp_user, rtsp_password)
163                 streamServerControl.enableHLS(False, hls_path, 8080, hls_user, hls_password)
164                 streamServerControl.config.streamserver.mediator.enabled.value = False
165
166                 streamServerControl.config.streamserver.source.value = str(inputMode)
167                 streamServerControl.setInputMode(inputMode)
168
169                 streamServerControl.enableRTSP(rtsp_enabled, rtsp_path, 554, rtsp_user, rtsp_password)
170                 streamServerControl.enableHLS(hls_enabled, hls_path, 8080, hls_user, hls_password)
171                 streamServerControl.config.streamserver.mediator.enabled.value = isMediatorEnabled
172
173         def endTemporaryLiveMode(self, idle = True):
174                 if not self._isTemporaryLiveMode:
175                         return
176
177                 self._isTemporaryLiveMode = False
178                 self._isTemporaryLiveModeActive = False
179                 self._temporaryLiveModeService = False
180                 
181                 if self._tvLastService:
182                         service = eServiceReference(self._tvLastService)
183                         if service and service.valid():
184                                 self._session.nav.playService(service)
185         
186                 print "[StreamserverSeek] Set input mode to BACKGROUND"
187                 self.forceInputMode(eStreamServer.INPUT_MODE_BACKGROUND)
188
189                 if idle:
190                         self.changeIdleMode(True)
191
192         def destroy(self):
193                 PerServiceBase.destroy(self)