304 lines
9.9 KiB
JavaScript
304 lines
9.9 KiB
JavaScript
/************************************************************************
|
|
Copyright (C) Ayushya Amitabh - All Rights Reserved
|
|
Unauthorized copying of this file, via any medium is strictly prohibited
|
|
Proprietary and confidential
|
|
Written by Ayushya Amitabh <admin@chromewatchparty.com>, 2020 - 2022
|
|
https://www.chromewatchparty.com/copyright
|
|
=========================================================================
|
|
ALL CONTENT ON WATCH PARTY'S WEBSITE OR IN WATCH PARTY'S CHROME EXTENSION APP, UNLESS OTHERWISE
|
|
CITED ARE THE SOLE INTELLECTUAL PROPERTY OF AYUSHYA AMITABH, AND MAY NOT BE
|
|
COPIED, EDITED, OR REPRODUCED WITHOUT PERMISSION.
|
|
************************************************************************/
|
|
import VoxeetSDK from "@voxeet/voxeet-web-sdk";
|
|
import {
|
|
GetVoxeetTokenApi,
|
|
GetRefreshedVoxeetTokenApi,
|
|
LocalData,
|
|
UpdateVoxeetApi,
|
|
updateLocalData,
|
|
} from "./Api";
|
|
|
|
export default class CallManager {
|
|
constructor(listener, notify) {
|
|
this.listener = listener;
|
|
this.notify = notify;
|
|
this.__refreshToken = LocalData().vaT;
|
|
this.__accessToken = LocalData().vrT;
|
|
this.__sessionInitialized = false;
|
|
this.__admin = false;
|
|
this.__adminOnly = true;
|
|
this.__useVideo = false;
|
|
}
|
|
toggleCall(onCall, conference, admin, adminOnly, useVideo) {
|
|
try {
|
|
this.listener({ callActionPending: true });
|
|
this.__admin = admin;
|
|
this.__adminOnly = adminOnly;
|
|
this.__useVideo = useVideo;
|
|
if (onCall === true) this.leaveCall();
|
|
else this.boot(conference, useVideo);
|
|
} catch (e) {
|
|
this.notify("Uh oh something went wrong, try rejoining the call.");
|
|
}
|
|
}
|
|
toggleMute(muted) {
|
|
this.listener({ callActionPending: true });
|
|
VoxeetSDK.conference.mute(VoxeetSDK.session.participant, !muted);
|
|
this.listener({ muted: !muted, callActionPending: false });
|
|
}
|
|
toggleVideo(useVideo) {
|
|
if (useVideo === true) {
|
|
VoxeetSDK.conference
|
|
.startVideo(VoxeetSDK.session.participant)
|
|
.then(() => {
|
|
this.listener({ usingVideo: useVideo });
|
|
});
|
|
} else {
|
|
VoxeetSDK.conference.stopVideo(VoxeetSDK.session.participant).then(() => {
|
|
this.listener({ usingVideo: useVideo });
|
|
});
|
|
}
|
|
}
|
|
async boot(conference, useVideo) {
|
|
await this.initialize();
|
|
const opened = await this.openSession();
|
|
if (opened && conference) {
|
|
await VoxeetSDK.conference
|
|
.fetch(conference._id)
|
|
.then((c) => this.joinCall(c, useVideo))
|
|
.catch((err) => {
|
|
console.error("Failed to fetch conference", err);
|
|
this.startCall(useVideo);
|
|
});
|
|
} else if (opened && !conference) {
|
|
this.startCall(useVideo);
|
|
} else {
|
|
this.listener({ onCall: false, muted: false, callActionPending: false });
|
|
console.error("Unable to open Voxeet Session");
|
|
}
|
|
}
|
|
async startCall(useVideo) {
|
|
if (!this.__adminOnly || (this.__adminOnly && this.__admin)) {
|
|
VoxeetSDK.conference
|
|
.create({
|
|
alias: `AUTODELETE_${LocalData().partyName}`,
|
|
pin: LocalData().partyPin,
|
|
})
|
|
.then(async (conference) => {
|
|
const updatedVoxeet = await UpdateVoxeetApi({
|
|
conference,
|
|
partyName: LocalData().partyName,
|
|
partyPin: LocalData().partyPin,
|
|
userName: LocalData().userName,
|
|
})
|
|
.then((res) => res.json())
|
|
.then((res) => res.status <= 299)
|
|
.catch((err) => {
|
|
if (err.conference) {
|
|
this.joinCall(err.conference, useVideo);
|
|
return true;
|
|
} else {
|
|
this.notify(err.message);
|
|
this.listener({
|
|
onCall: false,
|
|
muted: false,
|
|
callActionPending: false,
|
|
usingVideo: false,
|
|
});
|
|
console.error("Update Voxeet API Error", err);
|
|
return false;
|
|
}
|
|
});
|
|
if (updatedVoxeet === true) {
|
|
this.joinCall(conference, useVideo);
|
|
} else {
|
|
this.listener({
|
|
onCall: false,
|
|
muted: false,
|
|
callActionPending: false,
|
|
usingVideo: false,
|
|
});
|
|
console.error("Failed to update party Voxeet");
|
|
}
|
|
});
|
|
} else {
|
|
this.notify("Ask your party admin to start the call.");
|
|
this.leaveCall();
|
|
}
|
|
}
|
|
async joinCall(conference, useVideo) {
|
|
const joined = await VoxeetSDK.conference
|
|
.join(conference, { constraints: { audio: true, video: useVideo } })
|
|
.then(() => true)
|
|
.catch((e) => {
|
|
this.listener({
|
|
onCall: false,
|
|
muted: false,
|
|
callActionPending: false,
|
|
usingVideo: false,
|
|
});
|
|
this.notify("Unable to join call. Try again in a moment.");
|
|
console.error("Error joining call", e);
|
|
return false;
|
|
});
|
|
if (joined === true) {
|
|
this.listener({ usingVideo: useVideo });
|
|
}
|
|
// Leave changes as comment for later
|
|
// if (!joined) {
|
|
// this.startCall(useVideo);
|
|
// }
|
|
}
|
|
async leaveCall() {
|
|
VoxeetSDK.conference.leave().then(() => {
|
|
VoxeetSDK.session.close();
|
|
this.listener({
|
|
onCall: false,
|
|
muted: false,
|
|
callActionPending: false,
|
|
usingVideo: false,
|
|
conference: null,
|
|
});
|
|
});
|
|
}
|
|
async openSession() {
|
|
if (!this.__sessionInitialized) {
|
|
try {
|
|
await VoxeetSDK.session.open({
|
|
externalId: LocalData().userUid,
|
|
name: LocalData().userName,
|
|
});
|
|
return true;
|
|
} catch (error) {
|
|
console.error("Error Opening Voxeet Session", error);
|
|
}
|
|
console.error("Session not initialized");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
async initialize() {
|
|
VoxeetSDK.conference.on("joined", () => {
|
|
this.listener({
|
|
onCall: true,
|
|
callActionPending: false,
|
|
usingVideo: this.__useVideo,
|
|
});
|
|
});
|
|
|
|
VoxeetSDK.conference.on("left", () => {
|
|
this.listener({
|
|
onCall: false,
|
|
callActionPending: false,
|
|
usersOnCall: {},
|
|
usingVideo: false,
|
|
});
|
|
});
|
|
|
|
VoxeetSDK.conference.on("streamAdded", (participant, stream) => {
|
|
this.listener({ callActionPending: true });
|
|
const vid = "video#" + CSS.escape(participant.id);
|
|
if (!document.querySelector(vid)) {
|
|
const vidNode = document.createElement("video");
|
|
vidNode.id = participant.id;
|
|
vidNode.muted = true;
|
|
vidNode.srcObject = stream;
|
|
vidNode.onloadedmetadata = vidNode.play;
|
|
|
|
const vidContainerNode = document.createElement("div");
|
|
vidContainerNode.classList.add("vxt-video");
|
|
vidContainerNode.setAttribute("data-id", participant.id);
|
|
vidContainerNode.setAttribute("data-name", participant.info.name || "");
|
|
vidContainerNode.appendChild(vidNode);
|
|
|
|
if (participant.info.externalId !== LocalData().userUid) {
|
|
const volSliderNode = document.createElement("input");
|
|
volSliderNode.setAttribute("type", "range");
|
|
volSliderNode.min = "0";
|
|
volSliderNode.max = "1";
|
|
volSliderNode.value = "1";
|
|
volSliderNode.step = "0.1";
|
|
volSliderNode.id = "vxt-slider-" + participant.id;
|
|
volSliderNode.classList.add("vxt-slider");
|
|
volSliderNode.onchange = (e) => {
|
|
const v = e.target.value;
|
|
const audioOuts = document.querySelectorAll("audio.vxt-audio");
|
|
if (audioOuts.length > 0) {
|
|
audioOuts.forEach((el) => {
|
|
if (el.id === `audio-${participant.id}`) {
|
|
el.volume = v;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
vidContainerNode.appendChild(volSliderNode);
|
|
}
|
|
|
|
document
|
|
.querySelector(".vxt-video-container")
|
|
.appendChild(vidContainerNode);
|
|
}
|
|
this.listener({ callActionPending: false });
|
|
});
|
|
|
|
VoxeetSDK.conference.on("streamRemoved", (participant, stream) => {
|
|
const vcid = ".vxt-video[data-id='" + CSS.escape(participant.id) + "']";
|
|
const vid = "video#" + CSS.escape(participant.id);
|
|
if (document.querySelector(vcid)) {
|
|
document
|
|
.querySelector(vid)
|
|
.srcObject.getTracks()
|
|
.forEach((track) => {
|
|
track.stop();
|
|
});
|
|
document.querySelector(vcid).remove();
|
|
}
|
|
this.listener({ callActionPending: false });
|
|
});
|
|
|
|
if (
|
|
this.__accessToken !== undefined ||
|
|
this.__refreshToken !== undefined ||
|
|
this.__accessToken !== null ||
|
|
this.__refreshToken !== null
|
|
) {
|
|
await GetVoxeetTokenApi({ partyName: LocalData().partyName })
|
|
.then((res) => res.json())
|
|
.then(async (tokenResult) => {
|
|
if (tokenResult.status <= 299) {
|
|
const { access_token, refresh_token } = tokenResult;
|
|
this.updateTokens(access_token, refresh_token);
|
|
await VoxeetSDK.initializeToken(access_token, refresh_token);
|
|
} else {
|
|
console.error("Get Voxeet Token API Result Error", tokenResult);
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.error("Get Voxeet Token API error", err);
|
|
});
|
|
} else {
|
|
await VoxeetSDK.initializeToken(this.__accessToken, this.__refreshToken);
|
|
}
|
|
}
|
|
async refreshToken() {
|
|
return new Promise((resolve, reject) => {
|
|
GetRefreshedVoxeetTokenApi({ token: this.__refreshToken })
|
|
.then((res) => res.json())
|
|
.then((tokenResult) => {
|
|
const { access_token, refresh_token } = tokenResult;
|
|
this.updateTokens(access_token, refresh_token);
|
|
resolve(access_token);
|
|
})
|
|
.catch((err) => {
|
|
console.error("Get Voxeet Token API error", err);
|
|
reject(err);
|
|
});
|
|
});
|
|
}
|
|
updateTokens(aT, rT) {
|
|
this.__accessToken = aT;
|
|
this.__refreshToken = rT;
|
|
updateLocalData({ vaT: aT, vrT: rT });
|
|
}
|
|
}
|