├── .gitignore ├── package.json ├── index.js ├── bin ├── index.js ├── hbbtv.js ├── start-cs.js └── start-terminal.js ├── lib ├── hbbtv-terminal-manager.js ├── cs-launcher-dial-server.js ├── hbbtv.js ├── cs-launcher-dial-client.js ├── hbbtv-app2app-server.js ├── hbbtv-cs-manager.js ├── hbbtv-dial-server.js └── hbbtv-dial-client.js ├── test ├── app2app-remote-client.js ├── app2app-local-client.js └── hbbtv-nodejs-client.js ├── www ├── hbbtv-app.html ├── cs-app.html └── js │ ├── hbbtvlib.js │ └── hbbtv-manager-polyfill.js ├── LICENSE └── Readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.project 2 | .idea 3 | node_modules 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hbbtv", 3 | "description": "Nodejs implementation of the HbbTV Companion Screen", 4 | "version": "0.0.11", 5 | "author": { 6 | "name": "Louay Bassbouss", 7 | "email": "louay.bassbouss@fokus.fraunhofer.de" 8 | }, 9 | "homepage": "http://www.fokus.fraunhofer.de/fame", 10 | "license": "LGPL-3.0", 11 | "preferGlobal": true, 12 | "keywords": ["ssdp", "nsd", "discovery", "launch", "dial","hbbtv","hbbtv 2.0","hbbtv 2.0 cs","cs", "ws", "websocket", "app2app"], 13 | "main": "index", 14 | "dependencies" : { 15 | "peer-dial": "0.0.8", 16 | "node-uuid": "1.4.1", 17 | "ws": "0.7.2", 18 | "express": "4.20.0", 19 | "opn": "2.0.0", 20 | "xml2js": "0.5.0", 21 | "xmlbuilder": "2.6.4", 22 | "commander": "2.8.1" 23 | }, 24 | "bin": { 25 | "hbbtv": "bin/index.js" 26 | }, 27 | "repository": "https://github.com/fraunhoferfokus/node-hbbtv.git", 28 | "readmeFilename": "Readme.md", 29 | "_id": "hbbtv@0.0.11", 30 | "_from": "hbbtv@*" 31 | } 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2013 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | module.exports = require('./lib/hbbtv'); -------------------------------------------------------------------------------- /bin/index.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | /******************************************************************************* 3 | * 4 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3.0 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library. If not, see . 18 | * 19 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 20 | * 21 | ******************************************************************************/ 22 | require("./hbbtv.js"); -------------------------------------------------------------------------------- /lib/hbbtv-terminal-manager.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var HbbTVCsManager = require("./hbbtv-cs-manager.js"); 22 | var util = require("util"); 23 | 24 | var HbbTVTerminalManager = function (httpServer) { 25 | var isCs = true; 26 | HbbTVCsManager.call(this,httpServer,isCs); 27 | }; 28 | 29 | util.inherits(HbbTVTerminalManager, HbbTVCsManager); 30 | module.exports = HbbTVTerminalManager; -------------------------------------------------------------------------------- /lib/cs-launcher-dial-server.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var HbbTVDialServer = require("./hbbtv-dial-server.js"); 22 | var util = require("util"); 23 | 24 | var CsLauncherDialServer = function (expressApp) { 25 | var isCsLauncher = true; 26 | HbbTVDialServer.call(this,expressApp,isCsLauncher); 27 | }; 28 | 29 | util.inherits(CsLauncherDialServer, HbbTVDialServer); 30 | module.exports = CsLauncherDialServer; -------------------------------------------------------------------------------- /test/app2app-remote-client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lba on 16/06/15. 3 | */ 4 | 5 | (function(){ 6 | // this example code works in Node.js and Browser. 7 | if(typeof window == "undefined"){ 8 | // we are in Node.js. import required modules 9 | var hbbtv = require("../index.js"); 10 | WebSocket = hbbtv.WebSocket; 11 | } 12 | var run = function(){ 13 | var app2appRemoteBaseUrl = "ws://localhost:8080/remote/" ; 14 | var appEndpoint = "org.mychannel.myapp"; 15 | var ws = new WebSocket(app2appRemoteBaseUrl + appEndpoint); 16 | ws.binaryType = "arraybuffer"; 17 | ws.onopen = function(evt) { 18 | console.log("Connection waiting ..."); 19 | }; 20 | ws.onclose = function(evt) { 21 | console.log("Connection closed."); 22 | }; 23 | ws.onerror = function (evt) { 24 | console.log("Connection error."); 25 | }; 26 | ws.onmessage = function(evt) { 27 | if (evt.data == "pairingcompleted") { 28 | console.log("connection paired"); 29 | ws.onmessage = function(evt) { 30 | console.log( "Received Message: " + evt.data); 31 | }; 32 | var data = "Hello from Companion Screen"; 33 | ws.send(data); 34 | var array = [0,1,2,3,4,5,6,7,8,9]; 35 | data = typeof Buffer != "undefined"?new Buffer(array): new Int8Array(array).buffer; 36 | ws.send(data); 37 | } else { 38 | console.log("Unexpected message received from terminal."); 39 | ws.close(); 40 | } 41 | }; 42 | } 43 | run(); 44 | })(); 45 | 46 | -------------------------------------------------------------------------------- /lib/hbbtv.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var WebSocket = require("ws"); 22 | var HbbTVApp2AppServer = require("./hbbtv-app2app-server.js"); 23 | var HbbTVDialServer = require("./hbbtv-dial-server.js"); 24 | var HbbTVDialClient = require("./hbbtv-dial-client.js"); 25 | var CsLauncherDialServer = require("./cs-launcher-dial-server.js"); 26 | var CsLauncherDialClient = require("./cs-launcher-dial-client.js"); 27 | var HbbTVCsManager = require("./hbbtv-cs-manager.js"); 28 | var HbbTVTerminalManager = require("./hbbtv-terminal-manager.js"); 29 | 30 | module.exports.HbbTVApp2AppServer = HbbTVApp2AppServer; 31 | module.exports.HbbTVDialServer = HbbTVDialServer; 32 | module.exports.HbbTVDialClient = HbbTVDialClient; 33 | module.exports.CsLauncherDialServer = CsLauncherDialServer; 34 | module.exports.CsLauncherDialClient = CsLauncherDialClient; 35 | module.exports.HbbTVCsManager = HbbTVCsManager; 36 | module.exports.HbbTVTerminalManager = HbbTVTerminalManager; 37 | module.exports.WebSocket = WebSocket; -------------------------------------------------------------------------------- /test/app2app-local-client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by lba on 16/06/15. 3 | */ 4 | 5 | (function(){ 6 | // this example code works in Node.js and Browser. 7 | if(typeof window == "undefined"){ 8 | // we are in Node.js. import required modules 9 | var hbbtv = require("../index.js"); 10 | WebSocket = hbbtv.WebSocket; 11 | } 12 | var run = function(){ 13 | var app2appLocalBaseUrl = "ws://localhost:8080/local/" ; 14 | var appEndpoint = "org.mychannel.myapp"; 15 | var createConnection = function (index) { 16 | var ws = new WebSocket(app2appLocalBaseUrl + appEndpoint); 17 | ws.binaryType = "arraybuffer"; 18 | ws.onopen = function(evt) { 19 | console.log("Connection ",index," waiting ..."); 20 | }; 21 | ws.onclose = function(evt) { 22 | console.log("Connection ",index," closed."); 23 | }; 24 | ws.onerror = function (evt) { 25 | console.log("Connection error."); 26 | }; 27 | ws.onmessage = function(evt) { 28 | if (evt.data == "pairingcompleted") { 29 | console.log("connection ",index," paired"); 30 | ws.onmessage = function(evt) { 31 | if(typeof evt.data == "string"){ 32 | console.log( "Received Message: " + evt.data); 33 | } 34 | else { 35 | var data = typeof Buffer != "undefined"?new Buffer(evt.data): new Int8Array(evt.data); 36 | console.log("Received Binary Message of " + data.length + " bytes", data); 37 | } 38 | }; 39 | ws.send("Hello from HbbTV App: "+index); 40 | createConnection(index+1); 41 | } else { 42 | console.log("Unexpected message received from terminal."); 43 | ws.close(); 44 | } 45 | }; 46 | }; 47 | createConnection(0); 48 | }; 49 | run(); 50 | })(); -------------------------------------------------------------------------------- /bin/hbbtv.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var program = require("commander"); 22 | var package = require("../package.json"); 23 | program.version(package.version) 24 | .allowUnknownOption(false) 25 | .option("-m, --mode ", "select mode. It is either 'terminal' to start as HbbTV Terminal or 'cs' to start as Companion Screen", /^(terminal|cs)$/i) 26 | .option("-p, --port ", "specify the port number of the HbbTV Terminal or CS Launcher. e.g. 8080",parseInt) 27 | .option("-i, --interdevsync-url ", "specify the URL of the inter-device synchronisation CSS-CII server. Applies to 'terminal' mode only. '{hostname}' substring will be replaced with the hostname of this server, as viewed by the client. Optional.") 28 | .option("-u, --useragent ", "specify the user agent string to be advertised. Applies to 'terminal' mode only. Optional.") 29 | .option("-o, --opn-args ", "specify the arguments to opn (used for launching apps), separated by | characters. e.g. firefox|-no-remote. Optional.") 30 | .option("-f, --friendly-name ", "specify the device name to be advertised (overriding system hostname). Applies to 'terminal' mode only. Optional.") 31 | 32 | program.parse(process.argv); 33 | var port = program.port>0 && program.port || null; 34 | var mode = program.mode || null; 35 | var interDevSyncUrl = program["interdevsyncUrl"] || null; 36 | var userAgent = program["useragent"] || null; 37 | var opn_params = program["opnArgs"] ? program["opnArgs"].split('|') : undefined; 38 | var friendlyName = program["friendlyName"] || null; 39 | 40 | if(port){ 41 | global.PORT = port; 42 | global.OPN_PARAMS = opn_params; 43 | if(mode == "terminal"){ 44 | global.INTERDEVSYNC_URL = interDevSyncUrl; 45 | global.USERAGENT = userAgent; 46 | global.FRIENDLY_NAME = friendlyName; 47 | require("./start-terminal.js"); 48 | } 49 | else if(mode == "cs"){ 50 | require("./start-cs.js"); 51 | } 52 | else { 53 | program.help(); 54 | } 55 | } 56 | else{ 57 | program.help(); 58 | } 59 | -------------------------------------------------------------------------------- /bin/start-cs.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var PORT = global.PORT; 22 | if(!PORT){ 23 | console.log("variable 'global.PORT' is missing or not a valid port"); 24 | process.exit(1); 25 | } 26 | var hbbtv = require("../index.js"); 27 | var HbbTVTerminalManager = hbbtv.HbbTVTerminalManager; 28 | var CsLauncherDialServer = hbbtv.CsLauncherDialServer; 29 | var http = require('http'); 30 | var express = require("express"); 31 | var app = express(); 32 | var DIAL_PREFIX = "/dial"; 33 | app.set("port",PORT); 34 | app.set("dial-prefix",DIAL_PREFIX); 35 | http.globalAgent.maxSockets = 100; 36 | var counter = 0; 37 | var httpServer = http.createServer(app); 38 | 39 | var csLauncherDialServer = new CsLauncherDialServer(app).on("ready", function () { 40 | console.log("HbbTV CS Launcher is ready"); 41 | counter++; 42 | }).on("stop", function () { 43 | console.log("HbbTV CS Launcher is stopped"); 44 | if(--counter == 0){ 45 | process.exit(); 46 | } 47 | }).on("error", function (err) { 48 | console.error(err); 49 | }); 50 | 51 | var hbbTVTerminalManager = new HbbTVTerminalManager(httpServer).on("ready", function () { 52 | counter++; 53 | console.log("HbbTV Terminal Manager is ready"); 54 | }).on("stop", function () { 55 | console.log("HbbTV Terminal Manager is stopped"); 56 | if(--counter == 0){ 57 | process.exit(); 58 | } 59 | }).on("error", function (err) { 60 | console.error(err); 61 | }); 62 | 63 | httpServer.listen(PORT, function() { 64 | console.log("HbbTV Companion Screen is listening on port ", PORT); 65 | //console.log("***** Please append the hash query '#port="+PORT+"'"," to the URL of your CS Web App.\n***** The JavaScript Lib 'hbbtv-manager-polyfill.js' must be included in the CS Web App"); 66 | hbbTVTerminalManager.start(); 67 | csLauncherDialServer.start(); 68 | }); 69 | 70 | process.on('SIGINT', function() { 71 | console.log("Stopping HbbTV Companion Screen. Please wait ..."); 72 | hbbTVTerminalManager.stop(); 73 | csLauncherDialServer.stop(); 74 | setTimeout(function () { 75 | process.exit(); 76 | },3000); 77 | }); -------------------------------------------------------------------------------- /test/hbbtv-nodejs-client.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var hbbtv = require("../index.js"); 22 | var HbbTVDialClient = hbbtv.HbbTVDialClient; 23 | var WebSocket = hbbtv.WebSocket; 24 | 25 | var hbbTVDialClient = new HbbTVDialClient().on("ready", function () { 26 | console.log("HbbTV DIAL Client is ready"); 27 | }).on("stop", function () { 28 | console.log("HbbTV DIAL Client is stopped"); 29 | }).on("found", function (terminal) { 30 | console.log("HbbTV Terminal ", terminal.getFriendlyName()," (", terminal.getAppLaunchURL(), ") found"); 31 | var channel = (""+Math.random()).substr(2,16); 32 | terminal.launchHbbTVApp({ 33 | "appUrlBase": "http://fraunhoferfokus.github.io/node-hbbtv/www/hbbtv-app.html", 34 | "appLocation": "?channel="+channel 35 | }, function (launchRes,err) { 36 | if(err){ 37 | console.error("Error on launch HbbTV App", err); 38 | } 39 | else { 40 | console.log("HbbTV App launched successfully: ",launchRes || ""); 41 | createConnection(terminal, channel); 42 | } 43 | }); 44 | }).on("error", function (err) { 45 | console.error(err); 46 | }); 47 | 48 | var createConnection = function (terminal, channel) { 49 | var app2appRemoteBaseUrl = terminal.getApp2AppURL(); 50 | var ws = new WebSocket(app2appRemoteBaseUrl + channel); 51 | ws.binaryType = "arraybuffer"; 52 | ws.onopen = function(evt) { 53 | console.log("Connection waiting ..."); 54 | }; 55 | ws.onclose = function(evt) { 56 | console.log("Connection closed."); 57 | }; 58 | ws.onerror = function (evt) { 59 | console.log("Connection error."); 60 | }; 61 | ws.onmessage = function(evt) { 62 | if (evt.data == "pairingcompleted") { 63 | console.log("pairing complete"); 64 | ws.onmessage = function(evt) { 65 | console.log( "Received Message: " + evt.data); 66 | }; 67 | var data = "Hello from Companion Screen"; 68 | ws.send(data); 69 | var array = [0,1,2,3,4,5,6,7,8,9]; 70 | data = typeof Buffer != "undefined"?new Buffer(array): new Int8Array(array).buffer; 71 | ws.send(data); 72 | } else { 73 | console.log("Unexpected message received from terminal."); 74 | ws.close(); 75 | } 76 | }; 77 | }; 78 | 79 | hbbTVDialClient.start(); -------------------------------------------------------------------------------- /bin/start-terminal.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2013 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var PORT = global.PORT; 22 | var INTERDEVSYNC_URL = global.INTERDEVSYNC_URL; 23 | var USERAGENT = global.USERAGENT; 24 | var OPN_PARAMS = global.OPN_PARAMS; 25 | if(!PORT){ 26 | console.log("variable 'global.PORT' is missing or not a valid port"); 27 | process.exit(1); 28 | } 29 | var hbbtv = require("../index.js"); 30 | var HbbTVApp2AppServer = hbbtv.HbbTVApp2AppServer; 31 | var HbbTVDialServer = hbbtv.HbbTVDialServer; 32 | var HbbTVCsManager = hbbtv.HbbTVCsManager; 33 | var http = require('http'); 34 | var express = require("express"); 35 | var app = express(); 36 | var DIAL_PREFIX = "/dial"; 37 | var CS_MANAGER_PREFIX = "/csmanager"; 38 | http.globalAgent.maxSockets = 100; 39 | var counter = 0; 40 | app.set("port",PORT); 41 | app.set("dial-prefix",DIAL_PREFIX); 42 | app.set("cs-manager-prefix", CS_MANAGER_PREFIX); 43 | app.set("inter-dev-sync-url", INTERDEVSYNC_URL); 44 | app.set("user-agent", USERAGENT); 45 | app.set("opn-params", OPN_PARAMS); 46 | // The HTTP Server is used to in the HbbTVApp2AppServer and the HbbTVDialServer 47 | var httpServer = http.createServer(app); 48 | 49 | var hbbtvApp2AppServer = new HbbTVApp2AppServer(httpServer).on("ready", function () { 50 | console.log("HbbTV App2App Server is ready"); 51 | counter++; 52 | }).on("stop", function () { 53 | console.log("HbbTV App2App Server is stopped"); 54 | if(--counter == 0){ 55 | process.exit(); 56 | } 57 | }).on("error", function (err) { 58 | console.error("HbbTVApp2AppServer Error", err); 59 | }); 60 | 61 | var hbbtvDialServer = new HbbTVDialServer(app).on("ready", function () { 62 | console.log("HbbTV DIAL Server is ready"); 63 | counter++; 64 | }).on("stop", function () { 65 | console.log("HbbTV DIAL Server is stopped"); 66 | if(--counter == 0){ 67 | process.exit(); 68 | } 69 | }).on("error", function (err) { 70 | console.error("HbbTVDialServer Error", err); 71 | }); 72 | 73 | var hbbTVCsManager = new HbbTVCsManager(httpServer).on("ready", function () { 74 | console.log("HbbTV CS Manager is ready"); 75 | counter++; 76 | }).on("stop", function () { 77 | console.log("HbbTV CS Manager is stopped"); 78 | if(--counter == 0){ 79 | process.exit(); 80 | } 81 | }).on("error", function (err) { 82 | console.error("HbbTVCSManager Error", err); 83 | }); 84 | 85 | httpServer.listen(PORT, function() { 86 | console.log("HbbTV Terminal is listening on port ", PORT); 87 | //console.log("***** The JavaScript Lib 'hbbtv-manager-polyfill.js' must be included in the HbbTV App"); 88 | hbbtvApp2AppServer.start(); 89 | hbbtvDialServer.start(); 90 | hbbTVCsManager.start(); 91 | }); 92 | 93 | process.on('SIGINT', function() { 94 | console.log("Stopping HbbTV Terminal. Please wait ..."); 95 | hbbtvApp2AppServer.stop(); 96 | hbbtvDialServer.stop(); 97 | hbbTVCsManager.stop(); 98 | setTimeout(function () { 99 | process.exit(); 100 | },3000); 101 | }); -------------------------------------------------------------------------------- /lib/cs-launcher-dial-client.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var dial = require("peer-dial"); 22 | var util = require("util"); 23 | var events = require("events"); 24 | 25 | var CsLauncher = function (dialDevice, appInfo) { 26 | var appLaunchURL = dialDevice && dialDevice.applicationUrl && (dialDevice.applicationUrl+"/Famium") || null; 27 | var osId = appInfo && appInfo.additionalData && appInfo.additionalData.X_FAMIUM_CS_OS_ID || null; 28 | 29 | dialDevice && (dialDevice.appLaunchURL = appLaunchURL); 30 | dialDevice && (dialDevice.osId = osId); 31 | 32 | var getAppLaunchURL = function () { 33 | return appLaunchURL; 34 | }; 35 | 36 | var getInfo = function () { 37 | return dialDevice || null; 38 | }; 39 | 40 | var launchCsApp = function (launchData,callback) { 41 | var launchReq = launchData; 42 | dialDevice.launchApp("Famium",launchReq, "text/plain", function (launchRes, err) { 43 | if(typeof launchRes != "undefined"){ 44 | callback && callback(launchRes,err); 45 | } 46 | else if(err){ 47 | callback && callback(null,err); 48 | } 49 | }); 50 | }; 51 | 52 | Object.defineProperty(this,"launchCsApp", { 53 | get: function(){ 54 | return launchCsApp; 55 | } 56 | }); 57 | 58 | Object.defineProperty(this,"getInfo", { 59 | get: function(){ 60 | return getInfo; 61 | } 62 | }); 63 | 64 | Object.defineProperty(this,"getAppLaunchURL", { 65 | get: function(){ 66 | return getAppLaunchURL; 67 | } 68 | }); 69 | }; 70 | 71 | var CsLauncherDialClient = function () { 72 | var dialClient = new dial.Client(); 73 | var self = this; 74 | var csLaunchers = {}; 75 | dialClient.on("ready",function(){ 76 | self.emit("ready"); 77 | }).on("found",function(deviceDescriptionUrl, headers){ 78 | dialClient.getDialDevice(deviceDescriptionUrl, function (dialDevice, err) { 79 | if(dialDevice){ 80 | dialDevice.getAppInfo("Famium", function (appInfo, err) { 81 | if(appInfo){ 82 | var csLauncher = new CsLauncher(dialDevice, appInfo); 83 | csLaunchers[deviceDescriptionUrl] = csLauncher; 84 | self.emit("found", csLauncher); 85 | } 86 | else if(err){ 87 | // TODO check if this is an error or not 88 | //var error = new Error("Error on get CS Launcher FAMIUM App Info or DIAL device is not a FAMIUM CS Launcher", err.message); 89 | //self.emit("error", error); 90 | } 91 | }); 92 | } 93 | else if(err){ 94 | var error = new Error("Error on get device description from "+deviceDescriptionUrl, err.message); 95 | self.emit("error", error); 96 | } 97 | }); 98 | }).on("disappear", function(deviceDescriptionUrl, headers){ 99 | var csLauncher = csLaunchers[deviceDescriptionUrl]; 100 | delete csLaunchers[deviceDescriptionUrl]; 101 | self.emit("disappear",deviceDescriptionUrl, csLauncher); 102 | }).on("stop", function(){ 103 | self.emit("stop"); 104 | }).on("error", function (err) { 105 | self.emit("error",err); 106 | }); 107 | 108 | var start = function () { 109 | dialClient.start(); 110 | return this; 111 | }; 112 | 113 | var refresh = function () { 114 | dialClient.refresh(); 115 | return this; 116 | }; 117 | 118 | var stop = function () { 119 | dialClient.stop(); 120 | return this; 121 | }; 122 | 123 | Object.defineProperty(this,"start", { 124 | get: function(){ 125 | return start; 126 | } 127 | }); 128 | 129 | Object.defineProperty(this,"refresh", { 130 | get: function(){ 131 | return refresh; 132 | } 133 | }); 134 | 135 | Object.defineProperty(this,"stop", { 136 | get: function(){ 137 | return stop; 138 | } 139 | }); 140 | }; 141 | 142 | util.inherits(CsLauncherDialClient, events.EventEmitter); 143 | module.exports = CsLauncherDialClient; -------------------------------------------------------------------------------- /www/hbbtv-app.html: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | HbbTV App 28 | 29 | 30 | 31 | 37 | 38 | 39 |

Sample HbbTV Application

40 |
41 | 42 |
43 |
44 |
45 |
    46 | 47 |
48 |
49 |
50 | 51 |
52 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /www/cs-app.html: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | Companion Screen App 28 | 29 | 30 | 31 | 32 |

Sample CS Web Application

33 |
34 | 35 |
36 |
37 |
38 |
    39 | 40 |
41 |
42 |
43 | 44 |
45 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /lib/hbbtv-app2app-server.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var ws = require("ws"); 22 | var util = require("util"); 23 | var events = require("events"); 24 | var WebSocketServer = ws.Server; 25 | var HbbTVApp2AppServer = function (httpServer) { 26 | var wsServer = null; 27 | var pendingLocalConnections = null; 28 | var pendingRemoteConnections = null; 29 | var handlePendingConnectionsChanged = function (channel) { 30 | var channelPendingLocalConnections = pendingLocalConnections[channel] || []; 31 | var channelPendingRemoteConnections = pendingRemoteConnections[channel] || []; 32 | while(channelPendingLocalConnections.length>0 && channelPendingRemoteConnections.length>0){ 33 | var localConnection = channelPendingLocalConnections.pop(); 34 | var remoteConnection = channelPendingRemoteConnections.pop(); 35 | localConnection.pair = remoteConnection; 36 | remoteConnection.pair = localConnection; 37 | localConnection && (localConnection.readyState == ws.OPEN) && localConnection.send("pairingcompleted"); 38 | remoteConnection && (remoteConnection.readyState == ws.OPEN) && remoteConnection.send("pairingcompleted"); 39 | } 40 | if(channelPendingLocalConnections.length == 0){ 41 | delete pendingLocalConnections[channel]; 42 | } 43 | if(channelPendingRemoteConnections.length == 0){ 44 | delete pendingRemoteConnections[channel]; 45 | } 46 | }; 47 | var handleConnectionClosed = function (connection) { 48 | if(connection.local) { 49 | var channelPendingLocalConnections = pendingLocalConnections[connection.channel] || []; 50 | var index = channelPendingLocalConnections.indexOf(connection); 51 | index >= 0 && channelPendingLocalConnections.splice(index, 1); 52 | if(channelPendingLocalConnections.length == 0){ 53 | delete pendingLocalConnections[connection.channel]; 54 | } 55 | } 56 | else if(connection.remote){ 57 | var channelPendingRemoteConnections = pendingRemoteConnections[connection.channel] || []; 58 | var index = channelPendingRemoteConnections.indexOf(connection); 59 | index >= 0 && pendingRemoteConnections.splice(index, 1); 60 | if(channelPendingRemoteConnections.length == 0){ 61 | delete pendingRemoteConnections[connection.channel]; 62 | } 63 | } 64 | }; 65 | 66 | var handleConnectionReceived = function(connection) { 67 | var req = connection.upgradeReq; 68 | if(req.channel){ 69 | var channel = req.channel; 70 | connection.channel = channel; 71 | if(req.local){ 72 | connection.local = true; 73 | var channelPendingLocalConnections = pendingLocalConnections[channel] || (pendingLocalConnections[channel] = []); 74 | channelPendingLocalConnections.push(connection); 75 | } 76 | else { 77 | connection.remote = true; 78 | var channelPendingRemoteConnections = pendingRemoteConnections[channel] || (pendingRemoteConnections[channel] = []); 79 | channelPendingRemoteConnections.push(connection); 80 | } 81 | handlePendingConnectionsChanged(channel); 82 | connection.on("message", function(msg, flags) { 83 | var options = {}; 84 | flags.binary && (options.binary = true); 85 | flags.masked && (options.masked = true); 86 | if (flags && flags.binary) { 87 | connection.pair && (connection.pair.readyState == ws.OPEN) && connection.pair.send(msg, options); 88 | } 89 | else { 90 | connection.pair && (connection.pair.readyState == ws.OPEN) && connection.pair.send(msg, options); 91 | } 92 | }); 93 | connection.on("close", function(code, reason) { 94 | if(connection.pair){ 95 | connection.pair.close(); 96 | connection.pair = null; 97 | } 98 | else { 99 | handleConnectionClosed(connection); 100 | } 101 | connection = null; 102 | }); 103 | connection.on("error", function () { 104 | // TODO handle error and remove socket 105 | }); 106 | } 107 | else { 108 | connection.close(); 109 | } 110 | }; 111 | 112 | var verifyClient = function (info,callback) { 113 | var req = info.req; 114 | var url = req.url || ""; 115 | var channel = null; 116 | var verified; 117 | var code; 118 | if(url.indexOf("/local/") == 0){ 119 | channel = url.substr(7) || null; 120 | req.local = true; 121 | } 122 | else if(url.indexOf("/remote/") == 0){ 123 | channel = url.substr(8) || null; 124 | req.local = false; 125 | } 126 | if(channel){ 127 | req.channel = channel; 128 | verified = true; 129 | callback && callback(verified); 130 | } 131 | /*else{ 132 | verified = false; 133 | code = 400; 134 | } 135 | try{ 136 | callback(verified,code); 137 | } 138 | catch (e){ 139 | console.error("Error on verify client",e); 140 | }*/ 141 | }; 142 | 143 | var reset = function () { 144 | wsServer && wsServer.close(); 145 | wsServer = null; 146 | pendingLocalConnections = []; 147 | pendingRemoteConnections = []; 148 | }; 149 | 150 | var start = function () { 151 | reset(); 152 | wsServer = new WebSocketServer({ 153 | server: httpServer, 154 | verifyClient : verifyClient 155 | }).on("connection", handleConnectionReceived); 156 | this.emit("ready"); 157 | return this; 158 | }; 159 | 160 | var stop = function () { 161 | reset(); 162 | this.emit("stop"); 163 | return this; 164 | }; 165 | 166 | Object.defineProperty(this,"start", { 167 | get: function(){ 168 | return start; 169 | } 170 | }); 171 | 172 | Object.defineProperty(this,"stop", { 173 | get: function(){ 174 | return stop; 175 | } 176 | }); 177 | }; 178 | 179 | util.inherits(HbbTVApp2AppServer, events.EventEmitter); 180 | 181 | module.exports = HbbTVApp2AppServer; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /lib/hbbtv-cs-manager.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var dial = require("peer-dial"); 22 | var util = require("util"); 23 | var events = require("events"); 24 | var CsLauncherDialClient = require("./cs-launcher-dial-client.js"); 25 | var HbbTVDialClient = require("./hbbtv-dial-client.js"); 26 | var ws = require("ws"); 27 | var WebSocketServer = ws.Server; 28 | var enableCORS = function(req, res, next) { 29 | res.header("Access-Control-Allow-Origin", "*"); 30 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Application-URL"); 31 | next(); 32 | }; 33 | 34 | var HbbTVCSManager = function (httpServer, isCs) { 35 | //var prefix = expressApp.get("cs-manager-prefix") || ""; 36 | isCs = (isCs == true); 37 | var csLauncherDialClient = new CsLauncherDialClient(); 38 | var hbbTVDialClient = new HbbTVDialClient(); 39 | var self = this; 40 | var wsServer = null; 41 | var csLaunchers = {}; 42 | var tmpCsLaunchers = {}; 43 | var terminals = {}; 44 | var tmpTerminals = {}; 45 | var lastCsLauncherRefresh = 0; 46 | var lastHbbTVTerminalRefresh = 0; 47 | var discoveryTime = 5000; 48 | var readyCounter = isCs?1:0; 49 | var stopCounter = isCs?1:0; 50 | csLauncherDialClient.on("ready",function(){ 51 | readyCounter++ && self.emit("ready"); 52 | }).on("found",function(csLauncher){ 53 | csLaunchers[csLauncher.getAppLaunchURL()] = csLauncher; 54 | tmpCsLaunchers[csLauncher.getAppLaunchURL()] = csLauncher.getInfo(); 55 | }).on("disappear", function(deviceDescriptionUrl, csLauncher){ 56 | delete csLaunchers[deviceDescriptionUrl]; 57 | delete tmpCsLaunchers[deviceDescriptionUrl]; 58 | }).on("stop", function(){ 59 | stopCounter++ && self.emit("stop"); 60 | }).on("error", function (err) { 61 | self.emit("error",err); 62 | }); 63 | 64 | hbbTVDialClient.on("ready",function(){ 65 | readyCounter++ && self.emit("ready"); 66 | }).on("found",function(terminal){ 67 | terminals[terminal.getAppLaunchURL()] = terminal; 68 | tmpTerminals[terminal.getAppLaunchURL()] = terminal.getInfo(); 69 | }).on("disappear", function(deviceDescriptionUrl, terminal){ 70 | delete terminals[deviceDescriptionUrl]; 71 | delete tmpTerminals[deviceDescriptionUrl]; 72 | }).on("stop", function(){ 73 | stopCounter++ && self.emit("stop"); 74 | }).on("error", function (err) { 75 | self.emit("error",err); 76 | }); 77 | 78 | var handleConnectionReceived = function(connection) { 79 | connection.on("message", function(msg, flags) { 80 | // expect msg as jsonrpc request 81 | if(typeof msg == "string"){ 82 | try{ 83 | var req = JSON.parse(msg); 84 | var method = req.method; 85 | if(method == "discoverCSLaunchers"){ 86 | discoverCSLaunchers(connection,req); 87 | } 88 | else if(method == "discoverTerminals"){ 89 | discoverTerminals(connection,req); 90 | } 91 | else if(method == "launchCSApp"){ 92 | launchCSApp(connection,req); 93 | } 94 | else if(method == "launchHbbTVApp"){ 95 | launchHbbTVApp(connection,req); 96 | } 97 | } 98 | catch(err){ 99 | self.emit("error",err); 100 | } 101 | } 102 | }).on("close", function(code, reason) { 103 | 104 | }); 105 | }; 106 | 107 | var verifyClient = function (info,callback) { 108 | var req = info.req; 109 | var url = req.url || ""; 110 | if(url == "/hbbtvmanager"){ 111 | callback && callback(true); 112 | } 113 | /*else { 114 | callback && callback(false,400); 115 | }*/ 116 | }; 117 | 118 | var discoverCSLaunchers = function (connection, req) { 119 | var currentTime = new Date().getTime(); 120 | var timeElapsed = currentTime - lastCsLauncherRefresh; 121 | var timeout = 0; 122 | if(timeElapsed > discoveryTime){ 123 | lastCsLauncherRefresh = currentTime; 124 | tmpCsLaunchers = {}; 125 | csLauncherDialClient.refresh(); 126 | timeout = discoveryTime; 127 | } 128 | else { 129 | timeout = discoveryTime-timeElapsed; 130 | } 131 | setTimeout(function(){ 132 | var rsp = { 133 | "jsonrpc": "2.0", 134 | "result": tmpCsLaunchers, 135 | "id": req.id 136 | }; 137 | connection.send(JSON.stringify(rsp)); 138 | }, timeout); 139 | }; 140 | 141 | var launchCSApp = function (connection, req) { 142 | var launcherId = req.params[0]; 143 | var payload = req.params[1]; 144 | var csLauncher = csLaunchers[launcherId]; 145 | var code = null; 146 | // TODO check payload if it is conform with the HbbTV 2.0 Spec as described in 14.4.2 147 | if(csLauncher){ 148 | csLauncher.launchCsApp(payload, function (launchRes, err) { 149 | if(err){ 150 | code = 400; 151 | } 152 | else { 153 | code = 200; 154 | } 155 | }); 156 | } 157 | else { 158 | code = 404; 159 | } 160 | var rsp = { 161 | "jsonrpc": "2.0", 162 | "result": code, 163 | "id": req.id 164 | }; 165 | connection.send(JSON.stringify(rsp)); 166 | }; 167 | 168 | var discoverTerminals = function (connection, req) { 169 | var currentTime = new Date().getTime(); 170 | var timeElapsed = currentTime - lastHbbTVTerminalRefresh; 171 | var timeout = 0; 172 | if(timeElapsed > discoveryTime){ 173 | lastHbbTVTerminalRefresh = currentTime; 174 | tmpTerminals = {}; 175 | hbbTVDialClient.refresh(); 176 | timeout = discoveryTime; 177 | } 178 | else { 179 | timeout = discoveryTime-timeElapsed; 180 | } 181 | setTimeout(function(){ 182 | var rsp = { 183 | "jsonrpc": "2.0", 184 | "result": tmpTerminals, 185 | "id": req.id 186 | }; 187 | connection.send(JSON.stringify(rsp)); 188 | }, timeout); 189 | }; 190 | 191 | var launchHbbTVApp = function (connection, req) { 192 | var terminalId = req.params[0]; 193 | var options = req.params[1]; 194 | var terminal = terminals[terminalId]; 195 | var code = null; 196 | // TODO check options object 197 | if(terminal){ 198 | terminal.launchHbbTVApp(options, function (launchRes, err) { 199 | if(err){ 200 | code = 400; 201 | } 202 | else { 203 | code = 200; 204 | } 205 | }); 206 | } 207 | else { 208 | code = 404; 209 | } 210 | var rsp = { 211 | "jsonrpc": "2.0", 212 | "result": code, 213 | "id": req.id 214 | }; 215 | connection.send(JSON.stringify(rsp)); 216 | }; 217 | 218 | var start = function () { 219 | !isCs && csLauncherDialClient.start(); 220 | hbbTVDialClient.start(); 221 | wsServer = new WebSocketServer({ 222 | server: httpServer, 223 | verifyClient : verifyClient 224 | }).on("connection", handleConnectionReceived); 225 | return this; 226 | }; 227 | 228 | var stop = function () { 229 | !isCs && csLauncherDialClient.stop(); 230 | hbbTVDialClient.stop(); 231 | wsServer.close(); 232 | return this; 233 | }; 234 | 235 | Object.defineProperty(this,"start", { 236 | get: function(){ 237 | return start; 238 | } 239 | }); 240 | 241 | Object.defineProperty(this,"stop", { 242 | get: function(){ 243 | return stop; 244 | } 245 | }); 246 | }; 247 | 248 | util.inherits(HbbTVCSManager, events.EventEmitter); 249 | 250 | module.exports = HbbTVCSManager; -------------------------------------------------------------------------------- /lib/hbbtv-dial-server.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright (c) 2015 Louay Bassbouss, Fraunhofer FOKUS, All rights reserved. 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 3.0 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library. If not, see . 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var dial = require("peer-dial"); 22 | var util = require("util"); 23 | var events = require("events"); 24 | var opn = require("opn"); 25 | var xml2js = require("xml2js"); 26 | var HbbTVDialServer = function (expressApp, isCsLauncher) { 27 | var self = this; 28 | var MANUFACTURER = "Fraunhofer FOKUS"; 29 | var MODEL_NAME = "HbbTV 2.0 Node.js Companion Screen Feature Emulator"; 30 | var FRIENDLY_NAME = global.FRIENDLY_NAME; // May be null, in which case the hostname is used. 31 | var port = expressApp.get("port") || 80; 32 | var prefix = expressApp.get("dial-prefix") || ""; 33 | var csManagerPrefix = expressApp.get("cs.manager-prefix") || ""; 34 | var opnParams = expressApp.get("opn-params"); 35 | isCsLauncher = (isCsLauncher == true); 36 | var apps = { 37 | "YouTube": { 38 | disabled: isCsLauncher, 39 | name: "YouTube", 40 | state: "stopped", 41 | allowStop: true, 42 | pid: null 43 | }, 44 | "HbbTV": { 45 | disabled: isCsLauncher, 46 | name: "HbbTV", 47 | state: "running", 48 | allowStop: false, 49 | additionalData: { 50 | "hbbtv:X_HbbTV_App2AppURL":"", 51 | "hbbtv:X_HbbTV_InterDevSyncURL": "", 52 | "hbbtv:X_HbbTV_UserAgent": "" 53 | }, 54 | namespaces: { 55 | "hbbtv": "urn:hbbtv:HbbTVCompanionScreen:2014" 56 | } 57 | }, 58 | "Famium": { 59 | disabled: !isCsLauncher, 60 | name: "Famium", 61 | state: "running", 62 | allowStop: false, 63 | additionalData: { 64 | "famium:X_FAMIUM_CS_OS_ID":"de.fhg.fokus.famium.applauncher/0.0.1" 65 | }, 66 | namespaces: { 67 | "famium": "http://famium.fokus.fraunhofer.de" 68 | } 69 | } 70 | }; 71 | 72 | var openUrl = function (url) { 73 | try{ 74 | opn(url, opnParams); 75 | } 76 | catch(err){ 77 | console.error("Error on open URL", err.message); 78 | } 79 | }; 80 | 81 | var launchApp = function (app, launchData, callback) { 82 | var self = this; 83 | if(app.name == "YouTube"){ 84 | app.pid = "run"; 85 | app.state = "starting"; 86 | openUrl("http://www.youtube.com/tv?"+launchData); 87 | app.state = "running"; 88 | callback && callback(app.pid); 89 | } 90 | else if(app.name == "HbbTV"){ 91 | xml2js.parseString(launchData, { 92 | trim: true, 93 | explicitArray: false, 94 | mergeAttrs: true, 95 | explicitRoot: false, 96 | tagNameProcessors: [function(tagName){ 97 | tagName = tagName.substr(tagName.indexOf(":")+1); 98 | return tagName; 99 | }], 100 | attrNameProcessors: [function(attrName){ 101 | attrName = attrName.substr(attrName.indexOf(":")+1); 102 | return attrName; 103 | }] 104 | },function (err, launchData) { 105 | if(err){ 106 | callback && callback(null,err); 107 | } 108 | else { 109 | try { 110 | var appUrlBase = launchData.ApplicationDiscovery.ApplicationList.Application.applicationTransport.URLBase || ""; 111 | var appLocation = launchData.ApplicationDiscovery.ApplicationList.Application.applicationLocation || ""; 112 | var url = appUrlBase && (appUrlBase+appLocation) || null; 113 | if(url){ 114 | var csManagerParameters = "port="+port+"&hostname="+self.hostname; 115 | openUrl(url+"#"+csManagerParameters); 116 | app.state = "running"; 117 | callback && callback(app.pid); 118 | } 119 | else { 120 | callback && callback(null, new Error("URLBase element in the XML MHP of the DIAL Launch Request is missing or empty")); 121 | } 122 | } 123 | catch (err){ 124 | callback && callback(null, err); 125 | } 126 | } 127 | }); 128 | } 129 | else if(app.name == "Famium"){ 130 | try{ 131 | launchData = JSON.parse(launchData); 132 | var url = null; 133 | //for(var i in launchData.launch){ 134 | for(var i=0; i. 17 | * 18 | * AUTHORS: Louay Bassbouss (louay.bassbouss@fokus.fraunhofer.de) 19 | * 20 | ******************************************************************************/ 21 | var dial = require("peer-dial"); 22 | var util = require("util"); 23 | var events = require("events"); 24 | var URL = require("url"); 25 | var builder = require('xmlbuilder'); 26 | 27 | var HbbTVTerminal = function (dialDevice, appInfo) { 28 | 29 | var appLaunchURL = dialDevice && dialDevice.applicationUrl && (dialDevice.applicationUrl+"/HbbTV") || null; 30 | var app2AppURL = appInfo && appInfo.additionalData && appInfo.additionalData.X_HbbTV_App2AppURL || null; 31 | var interDevSyncURL = appInfo && appInfo.additionalData && appInfo.additionalData.X_HbbTV_InterDevSyncURL || null; 32 | var userAgent = appInfo && appInfo.additionalData && appInfo.additionalData.X_HbbTV_UserAgent || null; 33 | var friendlyName = dialDevice && dialDevice.friendlyName || null; 34 | dialDevice && (dialDevice.appLaunchURL = appLaunchURL); 35 | dialDevice && (dialDevice.app2AppURL = app2AppURL); 36 | dialDevice && (dialDevice.userAgent = userAgent); 37 | dialDevice && (dialDevice.interDevSyncURL = interDevSyncURL); 38 | 39 | var getInfo = function () { 40 | return dialDevice || null; 41 | }; 42 | var getApp2AppURL = function () { 43 | return app2AppURL; 44 | }; 45 | var getInterDevSyncURL = function () { 46 | return interDevSyncURL; 47 | }; 48 | var getUserAgent = function () { 49 | return userAgent; 50 | }; 51 | var getAppLaunchURL = function () { 52 | return appLaunchURL; 53 | }; 54 | var getFriendlyName = function () { 55 | return friendlyName; 56 | }; 57 | 58 | var launchHbbTVApp = function (launchData,callback) { 59 | var orgId = launchData.orgId || ""; 60 | var appId = launchData.appId || ""; 61 | var appName = launchData.appName || ""; 62 | var appNameLanguage = launchData.appNameLanguage || ""; 63 | var appUrlBase = launchData.appUrlBase || ""; 64 | var appLocation = launchData.appLocation || ""; 65 | var appUrl = URL.parse(appUrlBase); 66 | if(appUrl.protocol && appUrl.hostname){ 67 | var mhp = { 68 | "mhp:ServiceDiscovery": { 69 | "@xmlns:mhp": "urn:dvb:mhp:2009", 70 | "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", 71 | "mhp:ApplicationDiscovery": { 72 | "@DomainName": appUrl.hostname, 73 | "mhp:ApplicationList": { 74 | "mhp:Application": { 75 | "mhp:appName": { 76 | "@Language": appNameLanguage, 77 | "#text": appName 78 | }, 79 | "mhp:applicationIdentifier": { 80 | "mhp:orgId": orgId, 81 | "mhp:appId": appId 82 | }, 83 | "mhp:applicationDescriptor": { 84 | "mhp:type": { 85 | "mhp:OtherApp": "application/vnd.hbbtv.xhtml+xml" 86 | }, 87 | "mhp:controlCode": "AUTOSTART", 88 | "mhp:visibility": "VISIBLE_ALL", 89 | "mhp:serviceBound": "false", 90 | "mhp:priority": "1", 91 | "mhp:version": "01", 92 | "mhp:mhpVersion": { 93 | "mhp:profile": "0", 94 | "mhp:versionMajor": "1", 95 | "mhp:versionMinor": "3", 96 | "mhp:versionMicro": "1" 97 | } 98 | }, 99 | "mhp:applicationTransport": { 100 | "@xsi:type": "mhp:HTTPTransportType", 101 | "mhp:URLBase": appUrlBase 102 | }, 103 | "mhp:applicationLocation": appLocation 104 | } 105 | } 106 | } 107 | } 108 | }; 109 | var launchReq = builder.create(mhp).end({ pretty: true}); 110 | dialDevice.launchApp("HbbTV",launchReq, "text/plain", function (launchRes, err) { 111 | if(typeof launchRes != "undefined"){ 112 | callback && callback(launchRes,err); 113 | } 114 | else if(err){ 115 | callback && callback(null,err); 116 | } 117 | }); 118 | } 119 | else { 120 | var err = new Error("mhp:applicationTransport->URLBase is mandatory and must be an valid URL"); 121 | callback && callback(null,err); 122 | } 123 | }; 124 | 125 | Object.defineProperty(this,"launchHbbTVApp", { 126 | get: function(){ 127 | return launchHbbTVApp; 128 | } 129 | }); 130 | 131 | Object.defineProperty(this,"getAppLaunchURL", { 132 | get: function(){ 133 | return getAppLaunchURL; 134 | } 135 | }); 136 | 137 | Object.defineProperty(this,"getApp2AppURL", { 138 | get: function(){ 139 | return getApp2AppURL; 140 | } 141 | }); 142 | 143 | Object.defineProperty(this,"getInterDevSyncURL", { 144 | get: function(){ 145 | return getInterDevSyncURL; 146 | } 147 | }); 148 | 149 | Object.defineProperty(this,"getUserAgent", { 150 | get: function(){ 151 | return getUserAgent; 152 | } 153 | }); 154 | 155 | Object.defineProperty(this,"getFriendlyName", { 156 | get: function(){ 157 | return getFriendlyName; 158 | } 159 | }); 160 | 161 | Object.defineProperty(this,"getInfo", { 162 | get: function(){ 163 | return getInfo; 164 | } 165 | }); 166 | }; 167 | 168 | var HbbTVDialClient = function () { 169 | var dialClient = new dial.Client(); 170 | var self = this; 171 | var terminals = {}; 172 | dialClient.on("ready",function(){ 173 | self.emit("ready"); 174 | }).on("found",function(deviceDescriptionUrl, headers){ 175 | dialClient.getDialDevice(deviceDescriptionUrl, function (dialDevice, err) { 176 | if(dialDevice){ 177 | dialDevice.getAppInfo("HbbTV", function (appInfo, err) { 178 | if(appInfo){ 179 | var terminal = new HbbTVTerminal(dialDevice, appInfo); 180 | terminals[deviceDescriptionUrl] = terminal; 181 | self.emit("found", terminal); 182 | } 183 | else if(err){ 184 | // TODO check if this is an error or not 185 | //var error = new Error("Error on get HbbTV App Info or DIAL device is not a HbbTV Terminal", err.message); 186 | //self.emit("error", error); 187 | } 188 | }); 189 | } 190 | else if(err){ 191 | var error = new Error("Error on get device description from "+deviceDescriptionUrl, err.message); 192 | self.emit("error", error); 193 | } 194 | }); 195 | }).on("disappear", function(deviceDescriptionUrl, headers){ 196 | var terminal = terminals[deviceDescriptionUrl]; 197 | delete terminals[deviceDescriptionUrl]; 198 | self.emit("disappear",deviceDescriptionUrl, terminal); 199 | }).on("stop", function(){ 200 | self.emit("stop"); 201 | }).on("error", function (err) { 202 | self.emit("error",err); 203 | }); 204 | 205 | var start = function () { 206 | dialClient.start(); 207 | return this; 208 | }; 209 | 210 | var refresh = function () { 211 | dialClient.refresh(); 212 | return this; 213 | }; 214 | 215 | var stop = function () { 216 | dialClient.stop(); 217 | return this; 218 | }; 219 | 220 | Object.defineProperty(this,"start", { 221 | get: function(){ 222 | return start; 223 | } 224 | }); 225 | 226 | Object.defineProperty(this,"refresh", { 227 | get: function(){ 228 | return refresh; 229 | } 230 | }); 231 | 232 | Object.defineProperty(this,"stop", { 233 | get: function(){ 234 | return stop; 235 | } 236 | }); 237 | }; 238 | 239 | util.inherits(HbbTVDialClient, events.EventEmitter); 240 | module.exports = HbbTVDialClient; -------------------------------------------------------------------------------- /www/js/hbbtvlib.js: -------------------------------------------------------------------------------- 1 | /** 2 | * HbbTV library v1.0 3 | * 4 | * (C) 2009, IRT GmbH 5 | * 6 | * Overview: 7 | * 8 | * You need to add the OIPF application manager and the oipf configuration 9 | * embedded object to your HTML DOM tree e.g.: 10 | * 11 |
12 | 13 | 14 |
15 | * 16 | * Before using any other function call the initializer first. 17 | * 18 | * function hbbtvlib_intialize() 19 | * Creates and initializes HbbTV, i.e. OIPF DAE, embedded objects. 20 | * Always call this function prior to other functions of this library. 21 | * 22 | * function hbbtvlib_show() 23 | * Shows the application and requests keys via the keyset object. 24 | * 25 | * function hbbtvlib_hide() 26 | * Hides the application and releases keys via the keyset object. 27 | * 28 | * function hbbtvlib_createApp() 29 | * Create applications with the OIPF Application Manager 30 | * 31 | * function hbbtvlib_closeApp() 32 | * Destroys this application. 33 | * 34 | * function hbbtvlib_init_broadcast() 35 | * Convenience function that integrates the broadcast video in your application. 36 | * 37 | * function hbbtvlib_release_broadcast() 38 | * Convenience function that removes the broadcast video from your application. 39 | * 40 | * function hbbtvlib_current_service() 41 | * Returns the DVB service ID. 42 | */ 43 | 44 | /** 45 | * The last error occured in hbbtvlib. If one of the functions returns false, 46 | * the error can be retrieved via this property. 47 | */ 48 | var hbbtvlib_lastError = "no error"; 49 | 50 | /** 51 | * @return true if OIPF functions are available 52 | */ 53 | function hbbtvlib_initialize() { 54 | try { 55 | int_createOipfObjs(); 56 | 57 | var appMgr = int_objs[int_objTypes.appMan]; 58 | if (appMgr && typeof(appMgr.getOwnerApplication) != "undefined") 59 | int_app = appMgr.getOwnerApplication(document); 60 | else { 61 | hbbtvlib_lastError = "no application manager"; 62 | int_app = null; 63 | return false; 64 | } 65 | return int_initKeysetObj(); 66 | } catch (e) { 67 | hbbtvlib_lastError = e; 68 | int_app = null; 69 | } 70 | return false; 71 | }; 72 | 73 | /** 74 | * This function does everything HbbTV requires an application to do 75 | * when it wants to get visible. 76 | * 77 | * @return 78 | */ 79 | function hbbtvlib_show() { 80 | try { 81 | int_app.show(); 82 | int_keyset.setValue(int_ksVisible); 83 | return true; 84 | } catch (e) { 85 | hbbtvlib_lastError = e; 86 | return false; 87 | } 88 | } 89 | 90 | /** 91 | * This function does everything HbbTV requires an application to do 92 | * when it wants to transition to the hidden state. 93 | * 94 | * @return 95 | */ 96 | function hbbtvlib_hide() { 97 | try { 98 | int_app.hide(); 99 | int_keyset.setValue(int_ksHidden); 100 | return true; 101 | } catch (e) { 102 | hbbtvlib_lastError = e; 103 | return false; 104 | } 105 | } 106 | 107 | /** 108 | * Overrides the default keysets. 109 | * Default is RED for hidden state, all for visible state. 110 | * 111 | * @param visibleSet a keyset bitmask 112 | * @param hiddenSet a keyset bitmask 113 | * @return 114 | */ 115 | function hbbtvlib_setKeysets(visibleSet, hiddenSet) { 116 | if (typeof visibleSet == "Number") int_ksVisible = visibleSet; 117 | if (typeof hiddenSet == "Number") int_ksHidden = hiddenSet; 118 | }; 119 | 120 | 121 | /** 122 | * Starts a new application and destroys this application. 123 | * 124 | * @param dvbUrl including organization and application ids 125 | * @param httpUrl a fallback URL 126 | * 127 | * @return false 128 | */ 129 | function hbbtvlib_createApp(dvbUrl, httpUrl) { 130 | if (int_app) { 131 | try { 132 | if (dvbUrl && int_app.createApplication(dvbUrl, false)) { 133 | int_app.destroyApplication(); 134 | return true; 135 | } 136 | } catch (e) { 137 | hbbtvlib_lastError = e; 138 | } 139 | try { 140 | if (httpUrl && int_app.createApplication(httpUrl, false)) { 141 | int_app.destroyApplication(); 142 | return true; 143 | } 144 | } catch (e) { 145 | hbbtvlib_lastError = e; 146 | } 147 | } else { 148 | document.location.href = httpUrl; 149 | } 150 | return false; 151 | }; 152 | 153 | /** 154 | * Destroys this application. 155 | * 156 | * @param fallBackUrl 157 | * @return 158 | */ 159 | function hbbtvlib_closeApp(fallBackUrl) { 160 | if (int_app) { 161 | try { 162 | int_app.destroyApplication(); 163 | } catch (e) { 164 | hbbtvlib_lastError = e; 165 | } 166 | } else if (fallBackUrl) { 167 | document.location.href = fallBackUrl; 168 | } else { 169 | window.close(); 170 | } 171 | return false; 172 | }; 173 | 174 | /** 175 | * Handle OIPF DAE Broadcast video 176 | */ 177 | var int_bc_video = null; 178 | var int_bc_container = null; 179 | 180 | /** 181 | * Creates and initializes a broadcast video inside the element 182 | * identified by the containerId. If no bc video can be included 183 | * the dummy picture is added instead of the bc. 184 | * 185 | * @param parentId the id of the HTML container where the video/broadcast object will be added 186 | * @param objId id which shall be set for the video/broadcast object 187 | * @param dummyPic an optional picture to be shown if video/broadcast can not be added 188 | * 189 | * @return the video/broadcast object or false 190 | */ 191 | function hbbtvlib_init_broadcast (parentId, objId, dummyPic) { 192 | try { 193 | int_bc_container = document.getElementById(parentId); 194 | if (!int_bc_container) return false; 195 | 196 | // root container for video/broadcast object 197 | int_bc_container.innerHTML = ' '; 198 | int_bc_video = document.getElementById(objId); 199 | 200 | if (typeof (int_bc_video.fullScreen) != 'undefined') { 201 | int_bc_video.setFullScreen(false); 202 | } 203 | if (typeof (int_bc_video.bindToCurrentChannel) != 'undefined') { 204 | int_bc_video.bindToCurrentChannel(); 205 | } 206 | 207 | // check if OIPF video object is supported 208 | if (typeof (int_bc_video.currentChannel) != 'undefined') return int_bc_video; 209 | 210 | } catch (e) { 211 | hbbtvlib_lastError = e; 212 | } 213 | if (dummyPic) int_bc_container.innerHTML = 'TV Bild'; 214 | return false; 215 | }; 216 | 217 | /** 218 | * Releases the video/broadcast object and removes the object from the DOM. 219 | */ 220 | function hbbtvlib_release_broadcast () { 221 | try { 222 | if (int_bc_video && typeof (int_bc_video.release) != "undefined") { 223 | int_bc_video.release(); 224 | int_bc_video = null; 225 | } 226 | if (int_bc_container) { 227 | int_bc_container.innerHTML = ""; 228 | int_bc_container = null; 229 | } 230 | } catch (e) { 231 | hbbtvlib_lastError = e; 232 | } 233 | }; 234 | 235 | /** 236 | * Requires hbbtvlib_init_broadcast 237 | * 238 | * @return the DVB service id of the current presented service or -1 239 | */ 240 | function hbbtvlib_current_service () { 241 | try { 242 | return int_bc_video.currentChannel.sid; 243 | } catch (e) { 244 | hbbtvlib_lastError = e; 245 | } 246 | return -1; 247 | }; 248 | 249 | /** 250 | * Tunes to a DVB service identified by the DVB Triplet. The application may 251 | * get killed due to the application life cycle, i.e. if it is not signalled 252 | * with their application ID on the tuned service. 253 | * 254 | * @param onid the original network id 255 | * @param tsid the transport stream id 256 | * @param sid the service id 257 | * 258 | * @return false if there is no video broadcast object available or there is no 259 | * channel found for this triplet 260 | */ 261 | function hbbtvlib_tuneTo(onid, tsid, sid) { 262 | try { 263 | var chLst = int_bc_video.getChannelConfig().channelList; 264 | 265 | onid = (typeof(onid) == 'number') ? onid : parseInt(onid, 10); 266 | tsid = (typeof(tsid) == 'number') ? tsid : parseInt(tsid, 10); 267 | sid = (typeof(sid) == 'number') ? sid : parseInt(sid, 10); 268 | 269 | var ch = chLst.getChannelByTriplet(onid, tsid, sid); 270 | 271 | if (ch == null) { 272 | hbbtvlib_lastError = "Tuning failed, no channel object found for given DVB triplet."; 273 | return false; 274 | } 275 | 276 | int_bc_video.setChannel(ch, false); 277 | 278 | return true; 279 | }catch (e) { 280 | hbbtvlib_lastError = "Tuning failed due to " + e; 281 | } 282 | return false; 283 | }; 284 | 285 | /* 286 | * Library internal (private) properties and functions. 287 | */ 288 | 289 | /** 290 | * Array of OIPF DAE embedded objects. Access Key is the mime-type without "application/". 291 | */ 292 | var int_objs = new Array(); 293 | 294 | var int_objTypes = { 295 | appMan: "oipfApplicationManager", 296 | config: "oipfConfiguration" 297 | }; 298 | 299 | /** 300 | * OIPF DAE Application object 301 | * - to show/hide the application 302 | * - create or destroy applications 303 | * - providing the keyset object 304 | */ 305 | var int_app = null; 306 | 307 | /** 308 | * The OIPF keyset object used to request keys from terminal. 309 | * 310 | * Usually this is the RED button in hidden mode, and up to all 311 | * available keys in visible mode. 312 | */ 313 | var int_keyset = null; 314 | 315 | var int_ksHidden = null; 316 | 317 | var int_ksVisible = null; 318 | 319 | /** 320 | * Internal function to create OIPF embedded objects, 321 | * like ApplicationManager etc., if not already existing. 322 | */ 323 | function int_createOipfObjs() { 324 | if (int_objs.length) return; 325 | // Look for existing objects 326 | var objects = document.getElementsByTagName("object"); 327 | for (var i=0; i