import {logger} from "./Logger.js" import Workers from "./Workers.js" import Heartbeat from "./Heartbeat.js" export default class Rtcp extends EventEmitter { constructor(network) { super(); this.connection = null this.inputChannel = null this.mediaStream = null this.socket = null this.connected = !1 this.candidates = [] this.isAnswered = !1 this.isFlushing = !1 this.inputReady = !1 this.workers = null this.actived = !0 this.heartbeat = null this.network = network; //this.workers = new Workers(this,new Logger("decode")), //this.workers.registerLogger(new Logger("decode")), this.workers = new Workers(this); this.workers.registerLogger(); this.workers.registerFunction("data", t=>{ this.emit("data", t) } ), this.heartbeat = new Heartbeat({ ping: t=>{ e.room.actionsHandler.echo(t) } , pong(t, r) { var n; r && t > 500 && logger.warn(`high hb value ${t}, traceId:` + r), (n = e.room.stats) == null || n.assign({ hb: t }) } }) //解决onIcecandidate 获取不了this this.onIcecandidate =this.onIcecandidate.bind(this) this.onIceStateChange =this.onIceStateChange.bind(this) this.setRemoteDescription =this.setRemoteDescription.bind(this) this.start =this.start.bind(this) this.flushCandidate = this.flushCandidate.bind(this) this.addCandidate = this.addCandidate.bind(this) this.disconnect =this.disconnect.bind(this) } onIcecandidate(e){ if (e.candidate != null) { const t = JSON.stringify(e.candidate); logger.debug(`Got ice candidate: ${t}`), this.network.socket.send({ id: "ice_candidate", data: btoa(t) }) } } onIcecandidateerror(e){ logger.error("onicecandidateerror", e.errorCode, e.errorText, e) } onIceStateChange(e){ switch (e.target.iceGatheringState) { case "gathering": logger.info("ice gathering"); break; case "complete": logger.info("Ice gathering completed") } } onIceConnectionStateChange(){ if (!!this.connection) switch (logger.info(`iceConnectionState: ${this.connection.iceConnectionState}`), this.connection.iceConnectionState) { case "connected": { this.connected = !0; break } case "disconnected": { this.connected = !1, this.emit("rtcDisconnected"); break } case "failed": { this.emit("rtcDisconnected"), this.connected = !1; break } } } async setRemoteDescription(e,t){ var a, s, l; if (!this.connection) return; const r = JSON.parse(atob(e)) , n = new RTCSessionDescription(r); await this.connection.setRemoteDescription(n); const o = await this.connection.createAnswer(); if (o.sdp = (a = o.sdp) == null ? void 0 : a.replace(/(a=fmtp:111 .*)/g, "$1;stereo=1;sprop-stereo=1"), ((l = (s = o.sdp) == null ? void 0 : s.match(/a=mid:1/g)) == null ? void 0 : l.length) == 2) { const u = o.sdp.lastIndexOf("a=mid:1"); o.sdp = o.sdp.slice(0, u) + "a=mid:2" + o.sdp.slice(u + 7) } try { await this.connection.setLocalDescription(o) } catch (u) { logger.error("error", u) } this.isAnswered = !0, this.network.rtcp.flushCandidate(), this.network.socket.send({ id: "answer", data: btoa(JSON.stringify(o)) }), t.srcObject = this.mediaStream } flushCandidate(){ this.isFlushing || !this.isAnswered || (this.isFlushing = !0, this.candidates.forEach(e=>{ const t = atob(e) , r = JSON.parse(t); if (/172\./.test(r.candidate)) return; const n = new RTCIceCandidate(r); this.connection && this.connection.addIceCandidate(n).then(()=>{} , o=>{ logger.info("add candidate failed", o) } ) } ), this.isFlushing = !1) } input(e){ var t; !this.actived || !this.inputChannel || this.inputChannel.readyState === "open" && ((t = this.inputChannel) == null || t.send(e)) } start() { this.connection = new RTCPeerConnection; const e = Date.now(); this.connection.ondatachannel = t=>{ logger.info(`ondatachannel: ${t.channel.label}`); this.inputChannel = t.channel; this.inputChannel.onopen = ()=>{ var r; logger.info("The input channel has opened, id:", (r = this.inputChannel) == null ? void 0 : r.id), this.inputReady = !0, this.emit("rtcConnected"), this.network.room.currentNetworkOptions.reconnect || (logger.infoAndReportMeasurement({ metric: "datachannelOpenedAt", startTime: this.network.room._startTime, group: "joinRoom" }), logger.infoAndReportMeasurement({ metric: "datachannelOpenedCost", startTime: e, group: "joinRoom" })) } , this.inputChannel.onclose = ()=>{ var r; return logger.info("The input channel has closed, id:", (r = this.inputChannel) == null ? void 0 : r.id) } , this.inputChannel.onmessage = r=>{ this.workers.dataHandle(r.data) } } , this.connection.oniceconnectionstatechange = this.onIceConnectionStateChange, this.connection.onicegatheringstatechange = this.onIceStateChange, this.connection.onicecandidate = this.onIcecandidate, this.connection.onicecandidateerror = this.onIcecandidateerror, this.network.socket.send({ id: "init_webrtc", data: JSON.stringify({ is_mobile: !0 }) }) } addCandidate(e) { e === "" ? this.network.rtcp.flushCandidate() : this.candidates.push(e) } disconnect() { var e, t, r; this.heartbeat.stop(), logger.info("ready to close datachannel, id", (e = this.inputChannel) == null ? void 0 : e.id), (t = this.inputChannel) == null || t.close(), (r = this.connection) == null || r.close(), this.connection = null, this.inputChannel = null } sendStringData(e) { console.log('e',e) this.input(e) } sendData(e) { let t = ""; try { t = JSON.stringify(e) } catch (r) { logger.error(r); return } this.input(t) } }