[hbbtv] add playback status and volume control.
[vuplus_dvbapp] / lib / python / Plugins / Extensions / HbbTV / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2
3 from Screens.Screen import Screen
4 from Screens.InfoBar import InfoBar
5 from Screens.ChoiceBox import ChoiceBox
6 from Screens.MessageBox import MessageBox
7 from Screens.InfoBarGenerics import InfoBarNotifications
8 from Screens.VirtualKeyBoard import VirtualKeyBoard
9
10 from Components.PluginComponent import plugins
11 from Components.Button import Button
12 from Components.Label import Label
13 from Components.Sources.StaticText import StaticText
14 from Components.ActionMap import NumberActionMap, ActionMap
15 from Components.ServiceEventTracker import ServiceEventTracker
16 from Components.MenuList import MenuList
17 from Components.Label import Label, MultiColorLabel
18 from Components.ConfigList import ConfigListScreen
19 from Components.VolumeControl import VolumeControl
20 from Components.config import config, ConfigSubsection, ConfigPosition, getConfigListEntry, ConfigBoolean, ConfigInteger, ConfigText, ConfigSelection, configfile, getCharValue
21
22 from enigma import eTimer, eConsoleAppContainer, getDesktop, eServiceReference, iPlayableService, iServiceInformation, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_HALIGN_CENTER, RT_VALIGN_CENTER, getPrevAsciiCode, eRCInput, fbClass
23
24 import os, struct, threading, stat, select, time, socket, select
25
26 strIsEmpty = lambda x: x is None or len(x) == 0
27
28 HBBTVAPP_PATH = "/usr/local/hbb-browser"
29 COMMAND_PATH = '/tmp/.sock.hbbtv.cmd'
30
31 class GlobalValues:
32         command_util   = None
33         command_server = None
34
35         before_service = None
36
37         channel_info_sid   = None
38         channel_info_onid  = None
39         channel_info_tsid  = None
40         channel_info_name  = None
41         channel_info_orgid = None
42
43         hbbtv_handelr = None
44
45         packet_m  = 0xBBADBEE
46         packet_h  = '!IIII'
47         packet_hl = struct.calcsize(packet_h)
48 __gval__ = GlobalValues()
49
50 def getPacketHeaders():
51         global __gval__
52         return (__gval__.packet_m, __gval__.packet_h, __gval__.packet_hl)
53
54 def setChannelInfo(sid, onid, tsid, name, orgid):
55         if sid is None:   sid   = 0;
56         if onid is None:  onid  = 0;
57         if tsid is None:  tsid  = 0;
58         if name is None:  name  = "";
59         if orgid is None: orgid = 0;
60         global __gval__
61         __gval__.channel_info_sid   = sid
62         __gval__.channel_info_onid  = onid
63         __gval__.channel_info_tsid  = tsid
64         __gval__.channel_info_name  = name
65         __gval__.channel_info_orgid = orgid
66         print "Set Channel Info >> sid : %X, onid : %X, tsid : %X, name : %s, orgid : %d " % (sid, onid, tsid, name, orgid)
67 def getChannelInfos():
68         global __gval__
69         print "Get Channel Info >> sid : %X, onid : %X, tsid : %X, name : %s, orgid : %d " % (__gval__.channel_info_sid, 
70                 __gval__.channel_info_onid, __gval__.channel_info_tsid, __gval__.channel_info_name, __gval__.channel_info_orgid)
71         return (__gval__.channel_info_sid, 
72                 __gval__.channel_info_onid, 
73                 __gval__.channel_info_tsid, 
74                 __gval__.channel_info_name, 
75                 __gval__.channel_info_orgid)
76
77 def getCommandUtil():
78         global __gval__
79         return __gval__.command_util
80 def getCommandServer():
81         global __gval__
82         return __gval__.command_server
83
84 def setBeforeService(s):
85         global __gval__
86         __gval__.before_service = s
87 def getBeforeService():
88         global __gval__
89         return __gval__.before_service
90
91 def _unpack(packed_data):
92         (mg, h, hlen) = getPacketHeaders()
93
94         if strIsEmpty(packed_data):
95                 return None
96         (m, o, l, s) = struct.unpack(h, packed_data[:hlen])
97         if m != mg:
98                 return None
99         d = 0
100         if l > 0:
101                 d = packed_data[hlen:hlen+l]
102         return (o,d,s)
103
104 def _pack(opcode, params=None, reserved=0):
105         (m, h, hlen) = getPacketHeaders()
106         if strIsEmpty(params):
107                 params = ''
108         packed_data = struct.pack(h, m, opcode, len(params), reserved)
109         return packed_data + params
110
111 class MMSStreamURL:
112         headers = [
113                    'GET %s HTTP/1.0'
114                   ,'Accept: */* '
115                   ,'User-Agent: NSPlayer/7.10.0.3059 '
116                   ,'Host: %s '
117                   ,'Connection: Close '
118                   ]
119
120         def __init__(self):
121                 self.sendmsg = ''
122                 for m in self.headers:
123                         self.sendmsg += m + '\n'
124                 self.sendmsg += '\n\n'
125
126         def request(self, host, port=80, location='/'):
127                 sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
128                 sock.connect((host, port))
129                 sock.send(self.sendmsg%(location, host))
130                 print "Send Data : "
131                 print self.sendmsg%(location, host)
132                 fullydata = ''
133                 while 1:
134                         res = sock.recv(1024)
135                         if res == '': break
136                         fullydata += res
137                 sock.close()
138                 return fullydata
139
140         def parse(self, data):
141                 for d in data.splitlines():
142                         if d.startswith('Location: '):
143                                 return d[9:]
144                 return None
145
146         def getLocationData(self, url):
147                 url_list,host,location = None,None,None
148                 try:
149                         url = url[url.find(':')+3:]
150                         url_list = url.split('/')
151                         host = url_list[0]
152                         location = url[len(url_list[0]):]
153                 except Exception, err_msg:
154                         print err_msg
155                         return None
156                 html = self.request(host=host, location=location)
157                 return self.parse(html)
158
159 class OpCodeSet:
160         def __init__(self):
161                 self._opcode_ = {
162                          "OP_UNKNOWN"                   : 0x0000
163                         ,"OP_HBBTV_EXIT"                : 0x0001
164                         ,"OP_HBBTV_OPEN_URL"            : 0x0002
165                         ,"OP_HBBTV_LOAD_AIT"            : 0x0003
166                         ,"OP_HBBTV_UNLOAD_AIT"          : 0x0004
167                         ,"OP_HBBTV_FULLSCREEN"          : 0x0005
168                         ,"OP_HBBTV_TITLE"               : 0x0006
169                         ,"OP_OIPF_GET_CHANNEL_INFO_URL" : 0x0101
170                         ,"OP_OIPF_GET_CHANNEL_INFO_AIT" : 0x0102
171                         ,"OP_OIPF_GET_CHANNEL_INFO_LIST": 0x0103
172                         ,"OP_VOD_URI"                   : 0x0201
173                         ,"OP_VOD_PLAY"                  : 0x0202
174                         ,"OP_VOD_STOP"                  : 0x0203
175                         ,"OP_VOD_PAUSE"                 : 0x0204
176                         ,"OP_VOD_STATUS"                : 0x0205
177                         ,"OP_VOD_FORBIDDEN"             : 0x0206
178                         ,"OP_VOD_STOPED"                : 0x0207
179                         ,"OP_BROWSER_OPEN_URL"          : 0x0301
180                         ,"OP_DVBAPP_VOL_UP"             : 0x0401
181                         ,"OP_DVBAPP_VOL_DOWN"           : 0x0402
182                 }
183                 self._opstr_ = {
184                          0x0000 : "OP_UNKNOWN"
185                         ,0x0001 : "OP_HBBTV_EXIT"
186                         ,0x0002 : "OP_HBBTV_OPEN_URL"
187                         ,0x0003 : "OP_HBBTV_LOAD_AIT"
188                         ,0x0004 : "OP_HBBTV_UNLOAD_AIT"
189                         ,0x0005 : "OP_HBBTV_FULLSCREEN"
190                         ,0x0006 : "OP_HBBTV_TITLE"
191                         ,0x0101 : "OP_OIPF_GET_CHANNEL_INFO_URL"
192                         ,0x0102 : "OP_OIPF_GET_CHANNEL_INFO_AIT"
193                         ,0x0103 : "OP_OIPF_GET_CHANNEL_INFO_LIST"
194                         ,0x0201 : "OP_VOD_URI"
195                         ,0x0202 : "OP_VOD_PLAY"
196                         ,0x0203 : "OP_VOD_STOP"
197                         ,0x0204 : "OP_VOD_PAUSE"
198                         ,0x0205 : "OP_VOD_STATUS"
199                         ,0x0206 : "OP_VOD_FORBIDDEN"
200                         ,0x0207 : "OP_VOD_STOPED"
201                         ,0x0301 : "OP_BROWSER_OPEN_URL"
202                         ,0x0401 : "OP_DVBAPP_VOL_UP"
203                         ,0x0402 : "OP_DVBAPP_VOL_DOWN"
204                 }
205
206         def get(self, opstr):
207                 try:
208                         return self._opcode_[opstr]
209                 except: pass
210                 return self._opcode_["OP_UNKNOWN"]
211
212         def what(self, opcode):
213                 try:
214                         return self._opstr_[opcode]
215                 except: pass
216                 return self._opstr_["0x0000"]
217
218 class SocketParams:
219         def __init__(self):
220                 self.protocol = None
221                 self.type     = None
222                 self.addr     = None
223                 self.buf_size = 4096
224                 self.handler  = None
225                 self.timeout  = 5
226                 self.destroy  = None
227
228 class StreamServer:
229         def __init__(self, params):
230                 self._protocol = params.protocol
231                 self._type     = params.type
232                 self._addr     = params.addr
233                 self._buf_size = params.buf_size
234                 self._handler  = params.handler
235                 self._timeout  = params.timeout
236                 self._destroy  = params.destroy
237
238                 self._terminated = False
239                 self._server_thread = None
240
241                 self.onHbbTVCloseCB = []
242                 self.onSetPageTitleCB = []
243
244         def __del__(self):
245                 if self._destroy is not None:
246                         self._destroy(self._addr)
247
248         def stop(self):
249                 self._terminated = True
250                 if self._server_thread is not None:
251                         self._server_thread.join()
252                         self._server_thread = None
253
254         def start(self):
255                 self._socket = socket.socket(self._protocol, self._type)
256                 self._socket.settimeout(self._timeout)
257                 self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
258                 self._socket.bind(self._addr)
259                 self._socket.listen(True)
260
261                 self._server_thread = threading.Thread(target=self._listen)
262                 self._server_thread.start()
263
264         def _listen(self):
265                 select_list = [self._socket]
266                 def _accept():
267                         try:
268                                 conn, addr = self._socket.accept()
269                                 self._client(conn, addr)
270                         except Exception, ErrMsg:
271                                 print "ServerSocket Error >>", ErrMsg
272                                 pass
273
274                 while not self._terminated:
275                         readable, writable, errored = select.select(select_list, [], [], self._timeout)
276                         for s in readable:
277                                 if s is self._socket:
278                                         _accept()
279
280         def _client(self, conn, addr):
281                 try:
282                         send_data     = ''
283                         received_data = conn.recv(self._buf_size)
284                         if self._handler is not None and not strIsEmpty(received_data):
285                                 send_data = self._handler.doHandle(received_data, self.onHbbTVCloseCB, self.onSetPageTitleCB)
286                         self._send(conn, send_data)
287                 except Exception, ErrMsg: 
288                         try: conn.close()
289                         except:pass
290                         if self._handler is not None:
291                                 self._handler.printError(ErrMsg)
292         def _send(self, conn, data) :
293                 conn.send(data)
294                 conn.close()
295
296 class ServerFactory:
297         def doListenUnixTCP(self, name, handler):
298                 def destroy(name):
299                         if os.path.exists(name):
300                                 os.unlink(name)
301                                 print "Removed ", name
302                 destroy(name)
303
304                 params = SocketParams()
305                 params.protocol = socket.AF_UNIX
306                 params.type     = socket.SOCK_STREAM
307                 params.addr     = name
308                 params.handler  = handler
309                 params.destroy  = destroy
310
311                 streamServer = StreamServer(params)
312                 streamServer.start()
313                 return streamServer
314
315         def doListenInetTCP(self, ip, port, handler):
316                 print "not implemented yet!!"
317         def doListenUnixDGRAM(self, name, handler):
318                 print "not implemented yet!!"
319         def doListenInetDGRAM(self, ip, port, handler):
320                 print "not implemented yet!!"
321
322 class Handler:
323         def doUnpack(self, data):
324                 return _unpack(data)
325
326         def doPack(self, opcode, params, reserved=0):
327                 return _pack(opcode, params, reserved)
328
329         def doHandle(self, data, onCloseCB):
330                 opcode, params = 0x0, 'Invalid Request!!'
331                 return _pack(opcode, params)
332
333         def printError(self, reason):
334                 print reason
335
336 class BrowserCommandUtil(OpCodeSet):
337         def __init__(self):
338                 self._fd = None
339                 OpCodeSet.__init__(self)
340
341         def isConnected(self):
342                 if self._fd is None:
343                         return False
344                 return True
345
346         def doConnect(self, filename):
347                 if not os.path.exists(filename):
348                         print "file not exists :", filename
349                         return False
350                 try:
351                         self._fd = os.open(filename, os.O_WRONLY|os.O_NONBLOCK)
352                         if self._fd is None:
353                                 print "fail to open file :", filename
354                                 return False
355                 except Exception, ErrMsg:
356                         print ErrMsg
357                         self._fd = None
358                         return False
359                 print "connected!! to ", filename
360                 return True
361
362         def doDisconnect(self):
363                 if self._fd is None:
364                         return
365                 os.close(self._fd)
366                 self._fd = None
367
368         def doSend(self, command, params=None, reserved=0):
369                 if self._fd is None:
370                         print "connected pipe was not exists!!"
371                         return False
372                 data = ''
373                 try:
374                         data = _pack(self.get(command), params, reserved)
375                         if data is None:
376                                 return False
377                         os.write(self._fd, data)
378                         print "Send OK!! :", command
379                 except: return False
380                 return True
381
382         def sendCommand(self, command, params=None, reserved=0):
383                 if not self.isConnected():
384                         global COMMAND_PATH
385                         self.doConnect(COMMAND_PATH)
386                 result = self.doSend(command, params, reserved)
387                 self.doDisconnect()
388                 return result
389
390 class HandlerHbbTV(Handler):
391         _vod_service = None
392         def __init__(self, session):
393                 self._session = session
394                 self.opcode = OpCodeSet()
395                 self.handle_map = {
396                          0x0001 : self._cb_handleCloseHbbTVBrowser
397                         ,0x0006 : self._cb_handleSetPageTitle
398                         ,0x0101 : self._cb_handleGetChannelInfoForUrl
399                         ,0x0102 : self._cb_handleGetChannelInfoForAIT
400                         ,0x0103 : self._cb_handleGetChannelInfoList
401                         ,0x0201 : self._cb_handleVODPlayerURI
402                         ,0x0202 : self._cb_handleVODPlayerPlay
403                         ,0x0203 : self._cb_handleVODPlayerStop
404                         ,0x0204 : self._cb_handleVODPlayerPlayPause
405                         ,0x0401 : self._cb_handleDVBAppVolUp
406                         ,0x0402 : self._cb_handleDVBAppVolDown
407                 }
408                 self._on_close_cb = None
409                 self._on_set_title_cb = None
410
411                 self._vod_uri = None
412
413         def _handle_dump(self, handle, opcode, data=None):
414                 if True: return
415                 print str(handle)
416                 try:
417                         print "    - opcode : ", self.opcode.what(opcode)
418                 except: pass
419                 print "    - data   : ", data
420
421         def doHandle(self, data, onCloseCB, onSetPageTitleCB):
422                 opcode, params, reserved = None, None, 0
423                 self._on_close_cb = onCloseCB
424                 self._on_set_title_cb = onSetPageTitleCB
425                 try:
426                         datas  = self.doUnpack(data)
427                 except Exception, ErrMsg:
428                         print "Unpacking packet ERR :", ErrMsg
429                         params = 'fail to unpack packet!!'
430                         opcode = self.opcode.get("OP_UNKNOWN")
431                         return self.doPack(opcode, params)
432                 else:
433                         opcode = datas[0]
434                         params = datas[1]
435                 self.opcode.what(opcode)
436
437                 try:
438                         #print self.handle_map[opcode]
439                         (reserved, params) = self.handle_map[opcode](opcode, params)
440                 except Exception, ErrMsg:
441                         print "Handling packet ERR :", ErrMsg
442                         params = 'fail to handle packet!!'
443                         opcode = self.opcode.get("OP_UNKNOWN")
444                         return self.doPack(opcode, params)
445                 self._on_close_cb = None
446                 self._on_set_title_cb = None
447                 return self.doPack(opcode, params, reserved)
448
449         def _cb_handleDVBAppVolUp(self, opcode, data):
450                 self._handle_dump(self._cb_handleDVBAppVolUp, opcode, data)
451                 vcm = VolumeControl.instance
452                 vcm.volUp()
453                 return (0, "OK")
454
455         def _cb_handleDVBAppVolDown(self, opcode, data):
456                 self._handle_dump(self._cb_handleDVBAppVolDown, opcode, data)
457                 vcm = VolumeControl.instance
458                 vcm.volDown()
459                 return (0, "OK")
460
461         def _cb_handleGetChannelInfoForUrl(self, opcode, data):
462                 self._handle_dump(self._cb_handleGetChannelInfoForUrl, opcode, data)
463                 (sid, onid, tsid, name, orgid) = getChannelInfos()
464                 namelen = len(name)
465                 return (0, struct.pack('!IIII', sid, onid, tsid, namelen) + name)
466
467         def _cb_handleGetChannelInfoForAIT(self, opcode, data):
468                 self._handle_dump(self._cb_handleGetChannelInfoForAIT, opcode, data)
469                 (sid, onid, tsid, name, orgid) = getChannelInfos()
470                 namelen = len(name)
471                 return (0, struct.pack('!IIIII', orgid, sid, onid, tsid, namelen) + name)
472
473         def _cb_handleGetChannelInfoList(self, opcode, data):
474                 self._handle_dump(self._cb_handleGetChannelInfoList, opcode, data)
475                 (sid, onid, tsid, name, orgid) = getChannelInfos()
476                 namelen = len(name)
477                 channel_list_size = 1
478                 return (channel_list_size, struct.pack('!IIII', sid, onid, tsid, namelen) + name)
479
480         def _cb_handleSetPageTitle(self, opcode, data):
481                 self._handle_dump(self._cb_handleCloseHbbTVBrowser, opcode, data)
482                 if data.startswith('file://') or data.startswith('http://'):
483                         return "OK"
484                 if self._on_set_title_cb is not None:
485                         for x in self._on_set_title_cb:
486                                 try:
487                                         x(data)
488                                 except Exception, ErrMsg:
489                                         if x in self._on_set_title_cb:
490                                                 self._on_set_title_cb.remove(x)
491                 return (0, "OK")
492
493         def _cb_handleCloseHbbTVBrowser(self, opcode, data):
494                 self._handle_dump(self._cb_handleCloseHbbTVBrowser, opcode, data)
495
496                 if self._on_close_cb:
497                         for x in self._on_close_cb:
498                                 try:
499                                         x()
500                                 except Exception, ErrMsg:
501                                         if x in self._on_close_cb:
502                                                 self._on_close_cb.remove(x)
503
504                 command_util = getCommandUtil()
505                 command_util.sendCommand('OP_HBBTV_FULLSCREEN', None)
506
507                 before_service = getBeforeService()
508                 if before_service is not None:
509                         self._session.nav.playService(before_service)
510                         self._vod_uri = None
511                 return (0, "OK")
512
513         def _cb_handleVODPlayerURI(self, opcode, data):
514                 self._vod_uri = None
515                 hl = struct.calcsize('!II')
516                 datas = struct.unpack('!II', data[:hl])
517                 uriLength = datas[1]
518                 vodUri = data[hl:hl+uriLength]
519                 self._handle_dump(self._cb_handleVODPlayerURI, opcode, vodUri)
520                 self._vod_uri = vodUri
521                 return (0, "OK")
522
523         def doStop(self, restoreBeforeService=True, needStop=True):
524                 if needStop == True:
525                         self._session.nav.stopService()
526                 if self._vod_service is not None and restoreBeforeService:
527                         before_service = getBeforeService()
528                         self._session.nav.playService(before_service)
529                         self._vod_uri = None
530                 self._vod_service = None
531
532         def getUrl(self):
533                 return self._vod_uri
534
535         def doRetryOpen(self, url):
536                 if url is None:
537                         return False
538                 for ii in range(5):
539                         self._vod_service = None
540                         try:
541                                 print "try to open vod [%d] : %s" % (ii, url)
542                                 self._vod_service = eServiceReference(4097, 0, url)
543                                 self._session.nav.playService(self._vod_service)
544                                 if self._vod_service is not None:
545                                         return True
546                         except Exception, ErrMsg: 
547                                 print "OpenVOD ERR :", ErrMsg
548                         time.sleep(1)
549                 return False
550
551         def _cb_handleVODPlayerPlay(self, opcode, data):
552                 self._handle_dump(self._cb_handleVODPlayerPlay, opcode, data)
553                 self.doStop(restoreBeforeService=False)
554                 if self.doRetryOpen(url=self._vod_uri) == False:
555                         self.doStop()
556                 return (0, "OK")
557
558         def _cb_handleVODPlayerStop(self, opcode, data):
559                 self._handle_dump(self._cb_handleVODPlayerStop, opcode, data)
560                 self.doStop()   
561                 return (0, "OK")
562
563         def _cb_handleVODPlayerPlayPause(self, opcode, data):
564                 self._handle_dump(self._cb_handleVODPlayerPlayPause, opcode, data)
565                 service = self._session.nav.getCurrentService()
566                 try:
567                         pauseFlag = data[0]
568                         servicePause = service.pause()
569                         if pauseFlag == 'U':
570                                 servicePause.unpause()
571                         elif pauseFlag == 'P':
572                                 servicePause.pause()
573                 except Exception, ErrMsg:
574                         print "onPause ERR :", ErrMsg
575                 return (0, "OK")
576
577 from libshm import SimpleSharedMemory
578 class HbbTVWindow(Screen, InfoBarNotifications):
579         skin =  """
580                 <screen name="HbbTVWindow" position="0,0" size="1280,720" backgroundColor="transparent" flags="wfNoBorder" title="HbbTV Plugin">
581                 </screen>
582                 """
583         def __init__(self, session, url=None, cbf=None, useAIT=False, profile=0):
584                 self._session = session
585                 eRCInput.getInstance().lock()
586
587                 Screen.__init__(self, session)
588                 InfoBarNotifications.__init__(self)
589                 self.__event_tracker = ServiceEventTracker(screen = self, eventmap = {
590                         iPlayableService.evUser+20: self._serviceForbiden,
591                         iPlayableService.evStart: self._serviceStarted,
592                         iPlayableService.evEOF: self._serviceEOF,
593                 })
594
595                 self._url = url
596                 self._use_ait = useAIT
597                 self._profile = profile
598                 self._cb_closed_func = cbf
599                 self.onLayoutFinish.append(self._layoutFinished)
600
601                 command_server = getCommandServer()
602                 if self._cb_set_page_title not in command_server.onSetPageTitleCB:
603                         command_server.onSetPageTitleCB.append(self._cb_set_page_title)
604
605                 if self._cb_close_window not in command_server.onHbbTVCloseCB:
606                         command_server.onHbbTVCloseCB.append(self._cb_close_window)
607
608                 self._closeTimer = eTimer()
609                 self._closeTimer.callback.append(self._do_close)
610
611                 self._currentServicePositionTimer = eTimer()
612                 self._currentServicePositionTimer.callback.append(self._cb_currentServicePosition)
613                 self._vodLength = 0
614
615                 self._ssm = SimpleSharedMemory()
616                 self._vod_length = 0
617
618         def getVodPlayTime(self):
619                 try:
620                         service = self._session.nav.getCurrentService()
621                         seek = service and service.seek()
622                         l = seek.getLength()
623                         p = seek.getPlayPosition()
624                         #return (p[1]/90000, l[1]/90000)
625                         return (p[1], l[1])
626                 except: pass
627                 return (-1,-1)
628
629         def _cb_currentServicePosition(self):
630                 def getTimeString(t):
631                         t = time.localtime(t/90000)
632                         return "%2d:%02d:%02d" % (t.tm_hour, t.tm_min, t.tm_sec)
633                 position,length = 0,0
634                 try:
635                         (position,length) = self.getVodPlayTime()
636                         self._vod_length = length
637                         if position == -1 and length == -1:
638                                 raise "can't get play status"
639                         #print getTimeString(position), "/", getTimeString(length)
640                         self._ssm.setStatus(position, length, 1)
641                 except Exception, ErrMsg:
642                         print ErrMsg
643                         self._serviceEOF()
644
645         def _serviceStarted(self):
646                 try:
647                         self._ssm.doConnect()
648                         self._ssm.setStatus(0, 0, 0)
649                         self._currentServicePositionTimer.start(1000)
650                 except Exception, ErrMsg:
651                         print ErrMsg
652
653         def _serviceEOF(self):
654                 self._currentServicePositionTimer.stop()
655                 if self._vod_length == -1:
656                         self._vod_length = 0
657                 try:
658                         self._ssm.setStatus(self._vod_length, self._vod_length, 2)
659                         time.sleep(1)
660                         self._ssm.doClose()
661                 except Exception, ErrMsg:
662                         print ErrMsg
663                 command_util = getCommandUtil()
664                 command_util.sendCommand('OP_VOD_STOPED', None)
665
666         def _layoutFinished(self):
667                 command_util = getCommandUtil()
668                 profile = self._profile
669                 (sid, onid, tsid, name, orgid) = getChannelInfos()
670                 params  = struct.pack('!IIIIII', orgid, profile, sid, onid, tsid, len(name)) + name
671                 if self._use_ait:
672                         command_util.sendCommand('OP_HBBTV_UNLOAD_AIT')
673                         time.sleep(1)
674                         command_util.sendCommand('OP_HBBTV_LOAD_AIT', params, 1)
675                         return
676                 command_util.sendCommand('OP_HBBTV_LOAD_AIT', params)
677                 time.sleep(1)
678                 command_util.sendCommand('OP_HBBTV_OPEN_URL', self._url)
679
680         def _cb_close_window(self):
681                 self._closeTimer.start(1000)
682
683         def _do_close(self):
684                 self._closeTimer.stop()
685                 command_server = getCommandServer()
686                 try:
687                         if self._cb_set_page_title in command_server.onSetPageTitleCB:
688                                 command_server.onSetPageTitleCB.remove(self._cb_set_page_title)
689                 except Exception, ErrMsg: pass
690                 try:
691                         if self._cb_close_window in command_server.onHbbTVCloseCB:
692                                         command_server.onHbbTVCloseCB.remove(self._cb_close_window)
693                 except Exception, ErrMsg: pass
694                 try:
695                         if self._cb_closed_func is not None:
696                                 self._cb_closed_func()
697                 except: pass
698                 eRCInput.getInstance().unlock()
699                 self.close()
700
701         def _serviceForbiden(self):
702                 global __gval__
703                 real_url = MMSStreamURL().getLocationData(__gval__.hbbtv_handelr.getUrl())
704                 print "Received URI :\n",real_url
705
706                 if real_url is not None:
707                         __gval__.hbbtv_handelr.doRetryOpen(real_url.strip())
708
709         def _cb_set_page_title(self, title=None):
710                 print "page title :",title
711                 if title is None:
712                         return
713                 self.setTitle(title)
714
715 class HbbTVHelper(Screen):
716         skin =  """<screen name="HbbTVHelper" position="0,0" size="0,0" backgroundColor="transparent" flags="wfNoBorder" title=" "></screen>"""
717         def __init__(self, session):
718                 global __gval__
719                 __gval__.hbbtv_handelr = HandlerHbbTV(session)
720                 __gval__.command_server = ServerFactory().doListenUnixTCP('/tmp/.sock.hbbtv.url', __gval__.hbbtv_handelr)
721
722                 self._urls = None
723                 self._stop_opera()
724                 self._start_opera()
725
726                 Screen.__init__(self, session)
727                 self._session = session
728                 self._timer_infobar = eTimer()
729                 self._timer_infobar.callback.append(self._cb_registrate_infobar)
730                 self._timer_infobar.start(1000)
731
732                 self._excuted_browser = False
733                 self._profile = 0
734
735                 __gval__.command_util = BrowserCommandUtil()
736
737         def _cb_registrate_infobar(self):
738                 if InfoBar.instance:
739                         self._timer_infobar.stop()
740                         if self._cb_ready_for_ait not in InfoBar.instance.onReadyForAIT:
741                                 InfoBar.instance.onReadyForAIT.append(self._cb_ready_for_ait)
742                         if self._cb_hbbtv_activated not in InfoBar.instance.onHBBTVActivation:
743                                 InfoBar.instance.onHBBTVActivation.append(self._cb_hbbtv_activated)
744
745         def _cb_ready_for_ait(self, orgId=0):
746                 if orgId == 0:
747                         if not self._excuted_browser:
748                                 command_util = getCommandUtil()
749                                 command_util.sendCommand('OP_HBBTV_UNLOAD_AIT')
750                         return
751                 setChannelInfo(None, None, None, None, None)
752
753                 service = self._session.nav.getCurrentService()
754                 info = service and service.info()
755                 if info is not None:
756                         sid  = info.getInfo(iServiceInformation.sSID)
757                         onid = info.getInfo(iServiceInformation.sONID)
758                         tsid = info.getInfo(iServiceInformation.sTSID)
759                         name = info.getName()
760                         if name is None:
761                                 name = ""
762                         orgid   = 0
763                         namelen = len(name)
764                         for x in info.getInfoObject(iServiceInformation.sHBBTVUrl):
765                                 if x[0] in (1, -1) :
766                                         orgid = x[3]
767                                         break
768                         setChannelInfo(sid, onid, tsid, name, orgid)
769
770         def _cb_hbbtv_activated(self, title=None, url=None):
771                 if not self._is_browser_running():
772                         message = "HbbTV Browser was not running.\nPlease running browser before start HbbTV Application."
773                         self.session.open(MessageBox, message, MessageBox.TYPE_INFO)
774                         return
775                 service = self._session.nav.getCurrentlyPlayingServiceReference()
776                 setBeforeService(service)
777                 self._start_hbbtv_application(title, url)
778
779         def _start_hbbtv_application(self, title, url):
780                 tmp_url = self.getStartHbbTVUrl()
781                 if url is None:
782                         url = tmp_url
783                 if strIsEmpty(url):
784                         print "can't get url of hbbtv!!"
785                         return
786                 print "success to get url of hbbtv!! >>", url
787                 if self._excuted_browser:
788                         print "already excuted opera browser!!"
789                         return
790
791                 use_ait = False
792
793                 for x in self._urls:
794                         control_code = x[0]
795                         tmp_url = x[2]
796                         if tmp_url == url and control_code == 1:
797                                 use_ait = True
798                 self._excuted_browser = True
799                 self._session.open(HbbTVWindow, url, self._cb_closed_browser, use_ait, self._profile)
800
801         def _cb_closed_browser(self):
802                 self._excuted_browser = False
803
804         def _start_opera(self):
805                 if not self._is_browser_running():
806                         global HBBTVAPP_PATH
807                         start_command = '%s/launcher start'%(HBBTVAPP_PATH)
808                         os.system(start_command)
809
810         def _stop_opera(self):
811                 global HBBTVAPP_PATH
812                 try:    os.system('%s/launcher stop'%(HBBTVAPP_PATH))
813                 except: pass
814
815         def getStartHbbTVUrl(self):
816                 url, self._urls, self._profile = None, None, 0
817                 service = self._session.nav.getCurrentService()
818                 info = service and service.info()
819                 if not info: return None
820                 self._urls = info.getInfoObject(iServiceInformation.sHBBTVUrl)
821                 for u in self._urls:
822                         if u[0] in (1, -1): # 0:control code, 1:name, 2:url, 3:orgid, 4:appid, 5:profile code
823                                 url = u[2]
824                                 self._profile = u[5]
825                 if url is None:
826                         url = info.getInfoString(iServiceInformation.sHBBTVUrl)
827                 return url
828
829         def showApplicationSelectionBox(self):
830                 applications = []
831
832                 if self.getStartHbbTVUrl():
833                         for x in self._urls:
834                                 applications.append((x[1], x))
835                 else: applications.append(("No detected HbbTV applications.", None))
836                 self._session.openWithCallback(self._application_selected, ChoiceBox, title=_("Please choose an HbbTV application."), list=applications)
837
838         def _application_selected(self, selected):
839                 try:
840                         if selected[1] is None: return
841                         self._cb_hbbtv_activated(selected[1][1], selected[1][2])
842                 except Exception, ErrMsg: print ErrMsg
843
844         def showBrowserConfigBox(self):
845                 start_stop_mode = []
846                 if self._is_browser_running():
847                         start_stop_mode.append(('Stop',None))
848                 else:   start_stop_mode.append(('Start',None))
849                 self._session.openWithCallback(self._browser_config_selected, ChoiceBox, title=_("Please choose one."), list=start_stop_mode)
850
851         def _browser_config_selected(self, selected):
852                 if selected is None:
853                         return
854                 try:
855                         mode = selected[0]
856                         if mode == 'Start':
857                                 if not self._is_browser_running():
858                                         self._start_opera()
859                         elif mode == 'Stop':
860                                 self._stop_opera()
861                 except Exception, ErrMsg: print "Config ERR :", ErrMsg
862
863         def _is_browser_running(self):
864                 try:
865                         global HBBTVAPP_PATH
866                         ret = os.popen('%s/launcher check'%(HBBTVAPP_PATH)).read()
867                         return ret.strip() != "0"
868                 except Exception, ErrMsg:
869                         print "Check Browser Running ERR :", ErrMsg
870                 return False
871
872 _g_helper = None
873 class OperaBrowser(Screen):
874         MENUBAR_ITEM_WIDTH  = 150
875         MENUBAR_ITEM_HEIGHT = 30
876         SUBMENULIST_WIDTH   = 200
877         SUBMENULIST_HEIGHT  = 25
878         SUBMENULIST_NEXT    = 2
879
880         skin =  """
881                 <screen name="Opera Browser" position="0,0" size="1280,720" backgroundColor="transparent" flags="wfNoBorder" title="Opera Browser">
882                         <widget name="topArea" zPosition="-1" position="0,0" size="1280,60" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" />
883                         <widget name="menuitemFile" position="30,20" size="150,30" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" foregroundColors="#9f1313,#a08500" />
884                         <widget name="menuitemHelp" position="180,20" size="150,30" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" foregroundColors="#9f1313,#a08500" />
885                         <widget name="menulist" position="50,%d" size="%d,150" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />
886                         <widget name="submenulist" position="%d,%d" size="%d,150" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />
887                         <widget name="bottomArea" position="0,640" size="1280,80" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" />
888                 </screen>
889                 """ % (MENUBAR_ITEM_HEIGHT+30, SUBMENULIST_WIDTH, SUBMENULIST_WIDTH+50+SUBMENULIST_NEXT, MENUBAR_ITEM_HEIGHT+30, SUBMENULIST_WIDTH)
890
891         MENUITEMS_LIST =[[('Open Location', None), ('Start/Stop',None), ('Exit', None)],
892                          [('About', None)]]
893         def __init__(self, session):
894                 Screen.__init__(self, session)
895
896                 self["actions"] = ActionMap(["MinuteInputActions", "ColorActions", "InputActions", "InfobarChannelSelection", "EPGSelectActions", "KeyboardInputActions"], {
897                          "cancel"      : self.keyCancel
898                         ,"ok"          : self.keyOK
899                         ,"left"        : self.keyLeft
900                         ,"right"       : self.keyRight
901                         ,"up"          : self.keyUp
902                         ,"down"        : self.keyDown
903                         ,"menu"        : self.keyCancel
904                 }, -2)
905
906                 self.menubarCurrentIndex = 0
907                 self.lvMenuItems = []
908                 self.lvSubMenuItems = []
909
910                 self["topArea"]    = Label()
911                 self["bottomArea"] = Label()
912
913                 self["menuitemFile"] = MultiColorLabel()
914                 self["menuitemHelp"] = MultiColorLabel()
915
916                 self["menulist"] = MenuList(self.setListOnView())
917                 self["submenulist"] = MenuList(self.setSubListOnView())
918
919                 self.toggleMainScreenFlag = True
920                 self.toggleListViewFlag = False
921                 self.toggleSubListViewFlag = False
922                 self.currentListView = self["menulist"]
923
924                 self.onLayoutFinish.append(self.layoutFinished)
925
926                 self._onCloseTimer = eTimer()
927                 self._onCloseTimer.callback.append(self._cb_onClose)
928
929         def enableRCMouse(self, mode): #mode=[0|1]|[False|True]
930                 rcmouse_path = "/proc/stb/fp/mouse"
931                 if os.path.exists(rcmouse_path):
932                         os.system("echo %d > %s" % (mode, rcmouse_path))
933
934         def layoutFinished(self):
935                 self["menuitemFile"].setText("File")
936                 self["menuitemHelp"].setText("Help")
937
938                 self["menulist"].hide()
939                 self["submenulist"].hide()
940
941                 self["bottomArea"].setText("Opera Web Browser Plugin v0.1")
942                 self.setTitle("BrowserMain")
943                 self.selectMenuitem()
944
945         def selectMenuitem(self):
946                 tmp = [self["menuitemFile"], self["menuitemHelp"]]
947                 self["menuitemFile"].setForegroundColorNum(0)
948                 self["menuitemHelp"].setForegroundColorNum(0)
949                 tmp[self.menubarCurrentIndex].setForegroundColorNum(1)
950
951         def popupCloseAll(self):
952                 self.keyLeft()
953                 self.keyLeft()
954                 self.keyUp()
955                 self.keyCancel()
956
957         def setListOnView(self):
958                 self.lvMenuItems = self.MENUITEMS_LIST[self.menubarCurrentIndex]        
959                 return self.lvMenuItems
960
961         def setSubListOnView(self):
962                 self.lvSubMenuItems = []
963                 xl = self["menulist"].getCurrent()[1]
964                 if xl is None: return []
965                 for x in xl:
966                         self.lvSubMenuItems.append((x,None))
967                 return self.lvSubMenuItems
968
969         def toggleMainScreen(self):
970                 if not self.toggleMainScreenFlag:
971                         self.show()
972                 else:   self.hide()
973                 self.toggleMainScreenFlag = not self.toggleMainScreenFlag
974
975         def toggleListView(self):
976                 if not self.toggleListViewFlag:
977                         self["menulist"].show()
978                 else:   self["menulist"].hide()
979                 self.toggleListViewFlag = not self.toggleListViewFlag
980
981         def toggleSubListView(self):
982                 if not self.toggleSubListViewFlag:
983                         self["submenulist"].show()
984                 else:   self["submenulist"].hide()
985                 self.toggleSubListViewFlag = not self.toggleSubListViewFlag
986
987         def setCurrentListView(self, listViewIdx):
988                 if listViewIdx == 0:
989                         self.currentListView = None
990                 elif listViewIdx == 1:
991                         self.currentListView = self["menulist"]
992                 elif listViewIdx == 2:
993                         self.currentListView = self["submenulist"]
994
995         def _cb_onClose(self):
996                 self._onCloseTimer.stop()
997                 command_server = getCommandServer()
998                 try:
999                         if self._on_close_window in command_server.onHbbTVCloseCB:
1000                                         command_server.onHbbTVCloseCB.remove(self._on_close_window)
1001                 except Exception, ErrMsg: pass
1002                 try:
1003                         if self._on_setPageTitle in command_server.onSetPageTitleCB:
1004                                 command_server.onSetPageTitleCB.remove(self._on_setPageTitle)
1005                 except Exception, ErrMsg: pass
1006                 self._on_setPageTitle('Opera Browser')
1007                 self.enableRCMouse(False)
1008                 self.toggleMainScreen()
1009                 eRCInput.getInstance().unlock()
1010
1011         def _on_setPageTitle(self, title=None):
1012                 print "page title :",title
1013                 if title is None:
1014                         return
1015                 self.setTitle(title)
1016
1017         def cbUrlText(self, data=None):
1018                 print "Inputed Url :", data
1019                 if strIsEmpty(data):
1020                         return
1021                 command_server = getCommandServer()
1022                 if self._on_setPageTitle not in command_server.onSetPageTitleCB:
1023                                 command_server.onSetPageTitleCB.append(self._on_setPageTitle)
1024                 if self._on_close_window not in command_server.onHbbTVCloseCB:
1025                         command_server.onHbbTVCloseCB.append(self._on_close_window)
1026                 self.toggleMainScreen()
1027                 self.enableRCMouse(True)
1028                 eRCInput.getInstance().lock()
1029                 command_util = getCommandUtil()
1030                 command_util.sendCommand('OP_BROWSER_OPEN_URL', data)
1031
1032         def _on_close_window(self):
1033                 self._onCloseTimer.start(1000)
1034
1035         def _cmd_on_OpenLocation(self):
1036                 global _g_helper
1037                 if not _g_helper._is_browser_running():
1038                         message = "Opera Browser was not running.\nPlease running browser using [File]>[Start/Stop] menu."
1039                         self.session.open(MessageBox, message, MessageBox.TYPE_INFO)
1040                         return
1041                 self.session.openWithCallback(self.cbUrlText, VirtualKeyBoard, title=("Please enter URL here"), text='http://')
1042         def _cmd_on_About(self):
1043                 self.session.open(MessageBox, 'Opera Web Browser Plugin v0.1(beta)', type = MessageBox.TYPE_INFO)
1044         def _cmd_on_Exit(self):
1045                 self.close()
1046         def _cmd_on_StartStop(self):
1047                 global _g_helper
1048                 if _g_helper is None: 
1049                         return
1050                 _g_helper.showBrowserConfigBox()
1051         def doCommand(self, command):
1052                 cmd_map = {
1053                          'Exit'          :self._cmd_on_Exit
1054                         ,'About'         :self._cmd_on_About
1055                         ,'Open Location' :self._cmd_on_OpenLocation
1056                         ,'Start/Stop'    :self._cmd_on_StartStop
1057                 }
1058                 try:
1059                         cmd_map[command]()
1060                 except: pass
1061
1062         def keyOK(self):
1063                 if not self.toggleListViewFlag:
1064                         self.keyDown()
1065                         return
1066                 if self.currentListView.getCurrent()[1] is None:
1067                         self.doCommand(self.currentListView.getCurrent()[0])
1068                         #self.session.open(MessageBox, _(self.currentListView.getCurrent()[0]), type = MessageBox.TYPE_INFO)
1069                         return
1070                 self.keyRight()
1071
1072         def updateSelectedMenuitem(self, status):
1073                 if self.menubarCurrentIndex == 0 and status < 0:
1074                         self.menubarCurrentIndex = 1
1075                 elif self.menubarCurrentIndex == 1 and status > 0:
1076                         self.menubarCurrentIndex = 0
1077                 else:   self.menubarCurrentIndex += status
1078                 self.selectMenuitem()
1079
1080         def keyLeft(self):
1081                 if not self.toggleMainScreenFlag:
1082                         return
1083                 if not self.toggleListViewFlag:
1084                         self.updateSelectedMenuitem(-1)
1085                         return
1086                 if self.toggleSubListViewFlag:
1087                         self.setCurrentListView(1)
1088                         self.toggleSubListView()
1089                         return
1090                 if self.currentListView.getSelectedIndex():
1091                         self.currentListView.pageUp()
1092
1093         def keyRight(self):
1094                 if not self.toggleMainScreenFlag:
1095                         return
1096                 if not self.toggleListViewFlag:
1097                         self.updateSelectedMenuitem(1)
1098                         return
1099                 if self.currentListView is None:
1100                         return
1101                 if self.currentListView.getCurrent()[1] is not None:
1102                         parentSelectedIndex = self.currentListView.getSelectedIndex()
1103                         self.setCurrentListView(2)
1104                         self.currentListView.setList(self.setSubListOnView())
1105                         self.currentListView.resize(self.SUBMENULIST_WIDTH, self.SUBMENULIST_HEIGHT*len(self.lvSubMenuItems)+5)
1106                         self.currentListView.move(self.MENUBAR_ITEM_WIDTH*self.menubarCurrentIndex + self.SUBMENULIST_WIDTH+self.SUBMENULIST_NEXT + 50,self.MENUBAR_ITEM_HEIGHT+30+(parentSelectedIndex*self.SUBMENULIST_HEIGHT))
1107                         self.toggleSubListView()
1108
1109         def keyDown(self):
1110                 if not self.toggleMainScreenFlag:
1111                         return
1112                 if self.currentListView is None:
1113                         return
1114                 if not self.toggleListViewFlag:
1115                         self.currentListView.setList(self.setListOnView())
1116                         self.currentListView.resize(self.SUBMENULIST_WIDTH, self.SUBMENULIST_HEIGHT*len(self.lvMenuItems)+5)
1117                         self.currentListView.move(self.MENUBAR_ITEM_WIDTH*self.menubarCurrentIndex+1+ 50,self.MENUBAR_ITEM_HEIGHT+30)
1118                         self.toggleListView()
1119                         return
1120                 self.currentListView.down()
1121
1122         def keyUp(self):
1123                 if not self.toggleMainScreenFlag:
1124                         return
1125                 if self.currentListView is None:
1126                         return
1127                 if self.currentListView == self["menulist"]:
1128                         if self.currentListView.getSelectedIndex() == 0:
1129                                 self.toggleListView()
1130                                 return
1131                 self.currentListView.up()
1132
1133         def keyCancel(self):
1134                 self.toggleMainScreen()
1135
1136 def auto_start_main(reason, **kwargs):
1137         if reason:
1138                 command_server = getCommandServer()
1139                 command_server.stop()
1140
1141 def session_start_main(session, reason, **kwargs):
1142         global _g_helper
1143         _g_helper = session.open(HbbTVHelper)
1144
1145 def plugin_start_main(session, **kwargs):
1146         session.open(OperaBrowser)
1147
1148 def plugin_extension_start_application(session, **kwargs):
1149         global _g_helper
1150         if _g_helper is None: 
1151                 return
1152         _g_helper.showApplicationSelectionBox()
1153
1154 def plugin_extension_browser_config(session, **kwargs):
1155         global _g_helper
1156         if _g_helper is None: 
1157                 return
1158         _g_helper.showBrowserConfigBox()
1159
1160 def Plugins(path, **kwargs):
1161         return  [
1162                 PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, fnc=auto_start_main),
1163                 PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, needsRestart=True, fnc=session_start_main, weight=-10),
1164                 PluginDescriptor(name="HbbTV Applications", where=PluginDescriptor.WHERE_EXTENSIONSMENU, needsRestart=True, fnc=plugin_extension_start_application),
1165                 PluginDescriptor(name="Browser Start/Stop", where=PluginDescriptor.WHERE_EXTENSIONSMENU, needsRestart=True, fnc=plugin_extension_browser_config),
1166                 PluginDescriptor(name="Opera Web Browser", description="start opera web browser", where=PluginDescriptor.WHERE_PLUGINMENU, needsRestart=True, fnc=plugin_start_main),
1167                 ]
1168