mirror of https://github.com/movim/movim
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
11 KiB
355 lines
11 KiB
function logError(error) {
|
|
console.log(error.name + ': ' + error.message);
|
|
console.error(error);
|
|
}
|
|
|
|
var Visio = {
|
|
from: null,
|
|
id: null,
|
|
withVideo: false,
|
|
|
|
localVideo: null,
|
|
remoteVideo: null,
|
|
localAudio: null,
|
|
remoteAudio: null,
|
|
screenSharing: null,
|
|
|
|
calling: false,
|
|
|
|
videoSelect: undefined,
|
|
switchCamera: undefined,
|
|
|
|
inboundStream: null,
|
|
|
|
services: [],
|
|
|
|
tracksTypes: [],
|
|
|
|
init: function() {
|
|
Visio.from = MovimUtils.urlParts().params[0];
|
|
|
|
if (MovimUtils.urlParts().params[1] !== undefined) {
|
|
Visio.from += '/' + MovimUtils.urlParts().params[1];
|
|
}
|
|
|
|
if (Visio.withVideo) {
|
|
Visio.localVideo = document.getElementById('video');
|
|
Visio.remoteVideo = document.getElementById('remote_video');
|
|
Visio.screenSharing = document.getElementById('screen_sharing_video');
|
|
}
|
|
|
|
Visio.localAudio = document.getElementById('audio');
|
|
Visio.remoteAudio = document.getElementById('remote_audio');
|
|
|
|
var configuration = {
|
|
'iceServers': Visio.services
|
|
};
|
|
|
|
Visio.pc = new RTCPeerConnection(configuration);
|
|
|
|
Visio.pc.ontrack = event => {
|
|
if (Visio.withVideo) {
|
|
if (event.streams && event.streams[0]) {
|
|
Visio.remoteVideo.srcObject = event.streams[0];
|
|
} else {
|
|
if (!Visio.inboundStream) {
|
|
Visio.inboundStream = new MediaStream();
|
|
Visio.remoteVideo.srcObject = Visio.inboundStream;
|
|
}
|
|
Visio.inboundStream.addTrack(event.track);
|
|
}
|
|
|
|
VisioUtils.setRemoteAudioState('mic');
|
|
VisioUtils.setRemoteVideoState('videocam');
|
|
} else {
|
|
if (event.streams && event.streams[0]) {
|
|
Visio.remoteAudio.srcObject = event.streams[0];
|
|
} else {
|
|
if (!Visio.inboundStream) {
|
|
Visio.inboundStream = new MediaStream();
|
|
Visio.remoteAudio.srcObject = Visio.inboundStream;
|
|
}
|
|
Visio.inboundStream.addTrack(event.track);
|
|
}
|
|
VisioUtils.handleRemoteAudio();
|
|
VisioUtils.setRemoteAudioState('mic');
|
|
}
|
|
|
|
Visio.tracksTypes['mid'+event.transceiver.mid] = event.track.kind;
|
|
};
|
|
|
|
Visio.pc.onicecandidate = event => {
|
|
let candidate = event.candidate;
|
|
if (candidate && candidate.candidate && candidate.candidate.length > 0) {
|
|
Visio_ajaxCandidate(event.candidate, Visio.from, Visio.id);
|
|
}
|
|
};
|
|
|
|
Visio.pc.oniceconnectionstatechange = () => VisioUtils.toggleMainButton();
|
|
|
|
Visio.pc.onicegatheringstatechange = function (event) {
|
|
// When we didn't receive the WebRTC termination before Jingle
|
|
if (Visio.pc.iceConnectionState == 'disconnected') {
|
|
Visio.onTerminate();
|
|
}
|
|
|
|
VisioUtils.toggleMainButton();
|
|
};
|
|
|
|
VisioUtils.toggleMainButton();
|
|
|
|
if (Visio.withVideo) {
|
|
VisioUtils.switchCameraSetup();
|
|
}
|
|
|
|
Visio.getStream();
|
|
},
|
|
|
|
onMute: function(name) {
|
|
if (Visio.tracksTypes[name]) {
|
|
if (Visio.tracksTypes[name] == 'audio') {
|
|
VisioUtils.setRemoteAudioState('mic_off');
|
|
}
|
|
|
|
if (Visio.tracksTypes[name] == 'video') {
|
|
document.querySelector('#remote_video').classList.add('muted');
|
|
VisioUtils.setRemoteVideoState('videocam_off');
|
|
}
|
|
}
|
|
},
|
|
|
|
onUnmute: function(name) {
|
|
if (Visio.tracksTypes[name]) {
|
|
if (Visio.tracksTypes[name] == 'audio') {
|
|
VisioUtils.setRemoteAudioState('mic');
|
|
}
|
|
|
|
if (Visio.tracksTypes[name] == 'video') {
|
|
document.querySelector('#remote_video').classList.remove('muted');
|
|
VisioUtils.setRemoteVideoState('videocam');
|
|
}
|
|
}
|
|
},
|
|
|
|
setServices: function(services) {
|
|
Visio.services = services;
|
|
},
|
|
|
|
getStream: function() {
|
|
if (Visio.withVideo) {
|
|
// On Android where you can't have both camera enabled at the same time
|
|
var videoTrack = Visio.pc.getSenders().find(rtc => rtc.track && rtc.track.kind == 'video');
|
|
if (videoTrack) videoTrack.track.stop();
|
|
|
|
Visio.switchCamera.classList.add('disabled');
|
|
}
|
|
|
|
var constraints = {
|
|
audio: true,
|
|
video: false
|
|
};
|
|
|
|
if (localStorage.getItem('defaultMicrophone')) {
|
|
constraints.audio = {
|
|
deviceId: localStorage.getItem('defaultMicrophone')
|
|
}
|
|
}
|
|
|
|
if (Visio.withVideo) {
|
|
const videoSource = Visio.videoSelect.value;
|
|
var defaultCamera = undefined;
|
|
|
|
if (localStorage.getItem('defaultCamera')) {
|
|
defaultCamera = localStorage.getItem('defaultMicrophone');
|
|
}
|
|
|
|
constraints.video = {
|
|
deviceId: videoSource ? {exact: videoSource} : defaultCamera,
|
|
facingMode: 'user',
|
|
width: { ideal: 4096 },
|
|
height: { ideal: 4096 }
|
|
};
|
|
}
|
|
|
|
navigator.mediaDevices.getUserMedia(constraints).then(stream => {
|
|
var tracks = stream.getTracks();
|
|
for(var i = 0; i < tracks.length; i++){
|
|
if (tracks[i].getSettings().channelCount) {
|
|
localStorage.setItem('defaultMicrophone', tracks[i].getSettings().deviceId);
|
|
} else {
|
|
localStorage.setItem('defaultCamera', tracks[i].getSettings().deviceId);
|
|
}
|
|
}
|
|
|
|
if (!Visio.withVideo) {
|
|
Visio.localAudio.srcObject = stream;
|
|
} else {
|
|
Visio.switchCamera.classList.remove('disabled');
|
|
Visio.localVideo.srcObject = stream;
|
|
|
|
// Toggle video icon
|
|
var cameraIcon = document.querySelector('#toggle_video i');
|
|
cameraIcon.innerText = 'videocam';
|
|
|
|
// Switch camera
|
|
VisioUtils.pcReplaceTrack(stream);
|
|
VisioUtils.enableScreenSharingButton();
|
|
}
|
|
|
|
VisioUtils.handleAudio();
|
|
VisioUtils.toggleMainButton();
|
|
|
|
// For the first time we attach all the tracks and we launch the call
|
|
if (Visio.pc.getSenders().length == 0) {
|
|
stream.getTracks().forEach(track => Visio.pc.addTrack(track, stream));
|
|
|
|
if (Visio.id) {
|
|
Visio_ajaxAccept(Visio.from, Visio.id);
|
|
} else {
|
|
// TODO launch when button pressed
|
|
Visio.id = Math.random().toString(36).substr(2, 9);
|
|
Visio.calling = true;
|
|
VisioUtils.toggleMainButton();
|
|
Visio_ajaxPropose(Visio.from, Visio.id, Visio.withVideo);
|
|
}
|
|
}
|
|
}, logError);
|
|
},
|
|
|
|
gotQuickStream: function() {
|
|
VisioUtils.pcReplaceTrack(Visio.localVideo.srcObject);
|
|
},
|
|
|
|
gotScreen: function() {
|
|
VisioUtils.pcReplaceTrack(Visio.screenSharing.srcObject);
|
|
},
|
|
|
|
onCandidate: function(candidate, mid, mlineindex) {
|
|
// filter the a=candidate lines
|
|
var filtered = candidate.split(/\n/).filter(line => {
|
|
return line.startsWith('a=candidate');
|
|
});
|
|
|
|
Visio.pc.addIceCandidate(new RTCIceCandidate({
|
|
'candidate': filtered.join('').substr(2),
|
|
'sdpMid': mid,
|
|
'sdpMLineIndex' : mlineindex
|
|
}), () => {}, logError);
|
|
},
|
|
|
|
onProceed: function(from, id) {
|
|
if (from.substring(0, Visio.from.length) == Visio.from && Visio.id == id) {
|
|
// We set the remote resource
|
|
Visio.from = from;
|
|
|
|
Visio.pc.createOffer().then(function(offer) {
|
|
Visio.calling = false;
|
|
VisioUtils.toggleMainButton();
|
|
return Visio.pc.setLocalDescription(offer);
|
|
})
|
|
.then(function() {
|
|
Visio_ajaxSessionInitiate(Visio.pc.localDescription, Visio.from, Visio.id);
|
|
});
|
|
} else {
|
|
console.error('Wrong call')
|
|
}
|
|
},
|
|
|
|
onInitiateSDP: function(sdp) {
|
|
Visio.pc.setRemoteDescription(new RTCSessionDescription({'sdp': sdp + "\n", 'type': 'offer'}), () => {
|
|
Visio.pc.createAnswer().then(function(answer) {
|
|
return Visio.pc.setLocalDescription(answer);
|
|
}).then(function() {
|
|
Visio_ajaxSessionAccept(Visio.pc.localDescription, Visio.from, Visio.id);
|
|
}).catch(logError);
|
|
}, logError);
|
|
},
|
|
|
|
onAcceptSDP: function(sdp) {
|
|
Visio.pc.setRemoteDescription(
|
|
new RTCSessionDescription({'sdp': sdp + "\n", 'type': 'answer'}), () => {},
|
|
(error) => {
|
|
Visio.goodbye('incompatible-parameters');
|
|
logError(error)
|
|
}
|
|
);
|
|
},
|
|
|
|
onTerminate: (reason) => {
|
|
if (!Visio.withVideo) {
|
|
let localStream = Visio.localAudio.srcObject;
|
|
|
|
if (localStream) {
|
|
localStream.getTracks().forEach(track => track.stop());
|
|
}
|
|
|
|
let remoteStream = Visio.remoteAudio.srcObject;
|
|
|
|
if (remoteStream) {
|
|
remoteStream.getTracks().forEach(track => track.stop());
|
|
}
|
|
|
|
Visio.localAudio.srcObject = null;
|
|
Visio.remoteAudio.srcObject = null;
|
|
} else {
|
|
let localStream = Visio.localVideo.srcObject;
|
|
|
|
if (localStream) {
|
|
localStream.getTracks().forEach(track => track.stop());
|
|
}
|
|
|
|
let remoteStream = Visio.remoteVideo.srcObject;
|
|
|
|
if (remoteStream) {
|
|
remoteStream.getTracks().forEach(track => track.stop());
|
|
}
|
|
|
|
Visio.localVideo.srcObject = null;
|
|
Visio.remoteVideo.srcObject = null;
|
|
|
|
Visio.localVideo.classList.add('hide');
|
|
}
|
|
|
|
|
|
if (Visio.pc) Visio.pc.close();
|
|
|
|
document.querySelector('p.state').innerText = reason == 'decline'
|
|
? Visio.states.declined
|
|
: Visio.states.ended;
|
|
button = document.querySelector('#main');
|
|
|
|
button.className = 'button action color red';
|
|
button.querySelector('i').className = 'material-icons';
|
|
button.querySelector('i').innerText = 'close';
|
|
|
|
button.onclick = () => {
|
|
window.close();
|
|
}
|
|
|
|
// And we force close the window after 2sec
|
|
window.setTimeout(() => {
|
|
window.close();
|
|
}, 2000);
|
|
},
|
|
|
|
goodbye: (reason) => {
|
|
Visio.onTerminate(reason);
|
|
Visio_ajaxTerminate(Visio.from, Visio.id, reason);
|
|
},
|
|
}
|
|
|
|
MovimWebsocket.attach(() => {
|
|
if (MovimUtils.urlParts().params[2] !== undefined) {
|
|
Visio.id = MovimUtils.urlParts().params[2];
|
|
}
|
|
|
|
if (MovimUtils.urlParts().page == 'visio') {
|
|
Visio.withVideo = true;
|
|
}
|
|
|
|
Visio_ajaxResolveServices();
|
|
});
|
|
|
|
window.onbeforeunload = () => {
|
|
Visio.goodbye();
|
|
}
|