@networked-aframe/naf-janus-adapter
Advanced tools
Comparing version 4.2.0 to 4.3.0
@@ -1,2 +0,2 @@ | ||
(()=>{var e={734:e=>{function t(e){this.session=e,this.id=void 0}function n(e,t){this.output=e,this.id=void 0,this.nextTxId=0,this.txns={},this.eventHandlers={},this.options=Object.assign({verbose:!1,timeoutMs:1e4,keepaliveMs:3e4},t)}t.prototype.attach=function(e,t){var n={plugin:e,loop_index:t,"force-bundle":!0,"force-rtcp-mux":!0};return this.session.send("attach",n).then((e=>(this.id=e.data.id,e)))},t.prototype.detach=function(){return this.send("detach")},t.prototype.on=function(e,t){return this.session.on(e,(e=>{e.sender==this.id&&t(e)}))},t.prototype.send=function(e,t){return this.session.send(e,Object.assign({handle_id:this.id},t))},t.prototype.sendMessage=function(e){return this.send("message",{body:e})},t.prototype.sendJsep=function(e){return this.send("message",{body:{},jsep:e})},t.prototype.sendTrickle=function(e){return this.send("trickle",{candidate:e})},n.prototype.create=function(){return this.send("create").then((e=>(this.id=e.data.id,e)))},n.prototype.destroy=function(){return this.send("destroy").then((e=>(this.dispose(),e)))},n.prototype.dispose=function(){for(var e in this._killKeepalive(),this.eventHandlers={},this.txns)if(this.txns.hasOwnProperty(e)){var t=this.txns[e];clearTimeout(t.timeout),t.reject(new Error("Janus session was disposed.")),delete this.txns[e]}},n.prototype.isError=function(e){return"error"===e.janus},n.prototype.on=function(e,t){var n=this.eventHandlers[e];null==n&&(n=this.eventHandlers[e]=[]),n.push(t)},n.prototype.receive=function(e){this.options.verbose&&this._logIncoming(e),e.session_id!=this.id&&console.warn("Incorrect session ID received in Janus signalling message: was "+e.session_id+", expected "+this.id+".");var t=e.janus,n=this.eventHandlers[t];if(null!=n)for(var s=0;s<n.length;s++)n[s](e);if(null!=e.transaction){var i=this.txns[e.transaction];if(null==i)return;if("ack"===t&&"message"==i.type)return;clearTimeout(i.timeout),delete this.txns[e.transaction],(this.isError(e)?i.reject:i.resolve)(e)}},n.prototype.send=function(e,t){return t=Object.assign({transaction:(this.nextTxId++).toString()},t),new Promise(((n,s)=>{var i=null;this.options.timeoutMs&&(i=setTimeout((()=>{delete this.txns[t.transaction],s(new Error("Signalling transaction with txid "+t.transaction+" timed out."))}),this.options.timeoutMs)),this.txns[t.transaction]={resolve:n,reject:s,timeout:i,type:e},this._transmit(e,t)}))},n.prototype._transmit=function(e,t){t=Object.assign({janus:e},t),null!=this.id&&(t=Object.assign({session_id:this.id},t)),this.options.verbose&&this._logOutgoing(t),this.output(JSON.stringify(t)),this._resetKeepalive()},n.prototype._logOutgoing=function(e){var t=e.janus;"message"===t&&e.jsep&&(t=e.jsep.type);var n="> Outgoing Janus "+(t||"signal")+" (#"+e.transaction+"): ";console.debug("%c"+n,"color: #040",e)},n.prototype._logIncoming=function(e){var t=e.janus,n=e.transaction?"< Incoming Janus "+(t||"signal")+" (#"+e.transaction+"): ":"< Incoming Janus "+(t||"signal")+": ";console.debug("%c"+n,"color: #004",e)},n.prototype._sendKeepalive=function(){return this.send("keepalive")},n.prototype._killKeepalive=function(){clearTimeout(this.keepaliveTimeout)},n.prototype._resetKeepalive=function(){this._killKeepalive(),this.options.keepaliveMs&&(this.keepaliveTimeout=setTimeout((()=>{this._sendKeepalive().catch((e=>console.error("Error received from keepalive: ",e)))}),this.options.keepaliveMs))},e.exports={JanusPluginHandle:t,JanusSession:n}},497:(e,t,n)=>{var s=n(734);s.JanusSession.prototype.sendOriginal=s.JanusSession.prototype.send,s.JanusSession.prototype.send=function(e,t){return this.sendOriginal(e,t).catch((e=>{if(!(e.message&&e.message.indexOf("timed out")>-1))throw e;console.error("web socket timed out"),NAF.connection.adapter.reconnect()}))};var i=n(963),r=n(833)("naf-janus-adapter:debug"),a=(n(833)("naf-janus-adapter:warn"),n(833)("naf-janus-adapter:error")),o=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function c(e){var t=Promise.resolve();return function(){var n=Array.prototype.slice.call(arguments);t=t.then((t=>e.apply(this,n)))}}function l(e){return new Promise(((t,n)=>{if("open"===e.readyState)t();else{let s,i;const r=()=>{e.removeEventListener("open",s),e.removeEventListener("error",i)};s=()=>{r(),t()},i=()=>{r(),n()},e.addEventListener("open",s),e.addEventListener("error",i)}}))}const d=""!==document.createElement("video").canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'),u={usedtx:1,stereo:0,"sprop-stereo":0},p={iceServers:[{urls:"stun:stun1.l.google.com:19302"},{urls:"stun:stun2.l.google.com:19302"}]};class h{constructor(){this.room=null,this.clientId=null,this.joinToken=null,this.serverUrl=null,this.webRtcOptions={},this.peerConnectionConfig=null,this.ws=null,this.session=null,this.reliableTransport="datachannel",this.unreliableTransport="datachannel",this.initialReconnectionDelay=1e3*Math.random(),this.reconnectionDelay=this.initialReconnectionDelay,this.reconnectionTimeout=null,this.maxReconnectionAttempts=10,this.reconnectionAttempts=0,this.publisher=null,this.occupantIds=[],this.occupants={},this.mediaStreams={},this.localMediaStream=null,this.pendingMediaRequests=new Map,this.pendingOccupants=new Set,this.availableOccupants=[],this.requestedOccupants=null,this.blockedClients=new Map,this.frozenUpdates=new Map,this.timeOffsets=[],this.serverTimeRequests=0,this.avgTimeOffset=0,this.onWebsocketOpen=this.onWebsocketOpen.bind(this),this.onWebsocketClose=this.onWebsocketClose.bind(this),this.onWebsocketMessage=this.onWebsocketMessage.bind(this),this.onDataChannelMessage=this.onDataChannelMessage.bind(this),this.onData=this.onData.bind(this)}setServerUrl(e){this.serverUrl=e}setApp(e){}setRoom(e){this.room=e}setJoinToken(e){this.joinToken=e}setClientId(e){this.clientId=e}setWebRtcOptions(e){this.webRtcOptions=e}setPeerConnectionConfig(e){this.peerConnectionConfig=e}setServerConnectListeners(e,t){this.connectSuccess=e,this.connectFailure=t}setRoomOccupantListener(e){this.onOccupantsChanged=e}setDataChannelListeners(e,t,n){this.onOccupantConnected=e,this.onOccupantDisconnected=t,this.onOccupantMessage=n}setReconnectionListeners(e,t,n){this.onReconnecting=e,this.onReconnected=t,this.onReconnectionError=n}setEventLoops(e){this.loops=e}connect(){r(`connecting to ${this.serverUrl}`);const e=new Promise(((e,t)=>{this.ws=new WebSocket(this.serverUrl,"janus-protocol"),this.session=new s.JanusSession(this.ws.send.bind(this.ws),{timeoutMs:4e4}),this.ws.addEventListener("close",this.onWebsocketClose),this.ws.addEventListener("message",this.onWebsocketMessage),this.wsOnOpen=()=>{this.ws.removeEventListener("open",this.wsOnOpen),this.onWebsocketOpen().then(e).catch(t)},this.ws.addEventListener("open",this.wsOnOpen)}));return Promise.all([e,this.updateTimeOffset()])}disconnect(){r("disconnecting"),clearTimeout(this.reconnectionTimeout),this.removeAllOccupants(),this.publisher&&(this.publisher.conn.close(),this.publisher=null),this.session&&(this.session.dispose(),this.session=null),this.ws&&(this.ws.removeEventListener("open",this.wsOnOpen),this.ws.removeEventListener("close",this.onWebsocketClose),this.ws.removeEventListener("message",this.onWebsocketMessage),this.ws.close(),this.ws=null),this.delayedReconnectTimeout&&(clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=null)}isDisconnected(){return null===this.ws}async onWebsocketOpen(){await this.session.create(),this.publisher=await this.createPublisher(),this.connectSuccess(this.clientId);for(let e=0;e<this.publisher.initialOccupants.length;e++){const t=this.publisher.initialOccupants[e];t!==this.clientId&&this.addAvailableOccupant(t)}this.syncOccupants()}onWebsocketClose(e){1e3!==e.code&&(console.warn("Janus websocket closed unexpectedly."),this.onReconnecting&&this.onReconnecting(this.reconnectionDelay),this.reconnectionTimeout=setTimeout((()=>this.reconnect()),this.reconnectionDelay))}reconnect(){this.disconnect(),this.connect().then((()=>{this.reconnectionDelay=this.initialReconnectionDelay,this.reconnectionAttempts=0,this.onReconnected&&this.onReconnected()})).catch((e=>{if(this.reconnectionDelay+=1e3,this.reconnectionAttempts++,this.reconnectionAttempts>this.maxReconnectionAttempts&&this.onReconnectionError)return this.onReconnectionError(new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts."));console.warn("Error during reconnect, retrying."),console.warn(e),this.onReconnecting&&this.onReconnecting(this.reconnectionDelay),this.reconnectionTimeout=setTimeout((()=>this.reconnect()),this.reconnectionDelay)}))}performDelayedReconnect(){this.delayedReconnectTimeout&&clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=setTimeout((()=>{this.delayedReconnectTimeout=null,this.reconnect()}),1e4)}onWebsocketMessage(e){this.session.receive(JSON.parse(e.data))}addAvailableOccupant(e){-1===this.availableOccupants.indexOf(e)&&this.availableOccupants.push(e)}removeAvailableOccupant(e){const t=this.availableOccupants.indexOf(e);-1!==t&&this.availableOccupants.splice(t,1)}syncOccupants(e){if(e&&(this.requestedOccupants=e),this.requestedOccupants){for(let e=0;e<this.requestedOccupants.length;e++){const t=this.requestedOccupants[e];this.occupants[t]||-1===this.availableOccupants.indexOf(t)||this.pendingOccupants.has(t)||this.addOccupant(t)}for(let e=0;e<this.availableOccupants.length;e++){const t=this.availableOccupants[e];this.occupants[t]&&-1===this.requestedOccupants.indexOf(t)&&this.removeOccupant(t)}this.onOccupantsChanged(this.occupants)}}async addOccupant(e){this.pendingOccupants.add(e),this.availableOccupants.length>5&&await(0,5e3,new Promise((e=>{const t=5e3*Math.random()+0;setTimeout(e,t)})));const t=await this.createSubscriber(e);t&&(this.pendingOccupants.has(e)?(this.pendingOccupants.delete(e),this.occupantIds.push(e),this.occupants[e]=t,this.setMediaStream(e,t.mediaStream),this.onOccupantConnected(e)):t.conn.close())}removeAllOccupants(){this.pendingOccupants.clear();for(let e=this.occupantIds.length-1;e>=0;e--)this.removeOccupant(this.occupantIds[e])}removeOccupant(e){if(this.pendingOccupants.delete(e),this.occupants[e]&&(this.occupants[e].conn.close(),delete this.occupants[e],this.occupantIds.splice(this.occupantIds.indexOf(e),1)),this.mediaStreams[e]&&delete this.mediaStreams[e],this.pendingMediaRequests.has(e)){const t="The user disconnected before the media stream was resolved.";this.pendingMediaRequests.get(e).audio.reject(t),this.pendingMediaRequests.get(e).video.reject(t),this.pendingMediaRequests.delete(e)}this.onOccupantDisconnected(e)}associate(e,t){e.addEventListener("icecandidate",(e=>{t.sendTrickle(e.candidate||null).catch((e=>a("Error trickling ICE: %o",e)))})),e.addEventListener("iceconnectionstatechange",(t=>{"connected"===e.iceConnectionState&&console.log("ICE state changed to connected"),"disconnected"===e.iceConnectionState&&console.warn("ICE state changed to disconnected"),"failed"===e.iceConnectionState&&(console.warn("ICE failure detected. Reconnecting in 10s."),this.performDelayedReconnect())})),e.addEventListener("negotiationneeded",c((n=>{r("Sending new offer for handle: %o",t);var s=e.createOffer().then(this.configurePublisherSdp).then(this.fixSafariIceUFrag),i=s.then((t=>e.setLocalDescription(t))),o=s;return o=o.then(this.fixSafariIceUFrag).then((e=>t.sendJsep(e))).then((t=>e.setRemoteDescription(t.jsep))),Promise.all([i,o]).catch((e=>a("Error negotiating offer: %o",e)))}))),t.on("event",c((n=>{var s=n.jsep;if(s&&"offer"==s.type){r("Accepting new offer for handle: %o",t);var i=e.setRemoteDescription(this.configureSubscriberSdp(s)).then((t=>e.createAnswer())).then(this.fixSafariIceUFrag),o=i.then((t=>e.setLocalDescription(t))),c=i.then((e=>t.sendJsep(e)));return Promise.all([o,c]).catch((e=>a("Error negotiating answer: %o",e)))}return null})))}async createPublisher(){var e=new s.JanusPluginHandle(this.session),t=new RTCPeerConnection(this.peerConnectionConfig||p);r("pub waiting for sfu"),await e.attach("janus.plugin.sfu",this.loops&&this.clientId?parseInt(this.clientId)%this.loops:void 0),this.associate(t,e),r("pub waiting for data channels & webrtcup");var n=new Promise((t=>e.on("webrtcup",t))),i=t.createDataChannel("reliable",{ordered:!0}),a=t.createDataChannel("unreliable",{ordered:!1,maxRetransmits:0});i.addEventListener("message",(e=>this.onDataChannelMessage(e,"janus-reliable"))),a.addEventListener("message",(e=>this.onDataChannelMessage(e,"janus-unreliable"))),await n,await l(i),await l(a),this.localMediaStream&&this.localMediaStream.getTracks().forEach((e=>{t.addTrack(e,this.localMediaStream)})),e.on("event",(e=>{var t=e.plugindata.data;if("join"==t.event&&t.room_id==this.room){if(this.delayedReconnectTimeout)return;this.addAvailableOccupant(t.user_id),this.syncOccupants()}else"leave"==t.event&&t.room_id==this.room?(this.removeAvailableOccupant(t.user_id),this.removeOccupant(t.user_id)):"blocked"==t.event?document.body.dispatchEvent(new CustomEvent("blocked",{detail:{clientId:t.by}})):"unblocked"==t.event?document.body.dispatchEvent(new CustomEvent("unblocked",{detail:{clientId:t.by}})):"data"===t.event&&this.onData(JSON.parse(t.body),"janus-event")})),r("pub waiting for join");var o=await this.sendJoin(e,{notifications:!0,data:!0});if(!o.plugindata.data.success){const e=o.plugindata.data.error;throw console.error(e),t.close(),e}var c=o.plugindata.data.response.users[this.room]||[];return c.includes(this.clientId)&&(console.warn("Janus still has previous session for this client. Reconnecting in 10s."),this.performDelayedReconnect()),r("publisher ready"),{handle:e,initialOccupants:c,reliableChannel:i,unreliableChannel:a,conn:t}}configurePublisherSdp(e){return e.sdp=e.sdp.replace(/a=fmtp:(109|111).*\r\n/g,((e,t)=>{const n=Object.assign(i.parseFmtp(e),u);return i.writeFmtp({payloadType:t,parameters:n})})),e}configureSubscriberSdp(e){return d||-1!==navigator.userAgent.indexOf("HeadlessChrome")&&(e.sdp=e.sdp.replace(/m=video[^]*m=/,"m=")),-1===navigator.userAgent.indexOf("Android")?e.sdp=e.sdp.replace("a=rtcp-fb:107 goog-remb\r\n","a=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\n"):e.sdp=e.sdp.replace("a=rtcp-fb:107 goog-remb\r\n","a=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\n"),e}async fixSafariIceUFrag(e){return e.sdp=e.sdp.replace(/[^\r]\na=ice-ufrag/g,"\r\na=ice-ufrag"),e}async createSubscriber(e,t=5){if(-1===this.availableOccupants.indexOf(e))return console.warn(e+": cancelled occupant connection, occupant left before subscription negotation."),null;var n=new s.JanusPluginHandle(this.session),i=new RTCPeerConnection(this.peerConnectionConfig||p);if(r(e+": sub waiting for sfu"),await n.attach("janus.plugin.sfu",this.loops?parseInt(e)%this.loops:void 0),this.associate(i,n),r(e+": sub waiting for join"),-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancelled occupant connection, occupant left after attach"),null;let a=!1;const c=new Promise((t=>{const s=setInterval((()=>{-1===this.availableOccupants.indexOf(e)&&(clearInterval(s),t())}),1e3),i=setTimeout((()=>{clearInterval(s),a=!0,t()}),15e3);n.on("webrtcup",(()=>{clearTimeout(i),clearInterval(s),t()}))}));if(await this.sendJoin(n,{media:e}),-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancelled occupant connection, occupant left after join"),null;if(r(e+": sub waiting for webrtcup"),await c,-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancel occupant connection, occupant left during or after webrtcup"),null;if(a)return i.close(),t>0?(console.warn(e+": webrtc up timed out, retrying"),this.createSubscriber(e,t-1)):(console.warn(e+": webrtc up timed out"),null);o&&!this._iOSHackDelayedInitialPeer&&(await new Promise((e=>setTimeout(e,3e3))),this._iOSHackDelayedInitialPeer=!0);var l=new MediaStream;return i.getReceivers().forEach((e=>{e.track&&l.addTrack(e.track)})),0===l.getTracks().length&&(l=null),r(e+": subscriber ready"),{handle:n,mediaStream:l,conn:i}}sendJoin(e,t){return e.sendMessage({kind:"join",room_id:this.room,user_id:this.clientId,subscribe:t,token:this.joinToken})}toggleFreeze(){this.frozen?this.unfreeze():this.freeze()}freeze(){this.frozen=!0}unfreeze(){this.frozen=!1,this.flushPendingUpdates()}dataForUpdateMultiMessage(e,t){for(let n=0,s=t.data.d.length;n<s;n++){const s=t.data.d[n];if(s.networkId===e)return s}return null}getPendingData(e,t){if(!t)return null;let n="um"===t.dataType?this.dataForUpdateMultiMessage(e,t):t.data;return n.owner&&!this.occupants[n.owner]||n.owner&&this.blockedClients.has(n.owner)?null:n}getPendingDataForNetworkId(e){return this.getPendingData(e,this.frozenUpdates.get(e))}flushPendingUpdates(){for(const[e,t]of this.frozenUpdates){let n=this.getPendingData(e,t);if(!n)continue;const s="um"===t.dataType?"u":t.dataType;this.onOccupantMessage(null,s,n,t.source)}this.frozenUpdates.clear()}storeMessage(e){if("um"===e.dataType)for(let t=0,n=e.data.d.length;t<n;t++)this.storeSingleMessage(e,t);else this.storeSingleMessage(e)}storeSingleMessage(e,t){const n=void 0!==t?e.data.d[t]:e.data,s=e.dataType,i=(e.source,n.networkId);if(this.frozenUpdates.has(i)){const t=this.frozenUpdates.get(i),r="um"===t.dataType?this.dataForUpdateMultiMessage(i,t):t.data,a=n.lastOwnerTime<r.lastOwnerTime,o=n.lastOwnerTime===r.lastOwnerTime;if(a||o&&r.owner>n.owner)return;"r"===s?r&&r.isFirstSync?this.frozenUpdates.delete(i):this.frozenUpdates.set(i,e):r.components&&n.components&&Object.assign(r.components,n.components)}else this.frozenUpdates.set(i,e)}onDataChannelMessage(e,t){this.onData(JSON.parse(e.data),t)}onData(e,t){r.enabled&&r(`DC in: ${e}`),e.dataType&&(e.source=t,this.frozen?this.storeMessage(e):this.onOccupantMessage(null,e.dataType,e.data,e.source))}shouldStartConnectionTo(e){return!0}startStreamConnection(e){}closeStreamConnection(e){}getConnectStatus(e){return this.occupants[e]?NAF.adapters.IS_CONNECTED:NAF.adapters.NOT_CONNECTED}async updateTimeOffset(){if(this.isDisconnected())return;const e=Date.now(),t=await fetch(document.location.href,{method:"HEAD",cache:"no-cache"}),n=new Date(t.headers.get("Date")).getTime()+500,s=Date.now(),i=n+(s-e)/2-s;this.serverTimeRequests++,this.serverTimeRequests<=10?this.timeOffsets.push(i):this.timeOffsets[this.serverTimeRequests%10]=i,this.avgTimeOffset=this.timeOffsets.reduce(((e,t)=>e+t),0)/this.timeOffsets.length,this.serverTimeRequests>10?(r(`new server time offset: ${this.avgTimeOffset}ms`),setTimeout((()=>this.updateTimeOffset()),3e5)):this.updateTimeOffset()}getServerTime(){return Date.now()+this.avgTimeOffset}getMediaStream(e,t="audio"){if(this.mediaStreams[e])return r(`Already had ${t} for ${e}`),Promise.resolve(this.mediaStreams[e][t]);if(r(`Waiting on ${t} for ${e}`),!this.pendingMediaRequests.has(e)){this.pendingMediaRequests.set(e,{});const t=new Promise(((t,n)=>{this.pendingMediaRequests.get(e).audio={resolve:t,reject:n}})),n=new Promise(((t,n)=>{this.pendingMediaRequests.get(e).video={resolve:t,reject:n}}));this.pendingMediaRequests.get(e).audio.promise=t,this.pendingMediaRequests.get(e).video.promise=n,t.catch((t=>console.warn(`${e} getMediaStream Audio Error`,t))),n.catch((t=>console.warn(`${e} getMediaStream Video Error`,t)))}return this.pendingMediaRequests.get(e)[t].promise}setMediaStream(e,t){const n=new MediaStream;try{t.getAudioTracks().forEach((e=>n.addTrack(e)))}catch(t){console.warn(`${e} setMediaStream Audio Error`,t)}const s=new MediaStream;try{t.getVideoTracks().forEach((e=>s.addTrack(e)))}catch(t){console.warn(`${e} setMediaStream Video Error`,t)}this.mediaStreams[e]={audio:n,video:s},this.pendingMediaRequests.has(e)&&(this.pendingMediaRequests.get(e).audio.resolve(n),this.pendingMediaRequests.get(e).video.resolve(s))}async setLocalMediaStream(e){if(this.publisher&&this.publisher.conn){const t=this.publisher.conn.getSenders(),n=[],s=e.getTracks();for(let i=0;i<s.length;i++){const r=s[i],a=t.find((e=>null!=e.track&&e.track.kind==r.kind));null!=a?(a.replaceTrack?(await a.replaceTrack(r),"video"===r.kind&&r.enabled&&navigator.userAgent.toLowerCase().indexOf("firefox")>-1&&(r.enabled=!1,setTimeout((()=>r.enabled=!0),1e3))):(e.removeTrack(a.track),e.addTrack(r)),n.push(a)):n.push(this.publisher.conn.addTrack(r,e))}t.forEach((e=>{n.includes(e)||(e.track.enabled=!1)}))}this.localMediaStream=e,this.setMediaStream(this.clientId,e)}enableMicrophone(e){this.publisher&&this.publisher.conn&&this.publisher.conn.getSenders().forEach((t=>{"audio"==t.track.kind&&(t.track.enabled=e)}))}sendData(e,t,n){if(this.publisher)switch(this.unreliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:t,data:n}),whom:e});break;case"datachannel":"open"===this.publisher.unreliableChannel.readyState&&this.publisher.unreliableChannel.send(JSON.stringify({clientId:e,dataType:t,data:n}));break;default:this.unreliableTransport(e,t,n)}else console.warn("sendData called without a publisher")}sendDataGuaranteed(e,t,n){if(this.publisher)switch(this.reliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:t,data:n}),whom:e});break;case"datachannel":"open"===this.publisher.reliableChannel.readyState&&this.publisher.reliableChannel.send(JSON.stringify({clientId:e,dataType:t,data:n}));break;default:this.reliableTransport(e,t,n)}else console.warn("sendDataGuaranteed called without a publisher")}broadcastData(e,t){if(this.publisher)switch(this.unreliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:e,data:t})});break;case"datachannel":"open"===this.publisher.unreliableChannel.readyState&&this.publisher.unreliableChannel.send(JSON.stringify({dataType:e,data:t}));break;default:this.unreliableTransport(void 0,e,t)}else console.warn("broadcastData called without a publisher")}broadcastDataGuaranteed(e,t){if(this.publisher)switch(this.reliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:e,data:t})});break;case"datachannel":"open"===this.publisher.reliableChannel.readyState&&this.publisher.reliableChannel.send(JSON.stringify({dataType:e,data:t}));break;default:this.reliableTransport(void 0,e,t)}else console.warn("broadcastDataGuaranteed called without a publisher")}kick(e,t){return this.publisher.handle.sendMessage({kind:"kick",room_id:this.room,user_id:e,token:t}).then((()=>{document.body.dispatchEvent(new CustomEvent("kicked",{detail:{clientId:e}}))}))}block(e){return this.publisher.handle.sendMessage({kind:"block",whom:e}).then((()=>{this.blockedClients.set(e,!0),document.body.dispatchEvent(new CustomEvent("blocked",{detail:{clientId:e}}))}))}unblock(e){return this.publisher.handle.sendMessage({kind:"unblock",whom:e}).then((()=>{this.blockedClients.delete(e),document.body.dispatchEvent(new CustomEvent("unblocked",{detail:{clientId:e}}))}))}}NAF.adapters.register("janus",h),e.exports=h},833:(e,t,n)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let s=0,i=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(s++,"%c"===e&&(i=s))})),t.splice(i,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(736)(t);const{formatters:s}=e.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},736:(e,t,n)=>{e.exports=function(e){function t(e){let n,i,r,a=null;function o(...e){if(!o.enabled)return;const s=o,i=Number(new Date),r=i-(n||i);s.diff=r,s.prev=n,s.curr=i,n=i,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let a=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";a++;const r=t.formatters[i];if("function"==typeof r){const t=e[a];n=r.call(s,t),e.splice(a,1),a--}return n})),t.formatArgs.call(s,e),(s.log||t.log).apply(s,e)}return o.namespace=e,o.useColors=t.useColors(),o.color=t.selectColor(e),o.extend=s,o.destroy=t.destroy,Object.defineProperty(o,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==a?a:(i!==t.namespaces&&(i=t.namespaces,r=t.enabled(e)),r),set:e=>{a=e}}),"function"==typeof t.init&&t.init(o),o}function s(e,n){const s=t(this.namespace+(void 0===n?":":n)+e);return s.log=this.log,s}function i(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(i),...t.skips.map(i).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const s=("string"==typeof e?e:"").split(/[\s,]+/),i=s.length;for(n=0;n<i;n++)s[n]&&("-"===(e=s[n].replace(/\*/g,".*?"))[0]?t.skips.push(new RegExp("^"+e.slice(1)+"$")):t.names.push(new RegExp("^"+e+"$")))},t.enabled=function(e){if("*"===e[e.length-1])return!0;let n,s;for(n=0,s=t.skips.length;n<s;n++)if(t.skips[n].test(e))return!1;for(n=0,s=t.names.length;n<s;n++)if(t.names[n].test(e))return!0;return!1},t.humanize=n(585),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((n=>{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;t<e.length;t++)n=(n<<5)-n+e.charCodeAt(t),n|=0;return t.colors[Math.abs(n)%t.colors.length]},t.enable(t.load()),t}},585:e=>{var t=1e3,n=60*t,s=60*n,i=24*s;function r(e,t,n,s){var i=t>=1.5*n;return Math.round(e/n)+" "+s+(i?"s":"")}e.exports=function(e,a){a=a||{};var o,c,l=typeof e;if("string"===l&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var r=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(r){var a=parseFloat(r[1]);switch((r[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*a;case"weeks":case"week":case"w":return 6048e5*a;case"days":case"day":case"d":return a*i;case"hours":case"hour":case"hrs":case"hr":case"h":return a*s;case"minutes":case"minute":case"mins":case"min":case"m":return a*n;case"seconds":case"second":case"secs":case"sec":case"s":return a*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return a;default:return}}}}(e);if("number"===l&&isFinite(e))return a.long?(o=e,(c=Math.abs(o))>=i?r(o,c,i,"day"):c>=s?r(o,c,s,"hour"):c>=n?r(o,c,n,"minute"):c>=t?r(o,c,t,"second"):o+" ms"):function(e){var r=Math.abs(e);return r>=i?Math.round(e/i)+"d":r>=s?Math.round(e/s)+"h":r>=n?Math.round(e/n)+"m":r>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},963:e=>{"use strict";const t={generateIdentifier:function(){return Math.random().toString(36).substring(2,12)}};t.localCName=t.generateIdentifier(),t.splitLines=function(e){return e.trim().split("\n").map((e=>e.trim()))},t.splitSections=function(e){return e.split("\nm=").map(((e,t)=>(t>0?"m="+e:e).trim()+"\r\n"))},t.getDescription=function(e){const n=t.splitSections(e);return n&&n[0]},t.getMediaSections=function(e){const n=t.splitSections(e);return n.shift(),n},t.matchPrefix=function(e,n){return t.splitLines(e).filter((e=>0===e.indexOf(n)))},t.parseCandidate=function(e){let t;t=0===e.indexOf("a=candidate:")?e.substring(12).split(" "):e.substring(10).split(" ");const n={foundation:t[0],component:{1:"rtp",2:"rtcp"}[t[1]]||t[1],protocol:t[2].toLowerCase(),priority:parseInt(t[3],10),ip:t[4],address:t[4],port:parseInt(t[5],10),type:t[7]};for(let e=8;e<t.length;e+=2)switch(t[e]){case"raddr":n.relatedAddress=t[e+1];break;case"rport":n.relatedPort=parseInt(t[e+1],10);break;case"tcptype":n.tcpType=t[e+1];break;case"ufrag":n.ufrag=t[e+1],n.usernameFragment=t[e+1];break;default:void 0===n[t[e]]&&(n[t[e]]=t[e+1])}return n},t.writeCandidate=function(e){const t=[];t.push(e.foundation);const n=e.component;"rtp"===n?t.push(1):"rtcp"===n?t.push(2):t.push(n),t.push(e.protocol.toUpperCase()),t.push(e.priority),t.push(e.address||e.ip),t.push(e.port);const s=e.type;return t.push("typ"),t.push(s),"host"!==s&&e.relatedAddress&&e.relatedPort&&(t.push("raddr"),t.push(e.relatedAddress),t.push("rport"),t.push(e.relatedPort)),e.tcpType&&"tcp"===e.protocol.toLowerCase()&&(t.push("tcptype"),t.push(e.tcpType)),(e.usernameFragment||e.ufrag)&&(t.push("ufrag"),t.push(e.usernameFragment||e.ufrag)),"candidate:"+t.join(" ")},t.parseIceOptions=function(e){return e.substring(14).split(" ")},t.parseRtpMap=function(e){let t=e.substring(9).split(" ");const n={payloadType:parseInt(t.shift(),10)};return t=t[0].split("/"),n.name=t[0],n.clockRate=parseInt(t[1],10),n.channels=3===t.length?parseInt(t[2],10):1,n.numChannels=n.channels,n},t.writeRtpMap=function(e){let t=e.payloadType;void 0!==e.preferredPayloadType&&(t=e.preferredPayloadType);const n=e.channels||e.numChannels||1;return"a=rtpmap:"+t+" "+e.name+"/"+e.clockRate+(1!==n?"/"+n:"")+"\r\n"},t.parseExtmap=function(e){const t=e.substring(9).split(" ");return{id:parseInt(t[0],10),direction:t[0].indexOf("/")>0?t[0].split("/")[1]:"sendrecv",uri:t[1],attributes:t.slice(2).join(" ")}},t.writeExtmap=function(e){return"a=extmap:"+(e.id||e.preferredId)+(e.direction&&"sendrecv"!==e.direction?"/"+e.direction:"")+" "+e.uri+(e.attributes?" "+e.attributes:"")+"\r\n"},t.parseFmtp=function(e){const t={};let n;const s=e.substring(e.indexOf(" ")+1).split(";");for(let e=0;e<s.length;e++)n=s[e].trim().split("="),t[n[0].trim()]=n[1];return t},t.writeFmtp=function(e){let t="",n=e.payloadType;if(void 0!==e.preferredPayloadType&&(n=e.preferredPayloadType),e.parameters&&Object.keys(e.parameters).length){const s=[];Object.keys(e.parameters).forEach((t=>{void 0!==e.parameters[t]?s.push(t+"="+e.parameters[t]):s.push(t)})),t+="a=fmtp:"+n+" "+s.join(";")+"\r\n"}return t},t.parseRtcpFb=function(e){const t=e.substring(e.indexOf(" ")+1).split(" ");return{type:t.shift(),parameter:t.join(" ")}},t.writeRtcpFb=function(e){let t="",n=e.payloadType;return void 0!==e.preferredPayloadType&&(n=e.preferredPayloadType),e.rtcpFeedback&&e.rtcpFeedback.length&&e.rtcpFeedback.forEach((e=>{t+="a=rtcp-fb:"+n+" "+e.type+(e.parameter&&e.parameter.length?" "+e.parameter:"")+"\r\n"})),t},t.parseSsrcMedia=function(e){const t=e.indexOf(" "),n={ssrc:parseInt(e.substring(7,t),10)},s=e.indexOf(":",t);return s>-1?(n.attribute=e.substring(t+1,s),n.value=e.substring(s+1)):n.attribute=e.substring(t+1),n},t.parseSsrcGroup=function(e){const t=e.substring(13).split(" ");return{semantics:t.shift(),ssrcs:t.map((e=>parseInt(e,10)))}},t.getMid=function(e){const n=t.matchPrefix(e,"a=mid:")[0];if(n)return n.substring(6)},t.parseFingerprint=function(e){const t=e.substring(14).split(" ");return{algorithm:t[0].toLowerCase(),value:t[1].toUpperCase()}},t.getDtlsParameters=function(e,n){return{role:"auto",fingerprints:t.matchPrefix(e+n,"a=fingerprint:").map(t.parseFingerprint)}},t.writeDtlsParameters=function(e,t){let n="a=setup:"+t+"\r\n";return e.fingerprints.forEach((e=>{n+="a=fingerprint:"+e.algorithm+" "+e.value+"\r\n"})),n},t.parseCryptoLine=function(e){const t=e.substring(9).split(" ");return{tag:parseInt(t[0],10),cryptoSuite:t[1],keyParams:t[2],sessionParams:t.slice(3)}},t.writeCryptoLine=function(e){return"a=crypto:"+e.tag+" "+e.cryptoSuite+" "+("object"==typeof e.keyParams?t.writeCryptoKeyParams(e.keyParams):e.keyParams)+(e.sessionParams?" "+e.sessionParams.join(" "):"")+"\r\n"},t.parseCryptoKeyParams=function(e){if(0!==e.indexOf("inline:"))return null;const t=e.substring(7).split("|");return{keyMethod:"inline",keySalt:t[0],lifeTime:t[1],mkiValue:t[2]?t[2].split(":")[0]:void 0,mkiLength:t[2]?t[2].split(":")[1]:void 0}},t.writeCryptoKeyParams=function(e){return e.keyMethod+":"+e.keySalt+(e.lifeTime?"|"+e.lifeTime:"")+(e.mkiValue&&e.mkiLength?"|"+e.mkiValue+":"+e.mkiLength:"")},t.getCryptoParameters=function(e,n){return t.matchPrefix(e+n,"a=crypto:").map(t.parseCryptoLine)},t.getIceParameters=function(e,n){const s=t.matchPrefix(e+n,"a=ice-ufrag:")[0],i=t.matchPrefix(e+n,"a=ice-pwd:")[0];return s&&i?{usernameFragment:s.substring(12),password:i.substring(10)}:null},t.writeIceParameters=function(e){let t="a=ice-ufrag:"+e.usernameFragment+"\r\na=ice-pwd:"+e.password+"\r\n";return e.iceLite&&(t+="a=ice-lite\r\n"),t},t.parseRtpParameters=function(e){const n={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},s=t.splitLines(e)[0].split(" ");n.profile=s[2];for(let i=3;i<s.length;i++){const r=s[i],a=t.matchPrefix(e,"a=rtpmap:"+r+" ")[0];if(a){const s=t.parseRtpMap(a),i=t.matchPrefix(e,"a=fmtp:"+r+" ");switch(s.parameters=i.length?t.parseFmtp(i[0]):{},s.rtcpFeedback=t.matchPrefix(e,"a=rtcp-fb:"+r+" ").map(t.parseRtcpFb),n.codecs.push(s),s.name.toUpperCase()){case"RED":case"ULPFEC":n.fecMechanisms.push(s.name.toUpperCase())}}}t.matchPrefix(e,"a=extmap:").forEach((e=>{n.headerExtensions.push(t.parseExtmap(e))}));const i=t.matchPrefix(e,"a=rtcp-fb:* ").map(t.parseRtcpFb);return n.codecs.forEach((e=>{i.forEach((t=>{e.rtcpFeedback.find((e=>e.type===t.type&&e.parameter===t.parameter))||e.rtcpFeedback.push(t)}))})),n},t.writeRtpDescription=function(e,n){let s="";s+="m="+e+" ",s+=n.codecs.length>0?"9":"0",s+=" "+(n.profile||"UDP/TLS/RTP/SAVPF")+" ",s+=n.codecs.map((e=>void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType)).join(" ")+"\r\n",s+="c=IN IP4 0.0.0.0\r\n",s+="a=rtcp:9 IN IP4 0.0.0.0\r\n",n.codecs.forEach((e=>{s+=t.writeRtpMap(e),s+=t.writeFmtp(e),s+=t.writeRtcpFb(e)}));let i=0;return n.codecs.forEach((e=>{e.maxptime>i&&(i=e.maxptime)})),i>0&&(s+="a=maxptime:"+i+"\r\n"),n.headerExtensions&&n.headerExtensions.forEach((e=>{s+=t.writeExtmap(e)})),s},t.parseRtpEncodingParameters=function(e){const n=[],s=t.parseRtpParameters(e),i=-1!==s.fecMechanisms.indexOf("RED"),r=-1!==s.fecMechanisms.indexOf("ULPFEC"),a=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute)),o=a.length>0&&a[0].ssrc;let c;const l=t.matchPrefix(e,"a=ssrc-group:FID").map((e=>e.substring(17).split(" ").map((e=>parseInt(e,10)))));l.length>0&&l[0].length>1&&l[0][0]===o&&(c=l[0][1]),s.codecs.forEach((e=>{if("RTX"===e.name.toUpperCase()&&e.parameters.apt){let t={ssrc:o,codecPayloadType:parseInt(e.parameters.apt,10)};o&&c&&(t.rtx={ssrc:c}),n.push(t),i&&(t=JSON.parse(JSON.stringify(t)),t.fec={ssrc:o,mechanism:r?"red+ulpfec":"red"},n.push(t))}})),0===n.length&&o&&n.push({ssrc:o});let d=t.matchPrefix(e,"b=");return d.length&&(d=0===d[0].indexOf("b=TIAS:")?parseInt(d[0].substring(7),10):0===d[0].indexOf("b=AS:")?1e3*parseInt(d[0].substring(5),10)*.95-16e3:void 0,n.forEach((e=>{e.maxBitrate=d}))),n},t.parseRtcpParameters=function(e){const n={},s=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute))[0];s&&(n.cname=s.value,n.ssrc=s.ssrc);const i=t.matchPrefix(e,"a=rtcp-rsize");n.reducedSize=i.length>0,n.compound=0===i.length;const r=t.matchPrefix(e,"a=rtcp-mux");return n.mux=r.length>0,n},t.writeRtcpParameters=function(e){let t="";return e.reducedSize&&(t+="a=rtcp-rsize\r\n"),e.mux&&(t+="a=rtcp-mux\r\n"),void 0!==e.ssrc&&e.cname&&(t+="a=ssrc:"+e.ssrc+" cname:"+e.cname+"\r\n"),t},t.parseMsid=function(e){let n;const s=t.matchPrefix(e,"a=msid:");if(1===s.length)return n=s[0].substring(7).split(" "),{stream:n[0],track:n[1]};const i=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"msid"===e.attribute));return i.length>0?(n=i[0].value.split(" "),{stream:n[0],track:n[1]}):void 0},t.parseSctpDescription=function(e){const n=t.parseMLine(e),s=t.matchPrefix(e,"a=max-message-size:");let i;s.length>0&&(i=parseInt(s[0].substring(19),10)),isNaN(i)&&(i=65536);const r=t.matchPrefix(e,"a=sctp-port:");if(r.length>0)return{port:parseInt(r[0].substring(12),10),protocol:n.fmt,maxMessageSize:i};const a=t.matchPrefix(e,"a=sctpmap:");if(a.length>0){const e=a[0].substring(10).split(" ");return{port:parseInt(e[0],10),protocol:e[1],maxMessageSize:i}}},t.writeSctpDescription=function(e,t){let n=[];return n="DTLS/SCTP"!==e.protocol?["m="+e.kind+" 9 "+e.protocol+" "+t.protocol+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctp-port:"+t.port+"\r\n"]:["m="+e.kind+" 9 "+e.protocol+" "+t.port+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctpmap:"+t.port+" "+t.protocol+" 65535\r\n"],void 0!==t.maxMessageSize&&n.push("a=max-message-size:"+t.maxMessageSize+"\r\n"),n.join("")},t.generateSessionId=function(){return Math.random().toString().substr(2,22)},t.writeSessionBoilerplate=function(e,n,s){let i;const r=void 0!==n?n:2;return i=e||t.generateSessionId(),"v=0\r\no="+(s||"thisisadapterortc")+" "+i+" "+r+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},t.getDirection=function(e,n){const s=t.splitLines(e);for(let e=0;e<s.length;e++)switch(s[e]){case"a=sendrecv":case"a=sendonly":case"a=recvonly":case"a=inactive":return s[e].substring(2)}return n?t.getDirection(n):"sendrecv"},t.getKind=function(e){return t.splitLines(e)[0].split(" ")[0].substring(2)},t.isRejected=function(e){return"0"===e.split(" ",2)[1]},t.parseMLine=function(e){const n=t.splitLines(e)[0].substring(2).split(" ");return{kind:n[0],port:parseInt(n[1],10),protocol:n[2],fmt:n.slice(3).join(" ")}},t.parseOLine=function(e){const n=t.matchPrefix(e,"o=")[0].substring(2).split(" ");return{username:n[0],sessionId:n[1],sessionVersion:parseInt(n[2],10),netType:n[3],addressType:n[4],address:n[5]}},t.isValidSDP=function(e){if("string"!=typeof e||0===e.length)return!1;const n=t.splitLines(e);for(let e=0;e<n.length;e++)if(n[e].length<2||"="!==n[e].charAt(1))return!1;return!0},e.exports=t}},t={};!function n(s){var i=t[s];if(void 0!==i)return i.exports;var r=t[s]={exports:{}};return e[s](r,r.exports,n),r.exports}(497)})(); | ||
(()=>{var e={734:e=>{function t(e){this.session=e,this.id=void 0}function n(e,t){this.output=e,this.id=void 0,this.nextTxId=0,this.txns={},this.eventHandlers={},this.options=Object.assign({verbose:!1,timeoutMs:1e4,keepaliveMs:3e4},t)}t.prototype.attach=function(e,t){var n={plugin:e,loop_index:t,"force-bundle":!0,"force-rtcp-mux":!0};return this.session.send("attach",n).then((e=>(this.id=e.data.id,e)))},t.prototype.detach=function(){return this.send("detach")},t.prototype.on=function(e,t){return this.session.on(e,(e=>{e.sender==this.id&&t(e)}))},t.prototype.send=function(e,t){return this.session.send(e,Object.assign({handle_id:this.id},t))},t.prototype.sendMessage=function(e){return this.send("message",{body:e})},t.prototype.sendJsep=function(e){return this.send("message",{body:{},jsep:e})},t.prototype.sendTrickle=function(e){return this.send("trickle",{candidate:e})},n.prototype.create=function(){return this.send("create").then((e=>(this.id=e.data.id,e)))},n.prototype.destroy=function(){return this.send("destroy").then((e=>(this.dispose(),e)))},n.prototype.dispose=function(){for(var e in this._killKeepalive(),this.eventHandlers={},this.txns)if(this.txns.hasOwnProperty(e)){var t=this.txns[e];clearTimeout(t.timeout),t.reject(new Error("Janus session was disposed.")),delete this.txns[e]}},n.prototype.isError=function(e){return"error"===e.janus},n.prototype.on=function(e,t){var n=this.eventHandlers[e];null==n&&(n=this.eventHandlers[e]=[]),n.push(t)},n.prototype.receive=function(e){this.options.verbose&&this._logIncoming(e),e.session_id!=this.id&&console.warn("Incorrect session ID received in Janus signalling message: was "+e.session_id+", expected "+this.id+".");var t=e.janus,n=this.eventHandlers[t];if(null!=n)for(var s=0;s<n.length;s++)n[s](e);if(null!=e.transaction){var i=this.txns[e.transaction];if(null==i)return;if("ack"===t&&"message"==i.type)return;clearTimeout(i.timeout),delete this.txns[e.transaction],(this.isError(e)?i.reject:i.resolve)(e)}},n.prototype.send=function(e,t){return t=Object.assign({transaction:(this.nextTxId++).toString()},t),new Promise(((n,s)=>{var i=null;this.options.timeoutMs&&(i=setTimeout((()=>{delete this.txns[t.transaction],s(new Error("Signalling transaction with txid "+t.transaction+" timed out."))}),this.options.timeoutMs)),this.txns[t.transaction]={resolve:n,reject:s,timeout:i,type:e},this._transmit(e,t)}))},n.prototype._transmit=function(e,t){t=Object.assign({janus:e},t),null!=this.id&&(t=Object.assign({session_id:this.id},t)),this.options.verbose&&this._logOutgoing(t),this.output(JSON.stringify(t)),this._resetKeepalive()},n.prototype._logOutgoing=function(e){var t=e.janus;"message"===t&&e.jsep&&(t=e.jsep.type);var n="> Outgoing Janus "+(t||"signal")+" (#"+e.transaction+"): ";console.debug("%c"+n,"color: #040",e)},n.prototype._logIncoming=function(e){var t=e.janus,n=e.transaction?"< Incoming Janus "+(t||"signal")+" (#"+e.transaction+"): ":"< Incoming Janus "+(t||"signal")+": ";console.debug("%c"+n,"color: #004",e)},n.prototype._sendKeepalive=function(){return this.send("keepalive")},n.prototype._killKeepalive=function(){clearTimeout(this.keepaliveTimeout)},n.prototype._resetKeepalive=function(){this._killKeepalive(),this.options.keepaliveMs&&(this.keepaliveTimeout=setTimeout((()=>{this._sendKeepalive().catch((e=>console.error("Error received from keepalive: ",e)))}),this.options.keepaliveMs))},e.exports={JanusPluginHandle:t,JanusSession:n}},497:(e,t,n)=>{var s=n(734);s.JanusSession.prototype.sendOriginal=s.JanusSession.prototype.send,s.JanusSession.prototype.send=function(e,t){return this.sendOriginal(e,t).catch((e=>{if(!(e.message&&e.message.indexOf("timed out")>-1))throw e;console.error("web socket timed out"),NAF.connection.adapter.reconnect()}))};var i=n(963),r=n(833)("naf-janus-adapter:debug"),a=(n(833)("naf-janus-adapter:warn"),n(833)("naf-janus-adapter:error")),o=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function c(e){var t=Promise.resolve();return function(){var n=Array.prototype.slice.call(arguments);t=t.then((t=>e.apply(this,n)))}}function l(e){return new Promise(((t,n)=>{if("open"===e.readyState)t();else{let s,i;const r=()=>{e.removeEventListener("open",s),e.removeEventListener("error",i)};s=()=>{r(),t()},i=()=>{r(),n()},e.addEventListener("open",s),e.addEventListener("error",i)}}))}const d=""!==document.createElement("video").canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'),u={usedtx:1,stereo:0,"sprop-stereo":0},p={iceServers:[{urls:"stun:stun1.l.google.com:19302"},{urls:"stun:stun2.l.google.com:19302"}]};class h{constructor(){this.room=null,this.clientId=null,this.joinToken=null,this.serverUrl=null,this.webRtcOptions={},this.peerConnectionConfig=null,this.ws=null,this.session=null,this.reliableTransport="datachannel",this.unreliableTransport="datachannel",this.initialReconnectionDelay=1e3*Math.random(),this.reconnectionDelay=this.initialReconnectionDelay,this.reconnectionTimeout=null,this.maxReconnectionAttempts=10,this.reconnectionAttempts=0,this.isReconnecting=!1,this.publisher=null,this.occupantIds=[],this.occupants={},this.mediaStreams={},this.localMediaStream=null,this.pendingMediaRequests=new Map,this.pendingOccupants=new Set,this.availableOccupants=[],this.requestedOccupants=null,this.blockedClients=new Map,this.frozenUpdates=new Map,this.timeOffsets=[],this.serverTimeRequests=0,this.avgTimeOffset=0,this.onWebsocketOpen=this.onWebsocketOpen.bind(this),this.onWebsocketClose=this.onWebsocketClose.bind(this),this.onWebsocketMessage=this.onWebsocketMessage.bind(this),this.onDataChannelMessage=this.onDataChannelMessage.bind(this),this.onData=this.onData.bind(this)}setServerUrl(e){this.serverUrl=e}setApp(e){}setRoom(e){this.room=e}setJoinToken(e){this.joinToken=e}setClientId(e){this.clientId=e}setWebRtcOptions(e){this.webRtcOptions=e}setPeerConnectionConfig(e){this.peerConnectionConfig=e}setServerConnectListeners(e,t){this.connectSuccess=e,this.connectFailure=t}setRoomOccupantListener(e){this.onOccupantsChanged=e}setDataChannelListeners(e,t,n){this.onOccupantConnected=e,this.onOccupantDisconnected=t,this.onOccupantMessage=n}setReconnectionListeners(e,t,n){this.onReconnecting=e,this.onReconnected=t,this.onReconnectionError=n}setEventLoops(e){this.loops=e}connect(){"/"===this.serverUrl&&(this.serverUrl="/janus"),"/janus"===this.serverUrl&&("https:"===location.protocol?this.serverUrl="wss://"+location.host+"/janus":this.serverUrl="ws://"+location.host+"/janus"),r(`connecting to ${this.serverUrl}`);const e=new Promise(((e,t)=>{this.ws=new WebSocket(this.serverUrl,"janus-protocol"),this.session=new s.JanusSession(this.ws.send.bind(this.ws),{timeoutMs:4e4}),this.websocketConnectionPromise={},this.websocketConnectionPromise.resolve=e,this.websocketConnectionPromise.reject=t,this.ws.addEventListener("close",this.onWebsocketClose),this.ws.addEventListener("message",this.onWebsocketMessage),this.wsOnOpen=()=>{this.ws.removeEventListener("open",this.wsOnOpen),this.onWebsocketOpen().then(e).catch(t)},this.ws.addEventListener("open",this.wsOnOpen)}));return Promise.all([e,this.updateTimeOffset()])}disconnect(){r("disconnecting"),clearTimeout(this.reconnectionTimeout),this.removeAllOccupants(),this.publisher&&(this.publisher.conn.close(),this.publisher=null),this.session&&(this.session.dispose(),this.session=null),this.ws&&(this.ws.removeEventListener("open",this.wsOnOpen),this.ws.removeEventListener("close",this.onWebsocketClose),this.ws.removeEventListener("message",this.onWebsocketMessage),this.ws.close(),this.ws=null),this.delayedReconnectTimeout&&(clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=null)}isDisconnected(){return null===this.ws}async onWebsocketOpen(){await this.session.create(),this.publisher=await this.createPublisher(),this.connectSuccess(this.clientId);for(let e=0;e<this.publisher.initialOccupants.length;e++){const t=this.publisher.initialOccupants[e];t!==this.clientId&&this.addAvailableOccupant(t)}this.syncOccupants()}onWebsocketClose(e){1e3!==e.code&&(this.websocketConnectionPromise.reject(e),this.isReconnecting||(this.isReconnecting=!0,console.warn("Janus websocket closed unexpectedly."),this.onReconnecting&&this.onReconnecting(this.reconnectionDelay),this.reconnectionTimeout=setTimeout((()=>this.reconnect()),this.reconnectionDelay)))}reconnect(){this.disconnect(),this.connect().then((()=>{this.reconnectionDelay=this.initialReconnectionDelay,this.reconnectionAttempts=0,this.isReconnecting=!1,this.onReconnected&&this.onReconnected()})).catch((e=>{if(this.reconnectionDelay+=1e3,this.reconnectionAttempts++,this.reconnectionAttempts>this.maxReconnectionAttempts){const e=new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts.");return this.onReconnectionError?this.onReconnectionError(e):void console.warn(e)}console.warn("Error during reconnect, retrying."),console.warn(e),this.onReconnecting&&this.onReconnecting(this.reconnectionDelay),this.reconnectionTimeout=setTimeout((()=>this.reconnect()),this.reconnectionDelay)}))}performDelayedReconnect(){this.delayedReconnectTimeout&&clearTimeout(this.delayedReconnectTimeout),this.delayedReconnectTimeout=setTimeout((()=>{this.delayedReconnectTimeout=null,this.reconnect()}),1e4)}onWebsocketMessage(e){this.session.receive(JSON.parse(e.data))}addAvailableOccupant(e){-1===this.availableOccupants.indexOf(e)&&this.availableOccupants.push(e)}removeAvailableOccupant(e){const t=this.availableOccupants.indexOf(e);-1!==t&&this.availableOccupants.splice(t,1)}syncOccupants(e){if(e&&(this.requestedOccupants=e),this.requestedOccupants){for(let e=0;e<this.requestedOccupants.length;e++){const t=this.requestedOccupants[e];this.occupants[t]||-1===this.availableOccupants.indexOf(t)||this.pendingOccupants.has(t)||this.addOccupant(t)}for(let e=0;e<this.availableOccupants.length;e++){const t=this.availableOccupants[e];this.occupants[t]&&-1===this.requestedOccupants.indexOf(t)&&this.removeOccupant(t)}this.onOccupantsChanged(this.occupants)}}async addOccupant(e){this.pendingOccupants.add(e),this.availableOccupants.length>5&&await new Promise((e=>{const t=5e3*Math.random()+0;setTimeout(e,t)}));const t=await this.createSubscriber(e);t&&(this.pendingOccupants.has(e)?(this.pendingOccupants.delete(e),this.occupantIds.push(e),this.occupants[e]=t,this.setMediaStream(e,t.mediaStream),this.onOccupantConnected(e)):t.conn.close())}removeAllOccupants(){this.pendingOccupants.clear();for(let e=this.occupantIds.length-1;e>=0;e--)this.removeOccupant(this.occupantIds[e])}removeOccupant(e){if(this.pendingOccupants.delete(e),this.occupants[e]&&(this.occupants[e].conn.close(),delete this.occupants[e],this.occupantIds.splice(this.occupantIds.indexOf(e),1)),this.mediaStreams[e]&&delete this.mediaStreams[e],this.pendingMediaRequests.has(e)){const t="The user disconnected before the media stream was resolved.";this.pendingMediaRequests.get(e).audio.reject(t),this.pendingMediaRequests.get(e).video.reject(t),this.pendingMediaRequests.delete(e)}this.onOccupantDisconnected(e)}associate(e,t){e.addEventListener("icecandidate",(e=>{t.sendTrickle(e.candidate||null).catch((e=>a("Error trickling ICE: %o",e)))})),e.addEventListener("iceconnectionstatechange",(t=>{"connected"===e.iceConnectionState&&console.log("ICE state changed to connected"),"disconnected"===e.iceConnectionState&&console.warn("ICE state changed to disconnected"),"failed"===e.iceConnectionState&&(console.warn("ICE failure detected. Reconnecting in 10s."),this.performDelayedReconnect())})),e.addEventListener("negotiationneeded",c((n=>{r("Sending new offer for handle: %o",t);var s=e.createOffer().then(this.configurePublisherSdp).then(this.fixSafariIceUFrag),i=s.then((t=>e.setLocalDescription(t))),o=s;return o=o.then(this.fixSafariIceUFrag).then((e=>t.sendJsep(e))).then((t=>e.setRemoteDescription(t.jsep))),Promise.all([i,o]).catch((e=>a("Error negotiating offer: %o",e)))}))),t.on("event",c((n=>{var s=n.jsep;if(s&&"offer"==s.type){r("Accepting new offer for handle: %o",t);var i=e.setRemoteDescription(this.configureSubscriberSdp(s)).then((t=>e.createAnswer())).then(this.fixSafariIceUFrag),o=i.then((t=>e.setLocalDescription(t))),c=i.then((e=>t.sendJsep(e)));return Promise.all([o,c]).catch((e=>a("Error negotiating answer: %o",e)))}return null})))}async createPublisher(){var e=new s.JanusPluginHandle(this.session),t=new RTCPeerConnection(this.peerConnectionConfig||p);r("pub waiting for sfu"),await e.attach("janus.plugin.sfu",this.loops&&this.clientId?parseInt(this.clientId)%this.loops:void 0),this.associate(t,e),r("pub waiting for data channels & webrtcup");var n=new Promise((t=>e.on("webrtcup",t))),i=t.createDataChannel("reliable",{ordered:!0}),a=t.createDataChannel("unreliable",{ordered:!1,maxRetransmits:0});i.addEventListener("message",(e=>this.onDataChannelMessage(e,"janus-reliable"))),a.addEventListener("message",(e=>this.onDataChannelMessage(e,"janus-unreliable"))),await n,await l(i),await l(a),this.localMediaStream&&this.localMediaStream.getTracks().forEach((e=>{t.addTrack(e,this.localMediaStream)})),e.on("event",(e=>{var t=e.plugindata.data;if("join"==t.event&&t.room_id==this.room){if(this.delayedReconnectTimeout)return;this.addAvailableOccupant(t.user_id),this.syncOccupants()}else"leave"==t.event&&t.room_id==this.room?(this.removeAvailableOccupant(t.user_id),this.removeOccupant(t.user_id)):"blocked"==t.event?document.body.dispatchEvent(new CustomEvent("blocked",{detail:{clientId:t.by}})):"unblocked"==t.event?document.body.dispatchEvent(new CustomEvent("unblocked",{detail:{clientId:t.by}})):"data"===t.event&&this.onData(JSON.parse(t.body),"janus-event")})),r("pub waiting for join");var o=await this.sendJoin(e,{notifications:!0,data:!0});if(!o.plugindata.data.success){const e=o.plugindata.data.error;throw console.error(e),t.close(),e}var c=o.plugindata.data.response.users[this.room]||[];return c.includes(this.clientId)&&(console.warn("Janus still has previous session for this client. Reconnecting in 10s."),this.performDelayedReconnect()),r("publisher ready"),{handle:e,initialOccupants:c,reliableChannel:i,unreliableChannel:a,conn:t}}configurePublisherSdp(e){return e.sdp=e.sdp.replace(/a=fmtp:(109|111).*\r\n/g,((e,t)=>{const n=Object.assign(i.parseFmtp(e),u);return i.writeFmtp({payloadType:t,parameters:n})})),e}configureSubscriberSdp(e){return d||-1!==navigator.userAgent.indexOf("HeadlessChrome")&&(e.sdp=e.sdp.replace(/m=video[^]*m=/,"m=")),-1===navigator.userAgent.indexOf("Android")?e.sdp=e.sdp.replace("a=rtcp-fb:107 goog-remb\r\n","a=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\n"):e.sdp=e.sdp.replace("a=rtcp-fb:107 goog-remb\r\n","a=rtcp-fb:107 goog-remb\r\na=rtcp-fb:107 transport-cc\r\na=fmtp:107 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\n"),e}async fixSafariIceUFrag(e){return e.sdp=e.sdp.replace(/[^\r]\na=ice-ufrag/g,"\r\na=ice-ufrag"),e}async createSubscriber(e,t=5){if(-1===this.availableOccupants.indexOf(e))return console.warn(e+": cancelled occupant connection, occupant left before subscription negotation."),null;var n=new s.JanusPluginHandle(this.session),i=new RTCPeerConnection(this.peerConnectionConfig||p);if(r(e+": sub waiting for sfu"),await n.attach("janus.plugin.sfu",this.loops?parseInt(e)%this.loops:void 0),this.associate(i,n),r(e+": sub waiting for join"),-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancelled occupant connection, occupant left after attach"),null;let a=!1;const c=new Promise((t=>{const s=setInterval((()=>{-1===this.availableOccupants.indexOf(e)&&(clearInterval(s),t())}),1e3),i=setTimeout((()=>{clearInterval(s),a=!0,t()}),15e3);n.on("webrtcup",(()=>{clearTimeout(i),clearInterval(s),t()}))}));if(await this.sendJoin(n,{media:e}),-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancelled occupant connection, occupant left after join"),null;if(r(e+": sub waiting for webrtcup"),await c,-1===this.availableOccupants.indexOf(e))return i.close(),console.warn(e+": cancel occupant connection, occupant left during or after webrtcup"),null;if(a)return i.close(),t>0?(console.warn(e+": webrtc up timed out, retrying"),this.createSubscriber(e,t-1)):(console.warn(e+": webrtc up timed out"),null);o&&!this._iOSHackDelayedInitialPeer&&(await new Promise((e=>setTimeout(e,3e3))),this._iOSHackDelayedInitialPeer=!0);var l=new MediaStream;return i.getReceivers().forEach((e=>{e.track&&l.addTrack(e.track)})),0===l.getTracks().length&&(l=null),r(e+": subscriber ready"),{handle:n,mediaStream:l,conn:i}}sendJoin(e,t){return e.sendMessage({kind:"join",room_id:this.room,user_id:this.clientId,subscribe:t,token:this.joinToken})}toggleFreeze(){this.frozen?this.unfreeze():this.freeze()}freeze(){this.frozen=!0}unfreeze(){this.frozen=!1,this.flushPendingUpdates()}dataForUpdateMultiMessage(e,t){for(let n=0,s=t.data.d.length;n<s;n++){const s=t.data.d[n];if(s.networkId===e)return s}return null}getPendingData(e,t){if(!t)return null;let n="um"===t.dataType?this.dataForUpdateMultiMessage(e,t):t.data;return n.owner&&!this.occupants[n.owner]||n.owner&&this.blockedClients.has(n.owner)?null:n}getPendingDataForNetworkId(e){return this.getPendingData(e,this.frozenUpdates.get(e))}flushPendingUpdates(){for(const[e,t]of this.frozenUpdates){let n=this.getPendingData(e,t);if(!n)continue;const s="um"===t.dataType?"u":t.dataType;this.onOccupantMessage(null,s,n,t.source)}this.frozenUpdates.clear()}storeMessage(e){if("um"===e.dataType)for(let t=0,n=e.data.d.length;t<n;t++)this.storeSingleMessage(e,t);else this.storeSingleMessage(e)}storeSingleMessage(e,t){const n=void 0!==t?e.data.d[t]:e.data,s=e.dataType,i=(e.source,n.networkId);if(this.frozenUpdates.has(i)){const t=this.frozenUpdates.get(i),r="um"===t.dataType?this.dataForUpdateMultiMessage(i,t):t.data,a=n.lastOwnerTime<r.lastOwnerTime,o=n.lastOwnerTime===r.lastOwnerTime;if(a||o&&r.owner>n.owner)return;"r"===s?r&&r.isFirstSync?this.frozenUpdates.delete(i):this.frozenUpdates.set(i,e):r.components&&n.components&&Object.assign(r.components,n.components)}else this.frozenUpdates.set(i,e)}onDataChannelMessage(e,t){this.onData(JSON.parse(e.data),t)}onData(e,t){r.enabled&&r(`DC in: ${e}`),e.dataType&&(e.source=t,this.frozen?this.storeMessage(e):this.onOccupantMessage(null,e.dataType,e.data,e.source))}shouldStartConnectionTo(e){return!0}startStreamConnection(e){}closeStreamConnection(e){}getConnectStatus(e){return this.occupants[e]?NAF.adapters.IS_CONNECTED:NAF.adapters.NOT_CONNECTED}async updateTimeOffset(){if(this.isDisconnected())return;const e=Date.now(),t=await fetch(document.location.href,{method:"HEAD",cache:"no-cache"}),n=new Date(t.headers.get("Date")).getTime()+500,s=Date.now(),i=n+(s-e)/2-s;this.serverTimeRequests++,this.serverTimeRequests<=10?this.timeOffsets.push(i):this.timeOffsets[this.serverTimeRequests%10]=i,this.avgTimeOffset=this.timeOffsets.reduce(((e,t)=>e+t),0)/this.timeOffsets.length,this.serverTimeRequests>10?(r(`new server time offset: ${this.avgTimeOffset}ms`),setTimeout((()=>this.updateTimeOffset()),3e5)):this.updateTimeOffset()}getServerTime(){return Date.now()+this.avgTimeOffset}getMediaStream(e,t="audio"){if(this.mediaStreams[e])return r(`Already had ${t} for ${e}`),Promise.resolve(this.mediaStreams[e][t]);if(r(`Waiting on ${t} for ${e}`),!this.pendingMediaRequests.has(e)){this.pendingMediaRequests.set(e,{});const t=new Promise(((t,n)=>{this.pendingMediaRequests.get(e).audio={resolve:t,reject:n}})),n=new Promise(((t,n)=>{this.pendingMediaRequests.get(e).video={resolve:t,reject:n}}));this.pendingMediaRequests.get(e).audio.promise=t,this.pendingMediaRequests.get(e).video.promise=n,t.catch((t=>console.warn(`${e} getMediaStream Audio Error`,t))),n.catch((t=>console.warn(`${e} getMediaStream Video Error`,t)))}return this.pendingMediaRequests.get(e)[t].promise}setMediaStream(e,t){const n=new MediaStream;try{t.getAudioTracks().forEach((e=>n.addTrack(e)))}catch(t){console.warn(`${e} setMediaStream Audio Error`,t)}const s=new MediaStream;try{t.getVideoTracks().forEach((e=>s.addTrack(e)))}catch(t){console.warn(`${e} setMediaStream Video Error`,t)}this.mediaStreams[e]={audio:n,video:s},this.pendingMediaRequests.has(e)&&(this.pendingMediaRequests.get(e).audio.resolve(n),this.pendingMediaRequests.get(e).video.resolve(s))}getLocalMediaStream(){return this.localMediaStream}async setLocalMediaStream(e){if(this.publisher&&this.publisher.conn){const t=this.publisher.conn.getSenders(),n=[],s=e.getTracks();for(let i=0;i<s.length;i++){const r=s[i],a=t.find((e=>null!=e.track&&e.track.kind==r.kind));null!=a?(a.replaceTrack?await a.replaceTrack(r):(e.removeTrack(a.track),e.addTrack(r)),n.push(a)):n.push(this.publisher.conn.addTrack(r,e))}t.forEach((e=>{n.includes(e)||(e.track.enabled=!1)}))}this.localMediaStream=e,this.setMediaStream(this.clientId,e)}enableMicrophone(e){this.publisher&&this.publisher.conn&&this.publisher.conn.getSenders().forEach((t=>{"audio"==t.track.kind&&(t.track.enabled=e)}))}sendData(e,t,n){if(this.publisher)switch(this.unreliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:t,data:n}),whom:e});break;case"datachannel":"open"===this.publisher.unreliableChannel.readyState&&this.publisher.unreliableChannel.send(JSON.stringify({clientId:e,dataType:t,data:n}));break;default:this.unreliableTransport(e,t,n)}else console.warn("sendData called without a publisher")}sendDataGuaranteed(e,t,n){if(this.publisher)switch(this.reliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:t,data:n}),whom:e});break;case"datachannel":"open"===this.publisher.reliableChannel.readyState&&this.publisher.reliableChannel.send(JSON.stringify({clientId:e,dataType:t,data:n}));break;default:this.reliableTransport(e,t,n)}else console.warn("sendDataGuaranteed called without a publisher")}broadcastData(e,t){if(this.publisher)switch(this.unreliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:e,data:t})});break;case"datachannel":"open"===this.publisher.unreliableChannel.readyState&&this.publisher.unreliableChannel.send(JSON.stringify({dataType:e,data:t}));break;default:this.unreliableTransport(void 0,e,t)}else console.warn("broadcastData called without a publisher")}broadcastDataGuaranteed(e,t){if(this.publisher)switch(this.reliableTransport){case"websocket":1===this.ws.readyState&&this.publisher.handle.sendMessage({kind:"data",body:JSON.stringify({dataType:e,data:t})});break;case"datachannel":"open"===this.publisher.reliableChannel.readyState&&this.publisher.reliableChannel.send(JSON.stringify({dataType:e,data:t}));break;default:this.reliableTransport(void 0,e,t)}else console.warn("broadcastDataGuaranteed called without a publisher")}kick(e,t){return this.publisher.handle.sendMessage({kind:"kick",room_id:this.room,user_id:e,token:t}).then((()=>{document.body.dispatchEvent(new CustomEvent("kicked",{detail:{clientId:e}}))}))}block(e){return this.publisher.handle.sendMessage({kind:"block",whom:e}).then((()=>{this.blockedClients.set(e,!0),document.body.dispatchEvent(new CustomEvent("blocked",{detail:{clientId:e}}))}))}unblock(e){return this.publisher.handle.sendMessage({kind:"unblock",whom:e}).then((()=>{this.blockedClients.delete(e),document.body.dispatchEvent(new CustomEvent("unblocked",{detail:{clientId:e}}))}))}}NAF.adapters.register("janus",h),e.exports=h},833:(e,t,n)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let s=0,i=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(s++,"%c"===e&&(i=s))})),t.splice(i,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){if("undefined"!=typeof window&&window.process&&("renderer"===window.process.type||window.process.__nwjs))return!0;if("undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))return!1;let e;return"undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&(e=navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/))&&parseInt(e[1],10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(736)(t);const{formatters:s}=e.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},736:(e,t,n)=>{e.exports=function(e){function t(e){let n,i,r,a=null;function o(...e){if(!o.enabled)return;const s=o,i=Number(new Date),r=i-(n||i);s.diff=r,s.prev=n,s.curr=i,n=i,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let a=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";a++;const r=t.formatters[i];if("function"==typeof r){const t=e[a];n=r.call(s,t),e.splice(a,1),a--}return n})),t.formatArgs.call(s,e),(s.log||t.log).apply(s,e)}return o.namespace=e,o.useColors=t.useColors(),o.color=t.selectColor(e),o.extend=s,o.destroy=t.destroy,Object.defineProperty(o,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==a?a:(i!==t.namespaces&&(i=t.namespaces,r=t.enabled(e)),r),set:e=>{a=e}}),"function"==typeof t.init&&t.init(o),o}function s(e,n){const s=t(this.namespace+(void 0===n?":":n)+e);return s.log=this.log,s}function i(e,t){let n=0,s=0,i=-1,r=0;for(;n<e.length;)if(s<t.length&&(t[s]===e[n]||"*"===t[s]))"*"===t[s]?(i=s,r=n,s++):(n++,s++);else{if(-1===i)return!1;s=i+1,r++,n=r}for(;s<t.length&&"*"===t[s];)s++;return s===t.length}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names,...t.skips.map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").trim().replace(" ",",").split(",").filter(Boolean);for(const e of n)"-"===e[0]?t.skips.push(e.slice(1)):t.names.push(e)},t.enabled=function(e){for(const n of t.skips)if(i(e,n))return!1;for(const n of t.names)if(i(e,n))return!0;return!1},t.humanize=n(585),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((n=>{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;t<e.length;t++)n=(n<<5)-n+e.charCodeAt(t),n|=0;return t.colors[Math.abs(n)%t.colors.length]},t.enable(t.load()),t}},585:e=>{var t=1e3,n=60*t,s=60*n,i=24*s,r=7*i;function a(e,t,n,s){var i=t>=1.5*n;return Math.round(e/n)+" "+s+(i?"s":"")}e.exports=function(e,o){o=o||{};var c,l,d=typeof e;if("string"===d&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var a=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(a){var o=parseFloat(a[1]);switch((a[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*o;case"weeks":case"week":case"w":return o*r;case"days":case"day":case"d":return o*i;case"hours":case"hour":case"hrs":case"hr":case"h":return o*s;case"minutes":case"minute":case"mins":case"min":case"m":return o*n;case"seconds":case"second":case"secs":case"sec":case"s":return o*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return o;default:return}}}}(e);if("number"===d&&isFinite(e))return o.long?(c=e,(l=Math.abs(c))>=i?a(c,l,i,"day"):l>=s?a(c,l,s,"hour"):l>=n?a(c,l,n,"minute"):l>=t?a(c,l,t,"second"):c+" ms"):function(e){var r=Math.abs(e);return r>=i?Math.round(e/i)+"d":r>=s?Math.round(e/s)+"h":r>=n?Math.round(e/n)+"m":r>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},963:e=>{"use strict";const t={generateIdentifier:function(){return Math.random().toString(36).substring(2,12)}};t.localCName=t.generateIdentifier(),t.splitLines=function(e){return e.trim().split("\n").map((e=>e.trim()))},t.splitSections=function(e){return e.split("\nm=").map(((e,t)=>(t>0?"m="+e:e).trim()+"\r\n"))},t.getDescription=function(e){const n=t.splitSections(e);return n&&n[0]},t.getMediaSections=function(e){const n=t.splitSections(e);return n.shift(),n},t.matchPrefix=function(e,n){return t.splitLines(e).filter((e=>0===e.indexOf(n)))},t.parseCandidate=function(e){let t;t=0===e.indexOf("a=candidate:")?e.substring(12).split(" "):e.substring(10).split(" ");const n={foundation:t[0],component:{1:"rtp",2:"rtcp"}[t[1]]||t[1],protocol:t[2].toLowerCase(),priority:parseInt(t[3],10),ip:t[4],address:t[4],port:parseInt(t[5],10),type:t[7]};for(let e=8;e<t.length;e+=2)switch(t[e]){case"raddr":n.relatedAddress=t[e+1];break;case"rport":n.relatedPort=parseInt(t[e+1],10);break;case"tcptype":n.tcpType=t[e+1];break;case"ufrag":n.ufrag=t[e+1],n.usernameFragment=t[e+1];break;default:void 0===n[t[e]]&&(n[t[e]]=t[e+1])}return n},t.writeCandidate=function(e){const t=[];t.push(e.foundation);const n=e.component;"rtp"===n?t.push(1):"rtcp"===n?t.push(2):t.push(n),t.push(e.protocol.toUpperCase()),t.push(e.priority),t.push(e.address||e.ip),t.push(e.port);const s=e.type;return t.push("typ"),t.push(s),"host"!==s&&e.relatedAddress&&e.relatedPort&&(t.push("raddr"),t.push(e.relatedAddress),t.push("rport"),t.push(e.relatedPort)),e.tcpType&&"tcp"===e.protocol.toLowerCase()&&(t.push("tcptype"),t.push(e.tcpType)),(e.usernameFragment||e.ufrag)&&(t.push("ufrag"),t.push(e.usernameFragment||e.ufrag)),"candidate:"+t.join(" ")},t.parseIceOptions=function(e){return e.substring(14).split(" ")},t.parseRtpMap=function(e){let t=e.substring(9).split(" ");const n={payloadType:parseInt(t.shift(),10)};return t=t[0].split("/"),n.name=t[0],n.clockRate=parseInt(t[1],10),n.channels=3===t.length?parseInt(t[2],10):1,n.numChannels=n.channels,n},t.writeRtpMap=function(e){let t=e.payloadType;void 0!==e.preferredPayloadType&&(t=e.preferredPayloadType);const n=e.channels||e.numChannels||1;return"a=rtpmap:"+t+" "+e.name+"/"+e.clockRate+(1!==n?"/"+n:"")+"\r\n"},t.parseExtmap=function(e){const t=e.substring(9).split(" ");return{id:parseInt(t[0],10),direction:t[0].indexOf("/")>0?t[0].split("/")[1]:"sendrecv",uri:t[1],attributes:t.slice(2).join(" ")}},t.writeExtmap=function(e){return"a=extmap:"+(e.id||e.preferredId)+(e.direction&&"sendrecv"!==e.direction?"/"+e.direction:"")+" "+e.uri+(e.attributes?" "+e.attributes:"")+"\r\n"},t.parseFmtp=function(e){const t={};let n;const s=e.substring(e.indexOf(" ")+1).split(";");for(let e=0;e<s.length;e++)n=s[e].trim().split("="),t[n[0].trim()]=n[1];return t},t.writeFmtp=function(e){let t="",n=e.payloadType;if(void 0!==e.preferredPayloadType&&(n=e.preferredPayloadType),e.parameters&&Object.keys(e.parameters).length){const s=[];Object.keys(e.parameters).forEach((t=>{void 0!==e.parameters[t]?s.push(t+"="+e.parameters[t]):s.push(t)})),t+="a=fmtp:"+n+" "+s.join(";")+"\r\n"}return t},t.parseRtcpFb=function(e){const t=e.substring(e.indexOf(" ")+1).split(" ");return{type:t.shift(),parameter:t.join(" ")}},t.writeRtcpFb=function(e){let t="",n=e.payloadType;return void 0!==e.preferredPayloadType&&(n=e.preferredPayloadType),e.rtcpFeedback&&e.rtcpFeedback.length&&e.rtcpFeedback.forEach((e=>{t+="a=rtcp-fb:"+n+" "+e.type+(e.parameter&&e.parameter.length?" "+e.parameter:"")+"\r\n"})),t},t.parseSsrcMedia=function(e){const t=e.indexOf(" "),n={ssrc:parseInt(e.substring(7,t),10)},s=e.indexOf(":",t);return s>-1?(n.attribute=e.substring(t+1,s),n.value=e.substring(s+1)):n.attribute=e.substring(t+1),n},t.parseSsrcGroup=function(e){const t=e.substring(13).split(" ");return{semantics:t.shift(),ssrcs:t.map((e=>parseInt(e,10)))}},t.getMid=function(e){const n=t.matchPrefix(e,"a=mid:")[0];if(n)return n.substring(6)},t.parseFingerprint=function(e){const t=e.substring(14).split(" ");return{algorithm:t[0].toLowerCase(),value:t[1].toUpperCase()}},t.getDtlsParameters=function(e,n){return{role:"auto",fingerprints:t.matchPrefix(e+n,"a=fingerprint:").map(t.parseFingerprint)}},t.writeDtlsParameters=function(e,t){let n="a=setup:"+t+"\r\n";return e.fingerprints.forEach((e=>{n+="a=fingerprint:"+e.algorithm+" "+e.value+"\r\n"})),n},t.parseCryptoLine=function(e){const t=e.substring(9).split(" ");return{tag:parseInt(t[0],10),cryptoSuite:t[1],keyParams:t[2],sessionParams:t.slice(3)}},t.writeCryptoLine=function(e){return"a=crypto:"+e.tag+" "+e.cryptoSuite+" "+("object"==typeof e.keyParams?t.writeCryptoKeyParams(e.keyParams):e.keyParams)+(e.sessionParams?" "+e.sessionParams.join(" "):"")+"\r\n"},t.parseCryptoKeyParams=function(e){if(0!==e.indexOf("inline:"))return null;const t=e.substring(7).split("|");return{keyMethod:"inline",keySalt:t[0],lifeTime:t[1],mkiValue:t[2]?t[2].split(":")[0]:void 0,mkiLength:t[2]?t[2].split(":")[1]:void 0}},t.writeCryptoKeyParams=function(e){return e.keyMethod+":"+e.keySalt+(e.lifeTime?"|"+e.lifeTime:"")+(e.mkiValue&&e.mkiLength?"|"+e.mkiValue+":"+e.mkiLength:"")},t.getCryptoParameters=function(e,n){return t.matchPrefix(e+n,"a=crypto:").map(t.parseCryptoLine)},t.getIceParameters=function(e,n){const s=t.matchPrefix(e+n,"a=ice-ufrag:")[0],i=t.matchPrefix(e+n,"a=ice-pwd:")[0];return s&&i?{usernameFragment:s.substring(12),password:i.substring(10)}:null},t.writeIceParameters=function(e){let t="a=ice-ufrag:"+e.usernameFragment+"\r\na=ice-pwd:"+e.password+"\r\n";return e.iceLite&&(t+="a=ice-lite\r\n"),t},t.parseRtpParameters=function(e){const n={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},s=t.splitLines(e)[0].split(" ");n.profile=s[2];for(let i=3;i<s.length;i++){const r=s[i],a=t.matchPrefix(e,"a=rtpmap:"+r+" ")[0];if(a){const s=t.parseRtpMap(a),i=t.matchPrefix(e,"a=fmtp:"+r+" ");switch(s.parameters=i.length?t.parseFmtp(i[0]):{},s.rtcpFeedback=t.matchPrefix(e,"a=rtcp-fb:"+r+" ").map(t.parseRtcpFb),n.codecs.push(s),s.name.toUpperCase()){case"RED":case"ULPFEC":n.fecMechanisms.push(s.name.toUpperCase())}}}t.matchPrefix(e,"a=extmap:").forEach((e=>{n.headerExtensions.push(t.parseExtmap(e))}));const i=t.matchPrefix(e,"a=rtcp-fb:* ").map(t.parseRtcpFb);return n.codecs.forEach((e=>{i.forEach((t=>{e.rtcpFeedback.find((e=>e.type===t.type&&e.parameter===t.parameter))||e.rtcpFeedback.push(t)}))})),n},t.writeRtpDescription=function(e,n){let s="";s+="m="+e+" ",s+=n.codecs.length>0?"9":"0",s+=" "+(n.profile||"UDP/TLS/RTP/SAVPF")+" ",s+=n.codecs.map((e=>void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType)).join(" ")+"\r\n",s+="c=IN IP4 0.0.0.0\r\n",s+="a=rtcp:9 IN IP4 0.0.0.0\r\n",n.codecs.forEach((e=>{s+=t.writeRtpMap(e),s+=t.writeFmtp(e),s+=t.writeRtcpFb(e)}));let i=0;return n.codecs.forEach((e=>{e.maxptime>i&&(i=e.maxptime)})),i>0&&(s+="a=maxptime:"+i+"\r\n"),n.headerExtensions&&n.headerExtensions.forEach((e=>{s+=t.writeExtmap(e)})),s},t.parseRtpEncodingParameters=function(e){const n=[],s=t.parseRtpParameters(e),i=-1!==s.fecMechanisms.indexOf("RED"),r=-1!==s.fecMechanisms.indexOf("ULPFEC"),a=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute)),o=a.length>0&&a[0].ssrc;let c;const l=t.matchPrefix(e,"a=ssrc-group:FID").map((e=>e.substring(17).split(" ").map((e=>parseInt(e,10)))));l.length>0&&l[0].length>1&&l[0][0]===o&&(c=l[0][1]),s.codecs.forEach((e=>{if("RTX"===e.name.toUpperCase()&&e.parameters.apt){let t={ssrc:o,codecPayloadType:parseInt(e.parameters.apt,10)};o&&c&&(t.rtx={ssrc:c}),n.push(t),i&&(t=JSON.parse(JSON.stringify(t)),t.fec={ssrc:o,mechanism:r?"red+ulpfec":"red"},n.push(t))}})),0===n.length&&o&&n.push({ssrc:o});let d=t.matchPrefix(e,"b=");return d.length&&(d=0===d[0].indexOf("b=TIAS:")?parseInt(d[0].substring(7),10):0===d[0].indexOf("b=AS:")?1e3*parseInt(d[0].substring(5),10)*.95-16e3:void 0,n.forEach((e=>{e.maxBitrate=d}))),n},t.parseRtcpParameters=function(e){const n={},s=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"cname"===e.attribute))[0];s&&(n.cname=s.value,n.ssrc=s.ssrc);const i=t.matchPrefix(e,"a=rtcp-rsize");n.reducedSize=i.length>0,n.compound=0===i.length;const r=t.matchPrefix(e,"a=rtcp-mux");return n.mux=r.length>0,n},t.writeRtcpParameters=function(e){let t="";return e.reducedSize&&(t+="a=rtcp-rsize\r\n"),e.mux&&(t+="a=rtcp-mux\r\n"),void 0!==e.ssrc&&e.cname&&(t+="a=ssrc:"+e.ssrc+" cname:"+e.cname+"\r\n"),t},t.parseMsid=function(e){let n;const s=t.matchPrefix(e,"a=msid:");if(1===s.length)return n=s[0].substring(7).split(" "),{stream:n[0],track:n[1]};const i=t.matchPrefix(e,"a=ssrc:").map((e=>t.parseSsrcMedia(e))).filter((e=>"msid"===e.attribute));return i.length>0?(n=i[0].value.split(" "),{stream:n[0],track:n[1]}):void 0},t.parseSctpDescription=function(e){const n=t.parseMLine(e),s=t.matchPrefix(e,"a=max-message-size:");let i;s.length>0&&(i=parseInt(s[0].substring(19),10)),isNaN(i)&&(i=65536);const r=t.matchPrefix(e,"a=sctp-port:");if(r.length>0)return{port:parseInt(r[0].substring(12),10),protocol:n.fmt,maxMessageSize:i};const a=t.matchPrefix(e,"a=sctpmap:");if(a.length>0){const e=a[0].substring(10).split(" ");return{port:parseInt(e[0],10),protocol:e[1],maxMessageSize:i}}},t.writeSctpDescription=function(e,t){let n=[];return n="DTLS/SCTP"!==e.protocol?["m="+e.kind+" 9 "+e.protocol+" "+t.protocol+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctp-port:"+t.port+"\r\n"]:["m="+e.kind+" 9 "+e.protocol+" "+t.port+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctpmap:"+t.port+" "+t.protocol+" 65535\r\n"],void 0!==t.maxMessageSize&&n.push("a=max-message-size:"+t.maxMessageSize+"\r\n"),n.join("")},t.generateSessionId=function(){return Math.random().toString().substr(2,22)},t.writeSessionBoilerplate=function(e,n,s){let i;const r=void 0!==n?n:2;return i=e||t.generateSessionId(),"v=0\r\no="+(s||"thisisadapterortc")+" "+i+" "+r+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},t.getDirection=function(e,n){const s=t.splitLines(e);for(let e=0;e<s.length;e++)switch(s[e]){case"a=sendrecv":case"a=sendonly":case"a=recvonly":case"a=inactive":return s[e].substring(2)}return n?t.getDirection(n):"sendrecv"},t.getKind=function(e){return t.splitLines(e)[0].split(" ")[0].substring(2)},t.isRejected=function(e){return"0"===e.split(" ",2)[1]},t.parseMLine=function(e){const n=t.splitLines(e)[0].substring(2).split(" ");return{kind:n[0],port:parseInt(n[1],10),protocol:n[2],fmt:n.slice(3).join(" ")}},t.parseOLine=function(e){const n=t.matchPrefix(e,"o=")[0].substring(2).split(" ");return{username:n[0],sessionId:n[1],sessionVersion:parseInt(n[2],10),netType:n[3],addressType:n[4],address:n[5]}},t.isValidSDP=function(e){if("string"!=typeof e||0===e.length)return!1;const n=t.splitLines(e);for(let e=0;e<n.length;e++)if(n[e].length<2||"="!==n[e].charAt(1))return!1;return!0},e.exports=t}},t={};!function n(s){var i=t[s];if(void 0!==i)return i.exports;var r=t[s]={exports:{}};return e[s](r,r.exports,n),r.exports}(497)})(); | ||
//# sourceMappingURL=naf-janus-adapter.min.js.map |
@@ -37,3 +37,4 @@ # Securing janus with JWT | ||
create `lib/myapp_web/perms_token.ex` | ||
``` | ||
```elixir | ||
defmodule MyAppWeb.PermsToken do | ||
@@ -92,15 +93,21 @@ @moduledoc """ | ||
config :myapp, MyAppWeb.PermsToken, perms_key: System.get_env("AUTH_KEY_PRIVATE") | ||
```elixir | ||
config :myapp, MyAppWeb.PermsToken, perms_key: System.get_env("AUTH_KEY_PRIVATE") | ||
``` | ||
in `config/releases.exs` or `config/runtime.exs` (for production): | ||
config :meetingrooms, MyAppWeb.PermsToken, perms_key: System.get_env("AUTH_KEY_PRIVATE") || | ||
raise """ | ||
environment variable AUTH_KEY_PRIVATE is missing. | ||
""" | ||
```elixir | ||
config :meetingrooms, MyAppWeb.PermsToken, perms_key: System.get_env("AUTH_KEY_PRIVATE") || | ||
raise """ | ||
environment variable AUTH_KEY_PRIVATE is missing. | ||
""" | ||
``` | ||
Do your security logic and generate a token like this for example: | ||
MyAppWeb.PermsToken.token_for_perms( | ||
%{user_id: user.id, kick_users: user.id == room.user_id, join_hub: true, room_ids: [room.slug]}) | ||
```elixir | ||
MyAppWeb.PermsToken.token_for_perms( | ||
%{user_id: user.id, kick_users: user.id == room.user_id, join_hub: true, room_ids: [room.slug]}) | ||
``` | ||
@@ -116,4 +123,6 @@ See what the different claims mean in the [janus-plugin-sfu api documentation](https://github.com/mozilla/janus-plugin-sfu/pull/86/files). | ||
const permsToken = await callSomeAPItoGetTheToken(); | ||
adapter.setJoinToken(permsToken); | ||
```js | ||
const permsToken = await callSomeAPItoGetTheToken(); | ||
adapter.setJoinToken(permsToken); | ||
``` | ||
@@ -124,2 +133,3 @@ The room should now be secure. | ||
The JWT is valid here 5 minutes. If participant A joins the room and participant B joins the room 5 minutes later, B will hear A, but A won't hear B because A couldn't subscribe to B's audio because of an expired token (`addOccupant/createSubscriber` called after receiving a `join` event in naf-janus-adapter). You will get in janus logs | ||
``` | ||
@@ -130,3 +140,4 @@ [WARN] Rejecting join from 0x7fb91400fc50 to room my-room as user 3196610745608672. Error: ExpiredSignature | ||
You need to renew the JWT regularly, like every 4 minutes, you can hard code the 4 minutes in the code below (`const nextRefresh = 4 * 60 * 1000;`) or check the `exp` in the JWT with [jwt-decode](https://www.npmjs.com/package/jwt-decode) and subtract a margin like 1 min (in case you change the ttl of the JWT in your backend later) . Here is an example: | ||
``` | ||
```js | ||
import jwt_decode from "jwt-decode"; | ||
@@ -133,0 +144,0 @@ |
{ | ||
"name": "@networked-aframe/naf-janus-adapter", | ||
"version": "4.2.0", | ||
"version": "4.3.0", | ||
"description": "networked-aframe Janus network adapter", | ||
@@ -13,5 +13,5 @@ "main": "src/index.js", | ||
"np": "^8.0.4", | ||
"webpack": "^5.90.2", | ||
"webpack": "^5.91.0", | ||
"webpack-cli": "^5.1.4", | ||
"webpack-dev-server": "^5.0.2" | ||
"webpack-dev-server": "^5.0.4" | ||
}, | ||
@@ -18,0 +18,0 @@ "dependencies": { |
@@ -29,3 +29,2 @@ # Networked-AFrame Janus Adapter | ||
adapter: janus; | ||
serverURL: wss://preprod-janus.example.com/janus; | ||
"> | ||
@@ -37,2 +36,13 @@ </a-scene> | ||
Default serverURL is `/janus` which is converted to `'wss://' + location.host + '/janus'`. | ||
You can also specify a full url if the server is not the same: | ||
```html | ||
<a-scene networked-scene=" | ||
room: 1; | ||
adapter: janus; | ||
serverURL: wss://janus.example.com/janus; | ||
"> | ||
``` | ||
Compared to other adapters like easyrtc, the janus adapter has a specific API, | ||
@@ -93,5 +103,2 @@ you need to call `NAF.connection.adapter.setClientId` and | ||
For development on the same LAN with `npm start` and if you run the janus docker image locally, you can use the config | ||
`serverURL: wss://192.168.1.15:8080/janus;` (change the ip by yours of course). | ||
## Janus SFU deployment | ||
@@ -98,0 +105,0 @@ |
@@ -114,2 +114,3 @@ /* global NAF */ | ||
this.reconnectionAttempts = 0; | ||
this.isReconnecting = false; | ||
@@ -196,2 +197,12 @@ this.publisher = null; | ||
connect() { | ||
if (this.serverUrl === '/') { | ||
this.serverUrl = '/janus'; | ||
} | ||
if (this.serverUrl === '/janus') { | ||
if (location.protocol === 'https:') { | ||
this.serverUrl = 'wss://' + location.host + '/janus'; | ||
} else { | ||
this.serverUrl = 'ws://' + location.host + '/janus'; | ||
} | ||
} | ||
debug(`connecting to ${this.serverUrl}`); | ||
@@ -204,2 +215,6 @@ | ||
this.websocketConnectionPromise = {}; | ||
this.websocketConnectionPromise.resolve = resolve; | ||
this.websocketConnectionPromise.reject = reject; | ||
this.ws.addEventListener("close", this.onWebsocketClose); | ||
@@ -287,8 +302,13 @@ this.ws.addEventListener("message", this.onWebsocketMessage); | ||
console.warn("Janus websocket closed unexpectedly."); | ||
if (this.onReconnecting) { | ||
this.onReconnecting(this.reconnectionDelay); | ||
this.websocketConnectionPromise.reject(event); | ||
if (!this.isReconnecting) { | ||
this.isReconnecting = true; | ||
console.warn("Janus websocket closed unexpectedly."); | ||
if (this.onReconnecting) { | ||
this.onReconnecting(this.reconnectionDelay); | ||
} | ||
this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay); | ||
} | ||
this.reconnectionTimeout = setTimeout(() => this.reconnect(), this.reconnectionDelay); | ||
} | ||
@@ -304,2 +324,3 @@ | ||
this.reconnectionAttempts = 0; | ||
this.isReconnecting = false; | ||
@@ -314,6 +335,12 @@ if (this.onReconnected) { | ||
if (this.reconnectionAttempts > this.maxReconnectionAttempts && this.onReconnectionError) { | ||
return this.onReconnectionError( | ||
new Error("Connection could not be reestablished, exceeded maximum number of reconnection attempts.") | ||
if (this.reconnectionAttempts > this.maxReconnectionAttempts) { | ||
const error = new Error( | ||
"Connection could not be reestablished, exceeded maximum number of reconnection attempts." | ||
); | ||
if (this.onReconnectionError) { | ||
return this.onReconnectionError(error); | ||
} else { | ||
console.warn(error); | ||
return; | ||
} | ||
} | ||
@@ -990,2 +1017,6 @@ | ||
getLocalMediaStream() { | ||
return this.localMediaStream; | ||
} | ||
async setLocalMediaStream(stream) { | ||
@@ -1011,8 +1042,2 @@ // our job here is to make sure the connection winds up with RTP senders sending the stuff in this stream, | ||
await sender.replaceTrack(t); | ||
// Workaround https://bugzilla.mozilla.org/show_bug.cgi?id=1576771 | ||
if (t.kind === "video" && t.enabled && navigator.userAgent.toLowerCase().indexOf('firefox') > -1) { | ||
t.enabled = false; | ||
setTimeout(() => t.enabled = true, 1000); | ||
} | ||
} else { | ||
@@ -1019,0 +1044,0 @@ // Fallback for browsers that don't support replaceTrack. At this time of this writing |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
957223
4143
105
23