decentralized-video-chat/public/chat.js

284 lines
12 KiB
JavaScript
Raw Normal View History

2020-03-25 07:27:09 +08:00
if (window.location.pathname === "/") {
// Generate random room name if needed
2020-03-23 04:26:11 +08:00
var adjectives = ["small", "big", "large", "smelly", "new", "happy", "shiny", "old", "clean", "nice", "bad", "cool",
"hot", "cold", "warm", "hungry", "slow", "fast", "red", "white", "black", "blue", "green"];
var nouns = ["dog", "bat", "wrench", "apple", "pear", "ghost", "cat", "wolf", "squid", "goat", "snail", "hat",
"sock", "plum", "bear", "snake", "turtle", "horse", "spoon", "fork", "spider", "tree", "chair", "table",
"couch", "towel"];
2020-03-23 01:09:22 +08:00
var adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
var noun = nouns[Math.floor(Math.random() * nouns.length)];
2020-03-25 07:27:09 +08:00
noun = noun.charAt(0).toUpperCase() + noun.substring(1);
adjective = adjective.charAt(0).toUpperCase() + adjective.substring(1);
window.location.href = window.location.href + adjective + noun;
}
2020-03-25 07:27:09 +08:00
const roomHash = window.location.pathname;
2020-03-22 05:23:46 +08:00
function logIt(message, error) {
// console.log(message);
2020-03-22 05:23:46 +08:00
// Add to logs on page
// let logs = document.getElementById('logs');
// let tmp = document.createElement('P');
// tmp.innerText = message;
// if (error) {
// tmp.classList.add('error');
// }
// logs.appendChild(tmp);
2020-03-22 05:23:46 +08:00
}
// Create an object to save various objects to without polluting the global namespace.
var VideoChat = {
connected: false,
2020-03-23 04:26:11 +08:00
willInitiateCall: false,
2020-03-22 05:23:46 +08:00
localICECandidates: [],
// Initialise our connection to the WebSocket.
socket: io(),
2020-03-22 05:50:35 +08:00
remoteVideo: document.getElementById('remote-video'),
localVideo: document.getElementById('local-video'),
2020-03-22 05:23:46 +08:00
// 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
// accepted callback to the onMediaStream function, otherwise callback to the
// noMediaStream function.
requestMediaStream: function (event) {
console.log("requestMediaStream");
2020-03-22 05:23:46 +08:00
navigator.mediaDevices
.getUserMedia({video: true, audio: true})
.then(stream => {
VideoChat.onMediaStream(stream);
})
.catch(error => {
VideoChat.noMediaStream(error);
});
},
requestScreenStream: function (event) {
navigator.mediaDevices
.getDisplayMedia({video: true, audio: true})
.then(stream => {
VideoChat.onMediaStream(stream);
})
.catch(error => {
VideoChat.noMediaStream(error);
});
},
// The onMediaStream function receives the media stream as an argument.
onMediaStream: function (stream) {
console.log("onMediaStream");
2020-03-22 05:23:46 +08:00
VideoChat.localStream = stream;
// Add the stream as video's srcObject.
VideoChat.localVideo.srcObject = stream;
// Now we're ready to join the chat room.
VideoChat.socket.emit('join', roomHash);
2020-03-23 00:47:35 +08:00
VideoChat.socket.on('temp', () => alert("temp called"));
VideoChat.socket.on('full', VideoChat.chatRoomFull);
2020-03-22 05:23:46 +08:00
VideoChat.socket.on('offer', VideoChat.onOffer);
VideoChat.socket.on('ready', VideoChat.readyToCall);
VideoChat.socket.on('willInitiateCall', () => VideoChat.willInitiateCall = true);
2020-03-22 05:23:46 +08:00
},
// There's not much to do in this demo if there is no media stream. So let's just stop.
noMediaStream: function () {
logIt('No media stream for us.');
},
2020-03-23 04:26:11 +08:00
chatRoomFull: function () {
2020-03-24 02:38:34 +08:00
alert("Chat room is full. Check to make sure you don't have multiple open tabs, or try with a new room link");
2020-03-23 00:47:35 +08:00
// VideoChat.socket.disconnect()
// todo handle this better
},
2020-03-22 05:23:46 +08:00
// When we are ready to call, enable the Call button.
readyToCall: function (event) {
console.log("readyToCall");
if (VideoChat.willInitiateCall) {
2020-03-22 05:23:46 +08:00
VideoChat.startCall()
}
},
// Set up a callback to run when we have the ephemeral token to use Twilio's TURN server.
2020-03-22 05:23:46 +08:00
startCall: function (event) {
console.log("startCall");
2020-03-22 05:23:46 +08:00
logIt('>>> Sending token request...');
VideoChat.socket.on('token', VideoChat.onToken(VideoChat.createOffer));
2020-03-23 01:09:22 +08:00
VideoChat.socket.emit('token', roomHash);
2020-03-22 05:23:46 +08:00
},
// When we receive the ephemeral token back from the server.
onToken: function (callback) {
console.log("onToken");
2020-03-22 05:23:46 +08:00
return function (token) {
logIt('<<< Received token');
// Set up a new RTCPeerConnection using the token's iceServers.
VideoChat.peerConnection = new RTCPeerConnection({iceServers: token.iceServers});
// Add the local video stream to the peerConnection.
VideoChat.peerConnection.addStream(VideoChat.localStream);
// Set up callbacks for the connection generating iceCandidates or
// receiving the remote media stream.
VideoChat.peerConnection.onicecandidate = VideoChat.onIceCandidate;
VideoChat.peerConnection.onaddstream = VideoChat.onAddStream;
// Set up listeners on the socket for candidates or answers being passed
// over the socket connection.
VideoChat.socket.on('candidate', VideoChat.onCandidate);
VideoChat.socket.on('answer', VideoChat.onAnswer);
callback();
};
},
// When the peerConnection generates an ice candidate, send it over the socket
// to the peer.
onIceCandidate: function (event) {
console.log("onIceCandidate");
2020-03-22 05:23:46 +08:00
if (event.candidate) {
logIt(`<<< Received local ICE candidate from STUN/TURN server (${event.candidate.address})`);
if (VideoChat.connected) {
logIt(`>>> Sending local ICE candidate (${event.candidate.address})`);
2020-03-23 01:09:22 +08:00
VideoChat.socket.emit('candidate', JSON.stringify(event.candidate), roomHash);
2020-03-22 05:23:46 +08:00
} else {
// If we are not 'connected' to the other peer, we are buffering the local ICE candidates.
// This most likely is happening on the "caller" side.
// 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.push(event.candidate);
}
}
},
// When receiving a candidate over the socket, turn it back into a real
// RTCIceCandidate and add it to the peerConnection.
onCandidate: function (candidate) {
console.log("onCandidate");
2020-03-22 05:23:46 +08:00
rtcCandidate = new RTCIceCandidate(JSON.parse(candidate));
logIt(`<<< Received remote ICE candidate (${rtcCandidate.address} - ${rtcCandidate.relatedAddress})`);
VideoChat.peerConnection.addIceCandidate(rtcCandidate);
},
// Create an offer that contains the media capabilities of the browser.
createOffer: function () {
console.log("createOffer");
2020-03-22 05:23:46 +08:00
logIt('>>> Creating offer...');
VideoChat.peerConnection.createOffer(
function (offer) {
// If the offer is created successfully, set it as the local description
// and send it over the socket connection to initiate the peerConnection
// on the other side.
VideoChat.peerConnection.setLocalDescription(offer);
2020-03-23 01:09:22 +08:00
VideoChat.socket.emit('offer', JSON.stringify(offer), roomHash);
2020-03-22 05:23:46 +08:00
},
function (err) {
logIt("failed offer creation");
logIt(err, true);
}
);
},
// Create an answer with the media capabilities that both 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
// same manner as the offer and sent over the socket.
createAnswer: function (offer) {
console.log("createAnswer");
2020-03-22 05:23:46 +08:00
return function () {
logIt('>>> Creating answer...');
VideoChat.connected = true;
rtcOffer = new RTCSessionDescription(JSON.parse(offer));
VideoChat.peerConnection.setRemoteDescription(rtcOffer);
VideoChat.peerConnection.createAnswer(
function (answer) {
VideoChat.peerConnection.setLocalDescription(answer);
2020-03-23 01:09:22 +08:00
VideoChat.socket.emit('answer', JSON.stringify(answer), roomHash);
2020-03-22 05:23:46 +08:00
},
function (err) {
2020-03-22 05:50:35 +08:00
logIt("Failed answer creation.");
2020-03-22 05:23:46 +08:00
logIt(err, true);
}
);
};
},
// When a browser receives an offer, set up a callback to be run when the
// ephemeral token is returned from Twilio.
onOffer: function (offer) {
console.log("onOffer");
2020-03-22 05:23:46 +08:00
logIt('<<< Received offer');
VideoChat.socket.on('token', VideoChat.onToken(VideoChat.createAnswer(offer)));
2020-03-23 01:09:22 +08:00
VideoChat.socket.emit('token', roomHash);
2020-03-22 05:23:46 +08:00
},
// When an answer is received, add it to the peerConnection as the remote
// description.
onAnswer: function (answer) {
console.log("onAnswer");
2020-03-22 05:23:46 +08:00
logIt('<<< Received answer');
var rtcAnswer = new RTCSessionDescription(JSON.parse(answer));
VideoChat.peerConnection.setRemoteDescription(rtcAnswer);
VideoChat.connected = true;
VideoChat.localICECandidates.forEach(candidate => {
2020-03-22 05:50:35 +08:00
// The caller now knows that the callee is ready to accept new ICE candidates, so sending the buffer over
2020-03-22 05:23:46 +08:00
logIt(`>>> Sending local ICE candidate (${candidate.address})`);
2020-03-23 01:09:22 +08:00
VideoChat.socket.emit('candidate', JSON.stringify(candidate), roomHash);
2020-03-22 05:23:46 +08:00
});
2020-03-22 05:50:35 +08:00
// Reset the buffer of local ICE candidates. This is not really needed
2020-03-22 05:23:46 +08:00
// in this specific client, but it's good practice
VideoChat.localICECandidates = [];
},
// When the peerConnection receives the actual media stream from the other
// browser, add it to the other video element on the page.
onAddStream: function (event) {
console.log("onAddStream");
2020-03-22 05:23:46 +08:00
logIt('<<< Received new stream from remote. Adding it...');
VideoChat.remoteVideo.srcObject = event.stream;
}
};
// auto get media
// VideoChat.requestScreenStream();
VideoChat.requestMediaStream();
2020-03-22 05:23:46 +08:00
function openFullscreen() {
if (VideoChat.remoteVideo.requestFullscreen) {
VideoChat.remoteVideo.requestFullscreen();
} else if (VideoChat.remoteVideo.mozRequestFullScreen) { /* Firefox */
VideoChat.remoteVideo.mozRequestFullScreen();
} else if (VideoChat.remoteVideo.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
VideoChat.remoteVideo.webkitRequestFullscreen();
} else if (VideoChat.remoteVideo.msRequestFullscreen) { /* IE/Edge */
VideoChat.remoteVideo.msRequestFullscreen();
}
}
function muteMicrophone() {
var muted = !VideoChat.localStream.getAudioTracks()[0].enabled;
VideoChat.localStream.getAudioTracks()[0].enabled = muted;
var mutedButton = document.getElementById("muteButton");
if (!muted) {
mutedButton.innerText = "Unmute"
} else {
mutedButton.innerText = "Mute"
}
}
var timedelay = 1;
function delayCheck() {
if (timedelay === 5) {
$('#buttons').fadeOut();
timedelay = 1;
}
timedelay = timedelay + 1;
}
$(document).mousemove(function () {
$('#buttons').fadeIn();
timedelay = 1;
clearInterval(_delay);
_delay = setInterval(delayCheck, 500);
});
// page loads starts delay timer
_delay = setInterval(delayCheck, 500);