var host = ""; var hosts = []; var pairingCert; var myUniqueid; var api; // Called by the common.js module. function attachListeners() { $('#selectResolution').on('change', saveResolution); $('#selectFramerate').on('change', saveFramerate); $('#bitrateSlider').on('input', updateBitrateField); // input occurs every notch you slide $('#bitrateSlider').on('change', saveBitrate); // change occurs once the mouse lets go. $('#hostChosen').on('click', hostChosen); $('#forgetHost').on('click', forgetHost); $('#cancelPairingDialog').on('click', pairingPopupCanceled); $('#selectGame').on('change', gameSelectUpdated); $('#startGameButton').on('click', startSelectedGame); $('#cancelReplaceApp').on('click', cancelReplaceApp); $('#continueReplaceApp').on('click', continueReplaceApp); $('#quitGameButton').on('click', stopGame); $(window).resize(fullscreenNaclModule); chrome.app.window.current().onMaximized.addListener(fullscreenChromeWindow); } function fullscreenChromeWindow() { // when the user clicks the maximize button on the window, // FIRST restore it to the previous size, then fullscreen it to the whole screen // this prevents the previous window size from being 'maximized', // and allows us to functionally retain two window sizes // so that when the user hits `esc`, they go back to the "restored" size, // instead of "maximized", which would immediately go to fullscreen chrome.app.window.current().restore(); chrome.app.window.current().fullscreen(); } function snackbarLog(givenMessage) { console.log(givenMessage); var data = { message: givenMessage, timeout: 5000 }; document.querySelector('#snackbar').MaterialSnackbar.showSnackbar(data); } function updateBitrateField() { $('#bitrateField').html($('#bitrateSlider').val() + " Mbps"); } function moduleDidLoad() { if(!myUniqueid) { console.log("Failed to get uniqueId. Generating new one"); myUniqueid = uniqueid(); storeData('uniqueid', myUniqueid, null); } if(!pairingCert) { // we couldn't load a cert. Make one. console.log("Failed to load local cert. Generating new one"); sendMessage('makeCert', []).then(function (cert) { storeData('cert', cert, null); pairingCert = cert; console.log("Generated new cert."); }, function (failedCert) { console.log('ERROR: failed to generate new cert!'); console.log('Returned error was: ' + failedCert); }).then(function (ret) { sendMessage('httpInit', [pairingCert.cert, pairingCert.privateKey, myUniqueid]); }, function (failedInit) { console.log('ERROR: failed httpInit!'); console.log('Returned error was: ' + failedInit); }); } else { sendMessage('httpInit', [pairingCert.cert, pairingCert.privateKey, myUniqueid]).then(function (ret) { snackbarLog('Initialization complete.'); }, function (failedInit) { console.log('ERROR: failed httpInit!'); console.log('Returned error was: ' + failedInit); }); } } // because the user can change the host at any time, we continually have to check function updateHost() { host = $('#GFEHostIPField').val(); if (host == null || host == "") { host = $("#selectHost option:selected").val(); } if(api && api.address != host) { api = new NvHTTP(host, myUniqueid); } } // we want the user to progress through the streaming process // but to save from the PITA of inter-chrome-app-page JS message passing, // I'm opting to do it in a single page, and keep the data around. function hideAllWorkflowDivs() { $('#streamSettings').css('display', 'inline-block'); $('#hostSettings').css('display', 'inline-block'); $('#gameSelection').css('display', 'none'); // do NOT hide the nacl module. you can't interact with it then } // pair to the given hostname or IP. Returns whether pairing was successful. function pairTo(host) { if(!pairingCert) { snackbarLog('ERROR: cert has not been generated yet. Is NaCL initialized?'); console.log("User wants to pair, and we still have no cert. Problem = very yes."); return false; } if(!api) { api = new NvHTTP(host, myUniqueid); } if(api.paired) { return true; } $('#pairButton').html('Pairing...'); snackbarLog('Attempting pair to: ' + host); var randomNumber = String("0000" + (Math.random()*10000|0)).slice(-4); var pairingDialog = document.querySelector('#pairingDialog'); $('#pairingDialogText').html('Please enter the number ' + randomNumber + ' on the GFE dialog on the computer. This dialog will be dismissed once complete'); pairingDialog.showModal(); console.log('sending pairing request to ' + host + ' with random number ' + randomNumber); api.pair(randomNumber).then(function (paired) { if (!paired) { if (api.currentGame != 0) { snackbarLog(host + ' is already in app. Cannot pair!'); $('#pairButton').html('Pairing Failed'); $('#pairingDialogText').html('Error: ' + host + ' is in app. Cannot pair until the app is stopped.'); } else { snackbarLog('Pairing failed'); $('#pairButton').html('Pairing Failed'); $('#pairingDialogText').html('Error: failed to pair with ' + host + '. failure reason unknown.'); } return false; } $('#pairButton').html('Paired'); snackbarLog('Pairing successful'); pairingDialog.close(); var hostSelect = $('#selectHost')[0]; for(var i = 0; i < hostSelect.length; i++) { // check if we already have the host. if (hostSelect.options[i].value == host) return true; } var opt = document.createElement('option'); opt.appendChild(document.createTextNode(host)); opt.value = host; $('#selectHost').append(opt); hosts.push(host); saveHosts(); return true; }, function (failedPairing) { snackbarLog('Failed pairing to: ' + host); console.log('pairing failed, and returned ' + failedPairing); return false; }); } function hostChosen() { updateHost(); if(!api || api.address != host) { api = new NvHTTP(host, myUniqueid); } api.refreshServerInfo().then(function (ret) { if(!api.paired) { pairTo(host); } if(hosts.indexOf(host) < 0) { // we don't have this host in our list. add it, and save it. var opt = document.createElement('option'); opt.appendChild(document.createTextNode(host)); opt.value = host; $('#selectHost').append(opt); hosts.push(host); saveHosts(); $('#GFEHostIPField').val(''); // eat the contents of the textbox $('#GFEHostIPField').parent().removeClass('is-dirty'); } showApps(); }, function (failedRefreshInfo) { snackbarLog('Failed to connect to ' + host + '! Are you sure the host is on?'); console.log('Returned error was: ' + failedRefreshInfo); }); } // locally remove the hostname/ip from the saved `hosts` array. // note: this does not make the host forget the pairing to us. // this means we can re-add the host, and will still be paired. function forgetHost() { updateHost(); $("#selectHost option:selected").remove(); hosts.splice(hosts.indexOf(host), 1); // remove the host from the array; saveHosts(); } function pairingPopupCanceled() { document.querySelector('#pairingDialog').close(); } // show the app list function showApps() { if(!api || !api.paired) { // safety checking. shouldn't happen. console.log('Moved into showApps, but `api` did not initialize properly! Failing.'); return; } api.getAppList().then(function (appList) { if ($('#selectGame').has('option').length > 0 ) { // there was already things in the dropdown. Clear it, then add the new ones. // Most likely, the user just hit the 'retrieve app list' button again $('#selectGame').empty(); } appList.forEach(function (app) { $('#selectGame').append($('