video-auth-js-sdk
Version:
A SDK to authenticate users with camera through a realtime stream
252 lines (235 loc) • 9.73 kB
JavaScript
import {errorList} from "../errorHandler";
import {WebrtcPeerConnection} from "./webrtcPeer";
import Utility from "../utility/utility";
function CallTopicManager(
{
app,
callId, topic, mediaType, direction, deviceManager, isScreenShare,
onHTMLElement, onPeerConnect
}) {
const config = {
callId,
state: 0, //0: disconnected, 1: connecting, 2: failed, 3: connected, 4: disconnected
peer: null,
topic,
mediaType,
direction,
isScreenShare,
sdpOfferRequestSent: false,
htmlElement: null,
isDestroyed: false,
dataStream: null,
statusEventsInterval: null,
audioObject: null,
alreadyAddedStreamTrackToElement: false
};
const peerStates = {
DISCONNECTED: 0,
CONNECTING: 1,
FAILED: 3,
CONNECTED: 4
};
const publicized = {
setPeerState(state) {
config.state = state;
},
setIsScreenShare() {
config.isScreenShare = true;
},
setDirection(direction) {
config.direction = direction;
},
getPeer() {
return config.peer;
},
isPeerConnecting() {
return config.state === peerStates.CONNECTING;
},
isPeerFailed() {
return config.state === peerStates.FAILED;
},
isPeerConnected() {
return config.state === peerStates.CONNECTED;
},
isPeerDisconnected() {
return config.state === peerStates.DISCONNECTED;
},
createTopic() {
let manager = this;
if (config.peer) {
return;
}
this.generateSdpOfferOptions().then(options => {
console.debug("[SDK][generateSdpOfferOptions] Options for this request have been resolved: ", {options}, "topic: ", config.topic, "direction: ", config.direction);
manager.establishPeerConnection(options);
}).catch(error => {
console.error(error)
});
},
generateSdpOfferOptions() {
return new Promise((resolve, reject) => {
let options = {
configuration: {
iceServers: app.authSessionInfo.turnsList
}
};
options.stream = app.store.localCameraStream;
resolve(options);
console.log("[SDK][getSdpOfferOptions] ", "topic: ", config.topic, "mediaType: ", config.mediaType, "direction: ", config.direction, "options: ", options);
});
},
establishPeerConnection(options) {
let manager = this;
config.state = peerStates.CONNECTING;
config.peer = new WebrtcPeerConnection({
callId: config.callId,
direction: config.direction,
mediaType: config.mediaType,
stream: options.stream,
rtcPeerConfig: options.configuration,
connectionStateChange: publicized.onConnectionStateChange,
iceConnectionStateChange: publicized.onIceConnectionStateChange,
}, function (err) {
if (err) {
let errorString = "[SDK][start/webRtc Peer] Error: " + err;
console.error(errorString);
app.publicCallbacks.onError({
code: errorList.FAILED_TO_OPEN_PEER.code,
message: errorString
});
return;
}
config.peer.generateOffer((err, sdpOffer) => {
// app.sdkParams.consoleLogging && console.debug("[SDK][establishPeerConnection][generateOffer] GenerateOffer:: ", " sdpOffer: ", sdpOffer, " err: ", err);
if (err) {
let errorString = "[SDK][start/WebRtc Peer/generateOffer] " + err;
console.error(errorString);
app.publicCallbacks.onError({
code: errorList.FAILED_TO_OPEN_PEER.code,
message: errorString
});
return;
}
if (!config.sdpOfferRequestSent) {
config.sdpOfferRequestSent = true;
manager.sendSDPOfferRequestMessage(sdpOffer, 1);
}
});
});
},
onConnectionStateChange() {
if (!config.peer || publicized.isDestroyed()) {
return; //avoid log errors
}
console.log("[SDK][peerConnection.onconnectionstatechange] ", "peer: ", config.topic, " peerConnection.connectionState: ", config.peer.peerConnection.connectionState);
if (config.peer.peerConnection.connectionState === "failed") {
if (publicized.isPeerFailed() || publicized.isDestroyed())
return;
config.state = peerStates.FAILED;
app.publicCallbacks.onDebug({
type: 'CALL_STATUS',
message: `Stream Peer (${config.topic}) has failed!`,
});
app.publicCallbacks.onError(errorList.PEER_FAILED);
}
if (config.peer.peerConnection.connectionState === 'connected') {
config.state = peerStates.CONNECTED;
onPeerConnect && onPeerConnect()
onPeerConnect = null;
}
},
onIceConnectionStateChange() {
if (!config.peer || publicized.isDestroyed()) {
return; //avoid log errors
}
console.log("[SDK][oniceconnectionstatechange] ", "peer: ", config.topic, " peerConnection.connectionState: ", config.peer.peerConnection.iceConnectionState);
if (config.peer.peerConnection.iceConnectionState === 'disconnected') {
config.state = peerStates.DISCONNECTED;
app.publicCallbacks.onDebug({
type: 'CALL_STATUS',
message: `Stream Peer (${config.topic}) is disconnected!`,
errorInfo: config.peer
});
}
if (config.peer.peerConnection.iceConnectionState === "failed") {
if (publicized.isPeerFailed() || publicized.isDestroyed())
return;
config.state = peerStates.FAILED;
app.publicCallbacks.onDebug({
type: 'CALL_STATUS',
message: `Stream Peer (${config.topic}) ice has failed!`
});
app.publicCallbacks.onError(errorList.PEER_FAILED);
}
if (config.peer.peerConnection.iceConnectionState === "connected") {
config.state = peerStates.CONNECTED;
onPeerConnect && onPeerConnect()
onPeerConnect = null;
app.publicCallbacks.onDebug({
type: 'CALL_STATUS',
message: `Stream Peer (${config.topic}) ice has connected!`,
});
}
},
sendSDPOfferRequestMessage(sdpOffer, retries) {
app.messenger.sendCallMessage({
id: 'SEND_SDP_OFFER',
sdpOffer: sdpOffer,
useComedia: true,
useSrtp: false,
topic: config.topic,
mediaType: 2,
chatId: app.authSessionInfo.callId
}, null, 4000, function (result) {
if (result.done === 'FALSE' && retries > 0) {
retries -= 1;
publicized.sendSDPOfferRequestMessage(sdpOffer);
}
});
},
stopTopicOnServer() {
return new Promise(resolve => {
app.messenger.sendCallMessage({
id: 'STOP',
topic: config.topic,
chatId: app.authSessionInfo.callId
}, function (result) {
if (result.done === 'TRUE' || result.done === 'SKIP') {
// manager.reconnectTopic();
resolve()
} else {
console.warn("[SDK] SDK tried to stop the topic but failed.", config.topic)
}
}, {});
})
},
async removeTopic() {
let manager = this;
app.messenger.sendCallMessage({
id: 'CLOSE',
}, null, {});
if (config.peer) {
config.peer.dispose();
config.peer = null;
config.state = peerStates.DISCONNECTED;
}
},
updateStream(stream) {
config.dataStream = stream;
config.peer.updateStream(stream);
},
stopStatusPrint() {
config.statusEventsInterval && clearInterval(config.statusEventsInterval);
},
isDestroyed() {
return config.isDestroyed;
},
async destroy() {
config.isDestroyed = true;
// publicized.removeStreamHTML();
await publicized.removeTopic();
}
}
return publicized
}
export {CallTopicManager}