mirror of
https://github.com/ianramzy/decentralized-video-chat.git
synced 2024-11-13 13:49:19 +08:00
Merge branch 'master' into disconnect_handling
This commit is contained in:
commit
dd26284e13
2
README.md
vendored
2
README.md
vendored
@ -20,12 +20,14 @@ technology.
|
||||
<img align="right" width="400" height="auto" src="public/images/preview.gif">
|
||||
|
||||
- Screen sharing
|
||||
- Group call with up to 4 peers
|
||||
- Picture in picture
|
||||
- Live captions
|
||||
- Text chat
|
||||
- Auto-scaling video quality
|
||||
- No download required, entirely browser based
|
||||
- Direct peer to peer connection ensures lowest latency
|
||||
- No SFU servers, group calls use mesh networks
|
||||
- Single use disposable chat rooms
|
||||
|
||||
## Quick start
|
||||
|
3
public/chat.html
vendored
3
public/chat.html
vendored
@ -46,8 +46,7 @@
|
||||
</div>
|
||||
|
||||
<p id="remote-video-text"></p>
|
||||
<div id="wrapper">
|
||||
</div>
|
||||
<div id="wrapper"></div>
|
||||
<div id="moveable">
|
||||
<p id="local-video-text">No webcam input</p>
|
||||
<video id="local-video" autoplay muted playsinline></video>
|
||||
|
33
public/css/chat.css
vendored
33
public/css/chat.css
vendored
@ -110,8 +110,10 @@ a {
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
display: grid;
|
||||
grid-gap: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@ -142,12 +144,33 @@ a {
|
||||
border-radius: 0 0 10px 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
#remote-video:first-child:nth-last-child(1) {
|
||||
/* -or- li:only-child { */
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
/* two items */
|
||||
#remote-video:first-child:nth-last-child(2),
|
||||
#remote-video:first-child:nth-last-child(2) ~ #remote-video {
|
||||
max-height: 40vh;
|
||||
}
|
||||
|
||||
/* three items */
|
||||
#remote-video:first-child:nth-last-child(3),
|
||||
#remote-video:first-child:nth-last-child(3) ~ #remote-video {
|
||||
max-height: 40vh;
|
||||
}
|
||||
|
||||
/* four items */
|
||||
#remote-video:first-child:nth-last-child(4),
|
||||
#remote-video:first-child:nth-last-child(4) ~ #remote-video {
|
||||
max-height: 40vh;
|
||||
}
|
||||
|
||||
#remote-video {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin: 10px;
|
||||
width: auto;
|
||||
border-radius: 10px;
|
||||
background-image: url(../images/loader.gif);
|
||||
background-size: 400px auto;
|
||||
|
@ -26,13 +26,13 @@ const captionButtontext = $("#caption-button-text");
|
||||
const entireChat = $("#entire-chat");
|
||||
const chatZone = $("#chat-zone");
|
||||
|
||||
// Need a Map to keep track of dataChannel connecting with each peer
|
||||
var dataChannel = new Map();
|
||||
|
||||
|
||||
var VideoChat = {
|
||||
nickname: undefined,
|
||||
videoEnabled: true,
|
||||
audioEnabled: true,
|
||||
videoEnabled: true,
|
||||
audioEnabled: true,
|
||||
connected: new Map(),
|
||||
localICECandidates: {},
|
||||
socket: io(),
|
||||
@ -40,7 +40,6 @@ var VideoChat = {
|
||||
localVideo: document.getElementById("local-video"),
|
||||
peerConnections: new Map(),
|
||||
recognition: undefined,
|
||||
answerCreatedUUIDs: [], // HACKY workaround: currently, onAnswer seems to be triggering twice and we don't know why
|
||||
|
||||
// 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
|
||||
@ -98,22 +97,26 @@ var VideoChat = {
|
||||
},
|
||||
});
|
||||
|
||||
// Used to identify client to other peers in chats, captions etc.
|
||||
VideoChat.nickname = prompt("Please enter a nickname", "");
|
||||
|
||||
while (VideoChat.nickname == null || VideoChat.nickname.trim() === "") {
|
||||
VideoChat.nickname = prompt("Nickname cannot be empty. Please enter a nickname", "");
|
||||
VideoChat.nickname = prompt(
|
||||
"Nickname cannot be empty. Please enter a nickname",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
VideoChat.localVideo.srcObject = stream;
|
||||
|
||||
// Now we're ready to join the chat room.
|
||||
VideoChat.socket.emit("join", roomHash);
|
||||
// Receive its own uuid
|
||||
VideoChat.socket.on("uuid", (uuid) => (VideoChat.uuid = uuid));
|
||||
|
||||
// Add listeners to the websocket
|
||||
VideoChat.socket.on("full", chatRoomFull);
|
||||
VideoChat.socket.on("offer", VideoChat.onOffer);
|
||||
VideoChat.socket.on("ready", VideoChat.readyToCall);
|
||||
VideoChat.socket.on("willInitiateCall", VideoChat.call);
|
||||
|
||||
// Set up listeners on the socket
|
||||
VideoChat.socket.on("candidate", VideoChat.onCandidate);
|
||||
VideoChat.socket.on("answer", VideoChat.onAnswer);
|
||||
@ -123,47 +126,50 @@ var VideoChat = {
|
||||
);
|
||||
},
|
||||
|
||||
// When we are ready to call, enable the Call button.
|
||||
readyToCall: function (event) {
|
||||
logIt("readyToCall");
|
||||
},
|
||||
call: function (uuid, room) {
|
||||
logIt("Initiating call");
|
||||
VideoChat.startCall(uuid);
|
||||
},
|
||||
|
||||
// Set up a callback to run when we have the ephemeral token to use Twilio's TURN server.
|
||||
startCall: function (uuid) {
|
||||
VideoChat.socket.on("token", VideoChat.establishConnection(uuid, function(a) {VideoChat.createOffer(a);}));
|
||||
logIt(`call >>> Initiating call with ${uuid}...`);
|
||||
VideoChat.socket.on(
|
||||
"token",
|
||||
VideoChat.establishConnection(uuid, function (a) {
|
||||
VideoChat.createOffer(a);
|
||||
})
|
||||
);
|
||||
VideoChat.socket.emit("token", roomHash, uuid);
|
||||
},
|
||||
|
||||
establishConnection: function (correctUuid, callback) {
|
||||
return function(token, uuid) {
|
||||
return function (token, uuid) {
|
||||
if (correctUuid != uuid) {
|
||||
return;
|
||||
}
|
||||
console.log("establishing connection to", uuid);
|
||||
|
||||
|
||||
VideoChat.localICECandidates[uuid] = []; // initialise uuid with empty array
|
||||
logIt(`<<< Received token, connecting to ${uuid}`);
|
||||
// Initialise localICEcandidates for peer uuid to empty array
|
||||
VideoChat.localICECandidates[uuid] = [];
|
||||
// Initialise connection status with peer uuid to false
|
||||
VideoChat.connected.set(uuid, false);
|
||||
|
||||
// Set up a new RTCPeerConnection using the token's iceServers.
|
||||
VideoChat.peerConnections.set(uuid, new RTCPeerConnection({
|
||||
iceServers: token.iceServers,
|
||||
}))
|
||||
VideoChat.peerConnections.set(
|
||||
uuid,
|
||||
new RTCPeerConnection({
|
||||
iceServers: token.iceServers,
|
||||
})
|
||||
);
|
||||
// Add the local video stream to the peerConnection.
|
||||
VideoChat.localStream.getTracks().forEach(function (track) {
|
||||
VideoChat.peerConnections.get(uuid).addTrack(track, VideoChat.localStream);
|
||||
VideoChat.peerConnections
|
||||
.get(uuid)
|
||||
.addTrack(track, VideoChat.localStream);
|
||||
});
|
||||
// Add general purpose data channel to peer connection,
|
||||
// used for text chats, captions, and toggling sending captions
|
||||
dataChannel.set(uuid, VideoChat.peerConnections.get(uuid).createDataChannel("chat", {
|
||||
negotiated: true,
|
||||
// both peers must have same id
|
||||
id: 0,
|
||||
}));
|
||||
dataChannel.set(
|
||||
uuid,
|
||||
VideoChat.peerConnections.get(uuid).createDataChannel("chat", {
|
||||
negotiated: true,
|
||||
// both peers must have same id
|
||||
id: 0,
|
||||
})
|
||||
);
|
||||
// Called when dataChannel is successfully opened
|
||||
dataChannel.get(uuid).onopen = function (event) {
|
||||
logIt("dataChannel opened");
|
||||
@ -182,21 +188,22 @@ var VideoChat = {
|
||||
toggleSendCaptions();
|
||||
}
|
||||
};
|
||||
|
||||
// Set up callbacks for the connection generating iceCandidates or
|
||||
// receiving the remote media stream.
|
||||
VideoChat.peerConnections.get(uuid).onicecandidate = function(u) {VideoChat.onIceCandidate(u, uuid)};
|
||||
VideoChat.peerConnections.get(uuid).onaddstream = function(u) {VideoChat.onAddStream(u, uuid)};
|
||||
|
||||
|
||||
// receiving the remote media stream. Wrapping callback functions
|
||||
// to pass in the peer uuids.
|
||||
VideoChat.peerConnections.get(uuid).onicecandidate = function (event) {
|
||||
VideoChat.onIceCandidate(event, uuid);
|
||||
};
|
||||
VideoChat.peerConnections.get(uuid).onaddstream = function (event) {
|
||||
VideoChat.onAddStream(event, uuid);
|
||||
};
|
||||
// Called when there is a change in connection state
|
||||
VideoChat.peerConnections.get(uuid).oniceconnectionstatechange = function (event) {
|
||||
VideoChat.peerConnections.get(
|
||||
uuid
|
||||
).oniceconnectionstatechange = function (event) {
|
||||
switch (VideoChat.peerConnections.get(uuid).iceConnectionState) {
|
||||
case "connected":
|
||||
logIt("connected");
|
||||
// Once connected we no longer have a need for the signaling server, so disconnect
|
||||
// VideoChat.socket.off("token");
|
||||
// VideoChat.socket.off("offer");
|
||||
break;
|
||||
case "disconnected":
|
||||
logIt("disconnected - UUID " + uuid);
|
||||
@ -222,7 +229,7 @@ var VideoChat = {
|
||||
}
|
||||
};
|
||||
callback(uuid);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// When the peerConnection generates an ice candidate, send it over the socket to the peer.
|
||||
@ -230,7 +237,7 @@ var VideoChat = {
|
||||
logIt("onIceCandidate");
|
||||
if (event.candidate) {
|
||||
logIt(
|
||||
`<<< Received local ICE candidate from STUN/TURN server (${event.candidate.address}) associated with UUID (${uuid})`
|
||||
`<<< Received local ICE candidate from STUN/TURN server (${event.candidate.address}) for connection with ${uuid}`
|
||||
);
|
||||
if (VideoChat.connected.get(uuid)) {
|
||||
logIt(`>>> Sending local ICE candidate (${event.candidate.address})`);
|
||||
@ -246,7 +253,6 @@ var VideoChat = {
|
||||
// The peer may not have created the RTCPeerConnection yet, so we are waiting for the 'answer'
|
||||
// to arrive. This will signal that the peer is ready to receive signaling.
|
||||
VideoChat.localICECandidates[uuid].push(event.candidate);
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -265,7 +271,7 @@ var VideoChat = {
|
||||
|
||||
// Create an offer that contains the media capabilities of the browser.
|
||||
createOffer: function (uuid) {
|
||||
console.log(">>> Creating offer to UUID: ", uuid, ". my UUID is", VideoChat.socket.id);
|
||||
logIt(`createOffer to ${uuid} >>> Creating offer...`);
|
||||
VideoChat.peerConnections.get(uuid).createOffer(
|
||||
function (offer) {
|
||||
// If the offer is created successfully, set it as the local description
|
||||
@ -281,7 +287,7 @@ var VideoChat = {
|
||||
);
|
||||
},
|
||||
|
||||
// Create an answer with the media capabilities that both browsers share.
|
||||
// Create an answer with the media capabilities that the client and peer browsers share.
|
||||
// This function is called with the offer from the originating browser, which
|
||||
// needs to be parsed into an RTCSessionDescription and added as the remote
|
||||
// description to the peerConnection object. Then the answer is created in the
|
||||
@ -289,12 +295,11 @@ var VideoChat = {
|
||||
createAnswer: function (offer, uuid) {
|
||||
logIt("createAnswer");
|
||||
rtcOffer = new RTCSessionDescription(JSON.parse(offer));
|
||||
console.log("createAnswer: setting remote description of " + uuid + " on " + VideoChat.socket.id);
|
||||
logIt(`>>> Creating answer to ${uuid}`);
|
||||
VideoChat.peerConnections.get(uuid).setRemoteDescription(rtcOffer);
|
||||
VideoChat.peerConnections.get(uuid).createAnswer(
|
||||
function (answer) {
|
||||
VideoChat.peerConnections.get(uuid).setLocalDescription(answer);
|
||||
console.log(">>> Creating answer to UUID: ", uuid, ". my UUID is", VideoChat.socket.id);
|
||||
VideoChat.socket.emit("answer", JSON.stringify(answer), roomHash, uuid);
|
||||
},
|
||||
function (err) {
|
||||
@ -308,33 +313,39 @@ var VideoChat = {
|
||||
// ephemeral token is returned from Twilio.
|
||||
onOffer: function (offer, uuid) {
|
||||
logIt("onOffer <<< Received offer");
|
||||
// VideoChat.socket.on("token", VideoChat.establishConnection(uuid, function(a) {VideoChat.createOffer(a);}));
|
||||
VideoChat.socket.on("token", VideoChat.establishConnection(uuid, function(a) {VideoChat.createAnswer(offer, a);}));
|
||||
VideoChat.socket.on(
|
||||
"token",
|
||||
VideoChat.establishConnection(uuid, function (a) {
|
||||
VideoChat.createAnswer(offer, a);
|
||||
})
|
||||
);
|
||||
VideoChat.socket.emit("token", roomHash, uuid);
|
||||
},
|
||||
|
||||
// When an answer is received, add it to the peerConnection as the remote description.
|
||||
onAnswer: function (answer, uuid) {
|
||||
console.log("onAnswer <<< Received answer", uuid, ". my UUID is", VideoChat.socket.id);
|
||||
|
||||
// if (!VideoChat.answerCreatedUUIDs.includes(uuid)) {
|
||||
VideoChat.answerCreatedUUIDs.push(uuid);
|
||||
// logIt("onAnswer <<< Received answer" + "");
|
||||
var rtcAnswer = new RTCSessionDescription(JSON.parse(answer));
|
||||
// Set remote description of RTCSession
|
||||
console.log("onAnswer: setting remote description of " + uuid + " on " + VideoChat.socket.id);
|
||||
VideoChat.peerConnections.get(uuid).setRemoteDescription(rtcAnswer);
|
||||
// The caller now knows that the callee is ready to accept new ICE candidates, so sending the buffer over
|
||||
VideoChat.localICECandidates[uuid].forEach((candidate) => {
|
||||
logIt(`>>> Sending local ICE candidate (${candidate.address})`);
|
||||
// Send ice candidate over websocket
|
||||
VideoChat.socket.emit("candidate", JSON.stringify(candidate), roomHash, uuid);
|
||||
});
|
||||
logIt(`onAnswer <<< Received answer from ${uuid}`);
|
||||
var rtcAnswer = new RTCSessionDescription(JSON.parse(answer));
|
||||
// Set remote description of RTCSession
|
||||
VideoChat.peerConnections.get(uuid).setRemoteDescription(rtcAnswer);
|
||||
// The caller now knows that the callee is ready to accept new ICE candidates, so sending the buffer over
|
||||
VideoChat.localICECandidates[uuid].forEach((candidate) => {
|
||||
logIt(`>>> Sending local ICE candidate (${candidate.address})`);
|
||||
// Send ice candidate over websocket
|
||||
VideoChat.socket.emit(
|
||||
"candidate",
|
||||
JSON.stringify(candidate),
|
||||
roomHash,
|
||||
uuid
|
||||
);
|
||||
});
|
||||
// Reset the buffer of local ICE candidates. This is not really needed, but it's good practice
|
||||
// VideoChat.localICECandidates[uuid] = []; // TESTING
|
||||
},
|
||||
|
||||
// Called when a stream is added to the peer connection
|
||||
onAddStream: function (event, uuid) {
|
||||
logIt("onAddStream <<< Received new stream from remote. Adding it..." + event);
|
||||
logIt("onAddStream <<< Received new stream from remote. Adding it...");
|
||||
// Create new remote video source in wrapper
|
||||
// Create a <video> node
|
||||
var node = document.createElement("video");
|
||||
@ -356,14 +367,6 @@ var VideoChat = {
|
||||
// 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);
|
||||
// var timesRun = 0;
|
||||
// var interval = setInterval(function () {
|
||||
// timesRun += 1;
|
||||
// if (timesRun === 10) {
|
||||
// clearInterval(interval);
|
||||
// }
|
||||
// rePositionLocalVideo();
|
||||
// }, 300);
|
||||
},
|
||||
};
|
||||
|
||||
@ -422,7 +425,7 @@ function rePositionCaptions() {
|
||||
// Get remote video position
|
||||
var bounds = remoteVideosWrapper.position();
|
||||
bounds.top -= 10;
|
||||
bounds.top = bounds.top + remoteVideosWrapper.height() - 1 * captionText.height();
|
||||
bounds.top += remoteVideosWrapper.height() - 1 * captionText.height();
|
||||
// Reposition captions
|
||||
captionText.css(bounds);
|
||||
}
|
||||
@ -438,7 +441,7 @@ function isConnected() {
|
||||
var connected = false;
|
||||
|
||||
// No way to 'break' forEach -> we go through all anyway
|
||||
VideoChat.connected.forEach(function(value, key, map) {
|
||||
VideoChat.connected.forEach(function (value, key, map) {
|
||||
if (value) {
|
||||
connected = true;
|
||||
}
|
||||
@ -449,7 +452,7 @@ function isConnected() {
|
||||
|
||||
function sendToAllDataChannels(message) {
|
||||
// key is UUID, value is dataChannel object
|
||||
dataChannel.forEach(function(value, key, map) {
|
||||
dataChannel.forEach(function (value, key, map) {
|
||||
value.send(message);
|
||||
});
|
||||
}
|
||||
@ -501,18 +504,19 @@ function sendToAllDataChannels(message) {
|
||||
|
||||
// Mute microphone
|
||||
function muteMicrophone() {
|
||||
VideoChat.audioEnabled = !VideoChat.audioEnabled;
|
||||
var audioTrack = null;
|
||||
|
||||
VideoChat.peerConnections.forEach(function(value, key, map) {
|
||||
VideoChat.peerConnections.forEach(function (value, key, map) {
|
||||
value.getSenders().find(function (s) {
|
||||
if (s.track.kind === "audio") {
|
||||
audioTrack = s.track;
|
||||
}
|
||||
})
|
||||
});
|
||||
audioTrack.enabled = VideoChat.audioEnabled;
|
||||
});
|
||||
|
||||
VideoChat.audioEnabled = !VideoChat.audioEnabled;
|
||||
|
||||
// select mic button and mic button text
|
||||
const micButtonIcon = document.getElementById("mic-icon");
|
||||
const micButtonText = document.getElementById("mic-text");
|
||||
@ -534,14 +538,14 @@ function pauseVideo() {
|
||||
VideoChat.videoEnabled = !VideoChat.videoEnabled;
|
||||
|
||||
// Communicate pause to all the peers' video tracks
|
||||
VideoChat.peerConnections.forEach(function(value, key, map) {
|
||||
VideoChat.peerConnections.forEach(function (value, key, map) {
|
||||
console.log("pausing video for ", key);
|
||||
value.getSenders().find(function (s) {
|
||||
if (s.track.kind === "video") {
|
||||
console.log("found video track")
|
||||
console.log("found video track");
|
||||
videoTrack = s.track;
|
||||
}
|
||||
})
|
||||
});
|
||||
videoTrack.enabled = VideoChat.videoEnabled;
|
||||
});
|
||||
|
||||
@ -640,18 +644,19 @@ function switchStreamHelper(stream) {
|
||||
videoTrack.onended = function () {
|
||||
swap();
|
||||
};
|
||||
|
||||
// Swap video for every peer connection
|
||||
VideoChat.connected.forEach(function(value, key, map) {
|
||||
VideoChat.connected.forEach(function (value, key, map) {
|
||||
// Just to be safe, check if connected before swapping video channel
|
||||
if (VideoChat.connected.get(key)) {
|
||||
const sender = VideoChat.peerConnections.get(key).getSenders().find (function(s) {
|
||||
return s.track.kind === videoTrack.kind;
|
||||
})
|
||||
const sender = VideoChat.peerConnections
|
||||
.get(key)
|
||||
.getSenders()
|
||||
.find(function (s) {
|
||||
return s.track.kind === videoTrack.kind;
|
||||
});
|
||||
sender.replaceTrack(videoTrack);
|
||||
}
|
||||
});
|
||||
|
||||
// Update local video stream
|
||||
VideoChat.localStream = videoTrack;
|
||||
// Update local video object
|
||||
@ -737,7 +742,7 @@ function startSpeech() {
|
||||
sendToAllDataChannels(
|
||||
"cap:" +
|
||||
interimTranscript.substring(interimTranscript.length - charsToKeep)
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
26
public/landing.html
vendored
26
public/landing.html
vendored
@ -67,9 +67,9 @@
|
||||
class="mt-0 mb-32 reveal-from-bottom"
|
||||
data-reveal-delay="300"
|
||||
>
|
||||
Simple, Secure, and Fast. Peer to peer 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.
|
||||
</p>
|
||||
<div class="reveal-from-bottom" data-reveal-delay="450">
|
||||
<a
|
||||
@ -191,18 +191,19 @@
|
||||
<div class="features-tiles-item-header">
|
||||
<div class="features-tiles-item-image mb-16">
|
||||
<img
|
||||
src="images/feature-tile-icon-03.svg"
|
||||
alt="Feature tile icon 03"
|
||||
src="images/feature-tile-icon-06.svg"
|
||||
alt="Feature tile icon 06"
|
||||
width="72"
|
||||
height="72"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="features-tiles-item-content">
|
||||
<h4 class="mt-0 mb-8">Total Privacy</h4>
|
||||
<h4 class="mt-0 mb-8">Decentralized group calls</h4>
|
||||
<p class="m-0 text-sm">
|
||||
Each chat is single use, data stays between you and your
|
||||
caller. Zipcall is built privacy first.
|
||||
Zipcall lets you talk to up to four friends by
|
||||
directly connecting to them, completely
|
||||
decentralized.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -236,17 +237,18 @@
|
||||
<div class="features-tiles-item-header">
|
||||
<div class="features-tiles-item-image mb-16">
|
||||
<img
|
||||
src="images/feature-tile-icon-06.svg"
|
||||
alt="Feature tile icon 06"
|
||||
src="images/feature-tile-icon-03.svg"
|
||||
alt="Feature tile icon 03"
|
||||
width="72"
|
||||
height="72"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="features-tiles-item-content">
|
||||
<h4 class="mt-0 mb-8">Maximum Security</h4>
|
||||
<h4 class="mt-0 mb-8">Total Privacy and Security</h4>
|
||||
<p class="m-0 text-sm">
|
||||
End to end state of the art encryption means your calls
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
|
35
server.js
35
server.js
@ -8,7 +8,6 @@ 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");
|
||||
@ -79,30 +78,16 @@ io.on("connection", function (socket) {
|
||||
var numClients = typeof clients !== "undefined" ? clients.length : 0;
|
||||
if (numClients === 0) {
|
||||
socket.join(room);
|
||||
twilio.tokens.create(function (err, response) {
|
||||
if (err) {
|
||||
logIt(err, room);
|
||||
} else {
|
||||
logIt("Token generated. Returning it to the browser client", room);
|
||||
socket.emit("token", response);
|
||||
// Existing callers initiates call with user
|
||||
}
|
||||
});
|
||||
} else if (numClients < 4) {
|
||||
} else if (numClients < 5) {
|
||||
socket.join(room);
|
||||
logIt("Connected clients", room)
|
||||
for (var clientId in clients.sockets) {
|
||||
logIt('ID: ' + clientId, 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);
|
||||
// socket.emit("uuid", socket.id);
|
||||
socket.emit("ready", room).to(room);
|
||||
socket.broadcast.to(room).emit("ready", room);
|
||||
} else {
|
||||
logIt("room already full with " + numClients + " people in the room.", room);
|
||||
logIt(
|
||||
"room already full with " + numClients + " people in the room.",
|
||||
room
|
||||
);
|
||||
socket.emit("full", room);
|
||||
}
|
||||
});
|
||||
@ -129,13 +114,19 @@ io.on("connection", function (socket) {
|
||||
|
||||
// Relay offers
|
||||
socket.on("offer", function (offer, room, uuid) {
|
||||
logIt("Received offer from " + socket.id + " and emitting to " + uuid, room);
|
||||
logIt(
|
||||
"Received offer from " + socket.id + " and emitting to " + uuid,
|
||||
room
|
||||
);
|
||||
io.to(uuid).emit("offer", offer, socket.id);
|
||||
});
|
||||
|
||||
// Relay answers
|
||||
socket.on("answer", function (answer, room, uuid) {
|
||||
logIt("Received answer from " + socket.id + " and emitting to " + uuid, room);
|
||||
logIt(
|
||||
"Received answer from " + socket.id + " and emitting to " + uuid,
|
||||
room
|
||||
);
|
||||
io.to(uuid).emit("answer", answer, socket.id);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user