@tessantech/rtc-light
Version:
Verry light package to simplify Webrtc and make a videoconference in a few lines of code.
164 lines (163 loc) • 7.01 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RTCInformation = exports.RTCReceiver = exports.RTCInitiator = exports.RTCConnection = void 0;
const external_promise_1 = require("./external-promise");
const ice_candidate_manager_1 = require("./ice-candidate-manager");
class RTCConnection {
constructor(stream, onInformation, createDataChannel = true, configuration, tricklePolicy = ice_candidate_manager_1.TricklePolicy.NONE, channels = []) {
this.tricklePolicy = tricklePolicy;
this.dataChanels = {};
if (!configuration) {
console.warn("Default configuration uses the twilio stun server : " +
RTCConnection.twilioStun +
". It may not work with complex network configuration.");
configuration = RTCConnection.defaultConfig;
}
this.peer = new RTCPeerConnection(configuration);
this.peer.addEventListener("iceconnectionstatechange", (e) => {
if (this.peer.iceConnectionState === "failed") {
console.warn("Ice failed");
if (this instanceof RTCInitiator) {
this.startOffer();
console.warn("Restart ice");
}
}
});
this.onInformation = onInformation;
const iceCandidateManager = new ice_candidate_manager_1.IceCandidateManager(this.peer, tricklePolicy, onInformation);
if (stream) {
stream.getTracks().forEach((track) => this.peer.addTrack(track, stream));
}
this.initChannels(channels);
this.subscribeChannels();
}
initChannels(channels) {
channels.forEach(chan => this.createChannel(chan));
}
createChannel(label) {
if (!!this.dataChanels[label])
return this.dataChanels[label];
const channelrdy = this.dataChanels[label] = new external_promise_1.ExternalPromise();
const channel = this.peer.createDataChannel(label);
channel.onopen = (ev) => channelrdy.resolve(channel);
return channelrdy;
}
subscribeChannels() {
this.peer.addEventListener("datachannel", ev => {
const channel = ev.channel;
const channelrdy = this.dataChanels[channel.label] || new external_promise_1.ExternalPromise();
this.dataChanels[channel.label] = channelrdy;
channel.onopen = (ev) => channelrdy.resolve(channel);
});
}
getPeer() {
return this.peer;
}
startOffer() {
return this.peer
.createOffer({
iceRestart: true,
offerToReceiveAudio: true,
offerToReceiveVideo: true,
})
.then((offer) => {
this.peer.setLocalDescription(offer);
this.onInformation(new RTCInformation("OFFER", offer));
});
}
onStream(streamReceived) {
this.peer.addEventListener("addstream", (event) => {
const stream = event.stream;
stream && streamReceived(stream);
});
}
addInformations(infos) {
switch (infos.type) {
case "ICECANDIDATE": {
const iceCandidates = Array.isArray(infos.content)
? infos.content
: [infos.content];
return Promise.all(iceCandidates.map((candidate) => this.peer.addIceCandidate(candidate))).then();
}
case "OFFER":
return this.peer
.setRemoteDescription(infos.content)
.then(() => this.peer.createAnswer())
.then((answer) => {
this.peer.setLocalDescription(answer);
this.onInformation(new RTCInformation("ANSWER", answer));
});
case "ANSWER":
return this.peer.setRemoteDescription(infos.content);
}
throw new Error(infos.type + " is not a valide information type for RTCInformation.");
}
getChannel(channel) {
this.dataChanels[channel] = this.dataChanels[channel] || new external_promise_1.ExternalPromise();
return this.dataChanels[channel];
}
send(channelName, msg) {
return __awaiter(this, void 0, void 0, function* () {
const channel = yield this.getChannel(channelName);
channel.send(msg);
return this;
});
}
onMsg(channelName, action) {
return __awaiter(this, void 0, void 0, function* () {
const channel = yield this.getChannel(channelName);
const listener = (ev) => action(ev.data);
channel.addEventListener('message', listener);
return () => channel.removeEventListener('message', listener);
});
}
}
exports.RTCConnection = RTCConnection;
RTCConnection.twilioStun = "stun:global.stun.twilio.com:3478";
RTCConnection.defaultConfig = {
iceServers: [
{
urls: RTCConnection.twilioStun,
},
],
};
class RTCInitiator extends RTCConnection {
constructor(stream, onInformation, onOfferError, configuration = {}) {
super(stream, onInformation, true, configuration.rtcConfig, configuration.tricklePolicy, configuration.channels);
this.startOffer().catch(onOfferError);
}
}
exports.RTCInitiator = RTCInitiator;
class RTCReceiver extends RTCConnection {
constructor(stream, onInformation, configuration = {}) {
super(stream, onInformation, false, configuration.rtcConfig, configuration.tricklePolicy);
}
}
exports.RTCReceiver = RTCReceiver;
class RTCInformation {
constructor(type, content) {
this.type = type;
this.content = content;
}
}
exports.RTCInformation = RTCInformation;
__exportStar(require("./ice-candidate-manager"), exports);