This commit is contained in:
nnduc
2026-10-24 14:03:52 +07:00
commit 4fe046de58
4790 changed files with 311146 additions and 0 deletions
+935
View File
@@ -0,0 +1,935 @@
var MovimJingleSession = function (jid, fullJid, id, name, avatarUrl) {
this.id = id ?? crypto.randomUUID();
this.jid = jid;
this.fullJid = fullJid;
this.tracksTypes = {};
this.tracksScreen = {};
this.name = name;
this.avatarUrl = avatarUrl;
this.audioLevel = 0;
this.lastPostMessage = 0;
this.audioSharingSender = null;
this.screenSharingSender = null;
this.pc = new RTCPeerConnection({
iceServers: MovimVisio.services,
bundlePolicy: 'max-bundle',
iceCandidatePoolSize: 10
});
this.screenSharingPc = null; // RTCPc specific for the SFU
this.adaptToNetworkCondition = setInterval(() => {
VisioUtils.adaptToNetworkCondition(this.pc);
}, 5000);
this.participant = document.createElement('div');
this.participant.dataset.jid = this.jid;
this.participant.classList.add('participant');
document.querySelector('#participants').appendChild(this.participant);
this.participant.classList.add('audio_off');
this.participant.classList.add('screen_off');
this.participant.classList.add('video_off');
this.remoteScreenVideo = document.createElement('video');
this.remoteScreenVideo.classList.add('screen');
this.remoteScreenVideo.autoplay = true;
this.remoteScreenVideo.disablePictureInPicture = true;
this.remoteScreenVideo.poster = BASE_URI + 'theme/img/empty.png';
this.participant.appendChild(this.remoteScreenVideo);
this.remoteVideo = document.createElement('video');
this.remoteVideo.autoplay = true;
this.remoteVideo.disablePictureInPicture = true;
this.remoteVideo.poster = BASE_URI + 'theme/img/empty.png';
this.remoteVideo.muted = true;
this.participant.appendChild(this.remoteVideo);
this.remoteAudio = document.createElement('audio');
this.remoteAudio.autoplay = true;
this.participant.appendChild(this.remoteAudio);
this.remoteScreenAudio = document.createElement('audio');
this.remoteScreenAudio.classList.add('screen');
this.remoteScreenAudio.autoplay = true;
this.participant.appendChild(this.remoteScreenAudio);
this.callStatus = document.createElement('div')
this.callStatus.classList.add('status');
this.participant.appendChild(this.callStatus);
this.audioOffStatus = document.createElement('span');
this.audioOffStatus.classList.add('audio_off');
this.callStatus.appendChild(this.audioOffStatus);
this.videoOffStatus = document.createElement('span');
this.videoOffStatus.classList.add('video_off');
this.callStatus.appendChild(this.videoOffStatus);
this.screenStatus = document.createElement('span');
this.screenStatus.classList.add('screen');
this.callStatus.appendChild(this.screenStatus);
// Pin button
this.pin = document.createElement('span');
this.pin.classList.add('pin');
this.participant.appendChild(this.pin);
this.pin.addEventListener('click', e => {
VisioUtils.toggleMode(true);
if (MovimJingles.pinned == this.jid) {
MovimJingles.pinned = null;
Visio_ajaxHttpUnpin();
} else {
MovimJingles.pinned = this.jid;
if (this.name) {
Visio_ajaxHttpPin(this.name);
}
}
MovimJingles.checkActiveSpeaker();
})
this.screenQualityInterval = setInterval(() => {
this.callStatus.classList.remove('screen_hd', 'screen_fhd');
if (!this.participant.classList.contains('screen_off')) {
if (this.remoteScreenVideo.videoWidth >= 1920) {
this.callStatus.classList.add('screen_fhd');
} else if (this.remoteScreenVideo.videoWidth >= 1280) {
this.callStatus.classList.add('screen_hd');
}
}
}, 3000);
if (this.name) {
this.callStatus.dataset.name = this.name;
}
if (this.avatarUrl) {
let background = document.createElement('img');
background.classList.add('avatar');
background.src = this.avatarUrl;
this.participant.prepend(background);
}
this.pc.ontrack = event => {
var srcObject = null;
if (event.streams && event.streams[0]) {
srcObject = event.streams[0];
} else {
srcObject = new MediaStream();
srcObject.addTrack(event.track);
}
if (event.track.kind == 'audio') {
if (this.tracksScreen[event.transceiver.mid]) {
this.remoteScreenAudio.srcObject = srcObject;
this.tracksTypes['mid' + event.transceiver.mid] = 'audio_screen';
} else {
this.remoteAudio.srcObject = srcObject;
this.participant.classList.remove('audio_off');
this.handleRemoteAudio();
this.tracksTypes['mid' + event.transceiver.mid] = 'audio';
}
} else if (event.track.kind === 'video') {
if (this.tracksScreen[event.transceiver.mid]) {
this.remoteScreenVideo.srcObject = srcObject;
this.tracksTypes['mid' + event.transceiver.mid] = 'video_screen';
this.remoteScreenVideo.oncanplay = event => {
this.participant.classList.remove('screen_off');
}
} else {
this.remoteVideo.srcObject = srcObject;
this.tracksTypes['mid' + event.transceiver.mid] = 'video';
this.participant.classList.remove('video_off');
}
}
}
this.pc.onnegotiationneeded = event => {
if (this.pc.localDescription) {
this.oldLocalDescription = this.pc.localDescription.sdp;
this.pc.getTransceivers().forEach(transceiver => {
if (transceiver.sender.track && transceiver.sender.track.kind === 'video') {
VisioUtils.setVideoCodecPreferences(transceiver);
}
});
this.pc.createOffer()
.then(offer => {
offer.sdp = this.maybeInjectScreenCategory(offer.sdp);
return this.pc.setLocalDescription(offer)
}).then(() => this.updateContent())
.catch(err => MovimUtils.logError(err));
}
};
this.pc.onicecandidate = event => {
let candidate = event.candidate;
if (candidate && candidate.candidate && candidate.candidate.length > 0) {
Visio_ajaxCandidate(this.fullJid, this.id, event.candidate);
}
};
/**
* Add all the existing tracks
*/
if (MovimVisio.sfu == null) {
MovimVisio.localStream.getTracks().forEach(track => {
this.pc.addTrack(track, MovimVisio.localStream);
});
if (MovimVisio.screenSharing.srcObject) {
this.enableScreenSharing();
}
}
Notif.userJoinedCall();
MovimJingles.checkActiveSpeaker();
}
MovimJingleSession.prototype.handleRemoteAudio = async function () {
this.remoteAudioContext = new AudioContext();
try {
var remoteMicrophone = this.remoteAudioContext.createMediaStreamSource(
this.remoteAudio.srcObject
);
await this.remoteAudioContext.audioWorklet.addModule(BASE_URI + 'scripts/movim_jingle_session_audio_worklet.js');
const audioWorkletNode = new AudioWorkletNode(this.remoteAudioContext, 'jinglesession-audioworklet');
remoteMicrophone.connect(audioWorkletNode);
audioWorkletNode.port.onmessage = (e) => {
this.processRemoteAudioMessage(e.data);
};
} catch (error) {
MovimUtils.logError(error);
return;
}
}
/**
* In some clients, such as Dino, the buffer is stopped when the microphone is muted
* we detect that there and send a clear message properly
*/
MovimJingleSession.prototype.clearRemoteAudioMessage = function () {
const second = 1000;
const secondAgo = Date.now() - second;
if (this.lastPostMessage < secondAgo) {
this.processRemoteAudioMessage({
"isMuteStep": 5,
"level": 0,
"published": Date.now()
});
}
}
MovimJingleSession.prototype.processRemoteAudioMessage = function (message) {
if (message.isMuteStep >= 5) {
this.participant.classList.add('audio_off');
} else {
this.participant.classList.remove('audio_off');
}
this.lastPostMessage = message.published;
this.audioLevel = message.level;
this.participant.style.setProperty('--level', message.level);
if (message.level > 0) {
clearTimeout(this.clearRemoteAudioMessageId);
this.clearRemoteAudioMessageId = setTimeout(this.clearRemoteAudioMessage.bind(this), 2000);
}
}
/**
* movim-rs: the signaling messages can arrive faster than the asynchronous
* WebRTC calls complete (a content-add right after a session-accept, candidates
* before the remote description), run them one after the other.
*/
MovimJingleSession.prototype.enqueue = function (task) {
this.queue = (this.queue || Promise.resolve())
.then(() => this.pc ? task() : null)
.catch(error => MovimUtils.logError(error));
}
MovimJingleSession.prototype.onCandidate = function (candidate, mid, mlineindex) {
this.enqueue(() => this._onCandidate(candidate, mid, mlineindex));
}
MovimJingleSession.prototype.onContentAdd = function (sdp, mids) {
this.enqueue(() => this._onContentAdd(sdp, mids));
}
MovimJingleSession.prototype.onContentModify = function (sdp, mid) {
this.enqueue(() => this._onContentModify(sdp, mid));
}
MovimJingleSession.prototype.onContentRemove = function (sdp, mids) {
this.enqueue(() => this._onContentRemove(sdp, mids));
}
MovimJingleSession.prototype.onAcceptSDP = function (sdp) {
this.enqueue(() => this._onAcceptSDP(sdp));
}
MovimJingleSession.prototype.onInitiateSDP = function (sdp) {
this.enqueue(() => this._onInitiateSDP(sdp));
}
MovimJingleSession.prototype.terminate = function (reason, muji) {
if (MovimVisio.sfu == null) {
Visio_ajaxTerminate(this.fullJid, this.id, reason, muji);
}
this.close();
}
MovimJingleSession.prototype.close = function () {
clearInterval(this.adaptToNetworkCondition);
clearInterval(this.screenQualityInterval);
Notif.userLeftCall();
if (this.pc) {
this.pc.close();
this.pc = null;
}
if (this.remoteAudioContext) {
this.remoteAudioContext.close();
this.remoteAudioContext = null;
}
let participant = document.querySelector('.participant[data-jid="' + this.jid + '"]');
if (participant) participant.remove();
let remoteVideoStream = this.remoteVideo.srcObject;
if (remoteVideoStream) {
remoteVideoStream.getTracks().forEach(track => track.stop());
remoteVideoStream = null;
}
let remoteAudioStream = this.remoteAudio.srcObject;
if (remoteAudioStream) {
remoteAudioStream.getTracks().forEach(track => track.stop());
remoteAudioStream = null;
}
}
MovimJingleSession.prototype._onCandidate = function (candidate, mid, mlineindex) {
const iceCandidate = new RTCIceCandidate({
// filter the a=candidate lines
'candidate': candidate.split(/\n/).filter(line => {
return line.startsWith('a=candidate');
}).join('').substring(2),
'sdpMid': mid,
'sdpMLineIndex': mlineindex
});
// When we share our own screen have some candidates from the SFU for our PC
if (this.jid == MovimVisio.sfu && MovimVisio.screenshareSFUPc) {
MovimVisio.screenshareSFUPc.addIceCandidate(iceCandidate).catch(error => MovimUtils.logError(error));
}
if (this.screenSharingPc) {
// In this case we send the candidate to both pcs, and let it sort it out ¯\_(ツ)_/¯
this.screenSharingPc.addIceCandidate(iceCandidate).catch(error => MovimUtils.logError(error));
} else if (this.pc && this.pc.remoteDescription) {
return this.pc.addIceCandidate(iceCandidate).catch(error => MovimUtils.logError(error));
}
}
MovimJingleSession.prototype._onContentAdd = function (sdp, mids) {
remoteDescription = this.pc.remoteDescription.sdp;
remoteDescription += sdp.match('m=[^]*');
remoteDescription = remoteDescription.replace(/^a=group.*/m, sdp.match(/a=group.*/)[0]);
this.maybeDetectTracksScreen(sdp);
return this.pc.setRemoteDescription({ 'sdp': remoteDescription + "\n", 'type': 'offer' })
.then(() => {
return this.pc.createAnswer()
.then(answer => this.pc.setLocalDescription(answer))
.then(() => Visio_ajaxContentAccept(this.fullJid, this.id, this.pc.localDescription.sdp))
.catch(MovimUtils.logError);
})
.catch(error => MovimUtils.logError(error));
}
MovimJingleSession.prototype._onContentModify = function (sdp, mid) {
// TODO, implement mid
this.maybeDetectTracksScreen(sdp);
return this.pc.setRemoteDescription({ 'sdp': sdp + "\n", 'type': 'offer' })
.then(() => {
return this.pc.createAnswer()
.then(answer => this.pc.setLocalDescription(answer))
.then(() => Visio_ajaxContentAccept(this.fullJid, this.id, this.pc.localDescription.sdp))
.catch(MovimUtils.logError);
})
.catch(error => MovimUtils.logError(error));
}
MovimJingleSession.prototype._onContentRemove = function (sdp, mids) {
remoteDescription = this.pc.remoteDescription.sdp;
mids.forEach(mid => delete this.tracksScreen[mid]);
let parts = remoteDescription.split('m=');
let filtered = [];
parts.forEach(part => {
let mid = part.match(/a=mid:(.*)/);
if (!mid || !mids.includes(mid[1])) {
filtered.push(part)
}
});
remoteDescription = filtered.join('m=');
return this.pc.setRemoteDescription({ 'sdp': sdp + "\n", 'type': 'offer' })
.then(() => {
return this.pc.createAnswer()
.then(answer => this.pc.setLocalDescription(answer))
.then(() => Visio_ajaxContentAccept(this.fullJid, this.id, this.pc.localDescription.sdp))
.catch(MovimUtils.logError);
})
.catch(error => MovimUtils.logError(error));
}
MovimJingleSession.prototype.sessionInitiate = function (fullJid, id, mujiRoom) {
this.id = id;
this.fullJid = fullJid;
this.pc.getTransceivers().forEach(transceiver => {
if (transceiver.sender.track.kind === 'video') {
VisioUtils.setVideoCodecPreferences(transceiver)
}
});
this.pc.createOffer()
.then(offer => this.pc.setLocalDescription(offer))
.then(() => Visio_ajaxSessionInitiate(this.fullJid, this.pc.localDescription, id, mujiRoom));
}
MovimJingleSession.prototype.updateContent = function () {
let oldMedias = this.oldLocalDescription.match(MovimVisio.bundleRegex)[2].split(' ');
let newMedias = this.pc.localDescription.sdp.match(MovimVisio.bundleRegex)[2].split(' ');
let createdMedias = newMedias.filter((e) => !oldMedias.includes(e));
let destroyedMedias = oldMedias.filter((e) => !newMedias.includes(e));
let changed = false;
let localDescription = this.maybeInjectScreenCategory(this.pc.localDescription.sdp);
if (createdMedias.length > 0) {
changed = true;
console.log('CONTENT ADD ?' + this.fullJid + ' ' + this.jid);
Visio_ajaxContentAdd(this.fullJid, localDescription, this.id, createdMedias);
}
if (destroyedMedias.length > 0) {
changed = true;
Visio_ajaxContentRemove(this.fullJid, this.oldLocalDescription, this.id, destroyedMedias);
}
// Nothing added, nothing removed, lets update everything...
if (changed == false) {
Visio_ajaxContentModify(this.fullJid, localDescription, this.id);
}
}
MovimJingleSession.prototype._onAcceptSDP = function (sdp) {
this.maybeDetectTracksScreen(sdp);
return this.pc.setRemoteDescription({ 'sdp': sdp + "\n", 'type': 'answer' })
.catch(error => {
let visio = document.querySelector('#visio');
Visio_ajaxGoodbye(visio.dataset.jid, this.id, 'incompatible-parameters');
MovimUtils.logError(error);
});
}
MovimJingleSession.prototype._onInitiateSDP = function (sdp) {
this.maybeDetectTracksScreen(sdp);
return this.pc.setRemoteDescription({ 'sdp': sdp + "\n", 'type': 'offer' })
.then(() => {
return this.pc.createAnswer()
.then(answer => this.pc.setLocalDescription(answer))
.then(() => {
if (MovimVisio.sfu != null) {
Visio_ajaxContentAccept(
this.fullJid,
this.id,
this.maybeInjectScreenCategory(this.pc.localDescription.sdp),
this.jid
);
} else {
Visio_ajaxSessionAccept(
this.fullJid,
this.id,
this.maybeInjectScreenCategory(this.pc.localDescription.sdp)
);
}
})
.catch(MovimUtils.logError);
}).catch(error => MovimUtils.logError(error));
}
/**
* With the SFU we can't have the screen as a new content, so we have to build a completely
* new RTPPc
*/
MovimJingleSession.prototype.onSFUScreenSharingPropose = function (sdp) {
this.maybeDetectTracksScreen(sdp);
this.screenSharingPc = new RTCPeerConnection({
iceServers: MovimVisio.services,
bundlePolicy: 'max-bundle',
iceCandidatePoolSize: 10
});
this.screenSharingPc.ontrack = event => {
var srcObject = null;
if (event.streams && event.streams[0]) {
srcObject = event.streams[0];
} else {
srcObject = new MediaStream();
srcObject.addTrack(event.track);
}
if (event.track.kind == 'audio') {
if (this.tracksScreen[event.transceiver.mid]) {
this.remoteScreenAudio.srcObject = srcObject;
this.tracksTypes['sfu_screen_mid' + event.transceiver.mid] = 'audio_screen';
}
} else if (event.track.kind === 'video') {
if (this.tracksScreen[event.transceiver.mid]) {
this.remoteScreenVideo.srcObject = srcObject;
this.tracksTypes['sfu_screen_mid' + event.transceiver.mid] = 'video_screen';
this.remoteScreenVideo.oncanplay = event => {
this.participant.classList.remove('screen_off');
}
}
}
}
this.screenSharingPc.onicecandidate = event => {
let candidate = event.candidate;
if (candidate && candidate.candidate && candidate.candidate.length > 0) {
Visio_ajaxCandidate(this.fullJid, this.id, event.candidate);
}
};
this.screenSharingPc.setRemoteDescription({ 'sdp': sdp + "\n", 'type': 'offer' })
.then(this.screenSharingPc.createAnswer()
.then(answer => this.screenSharingPc.setLocalDescription(answer))
.then(() => {
Visio_ajaxContentAccept(
this.fullJid,
this.id,
this.maybeInjectScreenCategory(this.screenSharingPc.localDescription.sdp),
this.jid
)
})
.catch(MovimUtils.logError));
}
MovimJingleSession.prototype.onSFUScreenSharingTerminate = function () {
if (this.screenSharingPc) {
this.screenSharingPc.close();
this.screenSharingPc = null;
}
this.participant.classList.add('screen_off');
Object.keys(MovimJingles.sessions[this.jid].tracksTypes).forEach(
key => {
if (key.startsWith('sfu_screen_mid')) {
delete MovimJingles.sessions[this.jid].tracksTypes[key]
}
}
);
}
MovimJingleSession.prototype.enableScreenSharing = function () {
MovimVisio.screenSharing.srcObject.getTracks().forEach(track => {
if (track.kind == 'video') {
if (this.screenSharingSender) {
this.screenSharingSender.replaceTrack(track).then(() => {
this.unmute(track);
});
} else {
this.screenSharingSender = this.pc.addTrack(track);
}
} else {
if (this.audioSharingSender) {
this.audioSharingSender.replaceTrack(track).then(() => {
this.unmute(track);
});
} else {
this.audioSharingSender = this.pc.addTrack(track);
}
}
});
}
MovimJingleSession.prototype.disableScreenSharing = function () {
if (this.pc && MovimVisio.screenSharing.srcObject) {
MovimVisio.screenSharing.srcObject.getTracks().forEach(track => this.mute(track));
}
}
MovimJingleSession.prototype.resolveTransceiver = function (track) {
const transceiver = this.pc.getTransceivers().find(transceiver => transceiver.sender.track && transceiver.sender.track.id == track.id);
return transceiver ?? null;
}
MovimJingleSession.prototype.mute = function (track) {
const transceiver = this.resolveTransceiver(track);
if (transceiver) {
Visio_ajaxMute(this.fullJid, this.id, 'mid' + transceiver.mid);
}
}
MovimJingleSession.prototype.unmute = function (track) {
const transceiver = this.resolveTransceiver(track);
if (transceiver) {
Visio_ajaxUnmute(this.fullJid, this.id, 'mid' + transceiver.mid);
} else if (track.kind == 'video') {
this.pc.addTrack(track);
}
}
MovimJingleSession.prototype.onMute = function (name) {
if (this.tracksTypes[name]) {
if (this.tracksTypes[name] == 'audio') {
this.participant.classList.add('audio_off');
}
if (this.tracksTypes[name] == 'video') {
this.participant.classList.add('video_off');
}
if (this.tracksTypes[name] == 'video_screen') {
this.participant.classList.add('screen_off');
}
}
}
MovimJingleSession.prototype.onUnmute = function (name) {
if (this.tracksTypes[name]) {
if (this.tracksTypes[name] == 'audio') {
this.participant.classList.remove('audio_off');
}
if (this.tracksTypes[name] == 'video') {
this.participant.classList.remove('video_off');
}
if (this.tracksTypes[name] == 'video_screen') {
this.participant.classList.remove('screen_off');
}
}
}
MovimJingleSession.prototype.insertDtmf = function (s) {
var rtc = this.pc.getSenders().find(rtc => rtc.track && rtc.track.kind == 'audio');
if (!rtc || !rtc.dtmf.canInsertDTMF) return;
rtc.dtmf.insertDTMF(s);
}
/**
* Detect RFC4796 content attribute
*/
MovimJingleSession.prototype.maybeDetectTracksScreen = function (sdp) {
sdp.split('m=').forEach(media => {
let content = media.match(/a=content:(.*)/);
if (content && content.includes('slides')) {
let mid = media.match(/a=mid:(.*)/);
this.tracksScreen[mid[1]] = true;
}
});
}
/**
* Inject RFC4796 content attribute to respect XEP-0507: Jingle Content Category
*/
MovimJingleSession.prototype.maybeInjectScreenCategory = function (sdp) {
if (this.audioSharingSender?.track || this.screenSharingSender?.track) {
let ids = [];
if (this.audioSharingSender) ids.push(this.audioSharingSender.track.id);
if (this.screenSharingSender) ids.push(this.screenSharingSender.track.id);
sdp = sdp.split('m=').map(media => {
let mid = media.match(MovimVisio.midRegex);
if (mid != null) {
const transceiver = this.pc.getTransceivers().find(transceiver => transceiver.mid == mid[1]);
if (transceiver) {
if (ids.includes(transceiver.sender.track.id)) {
return media + 'a=content:slides' + "\n";
}
}
}
return media;
}).join('m=');
}
return sdp;
}
var MovimJingles = {
sessions: {},
pinned: null,
startCalls: function (mujiRoom) {
for (const jid of Object.keys(MovimJingles.sessions)) {
MovimJingles.onProceed(jid, MovimJingles.sessions[jid].fullJid, MovimJingles.sessions[jid].id, mujiRoom);
}
},
initSession: function (jid, fullJid, id, name, avatarUrl) {
if (Object.keys(MovimJingles.sessions).includes(jid)) {
return;
}
if (!MovimVisio.localStream) {
throw Error('localStream is not ready');
};
MovimJingles.sessions[jid] = new MovimJingleSession(jid, fullJid, id, name, avatarUrl);
return MovimJingles.sessions[jid].id;
},
checkActiveSpeaker: function () {
let maxLevel = 0;
let maxJid = null;
for (const jid of Object.keys(MovimJingles.sessions)) {
if (maxLevel < MovimJingles.sessions[jid].audioLevel) {
maxLevel = MovimJingles.sessions[jid].audioLevel;
maxJid = jid;
}
MovimJingles.sessions[jid].participant.classList.remove('active', 'pinned');
}
// Pinned has priority
if (MovimJingles.pinned && MovimJingles.sessions[MovimJingles.pinned]) {
MovimJingles.sessions[MovimJingles.pinned].participant.classList.add('active', 'pinned');
return;
}
if (maxJid != null) {
MovimJingles.sessions[maxJid].participant.classList.add('active');
} else if (Object.values(MovimJingles.sessions).length > 0) {
Object.values(MovimJingles.sessions)[MovimVisio.sfu != null ? 1 : 0]?.participant.classList.add('active');
}
},
onManageTrack: function (stream, enable) {
for (const jid of Object.keys(MovimJingles.sessions)) {
MovimJingles.sessions[jid].onManageTrack(stream, enable);
}
},
enableScreenSharing: function () {
for (const jid of Object.keys(MovimJingles.sessions)) {
MovimJingles.sessions[jid].enableScreenSharing();
}
},
disableScreenSharing: function () {
for (const jid of Object.keys(MovimJingles.sessions)) {
MovimJingles.sessions[jid].disableScreenSharing();
}
},
enableAudio: function (enable = true) {
MovimVisio.localStream.getTracks().filter(track => track.kind == 'audio').forEach(track => {
track.enabled = enable;
for (const jid of Object.keys(MovimJingles.sessions)) {
if (enable) {
MovimJingles.sessions[jid].unmute(track);
} else {
MovimJingles.sessions[jid].mute(track);
}
}
});
},
enableVideo: function (enable = true) {
MovimVisio.mujiPublish();
MovimVisio.localStream.getTracks().filter(track => track.kind == 'video').forEach(track => {
track.enabled = enable;
for (const jid of Object.keys(MovimJingles.sessions)) {
if (enable) {
MovimJingles.sessions[jid].unmute(track);
} else {
MovimJingles.sessions[jid].mute(track);
}
}
});
},
insertDtmf: function (s) {
for (const jid of Object.keys(MovimJingles.sessions)) {
MovimJingles.sessions[jid].insertDtmf(s);
}
},
onCandidate: function (jid, candidate, mid, mlineindex, sid) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Candidate from a non initiated session ' + jid); return;
}
if (sid && sid === MovimVisio.screenshareSid) {
MovimVisio.onScreenshareCandidate(candidate, mid, mlineindex);
return;
}
MovimJingles.sessions[jid].onCandidate(candidate, mid, mlineindex);
},
onInitiateSDP: function (jid, sdp, sid) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Initiate SDP from a non initiated session ' + jid); return;
}
// Put the real sid
MovimJingles.sessions[jid].id = sid;
MovimJingles.sessions[jid].onInitiateSDP(sdp);
},
onAcceptSDP: function (jid, sdp, sid) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Accept SDP from a non initiated session ' + jid); return;
}
if (sid && sid === MovimVisio.screenshareSid) {
MovimVisio.onScreenshareAcceptSDP(sdp);
return;
}
MovimJingles.sessions[jid].onAcceptSDP(sdp);
},
onProceed: function (jid, fullJid, id, mujiRoom) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Proceed from a non initiated session ' + jid); return;
}
MovimJingles.sessions[jid].sessionInitiate(fullJid, id, mujiRoom);
},
onMute: function (jid, name) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Mute from a non initiated session ' + jid); return;
}
MovimJingles.sessions[jid].onMute(name);
},
onUnmute: function (jid, name) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Unmute from a non initiated session ' + jid); return;
}
MovimJingles.sessions[jid].onUnmute(name);
},
onContentAdd: function (jid, sdp, mid) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Content add from a non initiated session ' + jid); return;
}
MovimJingles.sessions[jid].onContentAdd(sdp, mid);
},
onContentModify: function (jid, sdp, mid) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Content modify from a non initiated session ' + jid); return;
}
MovimJingles.sessions[jid].onContentModify(sdp, mid);
},
onContentRemove: function (jid, sdp, mid) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('Content remove from a non initiated session ' + jid); return;
}
MovimJingles.sessions[jid].onContentRemove(sdp, mid);
},
onSFUScreenSharingPropose: function (jid, sdp) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('SFU screen sharing propose from a non initiated session ' + jid); return;
}
MovimJingles.sessions[jid].onSFUScreenSharingPropose(sdp);
},
onSFUScreenSharingTerminate: function (jid) {
if (MovimJingles.sessions[jid] == undefined) {
console.log('SFU screen sharing terminate from a non initiated session ' + jid); return;
}
MovimJingles.sessions[jid].onSFUScreenSharingTerminate();
},
terminate: function (jid, reason) {
if (MovimJingles.sessions[jid] == undefined) return;
let visio = document.querySelector('#visio');
MovimJingles.sessions[jid].terminate(reason, (visio.dataset.muji == 'true'));
delete MovimJingles.sessions[jid];
},
onTerminate: function (jid) {
if (MovimJingles.sessions[jid] == undefined) return;
MovimJingles.sessions[jid].close();
delete MovimJingles.sessions[jid];
let visio = document.querySelector('#visio');
// No sessions left
if (Object.keys(MovimJingles.sessions).length == 0) {
if (visio.dataset.muji == 'false') {
Visio_ajaxClear();
} else {
let state = document.querySelector('p.state');
if (state) {
state.innerText = MovimVisio.states.no_participants_left;
}
}
}
},
terminateAll: function (reason) {
for (const jid of Object.keys(MovimJingles.sessions)) {
MovimJingles.terminate(jid, reason);
}
MovimJingles.pinned = null;
Visio_ajaxClear();
}
}