@virusonic/react-native-sdk
Version:
234 lines (204 loc) • 7.3 kB
JavaScript
var Constants = require('../util/datatype');
const RTCPeerConnection = require('../dependencies').RTCPeerConnection;
const RTCSessionDescription = require('../dependencies').RTCSessionDescription;
const RTCIceCandidate = require('../dependencies').RTCIceCandidate;
function WebRTCWorker(options, isVideo, isAudio) {
EventBus.apply(this, arguments);
var me = this;
me._options = options;
me._connectionState = Constants.ConnectionState.new;
me._waitAnswer = false;
me._remoteNewSDPInfo = false;
me.pcConfig = {
iceServers: _prepareIceServers([...options.STUN_SERVERS, ...options.TURN_SERVERS])
};
me._iceCandidates = [];
me._destroyed = false;
console.log("PC CONFIG", me.pcConfig);
me._pc = new RTCPeerConnection(me.pcConfig);
me._pc.addEventListener('icecandidate', event => {
if (me._destroyed) {
return;
}
if (event.candidate) {
me.post(Constants.WorkerEvent.iceCandidate, [event.candidate]);
}
});
me._pc.addEventListener("track", (event) => {
if (me._destroyed) {
return;
}
me.post(Constants.WorkerEvent.onTrack, [event]);
});
me._pc.addEventListener("iceconnectionstatechange", (ev) => {
if (me._destroyed) {
return;
}
switch (me._pc.iceConnectionState) {
case 'checking':
me._connectionState = Constants.ConnectionState.connecting;
break;
case 'connected':
me._connectionState = Constants.ConnectionState.connected;
break;
case 'completed':
me._connectionState = Constants.ConnectionState.completed;
break;
case 'failed':
me._connectionState = Constants.ConnectionState.failed;
break;
case 'disconnected':
me._connectionState = Constants.ConnectionState.disconnected;
break;
default:
break;
}
me.post(Constants.WorkerEvent.connectionState, [me._connectionState]);
});
me._pc.addEventListener("signalingstatechange", (ev) => {
if (me._destroyed) {
return;
}
if (me._pc.signalingState === 'stable' && me._iceCandidates.length > 0) {
me._iceCandidates.forEach(ic => {
me.addIceCandidate(ic);
})
me._iceCandidates = [];
}
});
me._localSessionInfo = null;
me._remoteSessionInfo = null;
}
WebRTCWorker.prototype = Object.create(EventBus.prototype);
WebRTCWorker.prototype.constructor = WebRTCWorker;
WebRTCWorker.prototype.startConnectivity = function (stream) {
var me = this;
if (stream) {
//todo warning if stream already exist
me._stream = stream;
}
if (me._remoteNewSDPInfo) {
me._remoteNewSDPInfo = false;
// change connectionState for waitConnectivity return false
me._connectionState = Constants.ConnectionState.connecting;
if (Constants.SessionInfoType.offer === me._remoteSessionInfo.sdpInfo.type) {
return me.createAnswer(me._stream);
} else {
//todo add check if wee receive answer, but offer does not created - create offer
return Promise.resolve();
}
} else if (!me._waitAnswer) {
return me.createOffer(me._stream);
}
};
WebRTCWorker.prototype.waitConnectivity = function() {
var me = this;
console.log("AAAA", me._remoteNewSDPInfo, me._connectionState === Constants.ConnectionState.new, !me._waitAnswer);
return me._remoteNewSDPInfo || (me._connectionState === Constants.ConnectionState.new && !me._waitAnswer);
};
WebRTCWorker.prototype.setRemoteSessionInfo = function (sessionInfo) {
var me = this;
me._remoteSessionInfo = sessionInfo;
me._remoteNewSDPInfo = true;
me._waitAnswer = false;
if (me._remoteSessionInfo.tracksInfo) {
me.post(Constants.WorkerEvent.trackInfo, [me._remoteSessionInfo.tracksInfo]);
}
return me._pc.setRemoteDescription(new RTCSessionDescription(me._remoteSessionInfo.sdpInfo)).then(() => {
if (sessionInfo.extraSDPInfo) {
me.addExtraSdpInfo(sessionInfo.extraSDPInfo);
}
});
};
WebRTCWorker.prototype.addExtraSdpInfo = function (extraSDPInfo) {
var me = this;
extraSDPInfo.iceCandidates.forEach(ic => {
if (me._pc.signalingState === 'stable') {
me.addIceCandidate(ic);
} else {
me._iceCandidates.push(ic);
}
})
};
WebRTCWorker.prototype.destroy = function (msg) {
var me = this;
if (me._pc) {
me._pc.close();
}
me._destroyed = true;
};
WebRTCWorker.prototype.createOffer = function (stream) {
var me = this;
if (me._pc !== null) {
stream.getTracks().forEach(track => {
me._pc.addTrack(track);
});
return me._pc.createOffer({
optional: [],
mandatory: {OfferToReceiveAudio: true, OfferToReceiveVideo: true}
})
.then(sdpInfo => {
let localSessionInfo = me.gotLocalDescription(sdpInfo);
me._waitAnswer = true;
return localSessionInfo;
});
}
};
WebRTCWorker.prototype.createAnswer = function (stream) {
var me = this;
if (me._pc !== null) {
stream.getTracks().forEach(track => {
me._pc.addTrack(track, stream);
});
return me._pc.createAnswer({mandatory: {OfferToReceiveAudio: true, OfferToReceiveVideo: true}})
.then(sdpInfo => {
let localSessionInfo = me.gotLocalDescription(sdpInfo);
return localSessionInfo;
});
}
};
WebRTCWorker.prototype.gotLocalDescription = function (sdpInfo) {
var me = this;
me._pc.setLocalDescription(sdpInfo);
me._localSessionInfo = {sdpInfo: sdpInfo};
if (me._stream) {
me._localSessionInfo.tracksInfo = [];
me._stream.getTracks().forEach(track => {
const trackInfo = {id: track.id, type: track.kind, enabled: track.enabled};
me._localSessionInfo.tracksInfo.push(trackInfo);
});
}
return me._localSessionInfo;
};
WebRTCWorker.prototype.addIceCandidate = function (iceCandidate) {
var me = this;
me._pc.addIceCandidate(new RTCIceCandidate(iceCandidate),
() => {
},
error => {
console.log("Error on 'addIceCandidate': " + error);
});
}
function _prepareIceServers(iceServers) {
const iceServersCopy = cloneObject(iceServers);
Object.keys(iceServersCopy).forEach((c, i, a) => {
if (iceServersCopy[i].hasOwnProperty('url')) {
iceServersCopy[i].urls = iceServersCopy[i].url;
} else {
iceServersCopy[i].url = iceServersCopy[i].urls;
}
});
return iceServersCopy;
}
function cloneObject(obj = {}, escapeNull = false) {
try {
const json = JSON.stringify(obj)
const jsonObject = escapeNull
? json.replace(/null/g, "\"\"")
: json
return JSON.parse(jsonObject)
} catch (error) {
return obj
}
}
module.exports = WebRTCWorker;