cc19a78d7ebbf259a7920317e180c967e17e5392
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / FastChannelChange / plugin.py
1
2 from Plugins.Plugin import PluginDescriptor
3 import NavigationInstance
4
5 from Screens.Screen import Screen
6 from Screens.InfoBar import InfoBar
7 from Screens.MessageBox import MessageBox
8
9 from Components.NimManager import nimmanager
10 from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigYesNo, ConfigSelection
11 from Components.ConfigList import ConfigListScreen
12 from Components.ActionMap import ActionMap
13 from Components.Sources.StaticText import StaticText
14 from Components.ServiceEventTracker import ServiceEventTracker
15
16 from enigma import iPlayableService, iServiceInformation, eEnv, eTimer, eServiceReference, iRecordableService
17
18 import os
19 import glob
20
21 from enigma import eFCCServiceManager
22
23 g_max_fcc = len(glob.glob('/dev/fcc?'))
24 g_default_fcc = (g_max_fcc) > 5 and 5 or g_max_fcc
25
26 config.plugins.fccsetup = ConfigSubsection()
27 config.plugins.fccsetup.activate = ConfigYesNo(default = False)
28 config.plugins.fccsetup.maxfcc = ConfigSelection(default = str(g_default_fcc), choices = list((str(n), str(n)) for n in range(2, g_max_fcc+1)))
29 config.plugins.fccsetup.zapupdown = ConfigYesNo(default = True)
30 config.plugins.fccsetup.history = ConfigYesNo(default = False)
31 config.plugins.fccsetup.priority = ConfigSelection(default = "zapupdown", choices = { "zapupdown" : _("Zap Up/Down"), "historynextback" : _("History Prev/Next") })
32 config.plugins.fccsetup.disableforrec = ConfigYesNo(default = True)
33
34 FccInstance = None
35
36 def FCCChanged():
37         if FccInstance:
38                 FccInstance.FCCSetupChanged()
39
40 def checkSupportFCC():
41         global g_max_fcc
42         return bool(g_max_fcc)
43
44 class FCCSupport:
45         def __init__(self, session):
46                 self.session = session
47
48                 self.fccmgr = eFCCServiceManager.getInstance();
49
50                 self.fccList = []
51
52                 self.createListTimer = eTimer()
53                 self.createListTimer.callback.append(self.FCCCreateList)
54
55                 self.getSrefTimer = eTimer()
56                 self.getSrefTimer.callback.append(self.FCCGetCurSref)
57
58                 self.eventList = []
59                 self.fccEventTimer = eTimer()
60                 self.fccEventTimer.callback.append(self.FCCApplyEvent)
61
62                 self.fccForceStartTimer = eTimer()
63                 self.fccForceStartTimer.callback.append(self.FCCForceStartForREC)
64
65                 self.fccResetTimer = eTimer()
66                 self.fccResetTimer.callback.append(self.FCCResetTimerForREC)
67
68                 self.activating = False
69
70                 self.fccSetupActivate = checkSupportFCC() and config.plugins.fccsetup.activate.value
71                 self.maxFCC = int(config.plugins.fccsetup.maxfcc.value)
72                 self.zapdownEnable = config.plugins.fccsetup.zapupdown.value
73                 self.historyEnable = config.plugins.fccsetup.history.value
74                 self.priority = config.plugins.fccsetup.priority.value
75                 self.disableforrec = config.plugins.fccsetup.disableforrec.value
76                 self.fccmgr.setFCCEnable(int(self.fccSetupActivate))
77
78                 self.setProcFCC(self.fccSetupActivate)
79                 self.fccTimeoutTimer = eTimer()
80                 self.fccTimeoutTimer.callback.append(self.FCCTimeout)
81                 self.fccTimeoutEventCode = 0x102
82                 self.fccTimeoutWait = None
83
84                 self.fccmgr.m_fcc_event.get().append(self.FCCGetEvent)
85
86                 self.getRecordings()
87
88                 self.__event_tracker = None
89                 self.onClose = []
90                 self.changeEventTracker()
91
92         def setProcFCC(self, value):
93                 procPath = "/proc/stb/frontend/fbc/fcc"
94                 if os.access(procPath, os.W_OK):
95                         fd = open(procPath,'w')
96                         fd.write(value and "enable" or "disable")
97                         fd.close()
98                 else:
99                         print "[FCCSupport] write fail! : ", procPath
100
101         def gotRecordEvent(self, service, event):
102                 if self.disableforrec:
103                         if (not self.recordings) and (event == iRecordableService.evTuneStart):
104                                 self.getRecordings()
105                                 if self.recordings:
106                                         self.FCCForceStopForREC()
107
108                         elif event == iRecordableService.evEnd:
109                                 self.getRecordings()
110                                 if not self.recordings:
111                                         self.FCCForceStartForREC()
112                 else:
113                         if event == iRecordableService.evTuneStart:
114                                 self.fccResetTimer.stop()
115                                 self.FCCForceStopForREC()
116                                 self.fccForceStartTimer.start(2000, True)
117
118                         elif event == iRecordableService.evEnd:
119                                 self.fccForceStartTimer.stop()
120                                 self.fccResetTimer.start(2000, True)
121
122         def FCCForceStopForREC(self):
123                 self.enableEventTracker(False)
124                 self.FCCDisableServices()
125                 self.FCCStopAllServices()
126
127         def FCCForceStartForREC(self):
128                 self.enableEventTracker(True)
129                 self.FCCForceStart()
130
131         def FCCResetTimerForREC(self):
132                 self.FCCForceStopForREC()
133                 self.FCCForceStartForREC()
134
135         def FCCSetupChanged(self):
136                 fcc_changed = False
137
138                 newFccSetupActivate = checkSupportFCC() and config.plugins.fccsetup.activate.value
139                 if self.fccSetupActivate != newFccSetupActivate:
140                         self.fccSetupActivate = newFccSetupActivate
141                         self.setProcFCC(self.fccSetupActivate)
142                         fcc_changed = True
143
144                 if int(config.plugins.fccsetup.maxfcc.value) != self.maxFCC:
145                         self.maxFCC = int(config.plugins.fccsetup.maxfcc.value)
146                         fcc_changed = True
147
148                 if self.zapdownEnable != config.plugins.fccsetup.zapupdown.value:
149                         self.zapdownEnable = config.plugins.fccsetup.zapupdown.value
150                         fcc_changed = True
151
152                 if self.historyEnable != config.plugins.fccsetup.history.value:
153                         self.historyEnable = config.plugins.fccsetup.history.value
154                         fcc_changed = True
155
156                 if self.priority != config.plugins.fccsetup.priority.value:
157                         self.priority = config.plugins.fccsetup.priority.value
158                         fcc_changed = True
159
160                 if self.disableforrec != config.plugins.fccsetup.disableforrec.value:
161                         self.disableforrec = config.plugins.fccsetup.disableforrec.value
162                         fcc_changed = True
163
164                 self.getRecordings()
165                 self.changeEventTracker()
166
167                 if (not self.fccSetupActivate) or (self.disableforrec and self.recordings):
168                         self.FCCDisableServices()
169
170                 if fcc_changed:
171                         self.fccmgr.setFCCEnable(int(self.fccSetupActivate))
172                         curPlaying = self.session.nav.getCurrentlyPlayingServiceReference()
173                         if curPlaying:
174                                 self.session.nav.stopService()
175                                 self.session.nav.playService(curPlaying)
176
177         # get current recording state
178         def getRecordings(self):
179                 self.recordings = bool(self.session.nav.getRecordings())
180
181         def addRecordEventCallback(self, enable=True):
182                 if enable:
183                         if self.gotRecordEvent not in self.session.nav.record_event:
184                                 self.session.nav.record_event.append(self.gotRecordEvent)
185                 else:
186                         if self.gotRecordEvent in self.session.nav.record_event:
187                                 self.session.nav.record_event.remove(self.gotRecordEvent)
188
189         def changeEventTracker(self):
190                 if self.fccSetupActivate:
191                         self.addRecordEventCallback(True)
192                         if self.disableforrec and self.recordings:
193                                 self.enableEventTracker(False)
194                         else:
195                                 self.enableEventTracker(True)
196                 else:
197                         self.addRecordEventCallback(False)
198                         self.enableEventTracker(False)
199
200         def enableEventTracker(self, activate):
201                 if activate:
202                         if not self.__event_tracker:
203                                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
204                                 {
205                                         iPlayableService.evStart: self.getEvStart,
206                                         iPlayableService.evEnd: self.getEvEnd,
207                                         iPlayableService.evTunedIn: self.getEvTunedIn,
208                                         iPlayableService.evTuneFailed: self.getEvTuneFailed
209                                         })
210
211                 elif self.__event_tracker:
212                         # run ServiceEventTracker.__del_event()
213                         for x in self.onClose:
214                                 x()
215
216                         self.onClose = []
217                         self.__event_tracker = None
218
219         def getEvStart(self):
220                 self.createListTimer.start(0,True)
221
222         def getEvEnd(self):
223                 self.FCCDisableServices()
224
225         def getEvTunedIn(self):
226                 self.FCCTryStart()
227
228         def getEvTuneFailed(self):
229                 self.FCCTryStart()
230
231         def isPlayableFCC(self, sref):
232                 playable = True
233                 if isinstance(sref, str):
234                         sref = eServiceReference(sref)
235
236                 if sref.type != 1:
237                         playable = False
238
239                 elif sref.getPath(): # is PVR? or streaming?
240                         playable = False
241
242                 elif int(sref.getData(0)) in (2, 10): # is RADIO?
243                         playable = False
244
245                 return playable
246
247         def getZapUpDownList(self):
248                 fccZapUpDownList = []
249                 serviceList = InfoBar.instance.servicelist.servicelist.getList()
250                 curServiceRef = InfoBar.instance.servicelist.servicelist.getCurrent().toString()
251
252                 serviceRefList = []
253                 for idx in range(len(serviceList)):
254                         sref = serviceList[idx].toString()
255                         if (sref.split(':')[1] == '0') and self.isPlayableFCC(sref) : # remove marker
256                                 serviceRefList.append(sref)
257
258                 if curServiceRef in serviceRefList:
259                         serviceRefListSize = len(serviceRefList)
260                         curServiceIndex = serviceRefList.index(curServiceRef)
261
262                         for x in range(self.maxFCC-1):
263                                 if x > (serviceRefListSize-2): # if not ((x+1) <= (serviceRefListSize-1))
264                                         break
265
266                                 idx = (x / 2) + 1
267                                 if x % 2:
268                                         idx *= -1 # idx : [ 1, -1, 2, -2, 3, -3, 4, -4 ....]
269                                 idx = (curServiceIndex+idx) % serviceRefListSize # calc wraparound
270                                 try:
271                                         fccZapUpDownList.append(serviceRefList[idx])
272                                 except:
273                                         print "[FCCCreateList] append error, idx : %d" % idx
274                                         break
275
276                 return fccZapUpDownList
277
278         def getHistoryPrevNextList(self):
279                 historyList = []
280                 history = InfoBar.instance.servicelist.history[:]
281                 history_pos = InfoBar.instance.servicelist.history_pos
282                 history_len = len(history)
283
284                 if history_len > 1 and history_pos > 0:
285                         historyPrev = history[history_pos-1][:][-1].toString()
286                         if self.isPlayableFCC(historyPrev):
287                                 historyList.append(historyPrev)
288
289                 if history_len > 1 and history_pos < (history_len-1):
290                         historyNext = history[history_pos+1][:][-1].toString()
291                         if self.isPlayableFCC(historyNext):
292                                 historyList.append(historyNext)
293
294                 return historyList
295
296         def FCCCreateList(self):
297                 if (not self.fccSetupActivate) or (self.disableforrec and self.recordings):
298                         return
299
300                 if InfoBar.instance:
301                         self.fccList = []
302                         fccZapUpDownList = []
303                         historyList = []
304
305                         if self.zapdownEnable:
306                                 fccZapUpDownList = self.getZapUpDownList()
307
308                         if self.historyEnable:
309                                 historyList = self.getHistoryPrevNextList()
310
311                         if self.priority == "zapupdown":
312                                 fccZapDownLen = len(fccZapUpDownList)
313                                 if fccZapDownLen:
314                                         size = fccZapDownLen > 2 and 2 or fccZapDownLen
315                                         self.fccList = fccZapUpDownList[:size]
316                                         fccZapUpDownList = fccZapUpDownList[size:]
317
318                                 self.addFCCList(historyList)
319                                 self.addFCCList(fccZapUpDownList)
320                         else:
321                                 self.addFCCList(historyList)
322                                 self.addFCCList(fccZapUpDownList)
323
324                         self.FCCReconfigureFccList()
325
326         def addFCCList(self, newlist):
327                 fccListMaxLen = self.maxFCC-1
328                 for sref in newlist:
329                         if len(self.fccList) >= fccListMaxLen:
330                                 break
331
332                         if sref not in self.fccList:
333                                 self.fccList.append(sref)
334
335         def FCCReconfigureFccList(self):
336                 stopFCCList = []
337                 currentFCCList = self.fccmgr.getFCCServiceList()
338
339                 for (sref, value) in currentFCCList.items():
340                         state = value[0]
341
342                         if state == 2: # fcc_state_failed
343                                 stopFCCList.append(sref)
344
345                         elif sref in self.fccList: # check conflict FCC channel (decoder/prepare)
346                                 self.fccList.remove(sref)
347
348                         elif state == 0: # fcc_state_preparing
349                                 stopFCCList.append(sref)
350
351                 for sref in stopFCCList:
352                         self.fccmgr.stopFCCService(eServiceReference(sref))
353
354         def FCCTryStart(self):
355                 self.getSrefTimer.start(0, True)
356
357         def FCCGetCurSref(self):
358                 if (not self.fccSetupActivate) or (self.disableforrec and self.recordings):
359                         return
360
361                 if self.createListTimer.isActive():
362                         self.createListTimer.stop()
363                         self.FCCCreateList()
364
365                 curSref = self.session.nav.getCurrentlyPlayingServiceReference()
366
367                 if curSref and self.isPlayableFCC(curSref):
368                         self.FCCStart()
369                 else:
370                         print "[FCCSupport][FCCGetCurSref] get current serviceReference failed!!"
371
372         def FCCStart(self):
373                 self.activating = True
374                 self.FCCGetEvent(iPlayableService.evTunedIn)
375
376         def FCCGetEvent(self, event):
377                 if self.activating and event in (iPlayableService.evTunedIn, iPlayableService.evTuneFailed, iPlayableService.evFccFailed, self.fccTimeoutEventCode):
378                         self.eventList.append(event)
379                         self.fccEventTimer.start(0, True)
380
381         def FCCApplyEvent(self):
382                 if not self.activating:
383                         return
384
385                 while self.eventList:
386                         event = self.eventList.pop(0)
387
388                         self.FCCTimeoutTimerStop()
389
390                         if event in (iPlayableService.evTuneFailed, iPlayableService.evFccFailed):
391                                 self.fccmgr.stopFCCService() # stop FCC Services in failed state
392
393                         if not self.FCCCheckAndTimerStart() and len(self.fccList):
394                                 sref = self.fccList.pop(0)
395                                 if self.isPlayableFCC(sref): # remove PVR, streaming, radio channels
396                                         self.fccmgr.playFCCService(eServiceReference(sref))
397                                         self.FCCTimeoutTimerStart(sref)
398
399         def FCCStopAllServices(self):
400                 self.FCCTimeoutTimerStop()
401                 fccServiceList = self.fccmgr.getFCCServiceList()
402                 for (sref, value) in fccServiceList.items():
403                         state = value[0]
404                         if state != 1 : # 1  : fcc_state_decoding
405                                 self.fccmgr.stopFCCService(eServiceReference(sref))
406
407         def FCCDisableServices(self):
408                 self.FCCTimeoutTimerStop()
409                 self.getSrefTimer.stop()
410                 self.activating = False
411                 self.fccList = []
412
413                 self.fccEventTimer.stop()
414                 self.fccmgr.stopFCCService()
415                 self.eventList = []
416
417         def FCCForceStart(self):
418                 self.getEvStart()
419                 self.getEvTunedIn()
420
421         def FCCCheckNoLocked(self):
422                 for (sref, value) in self.fccmgr.getFCCServiceList().items():
423                         state = value[0]
424                         locked = value[1]
425                         if state != 1 and locked == 0: # no fcc decoding and no locked
426                                 return sref
427                 return None
428
429         def FCCTimeout(self):
430                 sref = self.FCCCheckNoLocked()
431                 if sref and sref == self.fccTimeoutWait:
432                         self.fccmgr.stopFCCService(eServiceReference(sref))
433                         self.FCCGetEvent(self.fccTimeoutEventCode)
434
435         def FCCCheckAndTimerStart(self):
436                 sref = self.FCCCheckNoLocked()
437                 if sref:
438                         self.FCCTimeoutTimerStart(sref)
439                         return True
440                 return False
441
442         def FCCTimeoutTimerStart(self, sref):
443                 self.fccTimeoutWait = sref
444                 self.fccTimeoutTimer.start(5000, True)
445
446         def FCCTimeoutTimerStop(self):
447                 self.fccTimeoutWait = None
448                 self.fccTimeoutTimer.stop()
449
450 class FCCSetup(Screen, ConfigListScreen):
451         skin =  """
452                 <screen position="center,center" size="590,320" >
453                         <ePixmap pixmap="skin_default/buttons/red.png" position="90,15" size="140,40" alphatest="on" />
454                         <ePixmap pixmap="skin_default/buttons/green.png" position="360,15" size="140,40" alphatest="on" />
455                         <widget source="key_red" render="Label" position="90,15" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" foregroundColor="#ffffff" transparent="1" />
456                         <widget source="key_green" render="Label" position="360,15" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
457                         <widget name="config" zPosition="2" position="15,80" size="560,140" scrollbarMode="showOnDemand" transparent="1" />
458                         <widget source="description" render="Label" position="30,240" size="530,60" font="Regular;24" halign="center" valign="center" />
459                 </screen>
460                 """
461
462         def __init__(self,session):
463                 Screen.__init__(self,session)
464                 self.title = _("Fast Channel Change Setup")
465                 self.session = session
466                 self["shortcuts"] = ActionMap(["ShortcutActions", "SetupActions" ],
467                 {
468                         "ok": self.keySave,
469                         "cancel": self.keyCancel,
470                         "red": self.keyCancel,
471                         "green": self.keySave,
472                 }, -2)
473                 self.list = []
474                 ConfigListScreen.__init__(self, self.list,session = self.session)
475                 self["key_red"] = StaticText(_("Cancel"))
476                 self["key_green"] = StaticText(_("Save"))
477
478                 self.isSupport = checkSupportFCC()
479
480                 if self.isSupport:
481                         self["description"] = StaticText("")
482                         self.createConfig()
483                         self.createSetup()
484                 else:
485                         self["description"] = StaticText(_("Box or driver is not support FCC."))
486
487         def createConfig(self):
488                 self.enableEntry = getConfigListEntry(_("FCC enabled"), config.plugins.fccsetup.activate)
489                 self.fccmaxEntry = getConfigListEntry(_("Max Channels"), config.plugins.fccsetup.maxfcc)
490                 self.zapupdownEntry = getConfigListEntry(_("Zap Up/Down"), config.plugins.fccsetup.zapupdown)
491                 self.historyEntry = getConfigListEntry(_("History Prev/Next"), config.plugins.fccsetup.history)
492                 self.priorityEntry = getConfigListEntry(_("priority"), config.plugins.fccsetup.priority)
493                 self.recEntry = getConfigListEntry(_("Disable FCC during recordings"), config.plugins.fccsetup.disableforrec)
494
495         def createSetup(self):
496                 self.list = []
497                 self.list.append( self.enableEntry )
498                 if self.enableEntry[1].value:
499                         self.list.append( self.fccmaxEntry )
500                         self.list.append( self.zapupdownEntry )
501                         self.list.append( self.historyEntry )
502                         if self.zapupdownEntry[1].value and self.historyEntry[1].value:
503                                 self.list.append( self.priorityEntry )
504                         self.list.append(self.recEntry)
505
506                 self["config"].list = self.list
507                 self["config"].l.setList(self.list)
508
509         def keyLeft(self):
510                 ConfigListScreen.keyLeft(self)
511                 self.setupChanged()
512
513         def keyRight(self):
514                 ConfigListScreen.keyRight(self)
515                 self.setupChanged()
516
517         def setupChanged(self):
518                 currentEntry = self["config"].getCurrent()
519                 if currentEntry in (self.zapupdownEntry, self.historyEntry, self.enableEntry):
520                         if not (self.zapupdownEntry[1].value or self.historyEntry[1].value):
521                                 if currentEntry == self.historyEntry:
522                                         self.zapupdownEntry[1].value = True
523                                 else:
524                                         self.historyEntry[1].value = True
525                         elif self.zapupdownEntry[1].value and self.historyEntry[1].value:
526                                 if int(self.fccmaxEntry[1].value) < 5:
527                                         if g_max_fcc < 5:
528                                                 self.fccmaxEntry[1].value = str(g_max_fcc)
529                                         else:
530                                                 self.fccmaxEntry[1].value = str(5)
531
532                         self.createSetup()
533
534         def keySave(self):
535                 if not self.isSupport:
536                         self.keyCancel()
537                         return
538
539                 ConfigListScreen.keySave(self)
540                 FCCChanged()
541
542 def getExtensionName():
543         if config.plugins.fccsetup.activate.value:
544                 return _("Disable FastChannelChange")
545
546         return _("Enable FastChannelChange")
547
548 def ToggleUpdate():
549         if config.plugins.fccsetup.activate.value:
550                 config.plugins.fccsetup.activate.value = False
551         else:
552                 config.plugins.fccsetup.activate.value = True
553         config.plugins.fccsetup.activate.save()
554         FCCChanged()
555
556 def FCCSupportInit(reason, **kwargs):
557         if kwargs.has_key("session"):
558                 global FccInstance
559                 FccInstance = FCCSupport(kwargs["session"])
560
561 def addExtentions(infobarExtensions):
562         infobarExtensions.addExtension((getExtensionName, ToggleUpdate, lambda: True), None)
563
564 def main(session, **kwargs):
565         session.open(FCCSetup)
566
567 def Plugins(**kwargs):
568         list = []
569
570         global g_max_fcc
571         if g_max_fcc:
572                 list.append(
573                         PluginDescriptor(name="FCCSupport",
574                         description="Fast Channel Change Support",
575                         where = [PluginDescriptor.WHERE_SESSIONSTART],
576                         fnc = FCCSupportInit))
577
578                 list.append(
579                         PluginDescriptor(name="FCCExtensionMenu",
580                         description="Fast Channel Change Extension Menu",
581                         where = [PluginDescriptor.WHERE_EXTENSIONSINGLE],
582                         fnc = addExtentions))
583
584         list.append(
585                 PluginDescriptor(name=_("FCCSetup"),
586                 description=_("Fast Channel Change Setup"),
587                 where = [PluginDescriptor.WHERE_PLUGINMENU],
588                 needsRestart = False,
589                 fnc = main))
590
591         return list
592