UNPKG

@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
"use strict"; 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);