mirror of
https://github.com/ianramzy/decentralized-video-chat.git
synced 2025-02-23 00:15:04 +08:00
Merge branch 'fixes' into stability
This commit is contained in:
commit
a12dd728e0
27
public/css/chat.css
vendored
27
public/css/chat.css
vendored
@ -111,7 +111,9 @@ a {
|
|||||||
|
|
||||||
#wrapper {
|
#wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
/* flex: 1 1 20em; */
|
||||||
|
/* flex-basis: 30%; */
|
||||||
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -122,8 +124,8 @@ a {
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
-ms-transform: translate(-50%, -50%);
|
-ms-transform: translate(-50%, -50%);
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
width: 65%;
|
width: 100%;
|
||||||
max-height: 100%;
|
max-height: 90vh;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +147,7 @@ a {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
#remote-video:first-child:nth-last-child(1) {
|
#remote-video:first-child:nth-last-child(1) {
|
||||||
/* -or- li:only-child { */
|
width: min(calc(80vh * 4/3), 80vw);
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +423,22 @@ button:hover {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 2rem;
|
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 {
|
#remote-video {
|
||||||
/* width: 75vw;
|
/* width: 75vw;
|
||||||
height: calc((16/9) * 75vw); */
|
height: calc((16/9) * 75vw); */
|
||||||
|
@ -37,10 +37,10 @@ var VideoChat = {
|
|||||||
socket: io(),
|
socket: io(),
|
||||||
remoteVideoWrapper: document.getElementById("wrapper"),
|
remoteVideoWrapper: document.getElementById("wrapper"),
|
||||||
localVideo: document.getElementById("local-video"),
|
localVideo: document.getElementById("local-video"),
|
||||||
|
peerColors: new Map(),
|
||||||
peerConnections: new Map(),
|
peerConnections: new Map(),
|
||||||
recognition: undefined,
|
recognition: undefined,
|
||||||
borderColor: "hsl(120,100%,70%)",
|
borderColor: undefined,
|
||||||
peerColors: new Map(),
|
|
||||||
|
|
||||||
// Call to getUserMedia (provided by adapter.js for cross browser compatibility)
|
// 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
|
// asking for access to both the video and audio streams. If the request is
|
||||||
@ -97,21 +97,18 @@ var VideoChat = {
|
|||||||
Snackbar.close();
|
Snackbar.close();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// VideoChat.borderColor = uuidToColor(VideoChat.socket.id);
|
|
||||||
VideoChat.localVideo.srcObject = stream;
|
VideoChat.localVideo.srcObject = stream;
|
||||||
VideoChat.localVideo.style.border = `3px solid ${VideoChat.borderColor}`;
|
|
||||||
|
|
||||||
// Now we're ready to join the chat room.
|
// Now we're ready to join the chat room.
|
||||||
VideoChat.socket.emit("join", roomHash);
|
VideoChat.socket.emit("join", roomHash);
|
||||||
|
VideoChat.borderColor = uuidToColor(VideoChat.socket.id);
|
||||||
|
VideoChat.localVideo.style.border = `3px solid ${VideoChat.borderColor}`;
|
||||||
|
|
||||||
// Add listeners to the websocket
|
// Add listeners to the websocket
|
||||||
VideoChat.socket.on("leave", VideoChat.onLeave);
|
VideoChat.socket.on("leave", VideoChat.onLeave);
|
||||||
VideoChat.socket.on("full", chatRoomFull);
|
VideoChat.socket.on("full", chatRoomFull);
|
||||||
VideoChat.socket.on("offer", VideoChat.onOffer);
|
VideoChat.socket.on("offer", VideoChat.onOffer);
|
||||||
VideoChat.socket.on("willInitiateCall", VideoChat.call);
|
VideoChat.socket.on("initiateCall", VideoChat.call);
|
||||||
|
|
||||||
// Set up listeners on the socket
|
|
||||||
VideoChat.socket.on("candidate", VideoChat.onCandidate);
|
VideoChat.socket.on("candidate", VideoChat.onCandidate);
|
||||||
VideoChat.socket.on("answer", VideoChat.onAnswer);
|
VideoChat.socket.on("answer", VideoChat.onAnswer);
|
||||||
VideoChat.socket.on("requestToggleCaptions", () => toggleSendCaptions());
|
VideoChat.socket.on("requestToggleCaptions", () => toggleSendCaptions());
|
||||||
@ -120,6 +117,7 @@ var VideoChat = {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Initiate a call with newly joined peer
|
||||||
call: function (uuid, room) {
|
call: function (uuid, room) {
|
||||||
logIt(`call >>> Initiating call with ${uuid}...`);
|
logIt(`call >>> Initiating call with ${uuid}...`);
|
||||||
VideoChat.socket.on(
|
VideoChat.socket.on(
|
||||||
@ -131,6 +129,7 @@ var VideoChat = {
|
|||||||
VideoChat.socket.emit("token", roomHash, uuid);
|
VideoChat.socket.emit("token", roomHash, uuid);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Handle a peer leaving the room
|
||||||
onLeave: function(uuid) {
|
onLeave: function(uuid) {
|
||||||
logIt("disconnected - UUID " + uuid);
|
logIt("disconnected - UUID " + uuid);
|
||||||
// Remove video element
|
// Remove video element
|
||||||
@ -374,6 +373,12 @@ var VideoChat = {
|
|||||||
VideoChat.connected.set(uuid, true);
|
VideoChat.connected.set(uuid, true);
|
||||||
// Hide caption status text
|
// Hide caption status text
|
||||||
captionText.fadeOut();
|
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
|
// Reposition local video after a second, as there is often a delay
|
||||||
// between adding a stream and the height of the video div changing
|
// between adding a stream and the height of the video div changing
|
||||||
setTimeout(() => rePositionLocalVideo(), 500);
|
setTimeout(() => rePositionLocalVideo(), 500);
|
||||||
@ -512,6 +517,32 @@ function sendToAllDataChannels(message) {
|
|||||||
// }
|
// }
|
||||||
// End Fullscreen
|
// 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
|
// Mute microphone
|
||||||
function muteMicrophone() {
|
function muteMicrophone() {
|
||||||
var audioTrack = null;
|
var audioTrack = null;
|
||||||
@ -843,29 +874,33 @@ function uuidToColor(uuid) {
|
|||||||
// Using uuid to generate random. unique pastel color
|
// Using uuid to generate random. unique pastel color
|
||||||
var hash = 0;
|
var hash = 0;
|
||||||
for (var i = 0; i < uuid.length; i++) {
|
for (var i = 0; i < uuid.length; i++) {
|
||||||
hash = uuid.charCodeAt(i) + ((hash << 5) - hash);
|
hash = uuid.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
hash = hash & hash;
|
hash = hash & hash;
|
||||||
}
|
}
|
||||||
var hue = Math.abs(hash % 360);
|
var hue = Math.abs(hash % 360);
|
||||||
// Ensure color is not similar to other colors
|
// Ensure color is not similar to other colors
|
||||||
var availColors = Array.from({length: 18}, (x,i) => i*20);
|
var availColors = Array.from({ length: 9 }, (x, i) => i * 40);
|
||||||
VideoChat.peerColors.forEach(function(value, key, map) {availColors[Math.floor(value/20)] = null});
|
VideoChat.peerColors.forEach(function (value, key, map) {
|
||||||
if (availColors[Math.floor(hue/20)] == null) {
|
availColors[Math.floor(value / 40)] = null;
|
||||||
|
});
|
||||||
|
if (availColors[Math.floor(hue / 40)] == null) {
|
||||||
for (var i = 0; i < availColors.length; i++) {
|
for (var i = 0; i < availColors.length; i++) {
|
||||||
if (availColors[i] != null) {
|
if (availColors[i] != null) {
|
||||||
hue = (hue % 20) + availColors[i];
|
hue = (hue % 40) + availColors[i];
|
||||||
availColors[i] = null;
|
availColors[i] = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `hsl(${hue},100%,70%)`;
|
return `hsl(${hue},100%,60%)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the border color of uuid's stream
|
// Sets the border color of uuid's stream
|
||||||
function setStreamColor(uuid) {
|
function setStreamColor(uuid) {
|
||||||
const color = uuidToColor(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;
|
VideoChat.peerColors[uuid] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -900,18 +935,27 @@ function togglePictureInPicture() {
|
|||||||
logIt("Error exiting pip.");
|
logIt("Error exiting pip.");
|
||||||
logIt(error);
|
logIt(error);
|
||||||
});
|
});
|
||||||
} else if (VideoChat.remoteVideoWrapper.lastChild.webkitPresentationMode === "inline") {
|
|
||||||
VideoChat.remoteVideoWrapper.lastChild.webkitSetPresentationMode("picture-in-picture");
|
|
||||||
} else if (
|
} 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 {
|
} else {
|
||||||
VideoChat.remoteVideoWrapper.lastChild.requestPictureInPicture().catch((error) => {
|
VideoChat.remoteVideoWrapper.lastChild
|
||||||
alert(
|
.requestPictureInPicture()
|
||||||
"You must be connected to another person to enter picture in picture."
|
.catch((error) => {
|
||||||
);
|
alert(
|
||||||
});
|
"You must be connected to another person to enter picture in picture."
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
alert(
|
alert(
|
||||||
@ -934,7 +978,6 @@ window.onbeforeunload = function () {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function startUp() {
|
function startUp() {
|
||||||
// Try and detect in-app browsers and redirect
|
// Try and detect in-app browsers and redirect
|
||||||
var ua = navigator.userAgent || navigator.vendor || window.opera;
|
var ua = navigator.userAgent || navigator.vendor || window.opera;
|
||||||
|
15
public/landing.html
vendored
15
public/landing.html
vendored
@ -67,9 +67,9 @@
|
|||||||
class="mt-0 mb-32 reveal-from-bottom"
|
class="mt-0 mb-32 reveal-from-bottom"
|
||||||
data-reveal-delay="300"
|
data-reveal-delay="300"
|
||||||
>
|
>
|
||||||
Simple, Secure, and Fast. Peer to peer group video
|
Simple, Secure, and Fast. Peer to peer group video calling
|
||||||
calling provides quality and latency simply not
|
provides quality and latency simply not available with
|
||||||
available with traditional technology.
|
traditional technology.
|
||||||
</p>
|
</p>
|
||||||
<div class="reveal-from-bottom" data-reveal-delay="450">
|
<div class="reveal-from-bottom" data-reveal-delay="450">
|
||||||
<a
|
<a
|
||||||
@ -201,9 +201,8 @@
|
|||||||
<div class="features-tiles-item-content">
|
<div class="features-tiles-item-content">
|
||||||
<h4 class="mt-0 mb-8">Decentralized group calls</h4>
|
<h4 class="mt-0 mb-8">Decentralized group calls</h4>
|
||||||
<p class="m-0 text-sm">
|
<p class="m-0 text-sm">
|
||||||
Zipcall lets you talk to up to four friends by
|
Zipcall lets you talk to up to four friends by directly
|
||||||
directly connecting to them, completely
|
connecting to them, completely decentralized.
|
||||||
decentralized.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -248,8 +247,8 @@
|
|||||||
<h4 class="mt-0 mb-8">Total Privacy and Security</h4>
|
<h4 class="mt-0 mb-8">Total Privacy and Security</h4>
|
||||||
<p class="m-0 text-sm">
|
<p class="m-0 text-sm">
|
||||||
Zipcall is built privacy first. Each chat is single use,
|
Zipcall is built privacy first. Each chat is single use,
|
||||||
and end to end state of the art encryption means your calls
|
and end to end state of the art encryption means your
|
||||||
are exactly that. Your calls.
|
calls are exactly that. Your calls.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,7 @@ var twillioAccountSID =
|
|||||||
var twilio = require("twilio")(twillioAccountSID, twillioAuthToken);
|
var twilio = require("twilio")(twillioAccountSID, twillioAuthToken);
|
||||||
var express = require("express");
|
var express = require("express");
|
||||||
var app = express();
|
var app = express();
|
||||||
|
const fs = require('fs');
|
||||||
var http = require("http").createServer(app);
|
var http = require("http").createServer(app);
|
||||||
var io = require("socket.io")(http);
|
var io = require("socket.io")(http);
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
@ -80,9 +81,9 @@ io.on("connection", function (socket) {
|
|||||||
socket.join(room);
|
socket.join(room);
|
||||||
} else if (numClients < 5) {
|
} else if (numClients < 5) {
|
||||||
socket.join(room);
|
socket.join(room);
|
||||||
// When the client is not the first to join the room, all clients are ready.
|
logIt("Broadcasting request to connect with new peer...", room);
|
||||||
logIt("Broadcasting ready message", room);
|
// Emits message to ask peers in room to connect with joining peer
|
||||||
socket.broadcast.to(room).emit("willInitiateCall", socket.id, room);
|
socket.broadcast.to(room).emit("initiateCall", socket.id, room);
|
||||||
} else {
|
} else {
|
||||||
logIt(
|
logIt(
|
||||||
"room already full with " + numClients + " people in the room.",
|
"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
|
// Listen for Heroku port, otherwise just use 3000
|
||||||
var port = process.env.PORT || 3000;
|
var port = process.env.PORT || 443;
|
||||||
http.listen(port, function () {
|
http.listen(port, function () {
|
||||||
console.log("http://localhost:" + port);
|
console.log("http://localhost:" + port);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user