2020-03-25 07:27:09 +08:00
|
|
|
if (window.location.pathname === "/") {
|
2020-03-25 14:02:06 +08:00
|
|
|
window.location.href = "/landing/newroom";
|
2020-03-22 22:02:40 +08:00
|
|
|
}
|
2020-03-25 07:27:09 +08:00
|
|
|
const roomHash = window.location.pathname;
|
2020-03-22 22:02:40 +08:00
|
|
|
|
2020-03-25 14:02:06 +08:00
|
|
|
|
|
|
|
var isWebRTCSupported =
|
|
|
|
navigator.getUserMedia ||
|
|
|
|
navigator.webkitGetUserMedia ||
|
|
|
|
navigator.mozGetUserMedia ||
|
|
|
|
navigator.msGetUserMedia ||
|
|
|
|
window.RTCPeerConnection;
|
|
|
|
|
|
|
|
// try {
|
|
|
|
// window.RTCPeerConnection.peerConnection.addStream
|
|
|
|
// } catch (e) {
|
|
|
|
// alert("Your browser doesn't support Neon Chat. Please use Chrome or Firefox.");
|
|
|
|
// window.location.href = "/landing";
|
|
|
|
// }
|
|
|
|
|
|
|
|
if (!isWebRTCSupported) {
|
|
|
|
alert("Your browser doesn't support Neon Chat. Please use Chrome or Firefox.");
|
|
|
|
window.location.href = "/landing";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-22 05:23:46 +08:00
|
|
|
function logIt(message, error) {
|
2020-03-22 23:20:01 +08:00
|
|
|
// console.log(message);
|
2020-03-22 05:23:46 +08:00
|
|
|
// Add to logs on page
|
2020-03-22 22:02:40 +08:00
|
|
|
// 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: [],
|
2020-03-22 22:02:40 +08:00
|
|
|
// 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) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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 => {
|
2020-03-25 14:02:06 +08:00
|
|
|
console.log(error);
|
|
|
|
logIt('No media stream for us.');
|
|
|
|
alert("Please check your webcam browser privacy settings.")
|
2020-03-22 05:23:46 +08:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
requestScreenStream: function (event) {
|
|
|
|
navigator.mediaDevices
|
|
|
|
.getDisplayMedia({video: true, audio: true})
|
|
|
|
.then(stream => {
|
|
|
|
VideoChat.onMediaStream(stream);
|
|
|
|
})
|
|
|
|
.catch(error => {
|
2020-03-25 14:02:06 +08:00
|
|
|
console.log(error);
|
|
|
|
logIt('No media stream for us.');
|
|
|
|
alert("Please check your screen sharing browser privacy settings.")
|
2020-03-22 05:23:46 +08:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
// The onMediaStream function receives the media stream as an argument.
|
|
|
|
onMediaStream: function (stream) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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.
|
2020-03-22 23:20:01 +08:00
|
|
|
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);
|
2020-03-22 23:20:01 +08:00
|
|
|
VideoChat.socket.on('willInitiateCall', () => VideoChat.willInitiateCall = true);
|
2020-03-22 05:23:46 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
|
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-25 14:02:06 +08:00
|
|
|
window.location.href = "/landing/newroom";
|
2020-03-23 00:47:35 +08:00
|
|
|
},
|
|
|
|
|
2020-03-22 05:23:46 +08:00
|
|
|
// When we are ready to call, enable the Call button.
|
|
|
|
readyToCall: function (event) {
|
2020-03-22 23:20:01 +08:00
|
|
|
console.log("readyToCall");
|
|
|
|
if (VideoChat.willInitiateCall) {
|
2020-03-22 05:23:46 +08:00
|
|
|
VideoChat.startCall()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-03-22 23:20:01 +08:00
|
|
|
// 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) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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();
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2020-03-25 14:02:06 +08:00
|
|
|
// When the peerConnection generates an ice candidate, send it over the socket to the peer.
|
2020-03-22 05:23:46 +08:00
|
|
|
onIceCandidate: function (event) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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 () {
|
2020-03-22 23:20:01 +08:00
|
|
|
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) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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) {
|
2020-03-22 23:20:01 +08:00
|
|
|
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) {
|
2020-03-22 23:20:01 +08:00
|
|
|
console.log("onAddStream");
|
2020-03-22 05:23:46 +08:00
|
|
|
logIt('<<< Received new stream from remote. Adding it...');
|
|
|
|
VideoChat.remoteVideo.srcObject = event.stream;
|
2020-03-26 05:57:54 +08:00
|
|
|
Snackbar.close();
|
2020-03-22 05:23:46 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// auto get media
|
|
|
|
// VideoChat.requestScreenStream();
|
2020-03-22 23:20:01 +08:00
|
|
|
VideoChat.requestMediaStream();
|
2020-03-22 05:23:46 +08:00
|
|
|
|
2020-03-25 06:47:10 +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"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-25 14:02:06 +08:00
|
|
|
function pauseVideo() {
|
|
|
|
var muted = !VideoChat.localStream.getAudioTracks()[0].enabled;
|
|
|
|
var videoPaused = !VideoChat.localStream.getVideoTracks()[0].enabled;
|
|
|
|
VideoChat.localStream.getAudioTracks()[0].enabled = muted;
|
|
|
|
VideoChat.localStream.getVideoTracks()[0].enabled = videoPaused;
|
|
|
|
var pausedButton = document.getElementById("videoPauseButton");
|
|
|
|
if (!muted) {
|
|
|
|
pausedButton.innerText = "Unpause"
|
|
|
|
} else {
|
|
|
|
pausedButton.innerText = "Pause"
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-03-26 05:57:54 +08:00
|
|
|
//Show and hide buttons automatically
|
2020-03-25 06:47:10 +08:00
|
|
|
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);
|
|
|
|
});
|
|
|
|
_delay = setInterval(delayCheck, 500);
|
2020-03-26 05:57:54 +08:00
|
|
|
|
|
|
|
|
|
|
|
// Show share URL
|
|
|
|
Snackbar.show({
|
|
|
|
text: 'Share this URL with a friend to get started',
|
|
|
|
actionText: 'Copy URL',
|
|
|
|
width: '355px',
|
|
|
|
pos: 'top-left',
|
|
|
|
actionTextColor: '#8688ff',
|
|
|
|
duration: 50000,
|
|
|
|
backgroundColor :'#292B32',
|
|
|
|
onActionClick: function (element) {
|
|
|
|
var copyContent = window.location.href;
|
|
|
|
$('<input id="some-element">').val(copyContent).appendTo('body').select();
|
|
|
|
document.execCommand('copy');
|
|
|
|
var toRemove = document.querySelector('#some-element');
|
|
|
|
toRemove.parentNode.removeChild(toRemove);
|
|
|
|
$(element).css('opacity', 0); //Set opacity of element to 0 to close Snackbar
|
|
|
|
}
|
|
|
|
});
|