[hbbtv] fix stream player.
[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 _g_ssm_ = None
579 class HbbTVWindow(Screen, InfoBarNotifications):
580         skin =  """
581                 <screen name="HbbTVWindow" position="0,0" size="1280,720" backgroundColor="transparent" flags="wfNoBorder" title="HbbTV Plugin">
582                 </screen>
583                 """
584         def __init__(self, session, url=None, cbf=None, useAIT=False, profile=0):
585                 self._session = session
586                 eRCInput.getInstance().lock()
587
588                 Screen.__init__(self, session)
589                 InfoBarNotifications.__init__(self)
590                 self.__event_tracker = ServiceEventTracker(screen = self, eventmap = {
591                         iPlayableService.evUser+20: self._serviceForbiden,
592                         iPlayableService.evStart: self._serviceStarted,
593                         iPlayableService.evEOF: self._serviceEOF,
594                 })
595
596                 self._url = url
597                 self._use_ait = useAIT
598                 self._profile = profile
599                 self._cb_closed_func = cbf
600                 self.onLayoutFinish.append(self._layoutFinished)
601
602                 command_server = getCommandServer()
603                 if self._cb_set_page_title not in command_server.onSetPageTitleCB:
604                         command_server.onSetPageTitleCB.append(self._cb_set_page_title)
605
606                 if self._cb_close_window not in command_server.onHbbTVCloseCB:
607                         command_server.onHbbTVCloseCB.append(self._cb_close_window)
608
609                 self._closeTimer = eTimer()
610                 self._closeTimer.callback.append(self._do_close)
611
612                 self._currentServicePositionTimer = eTimer()
613                 self._currentServicePositionTimer.callback.append(self._cb_currentServicePosition)
614                 self._vodLength = 0
615
616                 global _g_ssm_
617                 self._ssm = _g_ssm_
618                 self._vod_length = 0
619
620         def getVodPlayTime(self):
621                 try:
622                         service = self._session.nav.getCurrentService()
623                         seek = service and service.seek()
624                         l = seek.getLength()
625                         p = seek.getPlayPosition()
626                         #return (p[1]/90000, l[1]/90000)
627                         return (p[1], l[1])
628                 except: pass
629                 return (-1,-1)
630
631         def _cb_currentServicePosition(self):
632                 def getTimeString(t):
633                         t = time.localtime(t/90000)
634                         return "%2d:%02d:%02d" % (t.tm_hour, t.tm_min, t.tm_sec)
635                 position,length = 0,0
636                 try:
637                         (position,length) = self.getVodPlayTime()
638                         self._vod_length = length
639                         if position == -1 and length == -1:
640                                 raise "can't get play status"
641                         #print getTimeString(position), "/", getTimeString(length)
642                         self._ssm.setStatus(position, length, 1)
643                 except Exception, ErrMsg:
644                         print ErrMsg
645                         self._serviceEOF()
646
647         def _serviceStarted(self):
648                 try:
649                         self._ssm.setStatus(0, 0, 0)
650                         self._currentServicePositionTimer.start(1000)
651                 except Exception, ErrMsg:
652                         print ErrMsg
653
654         def _serviceEOF(self):
655                 self._currentServicePositionTimer.stop()
656
657         def _layoutFinished(self):
658                 command_util = getCommandUtil()
659                 profile = self._profile
660                 (sid, onid, tsid, name, orgid) = getChannelInfos()
661                 params  = struct.pack('!IIIIII', orgid, profile, sid, onid, tsid, len(name)) + name
662                 if self._use_ait:
663                         command_util.sendCommand('OP_HBBTV_UNLOAD_AIT')
664                         time.sleep(1)
665                         command_util.sendCommand('OP_HBBTV_LOAD_AIT', params, 1)
666                         return
667                 command_util.sendCommand('OP_HBBTV_LOAD_AIT', params)
668                 time.sleep(1)
669                 command_util.sendCommand('OP_HBBTV_OPEN_URL', self._url)
670
671         def _cb_close_window(self):
672                 self._closeTimer.start(1000)
673
674         def _do_close(self):
675                 self._closeTimer.stop()
676                 command_server = getCommandServer()
677                 try:
678                         if self._cb_set_page_title in command_server.onSetPageTitleCB:
679                                 command_server.onSetPageTitleCB.remove(self._cb_set_page_title)
680                 except Exception, ErrMsg: pass
681                 try:
682                         if self._cb_close_window in command_server.onHbbTVCloseCB:
683                                         command_server.onHbbTVCloseCB.remove(self._cb_close_window)
684                 except Exception, ErrMsg: pass
685                 try:
686                         if self._cb_closed_func is not None:
687                                 self._cb_closed_func()
688                 except: pass
689                 eRCInput.getInstance().unlock()
690                 self.close()
691
692         def _serviceForbiden(self):
693                 global __gval__
694                 real_url = MMSStreamURL().getLocationData(__gval__.hbbtv_handelr.getUrl())
695                 print "Received URI :\n",real_url
696
697                 if real_url is not None:
698                         __gval__.hbbtv_handelr.doRetryOpen(real_url.strip())
699
700         def _cb_set_page_title(self, title=None):
701                 print "page title :",title
702                 if title is None:
703                         return
704                 self.setTitle(title)
705
706 class HbbTVHelper(Screen):
707         skin =  """<screen name="HbbTVHelper" position="0,0" size="0,0" backgroundColor="transparent" flags="wfNoBorder" title=" "></screen>"""
708         def __init__(self, session):
709                 global __gval__
710                 __gval__.hbbtv_handelr = HandlerHbbTV(session)
711                 __gval__.command_server = ServerFactory().doListenUnixTCP('/tmp/.sock.hbbtv.url', __gval__.hbbtv_handelr)
712
713                 self._urls = None
714                 self._stop_opera()
715                 self._start_opera()
716
717                 Screen.__init__(self, session)
718                 self._session = session
719                 self._timer_infobar = eTimer()
720                 self._timer_infobar.callback.append(self._cb_registrate_infobar)
721                 self._timer_infobar.start(1000)
722
723                 self._excuted_browser = False
724                 self._profile = 0
725
726                 __gval__.command_util = BrowserCommandUtil()
727
728                 global _g_ssm_
729                 if _g_ssm_ is None:
730                         _g_ssm_ = SimpleSharedMemory()
731                         _g_ssm_.doConnect()
732
733         def _cb_registrate_infobar(self):
734                 if InfoBar.instance:
735                         self._timer_infobar.stop()
736                         if self._cb_ready_for_ait not in InfoBar.instance.onReadyForAIT:
737                                 InfoBar.instance.onReadyForAIT.append(self._cb_ready_for_ait)
738                         if self._cb_hbbtv_activated not in InfoBar.instance.onHBBTVActivation:
739                                 InfoBar.instance.onHBBTVActivation.append(self._cb_hbbtv_activated)
740
741         def _cb_ready_for_ait(self, orgId=0):
742                 if orgId == 0:
743                         if not self._excuted_browser:
744                                 command_util = getCommandUtil()
745                                 command_util.sendCommand('OP_HBBTV_UNLOAD_AIT')
746                         return
747                 setChannelInfo(None, None, None, None, None)
748
749                 service = self._session.nav.getCurrentService()
750                 info = service and service.info()
751                 if info is not None:
752                         sid  = info.getInfo(iServiceInformation.sSID)
753                         onid = info.getInfo(iServiceInformation.sONID)
754                         tsid = info.getInfo(iServiceInformation.sTSID)
755                         name = info.getName()
756                         if name is None:
757                                 name = ""
758                         orgid   = 0
759                         namelen = len(name)
760                         for x in info.getInfoObject(iServiceInformation.sHBBTVUrl):
761                                 if x[0] in (1, -1) :
762                                         orgid = x[3]
763                                         break
764                         setChannelInfo(sid, onid, tsid, name, orgid)
765
766         def _cb_hbbtv_activated(self, title=None, url=None):
767                 if not self._is_browser_running():
768                         message = "HbbTV Browser was not running.\nPlease running browser before start HbbTV Application."
769                         self.session.open(MessageBox, message, MessageBox.TYPE_INFO)
770                         return
771                 service = self._session.nav.getCurrentlyPlayingServiceReference()
772                 setBeforeService(service)
773                 self._start_hbbtv_application(title, url)
774
775         def _start_hbbtv_application(self, title, url):
776                 tmp_url = self.getStartHbbTVUrl()
777                 if url is None:
778                         url = tmp_url
779                 if strIsEmpty(url):
780                         print "can't get url of hbbtv!!"
781                         return
782                 print "success to get url of hbbtv!! >>", url
783                 if self._excuted_browser:
784                         print "already excuted opera browser!!"
785                         return
786
787                 use_ait = False
788
789                 for x in self._urls:
790                         control_code = x[0]
791                         tmp_url = x[2]
792                         if tmp_url == url and control_code == 1:
793                                 use_ait = True
794                 self._excuted_browser = True
795                 self._session.open(HbbTVWindow, url, self._cb_closed_browser, use_ait, self._profile)
796
797         def _cb_closed_browser(self):
798                 self._excuted_browser = False
799
800         def _start_opera(self):
801                 if not self._is_browser_running():
802                         global HBBTVAPP_PATH
803                         start_command = '%s/launcher start'%(HBBTVAPP_PATH)
804                         os.system(start_command)
805
806         def _stop_opera(self):
807                 global HBBTVAPP_PATH
808                 try:    os.system('%s/launcher stop'%(HBBTVAPP_PATH))
809                 except: pass
810
811         def getStartHbbTVUrl(self):
812                 url, self._urls, self._profile = None, None, 0
813                 service = self._session.nav.getCurrentService()
814                 info = service and service.info()
815                 if not info: return None
816                 self._urls = info.getInfoObject(iServiceInformation.sHBBTVUrl)
817                 for u in self._urls:
818                         if u[0] in (1, -1): # 0:control code, 1:name, 2:url, 3:orgid, 4:appid, 5:profile code
819                                 url = u[2]
820                                 self._profile = u[5]
821                 if url is None:
822                         url = info.getInfoString(iServiceInformation.sHBBTVUrl)
823                 return url
824
825         def showApplicationSelectionBox(self):
826                 applications = []
827
828                 if self.getStartHbbTVUrl():
829                         for x in self._urls:
830                                 applications.append((x[1], x))
831                 else: applications.append(("No detected HbbTV applications.", None))
832                 self._session.openWithCallback(self._application_selected, ChoiceBox, title=_("Please choose an HbbTV application."), list=applications)
833
834         def _application_selected(self, selected):
835                 try:
836                         if selected[1] is None: return
837                         self._cb_hbbtv_activated(selected[1][1], selected[1][2])
838                 except Exception, ErrMsg: print ErrMsg
839
840         def showBrowserConfigBox(self):
841                 start_stop_mode = []
842                 if self._is_browser_running():
843                         start_stop_mode.append(('Stop',None))
844                 else:   start_stop_mode.append(('Start',None))
845                 self._session.openWithCallback(self._browser_config_selected, ChoiceBox, title=_("Please choose one."), list=start_stop_mode)
846
847         def _browser_config_selected(self, selected):
848                 if selected is None:
849                         return
850                 try:
851                         mode = selected[0]
852                         if mode == 'Start':
853                                 if not self._is_browser_running():
854                                         self._start_opera()
855                         elif mode == 'Stop':
856                                 self._stop_opera()
857                 except Exception, ErrMsg: print "Config ERR :", ErrMsg
858
859         def _is_browser_running(self):
860                 try:
861                         global HBBTVAPP_PATH
862                         ret = os.popen('%s/launcher check'%(HBBTVAPP_PATH)).read()
863                         return ret.strip() != "0"
864                 except Exception, ErrMsg:
865                         print "Check Browser Running ERR :", ErrMsg
866                 return False
867
868 _g_helper = None
869 class OperaBrowser(Screen):
870         MENUBAR_ITEM_WIDTH  = 150
871         MENUBAR_ITEM_HEIGHT = 30
872         SUBMENULIST_WIDTH   = 200
873         SUBMENULIST_HEIGHT  = 25
874         SUBMENULIST_NEXT    = 2
875
876         skin =  """
877                 <screen name="Opera Browser" position="0,0" size="1280,720" backgroundColor="transparent" flags="wfNoBorder" title="Opera Browser">
878                         <widget name="topArea" zPosition="-1" position="0,0" size="1280,60" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" />
879                         <widget name="menuitemFile" position="30,20" size="150,30" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" foregroundColors="#9f1313,#a08500" />
880                         <widget name="menuitemHelp" position="180,20" size="150,30" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" foregroundColors="#9f1313,#a08500" />
881                         <widget name="menulist" position="50,%d" size="%d,150" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />
882                         <widget name="submenulist" position="%d,%d" size="%d,150" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />
883                         <widget name="bottomArea" position="0,640" size="1280,80" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" />
884                 </screen>
885                 """ % (MENUBAR_ITEM_HEIGHT+30, SUBMENULIST_WIDTH, SUBMENULIST_WIDTH+50+SUBMENULIST_NEXT, MENUBAR_ITEM_HEIGHT+30, SUBMENULIST_WIDTH)
886
887         MENUITEMS_LIST =[[('Open Location', None), ('Start/Stop',None), ('Exit', None)],
888                          [('About', None)]]
889         def __init__(self, session):
890                 Screen.__init__(self, session)
891
892                 self["actions"] = ActionMap(["MinuteInputActions", "ColorActions", "InputActions", "InfobarChannelSelection", "EPGSelectActions", "KeyboardInputActions"], {
893                          "cancel"      : self.keyCancel
894                         ,"ok"          : self.keyOK
895                         ,"left"        : self.keyLeft
896                         ,"right"       : self.keyRight
897                         ,"up"          : self.keyUp
898                         ,"down"        : self.keyDown
899                         ,"menu"        : self.keyCancel
900                 }, -2)
901
902                 self.menubarCurrentIndex = 0
903                 self.lvMenuItems = []
904                 self.lvSubMenuItems = []
905
906                 self["topArea"]    = Label()
907                 self["bottomArea"] = Label()
908
909                 self["menuitemFile"] = MultiColorLabel()
910                 self["menuitemHelp"] = MultiColorLabel()
911
912                 self["menulist"] = MenuList(self.setListOnView())
913                 self["submenulist"] = MenuList(self.setSubListOnView())
914
915                 self.toggleMainScreenFlag = True
916                 self.toggleListViewFlag = False
917                 self.toggleSubListViewFlag = False
918                 self.currentListView = self["menulist"]
919
920                 self.onLayoutFinish.append(self.layoutFinished)
921
922                 self._onCloseTimer = eTimer()
923                 self._onCloseTimer.callback.append(self._cb_onClose)
924
925         def enableRCMouse(self, mode): #mode=[0|1]|[False|True]
926                 rcmouse_path = "/proc/stb/fp/mouse"
927                 if os.path.exists(rcmouse_path):
928                         os.system("echo %d > %s" % (mode, rcmouse_path))
929
930         def layoutFinished(self):
931                 self["menuitemFile"].setText("File")
932                 self["menuitemHelp"].setText("Help")
933
934                 self["menulist"].hide()
935                 self["submenulist"].hide()
936
937                 self["bottomArea"].setText("Opera Web Browser Plugin v0.1")
938                 self.setTitle("BrowserMain")
939                 self.selectMenuitem()
940
941         def selectMenuitem(self):
942                 tmp = [self["menuitemFile"], self["menuitemHelp"]]
943                 self["menuitemFile"].setForegroundColorNum(0)
944                 self["menuitemHelp"].setForegroundColorNum(0)
945                 tmp[self.menubarCurrentIndex].setForegroundColorNum(1)
946
947         def popupCloseAll(self):
948                 self.keyLeft()
949                 self.keyLeft()
950                 self.keyUp()
951                 self.keyCancel()
952
953         def setListOnView(self):
954                 self.lvMenuItems = self.MENUITEMS_LIST[self.menubarCurrentIndex]        
955                 return self.lvMenuItems
956
957         def setSubListOnView(self):
958                 self.lvSubMenuItems = []
959                 xl = self["menulist"].getCurrent()[1]
960                 if xl is None: return []
961                 for x in xl:
962                         self.lvSubMenuItems.append((x,None))
963                 return self.lvSubMenuItems
964
965         def toggleMainScreen(self):
966                 if not self.toggleMainScreenFlag:
967                         self.show()
968                 else:   self.hide()
969                 self.toggleMainScreenFlag = not self.toggleMainScreenFlag
970
971         def toggleListView(self):
972                 if not self.toggleListViewFlag:
973                         self["menulist"].show()
974                 else:   self["menulist"].hide()
975                 self.toggleListViewFlag = not self.toggleListViewFlag
976
977         def toggleSubListView(self):
978                 if not self.toggleSubListViewFlag:
979                         self["submenulist"].show()
980                 else:   self["submenulist"].hide()
981                 self.toggleSubListViewFlag = not self.toggleSubListViewFlag
982
983         def setCurrentListView(self, listViewIdx):
984                 if listViewIdx == 0:
985                         self.currentListView = None
986                 elif listViewIdx == 1:
987                         self.currentListView = self["menulist"]
988                 elif listViewIdx == 2:
989                         self.currentListView = self["submenulist"]
990
991         def _cb_onClose(self):
992                 self._onCloseTimer.stop()
993                 command_server = getCommandServer()
994                 try:
995                         if self._on_close_window in command_server.onHbbTVCloseCB:
996                                         command_server.onHbbTVCloseCB.remove(self._on_close_window)
997                 except Exception, ErrMsg: pass
998                 try:
999                         if self._on_setPageTitle in command_server.onSetPageTitleCB:
1000                                 command_server.onSetPageTitleCB.remove(self._on_setPageTitle)
1001                 except Exception, ErrMsg: pass
1002                 self._on_setPageTitle('Opera Browser')
1003                 self.enableRCMouse(False)
1004                 self.toggleMainScreen()
1005                 eRCInput.getInstance().unlock()
1006
1007         def _on_setPageTitle(self, title=None):
1008                 print "page title :",title
1009                 if title is None:
1010                         return
1011                 self.setTitle(title)
1012
1013         def cbUrlText(self, data=None):
1014                 print "Inputed Url :", data
1015                 if strIsEmpty(data):
1016                         return
1017                 command_server = getCommandServer()
1018                 if self._on_setPageTitle not in command_server.onSetPageTitleCB:
1019                                 command_server.onSetPageTitleCB.append(self._on_setPageTitle)
1020                 if self._on_close_window not in command_server.onHbbTVCloseCB:
1021                         command_server.onHbbTVCloseCB.append(self._on_close_window)
1022                 self.toggleMainScreen()
1023                 self.enableRCMouse(True)
1024                 eRCInput.getInstance().lock()
1025                 command_util = getCommandUtil()
1026                 command_util.sendCommand('OP_BROWSER_OPEN_URL', data)
1027
1028         def _on_close_window(self):
1029                 self._onCloseTimer.start(1000)
1030
1031         def _cmd_on_OpenLocation(self):
1032                 global _g_helper
1033                 if not _g_helper._is_browser_running():
1034                         message = "Opera Browser was not running.\nPlease running browser using [File]>[Start/Stop] menu."
1035                         self.session.open(MessageBox, message, MessageBox.TYPE_INFO)
1036                         return
1037                 self.session.openWithCallback(self.cbUrlText, VirtualKeyBoard, title=("Please enter URL here"), text='http://')
1038         def _cmd_on_About(self):
1039                 self.session.open(MessageBox, 'Opera Web Browser Plugin v0.1(beta)', type = MessageBox.TYPE_INFO)
1040         def _cmd_on_Exit(self):
1041                 self.close()
1042         def _cmd_on_StartStop(self):
1043                 global _g_helper
1044                 if _g_helper is None: 
1045                         return
1046                 _g_helper.showBrowserConfigBox()
1047         def doCommand(self, command):
1048                 cmd_map = {
1049                          'Exit'          :self._cmd_on_Exit
1050                         ,'About'         :self._cmd_on_About
1051                         ,'Open Location' :self._cmd_on_OpenLocation
1052                         ,'Start/Stop'    :self._cmd_on_StartStop
1053                 }
1054                 try:
1055                         cmd_map[command]()
1056                 except: pass
1057
1058         def keyOK(self):
1059                 if not self.toggleListViewFlag:
1060                         self.keyDown()
1061                         return
1062                 if self.currentListView.getCurrent()[1] is None:
1063                         self.doCommand(self.currentListView.getCurrent()[0])
1064                         #self.session.open(MessageBox, _(self.currentListView.getCurrent()[0]), type = MessageBox.TYPE_INFO)
1065                         return
1066                 self.keyRight()
1067
1068         def updateSelectedMenuitem(self, status):
1069                 if self.menubarCurrentIndex == 0 and status < 0:
1070                         self.menubarCurrentIndex = 1
1071                 elif self.menubarCurrentIndex == 1 and status > 0:
1072                         self.menubarCurrentIndex = 0
1073                 else:   self.menubarCurrentIndex += status
1074                 self.selectMenuitem()
1075
1076         def keyLeft(self):
1077                 if not self.toggleMainScreenFlag:
1078                         return
1079                 if not self.toggleListViewFlag:
1080                         self.updateSelectedMenuitem(-1)
1081                         return
1082                 if self.toggleSubListViewFlag:
1083                         self.setCurrentListView(1)
1084                         self.toggleSubListView()
1085                         return
1086                 if self.currentListView.getSelectedIndex():
1087                         self.currentListView.pageUp()
1088
1089         def keyRight(self):
1090                 if not self.toggleMainScreenFlag:
1091                         return
1092                 if not self.toggleListViewFlag:
1093                         self.updateSelectedMenuitem(1)
1094                         return
1095                 if self.currentListView is None:
1096                         return
1097                 if self.currentListView.getCurrent()[1] is not None:
1098                         parentSelectedIndex = self.currentListView.getSelectedIndex()
1099                         self.setCurrentListView(2)
1100                         self.currentListView.setList(self.setSubListOnView())
1101                         self.currentListView.resize(self.SUBMENULIST_WIDTH, self.SUBMENULIST_HEIGHT*len(self.lvSubMenuItems)+5)
1102                         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))
1103                         self.toggleSubListView()
1104
1105         def keyDown(self):
1106                 if not self.toggleMainScreenFlag:
1107                         return
1108                 if self.currentListView is None:
1109                         return
1110                 if not self.toggleListViewFlag:
1111                         self.currentListView.setList(self.setListOnView())
1112                         self.currentListView.resize(self.SUBMENULIST_WIDTH, self.SUBMENULIST_HEIGHT*len(self.lvMenuItems)+5)
1113                         self.currentListView.move(self.MENUBAR_ITEM_WIDTH*self.menubarCurrentIndex+1+ 50,self.MENUBAR_ITEM_HEIGHT+30)
1114                         self.toggleListView()
1115                         return
1116                 self.currentListView.down()
1117
1118         def keyUp(self):
1119                 if not self.toggleMainScreenFlag:
1120                         return
1121                 if self.currentListView is None:
1122                         return
1123                 if self.currentListView == self["menulist"]:
1124                         if self.currentListView.getSelectedIndex() == 0:
1125                                 self.toggleListView()
1126                                 return
1127                 self.currentListView.up()
1128
1129         def keyCancel(self):
1130                 self.toggleMainScreen()
1131
1132 def auto_start_main(reason, **kwargs):
1133         if reason:
1134                 command_server = getCommandServer()
1135                 command_server.stop()
1136
1137 def session_start_main(session, reason, **kwargs):
1138         global _g_helper
1139         _g_helper = session.open(HbbTVHelper)
1140
1141 def plugin_start_main(session, **kwargs):
1142         session.open(OperaBrowser)
1143
1144 def plugin_extension_start_application(session, **kwargs):
1145         global _g_helper
1146         if _g_helper is None: 
1147                 return
1148         _g_helper.showApplicationSelectionBox()
1149
1150 def plugin_extension_browser_config(session, **kwargs):
1151         global _g_helper
1152         if _g_helper is None: 
1153                 return
1154         _g_helper.showBrowserConfigBox()
1155
1156 def Plugins(path, **kwargs):
1157         return  [
1158                 PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, fnc=auto_start_main),
1159                 PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, needsRestart=True, fnc=session_start_main, weight=-10),
1160                 PluginDescriptor(name="HbbTV Applications", where=PluginDescriptor.WHERE_EXTENSIONSMENU, needsRestart=True, fnc=plugin_extension_start_application),
1161                 PluginDescriptor(name="Browser Start/Stop", where=PluginDescriptor.WHERE_EXTENSIONSMENU, needsRestart=True, fnc=plugin_extension_browser_config),
1162                 PluginDescriptor(name="Opera Web Browser", description="start opera web browser", where=PluginDescriptor.WHERE_PLUGINMENU, needsRestart=True, fnc=plugin_start_main),
1163                 ]
1164