diff --git a/public/css/chat.css b/public/css/chat.css index cc49ab6..efb74ab 100644 --- a/public/css/chat.css +++ b/public/css/chat.css @@ -111,7 +111,9 @@ a { #wrapper { display: flex; - flex-direction: column; + /* flex: 1 1 20em; */ + /* flex-basis: 30%; */ + flex-direction: row; align-items: center; flex-wrap: wrap; justify-content: center; @@ -122,8 +124,8 @@ a { left: 50%; -ms-transform: translate(-50%, -50%); transform: translate(-50%, -50%); - width: 65%; - max-height: 100%; + width: 100%; + max-height: 90vh; max-width: 100%; } @@ -145,7 +147,7 @@ a { padding: 10px; } #remote-video:first-child:nth-last-child(1) { -/* -or- li:only-child { */ + width: min(calc(80vh * 4/3), 80vw); max-height: 80vh; } @@ -421,7 +423,22 @@ button:hover { margin: 0; line-height: 2rem; } - + #wrapper { + display: flex; + flex-direction: row; + align-items: center; + flex-wrap: wrap; + justify-content: center; + padding: 0; + margin: 0; + position: absolute; + top: 50%; + left: 50%; + -ms-transform: translate(-50%, -50%); + transform: translate(-50%, calc(-50% - 3rem)); + max-height: 90%; + max-width: 100%; + } #remote-video { /* width: 75vw; height: calc((16/9) * 75vw); */ diff --git a/public/js/chat.js b/public/js/chat.js index fd76fa3..212cd15 100644 --- a/public/js/chat.js +++ b/public/js/chat.js @@ -37,10 +37,10 @@ var VideoChat = { socket: io(), remoteVideoWrapper: document.getElementById("wrapper"), localVideo: document.getElementById("local-video"), + peerColors: new Map(), peerConnections: new Map(), recognition: undefined, - borderColor: "hsl(120,100%,70%)", - peerColors: new Map(), + borderColor: undefined, // Call to getUserMedia (provided by adapter.js for cross browser compatibility) // asking for access to both the video and audio streams. If the request is @@ -97,21 +97,18 @@ var VideoChat = { Snackbar.close(); }, }); - - // VideoChat.borderColor = uuidToColor(VideoChat.socket.id); VideoChat.localVideo.srcObject = stream; - VideoChat.localVideo.style.border = `3px solid ${VideoChat.borderColor}`; // Now we're ready to join the chat room. VideoChat.socket.emit("join", roomHash); + VideoChat.borderColor = uuidToColor(VideoChat.socket.id); + VideoChat.localVideo.style.border = `3px solid ${VideoChat.borderColor}`; // Add listeners to the websocket VideoChat.socket.on("leave", VideoChat.onLeave); VideoChat.socket.on("full", chatRoomFull); VideoChat.socket.on("offer", VideoChat.onOffer); - VideoChat.socket.on("willInitiateCall", VideoChat.call); - - // Set up listeners on the socket + VideoChat.socket.on("initiateCall", VideoChat.call); VideoChat.socket.on("candidate", VideoChat.onCandidate); VideoChat.socket.on("answer", VideoChat.onAnswer); VideoChat.socket.on("requestToggleCaptions", () => toggleSendCaptions()); @@ -120,6 +117,7 @@ var VideoChat = { ); }, + // Initiate a call with newly joined peer call: function (uuid, room) { logIt(`call >>> Initiating call with ${uuid}...`); VideoChat.socket.on( @@ -131,6 +129,7 @@ var VideoChat = { VideoChat.socket.emit("token", roomHash, uuid); }, + // Handle a peer leaving the room onLeave: function(uuid) { logIt("disconnected - UUID " + uuid); // Remove video element @@ -374,6 +373,12 @@ var VideoChat = { VideoChat.connected.set(uuid, true); // Hide caption status text captionText.fadeOut(); + // Downscale send resolution and bitrate if num in room > 4 + // if (VideoChat.peerConnections.size > 3) { + // VideoChat.peerConnections.forEach(function (value, key, map) { + // downscaleStream(value); + // }); + // } // Reposition local video after a second, as there is often a delay // between adding a stream and the height of the video div changing setTimeout(() => rePositionLocalVideo(), 500); @@ -512,6 +517,32 @@ function sendToAllDataChannels(message) { // } // End Fullscreen +// Downscale single stream +// async function downscaleStream(pc, applying = false) { +// height = 240; +// rate = 800000; +// if (applying) return; +// try { +// applying = true; +// do { +// h = height; +// const sender = pc.getSenders().find(function (s) { +// return s.track.kind === "video"; +// }); +// const ratio = sender.track.getSettings().height / height; +// const params = sender.getParameters(); +// if (!params.encodings) params.encodings = [{}]; // Firefox workaround! +// params.encodings[0].scaleResolutionDownBy = Math.max(ratio, 1); +// params.encodings[0].maxBitrate = rate; +// await sender.setParameters(params); +// } while (h != height); +// } catch (e) { +// logIt(e); +// } finally { +// applying = false; +// } +// } + // Mute microphone function muteMicrophone() { var audioTrack = null; @@ -524,7 +555,7 @@ function muteMicrophone() { }); audioTrack.enabled = VideoChat.audioEnabled; }); - + // select mic button and mic button text const micButtonIcon = document.getElementById("mic-icon"); const micButtonText = document.getElementById("mic-text"); @@ -843,29 +874,33 @@ function uuidToColor(uuid) { // Using uuid to generate random. unique pastel color var hash = 0; for (var i = 0; i < uuid.length; i++) { - hash = uuid.charCodeAt(i) + ((hash << 5) - hash); - hash = hash & hash; + hash = uuid.charCodeAt(i) + ((hash << 5) - hash); + hash = hash & hash; } var hue = Math.abs(hash % 360); // Ensure color is not similar to other colors - var availColors = Array.from({length: 18}, (x,i) => i*20); - VideoChat.peerColors.forEach(function(value, key, map) {availColors[Math.floor(value/20)] = null}); - if (availColors[Math.floor(hue/20)] == null) { + var availColors = Array.from({ length: 9 }, (x, i) => i * 40); + VideoChat.peerColors.forEach(function (value, key, map) { + availColors[Math.floor(value / 40)] = null; + }); + if (availColors[Math.floor(hue / 40)] == null) { for (var i = 0; i < availColors.length; i++) { if (availColors[i] != null) { - hue = (hue % 20) + availColors[i]; + hue = (hue % 40) + availColors[i]; availColors[i] = null; break; } } } - return `hsl(${hue},100%,70%)`; + return `hsl(${hue},100%,60%)`; } // Sets the border color of uuid's stream function setStreamColor(uuid) { const color = uuidToColor(uuid); - document.querySelectorAll(`[uuid="${uuid}"]`)[0].style.border = `3px solid ${color}`; + document.querySelectorAll( + `[uuid="${uuid}"]` + )[0].style.border = `3px solid ${color}`; VideoChat.peerColors[uuid] = color; } @@ -900,18 +935,27 @@ function togglePictureInPicture() { logIt("Error exiting pip."); logIt(error); }); - } else if (VideoChat.remoteVideoWrapper.lastChild.webkitPresentationMode === "inline") { - VideoChat.remoteVideoWrapper.lastChild.webkitSetPresentationMode("picture-in-picture"); } else if ( - VideoChat.remoteVideoWrapper.lastChild.webkitPresentationMode === "picture-in-picture" + VideoChat.remoteVideoWrapper.lastChild.webkitPresentationMode === "inline" ) { - VideoChat.remoteVideoWrapper.lastChild.webkitSetPresentationMode("inline"); + VideoChat.remoteVideoWrapper.lastChild.webkitSetPresentationMode( + "picture-in-picture" + ); + } else if ( + VideoChat.remoteVideoWrapper.lastChild.webkitPresentationMode === + "picture-in-picture" + ) { + VideoChat.remoteVideoWrapper.lastChild.webkitSetPresentationMode( + "inline" + ); } else { - VideoChat.remoteVideoWrapper.lastChild.requestPictureInPicture().catch((error) => { - alert( - "You must be connected to another person to enter picture in picture." - ); - }); + VideoChat.remoteVideoWrapper.lastChild + .requestPictureInPicture() + .catch((error) => { + alert( + "You must be connected to another person to enter picture in picture." + ); + }); } } else { alert( @@ -934,7 +978,6 @@ window.onbeforeunload = function () { return null; }; - function startUp() { // Try and detect in-app browsers and redirect var ua = navigator.userAgent || navigator.vendor || window.opera; diff --git a/public/landing.html b/public/landing.html index 7e1b62d..693a094 100755 --- a/public/landing.html +++ b/public/landing.html @@ -67,9 +67,9 @@ class="mt-0 mb-32 reveal-from-bottom" data-reveal-delay="300" > - Simple, Secure, and Fast. Peer to peer group video - calling provides quality and latency simply not - available with traditional technology. + Simple, Secure, and Fast. Peer to peer group video calling + provides quality and latency simply not available with + traditional technology.
@@ -248,8 +247,8 @@Zipcall is built privacy first. Each chat is single use, - and end to end state of the art encryption means your calls - are exactly that. Your calls. + and end to end state of the art encryption means your + calls are exactly that. Your calls.
diff --git a/server.js b/server.js index 054953b..84c4d00 100644 --- a/server.js +++ b/server.js @@ -8,6 +8,7 @@ var twillioAccountSID = var twilio = require("twilio")(twillioAccountSID, twillioAuthToken); var express = require("express"); var app = express(); +const fs = require('fs'); var http = require("http").createServer(app); var io = require("socket.io")(http); var path = require("path"); @@ -80,9 +81,9 @@ io.on("connection", function (socket) { socket.join(room); } else if (numClients < 5) { socket.join(room); - // When the client is not the first to join the room, all clients are ready. - logIt("Broadcasting ready message", room); - socket.broadcast.to(room).emit("willInitiateCall", socket.id, room); + logIt("Broadcasting request to connect with new peer...", room); + // Emits message to ask peers in room to connect with joining peer + socket.broadcast.to(room).emit("initiateCall", socket.id, room); } else { logIt( "room already full with " + numClients + " people in the room.", @@ -137,7 +138,7 @@ io.on("connection", function (socket) { }); // Listen for Heroku port, otherwise just use 3000 -var port = process.env.PORT || 3000; +var port = process.env.PORT || 443; http.listen(port, function () { console.log("http://localhost:" + port); });