UNPKG

electron-window-rtc

Version:

Exchange media streams between Electron windows with WebRTC.

241 lines (240 loc) 7.74 kB
var p = Object.defineProperty; var w = (s, i, e) => i in s ? p(s, i, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[i] = e; var h = (s, i, e) => w(s, typeof i != "symbol" ? i + "" : i, e); var a = /* @__PURE__ */ ((s) => (s.Log = "electron-window-rtc:log", s.Signal = "electron-window-rtc:signal", s.GetOwnWindowName = "electron-window-rtc:registered-window:own-name", s.GetRegisteredWindows = "electron-window-rtc:registered-windows:get", s))(a || {}); class m { constructor() { h(this, "listeners", {}); } dispose() { for (const i in this.listeners) this.listeners[i].length = 0; } on(i, e) { this.listeners[i] || (this.listeners[i] = []), this.listeners[i].push(e); } off(i, e) { if (this.listeners[i]) { if (e) { const t = this.listeners[i].indexOf(e); t >= 0 && this.listeners[i].splice(t, 1); return; } delete this.listeners[i]; } } emit(i, e) { if (this.listeners["*"]) for (const t of this.listeners["*"]) t({ channel: i, ...e }); if (this.listeners[i]) for (const t of this.listeners[i]) t(e); } } let o; const S = (s) => { o = s; }; class g extends m { constructor(e, t) { super(); h(this, "connection"); h(this, "senderStream"); h(this, "_signalCallback"); this.name = e, this.peer = t, this.connection = new RTCPeerConnection(), this._signalCallback = this.signalCallback.bind(this), o.on(a.Signal, this._signalCallback), this.connection.onicecandidate = async (n) => { if (n.candidate) { const c = await o.invoke(a.Signal, { channel: "candidate", sender: this.name, receiver: this.peer, payload: JSON.stringify(n.candidate) }); c && this.dispatch("error", c), this.dispatch("icecandidate", n); } }, this.connection.oniceconnectionstatechange = async (n) => { (this.connection.iceConnectionState === "failed" || this.connection.iceConnectionState === "disconnected") && this.connection.restartIce(), this.dispatch("iceconnectionstatechange", n); }, this.connection.onicecandidateerror = (n) => { this.dispatch("icecandidateerror", n); }, this.connection.onicegatheringstatechange = async (n) => { this.dispatch("icegatheringstatechange", n); }, this.connection.onnegotiationneeded = async (n) => { this.dispatch("negotiationneeded", n); }, this.connection.onsignalingstatechange = (n) => { this.dispatch("signalingstatechange", n); }, this.connection.ontrack = (n) => { this.dispatch("track", n); }; } static async with(e) { if (!o) throw new Error( "Ipc functions are not defined. Call 'defineIpc' method early." ); const t = e.trim(); if (!(await o.invoke(a.GetRegisteredWindows)).includes(e)) throw new Error(`Peer window with name '${e}' was not registered.`); const c = await o.invoke(a.GetOwnWindowName); if (!c) throw new Error( "Unable to get own registered window name. Window may not have been properly registered." ); return new g(c, t); } dispose() { o.invoke(a.Signal, { channel: "peer-left", sender: this.name, receiver: this.peer, payload: void 0 }).then((t) => { t && this.dispatch("error", t); }), this.dispatch("leave"); const e = this.connection.getSenders(); for (const t of e) t.track && (t.track.enabled = !1, this.connection.removeTrack(t)); o.removeListener(a.Signal, this._signalCallback), this.removeWebRTCListeners(), this.connection.close(), super.dispose(); } /* public async addTrack( track: MediaStreamTrack, constraints?: MediaTrackConstraints ): Promise<void> { if (constraints) { track.applyConstraints(constraints); } } */ async addStream(e, t = { audio: 5e3, video: 5e3 }) { this.senderStream || (this.senderStream = new MediaStream()); for (const r of e.getTracks()) this.connection.addTrack(r, this.senderStream); const n = await this.connection.createOffer(); this.connection.setLocalDescription(n); const c = this.connection.getSenders(); for (const r of c) if (r.track) { if (t.video && r.track.kind === "video") { const d = r.getParameters(); for (const l of d.encodings) l.maxBitrate = /* Kbps */ t.video * /* Mbps */ 1e3; r.setParameters(d); continue; } if (t.audio && r.track.kind === "audio") { const d = r.getParameters(); for (const l of d.encodings) l.maxBitrate = /* Kbps */ t.audio * /* Mbps */ 1e3; r.setParameters(d); continue; } } const f = await o.invoke(a.Signal, { channel: "offer", sender: this.name, receiver: this.peer, payload: JSON.stringify(n) }); f && this.dispatch("error", f), this.dispatch("sent-offer", n); } async requestOffer() { const e = await o.invoke(a.Signal, { channel: "request-offer", sender: this.name, receiver: this.peer }); e && this.dispatch("error", e), this.dispatch("request-offer"); } get stream() { return this.senderStream; } async signalCallback(e, t) { switch (t.channel) { case "request-offer": { const n = await this.connection.createOffer(); this.connection.setLocalDescription(n); const c = await o.invoke(a.Signal, { channel: "offer", sender: this.name, receiver: this.peer, payload: JSON.stringify(n) }); c && this.dispatch("error", c), this.emit("sent-offer", { local: this.name, remote: this.peer, payload: n }); break; } case "offer": { const n = JSON.parse(t.payload); await this.handleOffer(n); break; } case "answer": { const n = JSON.parse(t.payload); this.handleAnswer(n); break; } case "candidate": { const n = JSON.parse(t.payload); this.handleCandidate(n); break; } case "peer-left": { t.sender === this.peer && this.handleLeave(); break; } } } async handleOffer(e) { if (this.connection.signalingState === "closed") return; this.connection.setRemoteDescription(e); let t = await this.connection.createAnswer(); await this.connection.setLocalDescription(t); const n = await o.invoke(a.Signal, { channel: "answer", sender: this.name, receiver: this.peer, payload: JSON.stringify(this.connection.localDescription) }); n && this.dispatch("error", n), this.dispatch("received-offer", { offer: e, answer: t }); } handleAnswer(e) { this.connection.signalingState === "closed" || this.connection.signalingState === "stable" || (this.connection.setRemoteDescription(e), this.dispatch("received-answer", e)); } handleCandidate(e) { this.connection.iceConnectionState !== "closed" && (this.connection.addIceCandidate(e), this.dispatch("received-candidate", e)); } handleLeave() { this.dispatch("peer-left"); } removeWebRTCListeners() { this.connection.close(), this.connection.onicecandidate = null, this.connection.onicecandidateerror = null, this.connection.oniceconnectionstatechange = null, this.connection.ontrack = null; } dispatch(e, t) { this.emit(e, { local: this.name, remote: this.peer, payload: t }); } } export { g as WindowRTCPeerConnection, S as defineIpc };