From 9ebe7067c5053bd12832484222b01fcd01ea75f9 Mon Sep 17 00:00:00 2001 From: milad Date: Wed, 13 Nov 2019 13:08:34 -0800 Subject: [PATCH] fixed the ordering of selects --- screenshare/package.json | 2 +- screenshare/src/app.js | 247 --------------- .../src/{index.html => screenshareApp.html} | 14 +- screenshare/src/screenshareApp.js | 297 ++++++++++++++++++ .../{main.js => screenshareMainProcess.js} | 12 +- 5 files changed, 321 insertions(+), 251 deletions(-) delete mode 100644 screenshare/src/app.js rename screenshare/src/{index.html => screenshareApp.html} (87%) create mode 100644 screenshare/src/screenshareApp.js rename screenshare/src/{main.js => screenshareMainProcess.js} (84%) diff --git a/screenshare/package.json b/screenshare/package.json index 8418f8cec6..372679082f 100644 --- a/screenshare/package.json +++ b/screenshare/package.json @@ -2,7 +2,7 @@ "name": "highfidelity_screenshare", "version": "1.0.0", "description": "High Fidelity Screenshare", - "main": "src/main.js", + "main": "src/screenshareMainProcess.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "packager": "node packager.js" diff --git a/screenshare/src/app.js b/screenshare/src/app.js deleted file mode 100644 index a79e89bbbb..0000000000 --- a/screenshare/src/app.js +++ /dev/null @@ -1,247 +0,0 @@ -// Helpers - function handleError(error) { - if (error) { - console.error(error); - } - } - -/* SOURCE EXAMPLE - [23584:1028/110448.237:INFO:CONSOLE(67)] "{ - "id": "screen:0:0", - "name": "Screen 1", - "thumbnail": {}, - "display_id": "2528732444", - "appIcon": null - }" -*/ - -const imageWidth = 265; -const imageHeight = 165; - -var images = 10; -var testImage = "resources/test.jpg"; -function MakeSource(name, thumbnail, id, newWidth, newHeight){ - this.name = name; - this.thumbnail = thumbnail; - this.id = id; - this.width = newWidth; - this.height = newHeight; -} - -let testSources = []; - -for (let index = 0; index < images; index++) { - let test = new MakeSource("REALLY LONG LONG title" + index, testImage, index, imageWidth, imageHeight); - testSources.push(test); -} - -const electron = require('electron'); - -let currentScreensharePickID = ""; -function screensharePicked(id){ - currentScreensharePickID = id; - document.getElementById("share_pick").innerHTML = ""; - addSource(sourceMap[id], "share_pick"); - togglePage(); -} - - - -function screenConfirmed(isConfirmed){ - if (isConfirmed === true){ - onAccessApproved(currentScreensharePickID); - } - togglePage(); -} - - -let currentPage = "mainPage"; -function togglePage(){ - if (currentPage === "mainPage") { - currentPage = "confirmationPage"; - document.getElementById("select_screen").style.display = "none"; - document.getElementById("subtitle").innerHTML = "Confirm that you'd like to share this content."; - document.getElementById("confirmation_screen").style.display = "block"; - } else { - currentPage = "mainPage"; - document.getElementById("select_screen").style.display = "block"; - document.getElementById("subtitle").innerHTML = "Please select the content you'd like to share."; - document.getElementById("confirmation_screen").style.display = "none"; - } -} - -// UI - function addSource(source, type) { - let sourceBody = document.createElement('div') - let thumbnail = source.thumbnail.toDataURL(); - sourceBody.classList.add("box") - if (type === "share_pick") { - sourceBody.style.marginLeft = "0px"; - } - - let image = ""; - if (source.appIcon) { - image = ``; - } - sourceBody.innerHTML = ` -
- ${image} - ${source.name} -
-
- -
- ` - if (type === "selects") { - document.getElementById("selects").appendChild(sourceBody); - } else { - document.getElementById("share_pick").appendChild(sourceBody); - document.getElementById("content_name").innerHTML = source.name; - } - } - - - let sourceMap = {}; - function showSources() { - document.getElementById("selects").innerHTML=""; - electron.desktopCapturer.getSources({ - types:['window', 'screen'], - thumbnailSize: { - width: imageWidth, - height: imageHeight - }, - fetchWindowIcons: true - }, (error, sources) => { - if (error) { - console.log("Error getting sources", error); - } - - // MN TODO: - // Add all sources to array, sort array by type, then call `addSource()` - // for all of those sources. - - for (let source of sources) { - sourceMap[source.id] = source; - addSource(source, "selects"); - } - }); - } - - - let localStream; - function stopSharing(){ - desktopSharing = false; - - if (localStream) { - localStream.getTracks()[0].stop(); - localStream = null; - } - - document.getElementById('screenshare').style.display = "none"; - stopTokBoxPublisher(); - } - - function gotStream(stream) { - localStream = stream; - startTokboxPublisher(localStream); - - stream.onended = () => { - if (desktopSharing) { - toggle(); - } - }; - } - - - function onAccessApproved(desktop_id) { - if (!desktop_id) { - console.log('Desktop Capture access rejected.'); - return; - } - showSources(); - document.getElementById('screenshare').style.visibility = "block"; - desktopSharing = true; - navigator.webkitGetUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: desktop_id, - minWidth: 1280, - maxWidth: 1280, - minHeight: 720, - maxHeight: 720 - } - } - }, gotStream, handleError); - } - -// Tokbox - - function initializeTokboxSession() { - session = OT.initSession(projectAPIKey, sessionID); - session.on('sessionDisconnected', (event) => { - console.log('You were disconnected from the session.', event.reason); - }); - - // Connect to the session - session.connect(token, (error) => { - if (error) { - handleError(error); - } - }); - } - - - var publisher; - function startTokboxPublisher(stream){ - publisher = document.createElement("div"); - var publisherOptions = { - videoSource: stream.getVideoTracks()[0], - audioSource: null, - insertMode: 'append', - width: 1280, - height: 720 - }; - - publisher = OT.initPublisher(publisher, publisherOptions, function(error){ - if (error) { - console.log("ERROR: " + error); - } else { - session.publish(publisher, function(error) { - if (error) { - console.log("ERROR FROM Session.publish: " + error); - return; - } - console.log("MADE IT TO PUBLISH") - }) - } - }); - } - - - function stopTokBoxPublisher(){ - publisher.destroy(); - } - - -// main TODO: - const ipcRenderer = electron.ipcRenderer; - let projectAPIKey; - let sessionID; - let token; - let session; - - ipcRenderer.on('connectionInfo', function(event, message){ - const connectionInfo = JSON.parse(message); - projectAPIKey = connectionInfo.projectAPIKey; - sessionID = connectionInfo.sessionID; - token = connectionInfo.token; - - initializeTokboxSession(); - }) - - - document.addEventListener("DOMContentLoaded", () => { - showSources(); - }) diff --git a/screenshare/src/index.html b/screenshare/src/screenshareApp.html similarity index 87% rename from screenshare/src/index.html rename to screenshare/src/screenshareApp.html index 5d3441ea76..ed722f7fde 100644 --- a/screenshare/src/index.html +++ b/screenshare/src/screenshareApp.html @@ -1,3 +1,15 @@ + + @@ -49,7 +61,7 @@ - + diff --git a/screenshare/src/screenshareApp.js b/screenshare/src/screenshareApp.js new file mode 100644 index 0000000000..db38054e1b --- /dev/null +++ b/screenshare/src/screenshareApp.js @@ -0,0 +1,297 @@ +// +// screenshareApp.js +// +// Created by Milad Nazeri, Rebecca Stankus, and Zach Fox 2019/11/13 +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +// Helpers +function handleError(error) { + if (error) { + console.error(error); + } +} + + +// When an application is picked, make sure we clear out the previous pick, toggle the page, +// and add the correct source +let currentScreensharePickID = ""; +function screensharePicked(id){ + currentScreensharePickID = id; + document.getElementById("share_pick").innerHTML = ""; + togglePage(); + addSource(sourceMap[id], "share_pick"); +} + + +// Once we have confirmed that we want to share, prepare the tokbox publishing initiating +// and toggle back to the selects page +function screenConfirmed(isConfirmed){ + document.getElementById("selects").innerHTML=""; + if (isConfirmed === true){ + onAccessApproved(currentScreensharePickID); + } + togglePage(); +} + + +// Hide/show the select page or the confirmation page +let currentPage = "mainPage"; +function togglePage(){ + if (currentPage === "mainPage") { + currentPage = "confirmationPage"; + document.getElementById("select_screen").style.display = "none"; + document.getElementById("subtitle").innerHTML = "Confirm that you'd like to share this content."; + document.getElementById("confirmation_screen").style.display = "block"; + } else { + showSources(); + currentPage = "mainPage"; + document.getElementById("select_screen").style.display = "block"; + document.getElementById("subtitle").innerHTML = "Please select the content you'd like to share."; + document.getElementById("confirmation_screen").style.display = "none"; + } +} + + +// UI + +// Render the html properly and append that to the correct parent +function addSource(source, type) { + let renderedHTML = renderSourceHTML(source); + if (type === "selects") { + document.getElementById("selects").appendChild(renderedHTML); + } else { + document.getElementById("share_pick").appendChild(renderedHTML); + document.getElementById("content_name").innerHTML = source.name; + } +} + + +// Get the html created from the source. Alter slightly depending on whether this source +// is on the selects screen, or the confirmation screen. Mainly removing highlighting. +// If there is an app Icon, then add it. +function renderSourceHTML(source){ + let type = currentPage === "confirmationPage" ? "share_pick" : "selects"; + let sourceBody = document.createElement('div') + let thumbnail = source.thumbnail.toDataURL(); + sourceBody.classList.add("box") + if (type === "share_pick") { + sourceBody.style.marginLeft = "0px"; + } + + let image = ""; + if (source.appIcon) { + image = ``; + } + sourceBody.innerHTML = ` +
+ ${image} + ${source.name} +
+
+ +
+ ` + return sourceBody; +} + + +// Separate out the screenshares and applications +// Make sure the screens are labeled in order +// Concact the two arrays back together and return +function sortSources(){ + let screenSources = []; + let applicationSources = []; + // Difference with Mac selects: + // 1 screen = "Enitre Screen", more than one like PC "Screen 1, Screen 2..." + screenshareSourceArray.forEach((source) => { + if (source.name.match(/(entire )?screen( )?([0-9]?)/i)) { + screenSources.push(source); + } else { + applicationSources.push(source) + } + }) + screenSources.sort( (a, b) => { + let aNumber = a.name.replace(/[^\d]/, ""); + let bNumber = b.name.replace(/[^\d]/, ""); + return aNumber - bNumber; + }) + let finalSources = [...screenSources, ...applicationSources]; + return finalSources; +} + + +// Setup sorting the selection array, add individual sources, and update the sourceMap +function addSources(){ + screenshareSourceArray = sortSources(); + for (let i = 0; i < screenshareSourceArray.length; i++) { + addSource(screenshareSourceArray[i], "selects"); + sourceMap[screenshareSourceArray[i].id] = screenshareSourceArray[i]; + } +} + + +// 1. Get the screens and window that are available from electron +// 2. Remove the screenshare app itself +// 3. Create a source map to help grab the correct source when picked +// 4. push all the sources for sorting to the source array +// 5. Add thse sources +const electron = require('electron'); +const SCREENSHARE_TITLE = "Screen share"; +const IMAGE_WIDTH = 265; +const IMAGE_HEIGHT = 165; +let screenshareSourceArray = []; +let sourceMap = {}; +function showSources() { + screenshareSourceArray = []; + electron.desktopCapturer.getSources({ + types:['window', 'screen'], + thumbnailSize: { + width: IMAGE_WIDTH, + height: IMAGE_HEIGHT + }, + fetchWindowIcons: true + }, (error, sources) => { + if (error) { + console.log("Error getting sources", error); + } + for (let source of sources) { + if (source.name.indexOf(SCREENSHARE_TITLE) > -1){ + continue; + } + sourceMap[source.id] = source; + screenshareSourceArray.push(source); + } + addSources(); + }); +} + + +// Stop the localstream and end the tokrok publishing +let localStream; +function stopSharing(){ + desktopSharing = false; + + if (localStream) { + localStream.getTracks()[0].stop(); + localStream = null; + } + + document.getElementById('screenshare').style.display = "none"; + stopTokBoxPublisher(); +} + + +// Callback to start publishing after we have setup the chromium stream +function gotStream(stream) { + localStream = stream; + startTokboxPublisher(localStream); + + stream.onended = () => { + if (desktopSharing) { + toggle(); + } + }; +} + + +// After we grant access to electron, create a stream and using the callback +// start the tokbox publisher +function onAccessApproved(desktop_id) { + if (!desktop_id) { + console.log('Desktop Capture access rejected.'); + return; + } + document.getElementById('screenshare').style.visibility = "block"; + desktopSharing = true; + navigator.webkitGetUserMedia({ + audio: false, + video: { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: desktop_id, + minWidth: 1280, + maxWidth: 1280, + minHeight: 720, + maxHeight: 720 + } + } + }, gotStream, handleError); +} + + +// Tokbox + +// Once we have the connection info, this will create the session which will allow +// us to publish a stream when we are ready +function initializeTokboxSession() { + session = OT.initSession(projectAPIKey, sessionID); + session.on('sessionDisconnected', (event) => { + console.log('You were disconnected from the session.', event.reason); + }); + + // Connect to the session + session.connect(token, (error) => { + if (error) { + handleError(error); + } + }); +} + + +// Init the tokbox publisher with our newly created stream +var publisher; +function startTokboxPublisher(stream){ + publisher = document.createElement("div"); + var publisherOptions = { + videoSource: stream.getVideoTracks()[0], + audioSource: null, + insertMode: 'append', + width: 1280, + height: 720 + }; + + publisher = OT.initPublisher(publisher, publisherOptions, function(error){ + if (error) { + console.log("ERROR: " + error); + } else { + session.publish(publisher, function(error) { + if (error) { + console.log("ERROR FROM Session.publish: " + error); + return; + } + }) + } + }); +} + + +// Kills the streaming being sent to tokbox +function stopTokBoxPublisher(){ + publisher.destroy(); +} + + +// When the app is ready, we get this info from the command line arguments. +const ipcRenderer = electron.ipcRenderer; +let projectAPIKey; +let sessionID; +let token; +let session; +ipcRenderer.on('connectionInfo', function(event, message){ + const connectionInfo = JSON.parse(message); + projectAPIKey = connectionInfo.projectAPIKey; + sessionID = connectionInfo.sessionID; + token = connectionInfo.token; + + initializeTokboxSession(); +}) + + +// Show the initial sources after the dom has loaded +// Sources come from electron.desktopCapturer +document.addEventListener("DOMContentLoaded", () => { + showSources(); +}) diff --git a/screenshare/src/main.js b/screenshare/src/screenshareMainProcess.js similarity index 84% rename from screenshare/src/main.js rename to screenshare/src/screenshareMainProcess.js index a9c52ad8e8..989b0d79ef 100644 --- a/screenshare/src/main.js +++ b/screenshare/src/screenshareMainProcess.js @@ -1,4 +1,12 @@ 'use strict'; +// +// screenshareMainProcess.js +// +// Created by Milad Nazeri, and Zach Fox 2019/11/13 +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html const {app, BrowserWindow, ipcMain} = require('electron'); const gotTheLock = app.requestSingleInstanceLock() @@ -53,15 +61,15 @@ function createWindow(){ // as the screenshare executable during a post-build step //icon: "hifi-screenshare-icon.png" }); - window.loadURL('file://' + __dirname + '/index.html'); + window.loadURL('file://' + __dirname + '/screenshareApp.html'); window.setMenu(null); window.webContents.on("did-finish-load", () => { window.webContents.send('connectionInfo', JSON.stringify(connectionInfo)); }); - } + // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.on('ready', function() {