@moveo-ai/web-client
Version:
Client side library to load the moveo chat widget and connect it with your agent
2 lines • 25.7 kB
JavaScript
/*! For license information please see 882.min.js.LICENSE.txt */
"use strict";(this.webpackChunkMoveoAI=this.webpackChunkMoveoAI||[]).push([[882],{2229:function(t,e,i){i.d(e,{h:function(){return s}});class s{constructor(){this.analyserNode=null,this.audioSource=null,this.animationId=null,this.audioContext=null}start(t,e){try{this.audioContext=new AudioContext,this.audioSource=this.audioContext.createMediaStreamSource(t),this.analyserNode=this.audioContext.createAnalyser(),this.analyserNode.fftSize=256,this.analyserNode.smoothingTimeConstant=.3,this.audioSource.connect(this.analyserNode);const i=new Float32Array(this.analyserNode.fftSize),s=()=>{if(!this.analyserNode)return void this.stop();this.analyserNode.getFloatTimeDomainData(i);let t=0;for(const e of i)t+=e*e;const n=Math.sqrt(t/i.length),o=Math.min(1,10*n);e((o>.01?o:0).toFixed(3)),this.animationId=requestAnimationFrame(s)};s()}catch(t){}}stop(){if(null!==this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null),this.audioSource){try{this.audioSource.disconnect()}catch(t){}this.audioSource=null}this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.analyserNode=null}}},6815:function(t,e,i){i.d(e,{n:function(){return s}});const s={NotAllowedError:"Microphone permission denied",NotFoundError:"No microphone found",NotReadableError:"Microphone is in use by another application",OverconstrainedError:"Microphone does not support required settings"}},3564:function(t,e,i){i.d(e,{M:function(){return o}});var s=i(2076);const n={"high-rtt":"High network latency detected","low-mos":"Poor call quality detected","high-jitter":"Network instability detected","high-packet-loss":"Packet loss detected"};class o{constructor(t,e,i,s=5e3){this.pc=t,this.onWarning=e,this.onWarningCleared=i,this.pollIntervalMs=s,this.interval=null,this.prevStats=null,this.activeWarnings=new Set}start(){this.interval=setInterval(()=>{this.pollStats()},this.pollIntervalMs)}stop(){null!==this.interval&&(clearInterval(this.interval),this.interval=null),this.prevStats=null,this.activeWarnings.clear()}async pollStats(){try{const t=await this.pc.getStats();let e=null,i=0,n=0;const o=(0,s._)(t),r=null!=(null==o?void 0:o.currentRoundTripTime)?1e3*o.currentRoundTripTime:null;t.forEach(t=>{var s,o,r;if("inbound-rtp"===t.type&&"audio"===t.kind){const a=t;e=null!==(s=a.jitter)&&void 0!==s?s:null,i=null!==(o=a.packetsReceived)&&void 0!==o?o:0,n=null!==(r=a.packetsLost)&&void 0!==r?r:0}});let a=0;if(this.prevStats){const t=i-this.prevStats.packetsReceived,e=n-this.prevStats.packetsLost,s=t+e;a=s>0?e/s:0}if(this.prevStats={packetsReceived:i,packetsLost:n},this.checkWarning("high-rtt",null!==r&&r>400),this.checkWarning("high-jitter",null!==e&&e>.03),this.checkWarning("high-packet-loss",a>.03),null!==r&&null!==e){const t=93.2-1e3*e*2-100*a*40-.1*Math.max(0,r-150),i=1+.035*t+t*(t-60)*(100-t)*7e-6;this.checkWarning("low-mos",i<3)}}catch(t){}}checkWarning(t,e){e&&!this.activeWarnings.has(t)?(this.activeWarnings.add(t),this.onWarning(t,n[t]||t)):!e&&this.activeWarnings.has(t)&&(this.activeWarnings.delete(t),this.onWarningCleared(t))}}},6845:function(t,e,i){i.d(e,{PA:function(){return s},TM:function(){return o},Xq:function(){return n}});class s extends Error{constructor(t="Voice service is busy, please try again."){super(t),this.name="ServerBusyError"}}class n extends Error{constructor(t){super(t),this.name="ConfigUnavailableError"}}class o extends Error{constructor(t="Too many attempts. Please try again in a moment."){super(t),this.name="RateLimitedError"}}},7943:function(t,e,i){i.d(e,{$:function(){return r}});var s=i(1931),n=i.n(s),o=i(2076);class r{constructor(t,e,i,s=1e3,o=3,r=!function(t=navigator.userAgent){return/\b(iPad|iPhone|iPod)\b/.test(t)||/AppleWebKit/.test(t)&&!/Chrome|Chromium|CriOS|Edg|OPR/.test(t)}()){this.pc=t,this.onStall=e,this.onRecover=i,this.pollIntervalMs=s,this.flatPollsThreshold=o,this.escalate=r,this.log=n()("moveo:webrtc:media"),this.interval=null,this.prevCounts=null,this.flatPolls=0,this.stalled=!1,this.cannotAssessLogged=!1}start(){this.log("started (escalate=%s)",this.escalate),this.interval=setInterval(()=>{this.poll()},this.pollIntervalMs)}stop(){null!==this.interval&&(clearInterval(this.interval),this.interval=null),this.prevCounts=null,this.flatPolls=0,this.stalled=!1,this.cannotAssessLogged=!1}async poll(){try{const t=await this.pc.getStats(),e=function(t){const e=new Map;return t.forEach(t=>{if("inbound-rtp"===t.type){const i=t;"audio"===i.kind&&void 0!==i.packetsReceived&&e.set(i.id,i.packetsReceived)}}),e}(t);if(0===e.size)return void(this.cannotAssessLogged||(this.cannotAssessLogged=!0,this.log("cannot assess: no audio inbound-rtp with packetsReceived")));this.cannotAssessLogged=!1;const i=this.prevCounts;if(this.prevCounts=e,null===i)return void this.log("assessing %d audio inbound-rtp report(s)",e.size);let s=!1,n=!1,o=0,r=!1;if(e.forEach((t,e)=>{const a=i.get(e);void 0!==a?(o++,t>a?s=!0:t<a&&(n=!0)):r=!0}),s)return this.stalled&&(this.stalled=!1,this.log("recovered%s (pair %s)",this.escalate?"":" (log-only)",this.describeSelectedPair(t)),this.escalate&&this.onRecover()),void(this.flatPolls=0);if(0===o||n||r)return this.log("inbound-rtp reports reseeded (comparable=%d new=%s)",o,r),void(this.flatPolls=0);this.flatPolls++,this.log("flat poll reports=%d flat=%d",e.size,this.flatPolls),this.flatPolls>=this.flatPollsThreshold&&!this.stalled&&(this.stalled=!0,this.log("stall declared%s after %d flat polls (pair %s)",this.escalate?"":" (log-only, escalation disabled)",this.flatPolls,this.describeSelectedPair(t)),this.escalate&&this.onStall())}catch(t){}}describeSelectedPair(t){const e=(0,o._)(t);return e?(0,o.t)(t,e):"?"}}},2076:function(t,e,i){function s(t){let e;const i=[];t.forEach(t=>{if("transport"===t.type){const{selectedCandidatePairId:i}=t;i&&!e&&(e=i)}else"candidate-pair"===t.type&&i.push(t)});const s=e&&i.find(t=>t.id===e)||i.find(t=>!0===t.selected);if(s)return s;let n;for(const t of i){if(!t.nominated)continue;if(void 0===n){n=t;continue}const e=n.lastPacketReceivedTimestamp,i=t.lastPacketReceivedTimestamp;void 0!==i&&(void 0===e||i>e)&&(n=t)}return n}function n(t,e){const i=e=>{var i,s;if(!e)return"?";const n=t.get(e);if(!n)return"?";const o=`${null!==(i=n.candidateType)&&void 0!==i?i:"?"}/${null!==(s=n.protocol)&&void 0!==s?s:"?"}`;return n.relayProtocol?`${o}(${n.relayProtocol})`:o};return`${i(e.localCandidateId)} -> ${i(e.remoteCandidateId)}`}i.d(e,{_:function(){return s},t:function(){return n}})},4623:function(t,e,i){i.d(e,{g:function(){return r}});var s=i(1931),n=i.n(s),o=i(4587);class r{constructor(t,e,i,s,o){this.url=t,this.sessionToken=e,this.onMessage=i,this.onClose=s,this.onError=o,this.log=n()("moveo:webrtc:media"),this.ws=null}connect(){return new Promise((t,e)=>{this.log("connecting to %s",this.url);const i=`${this.url}?token=${encodeURIComponent(this.sessionToken)}`;this.ws=new WebSocket(i);const s=setTimeout(()=>{this.close(),e(new Error("Signaling connection timed out"))},1e4);this.ws.onopen=()=>{},this.ws.onmessage=e=>{let i;try{i=JSON.parse(e.data)}catch(t){return}this.log("recv %s",i.type),"welcome"===i.type&&(clearTimeout(s),t()),this.onMessage(i)},this.ws.onerror=t=>{clearTimeout(s),this.log("websocket error"),this.onError(t),e(new Error("Signaling WebSocket error"))},this.ws.onclose=t=>{clearTimeout(s),this.log("closed code=%d reason=%s",t.code,t.reason),e(new Error("Signaling WebSocket closed before connection established")),this.onClose(t.code,t.reason)}})}connectForReconnect(t){return new Promise((e,i)=>{this.log("reconnecting to %s",this.url);const s=`${this.url}?token=${encodeURIComponent(this.sessionToken)}`;this.ws=new WebSocket(s);let n=!1;const r=setTimeout(()=>{n||(n=!0,this.close(o.c,"Resume timed out"),i(new Error("Signaling reconnect timed out")))},1e4);this.ws.onopen=()=>{var e;null===(e=this.ws)||void 0===e||e.send(JSON.stringify(t))},this.ws.onmessage=t=>{let s;try{s=JSON.parse(t.data)}catch(t){return}this.log("recv %s",s.type),this.onMessage(s),n||("reconnect_ack"===s.type?(n=!0,clearTimeout(r),e()):"error"===s.type&&(n=!0,clearTimeout(r),i(new Error(`reconnect rejected: ${s.error.code}`))))},this.ws.onerror=t=>{this.log("websocket error"),this.onError(t),n||(n=!0,clearTimeout(r),i(new Error("Signaling WebSocket error")))},this.ws.onclose=t=>{this.log("closed code=%d reason=%s",t.code,t.reason),n||(n=!0,clearTimeout(r),i(new Error("Signaling WebSocket closed before reconnect established"))),this.onClose(t.code,t.reason)}})}send(t){this.ws&&this.ws.readyState===WebSocket.OPEN&&(this.log("send %s",t.type),this.ws.send(JSON.stringify(t)))}close(t=1e3,e="Client closed"){this.ws&&(this.ws.onclose=null,this.ws.onerror=null,this.ws.onmessage=null,this.ws.close(t,e),this.ws=null)}get isConnected(){var t;return(null===(t=this.ws)||void 0===t?void 0:t.readyState)===WebSocket.OPEN}}},5882:function(t,e,i){i.r(e),i.d(e,{WebRTCProvider:function(){return v}}),i(4954);var s=i(1931),n=i.n(s),o=i(4587),r=i(2229),a=i(6815),c=i(3564),l=i(6845),h=i(7943),d=i(4623);const u=500,g=new Set(["session_expired","session_inactive","invalid_credential","max_recovery_exceeded","unexpected_first_frame"]),m={session_expired:"Your session has expired.",session_inactive:"The call has ended.",invalid_credential:"Could not resume the call.",max_recovery_exceeded:"Could not resume the call after several attempts.",unexpected_first_frame:"Could not resume the call."},p=Object.assign(Object.assign({},a.n),{setRemoteDescription:"Connection setup failed",setLocalDescription:"Connection setup failed",addIceCandidate:"Network configuration failed",createOffer:"Browser audio setup failed"});class v{constructor(t,e){this.wsUrl=t,this.fetchConfig=e,this.log=n()("moveo:webrtc:media"),this.pc=null,this.signaling=null,this.localStream=null,this.remoteStream=null,this.remoteAudio=null,this.remoteAudioMonitor=null,this.audioMonitor=null,this.qualityMonitor=null,this.stallDetector=null,this.pendingCandidates=[],this.state="idle",this.eventListeners=new Map,this.iceRestarting=!1,this.iceRestartAttempts=0,this.iceRestartTimeout=null,this.iceRestartAnswerTimeout=null,this.connectResolve=null,this.connectReject=null,this.resuming=!1,this.reconnectAttempts=0,this.reconnectErrorCode=null,this.brainResponseChunks=new Map,this.interruptedRequests=new Map}setConfig(t){this.config=t}async connect(){if(!this.config)throw new Error("Voice config not set; call setConfig() before connect().");this.setState("connecting");try{this.localStream=await navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}})}catch(t){const e=t instanceof Error?t.name:"",i=p[e]||"Microphone access failed";throw this.emitError(i),new Error(i)}this.signaling=new d.g(this.wsUrl,this.config.sessionToken,this.handleSignalingMessage.bind(this),this.handleSignalingClose.bind(this),this.handleSignalingError.bind(this));try{await this.signaling.connect()}catch(t){this.cleanupLocalStream();const e=t instanceof Error?t.message:"Signaling connection failed";throw this.emitError(e),new Error(e)}this.pc=new RTCPeerConnection({iceServers:this.config.iceServers,iceTransportPolicy:this.config.iceTransportPolicy||"relay"});const t=this.localStream.getAudioTracks()[0];this.pc.addTrack(t,this.localStream),this.pc.ontrack=this.handleRemoteTrack.bind(this),this.pc.onicecandidate=t=>{var e;t.candidate&&(null===(e=this.signaling)||void 0===e||e.send({type:"ice",candidate:t.candidate.toJSON()}))},this.pc.onconnectionstatechange=this.handleConnectionStateChange.bind(this);try{const t=await this.pc.createOffer();if(!t.sdp)throw new Error("createOffer returned no SDP");await this.pc.setLocalDescription(t),this.signaling.send({type:"offer",sdp:t.sdp})}catch(t){this.cleanup();const e=t instanceof Error?t.name:"createOffer",i=p[e]||"Failed to create call offer";throw this.emitError(i),new Error(i)}return this.audioMonitor=new r.h,this.audioMonitor.start(this.localStream,t=>{this.emit("audio-level",t,Number(t))}),new Promise((t,e)=>{this.connectResolve=t,this.connectReject=e})}disconnect(){this.disconnectInternal(!1)}disconnectInternal(t){var e,i,s,n,o,r,a;if(!t)try{null===(e=this.signaling)||void 0===e||e.send({type:"hangup"})}catch(t){}try{null===(i=this.qualityMonitor)||void 0===i||i.stop(),this.qualityMonitor=null}catch(t){}try{null===(s=this.stallDetector)||void 0===s||s.stop(),this.stallDetector=null}catch(t){}try{null===(n=this.audioMonitor)||void 0===n||n.stop(),this.audioMonitor=null}catch(t){}try{null===(o=this.remoteAudioMonitor)||void 0===o||o.stop(),this.remoteAudioMonitor=null}catch(t){}try{null===(r=this.pc)||void 0===r||r.close(),this.pc=null}catch(t){}this.cleanupLocalStream();try{null===(a=this.signaling)||void 0===a||a.close(),this.signaling=null}catch(t){}try{this.remoteAudio&&(this.remoteAudio.srcObject=null,this.remoteAudio.remove(),this.remoteAudio=null),this.remoteStream=null}catch(t){}this.clearIceRestart(),this.iceRestartAttempts=0,this.connectReject&&this.connectReject(new Error("Call disconnected before connection completed")),this.connectResolve=null,this.connectReject=null,this.resuming=!1,this.reconnectAttempts=0,this.reconnectErrorCode=null,this.originalSessionID=void 0,this.originalConnectionID=void 0,this.pendingCandidates=[],this.brainResponseChunks.clear(),this.interruptedRequests.clear(),this.setState("idle")}toggleMute(){var t,e;const i=null===(t=this.localStream)||void 0===t?void 0:t.getAudioTracks()[0];if(i){i.enabled=!i.enabled;const t=!i.enabled;return null===(e=this.signaling)||void 0===e||e.send({type:"mute",muted:t}),t}return!1}isMuted(){var t,e,i;return!(null===(i=null===(e=null===(t=this.localStream)||void 0===t?void 0:t.getAudioTracks()[0])||void 0===e?void 0:e.enabled)||void 0===i||i)}getLocalStream(){return this.localStream}getRemoteStream(){return this.remoteStream}sendDigits(t){var e;for(const i of t)null===(e=this.signaling)||void 0===e||e.send({type:"dtmf",digit:i})}on(t,e){var i;const s=null!==(i=this.eventListeners.get(t))&&void 0!==i?i:new Set;return s.add(e),this.eventListeners.set(t,s),()=>this.off(t,e)}off(t,e){const i=this.eventListeners.get(t);i&&(i.delete(e),0===i.size&&this.eventListeners.delete(t))}handleRemoteTrack(t){const[e]=t.streams;this.remoteStream=null!=e?e:null,this.remoteAudio=document.createElement("audio"),this.remoteAudio.srcObject=e,this.remoteAudio.autoplay=!0,document.body.appendChild(this.remoteAudio),this.remoteAudio.play().catch(()=>{}),this.remoteAudioMonitor=new r.h,this.remoteAudioMonitor.start(e,t=>{Number(t)>.02&&this.emit("remote-audio",t,Number(t))})}handleConnectionStateChange(){var t,e,i,s;if(this.pc)switch(this.log("connectionState %s",this.pc.connectionState),this.pc.connectionState){case"connecting":this.setState("connecting");break;case"connected":{const s="reconnecting"===this.state;this.setState("connected"),this.clearIceRestart(),this.iceRestartAttempts=0,s&&this.emit("warning-cleared",void 0,"reconnect"),null===(t=this.qualityMonitor)||void 0===t||t.stop(),this.qualityMonitor=new c.M(this.pc,(t,e)=>this.emit("warning",e,t),t=>this.emit("warning-cleared",void 0,t)),this.qualityMonitor.start(),null===(e=this.stallDetector)||void 0===e||e.stop(),this.stallDetector=new h.$(this.pc,()=>{this.log("media stall -> ICE restart"),this.triggerIceRestart()},()=>{this.log("media recovered"),this.clearIceRestart(),this.iceRestartAttempts=0,"reconnecting"===this.state&&this.setState("connected"),this.emit("warning-cleared",void 0,"reconnect")}),this.stallDetector.start(),null===(i=this.connectResolve)||void 0===i||i.call(this),this.connectResolve=null,this.connectReject=null;break}case"disconnected":if(this.resuming)break;this.triggerIceRestart();break;case"failed":if(this.resuming){null===(s=this.connectReject)||void 0===s||s.call(this,new Error("ICE connection failed")),this.connectResolve=null,this.connectReject=null;break}if(this.connectReject){this.connectReject(new Error("ICE connection failed")),this.connectResolve=null,this.connectReject=null,this.emitError("Connection failed"),this.cleanup();break}this.iceRestarting?this.onRestartAttemptExpired():this.triggerIceRestart();break;case"closed":this.cleanup()}}async triggerIceRestart(){if(this.resuming||!this.pc||!this.signaling)return;if(this.iceRestarting||this.iceRestartAttempts>=2)return;if(!this.signaling.isConnected)return this.isResumeEligible()?void this.beginResume(u):(this.emitError("Connection lost"),void this.cleanup());const t=this.pc,e=this.signaling;this.iceRestarting=!0,this.iceRestartAttempts++,this.log("ICE restart attempt %d/%d",this.iceRestartAttempts,2),this.setState("reconnecting"),this.emit("warning","Reconnecting…","reconnect");try{const i=await t.createOffer({iceRestart:!0});if(!i.sdp)throw new Error("createOffer returned no SDP");await t.setLocalDescription(i),e.send({type:"offer",sdp:i.sdp})}catch(e){if(this.resuming||!this.iceRestarting||this.pc!==t)return;return this.iceRestarting=!1,this.emitError("Connection lost"),void this.cleanup()}this.iceRestarting&&this.pc===t&&(this.iceRestartTimeout=setTimeout(()=>{this.onRestartAttemptExpired()},1e4),this.iceRestartAnswerTimeout=setTimeout(()=>{this.onIceRestartUnanswered()},3e3))}onIceRestartUnanswered(){this.iceRestartAnswerTimeout=null,this.iceRestarting&&this.isResumeEligible()&&(this.log("ICE restart offer unanswered -> resume"),this.beginResume(u))}onRestartAttemptExpired(){this.log("ICE restart attempt expired (attempts=%d)",this.iceRestartAttempts),this.iceRestartTimeout&&(clearTimeout(this.iceRestartTimeout),this.iceRestartTimeout=null),this.iceRestartAnswerTimeout&&(clearTimeout(this.iceRestartAnswerTimeout),this.iceRestartAnswerTimeout=null),this.iceRestarting=!1,this.iceRestartAttempts<2?this.triggerIceRestart():this.isResumeEligible()?this.beginResume(u):(this.emitError("Connection lost"),this.cleanup())}clearIceRestart(){this.iceRestarting&&this.log("ICE restart cleared"),this.iceRestartTimeout&&(clearTimeout(this.iceRestartTimeout),this.iceRestartTimeout=null),this.iceRestartAnswerTimeout&&(clearTimeout(this.iceRestartAnswerTimeout),this.iceRestartAnswerTimeout=null),this.iceRestarting=!1}handleSignalingMessage(t){var e;switch(t.type){case"answer":this.handleAnswer(t.sdp);break;case"ice":this.addIceCandidate(t.candidate);break;case"transcript":this.emit("transcript",t.text,{text:t.text,request_id:t.request_id,timestamp:t.timestamp});break;case"brain_response":this.handleBrainResponse(t);break;case"interrupt":this.handleInterrupt(t);break;case"hangup":this.disconnectInternal(!0);break;case"session_ready":this.originalSessionID=t.session_id,this.originalConnectionID=t.connection_id;break;case"reconnect_ack":this.originalConnectionID=t.connection_id;break;case"drain":this.handleDrain(t);break;case"error":this.resuming?(this.reconnectErrorCode=t.error.code,null===(e=this.connectReject)||void 0===e||e.call(this,new Error(`reconnect rejected: ${t.error.code}`))):this.emitError(t.error.message)}}handleSignalingClose(t,e){var i;this.resuming?null===(i=this.connectReject)||void 0===i||i.call(this,new Error("Signaling closed during resume")):this.isResumeEligible()?this.beginResume(u):"idle"!==this.state&&this.disconnect()}handleSignalingError(t){this.resuming||this.isResumeEligible()||"connected"===this.state&&this.emitError("Signaling error")}isResumeEligible(){return!this.resuming&&("connected"===this.state||"reconnecting"===this.state)&&void 0!==this.originalSessionID&&void 0!==this.originalConnectionID}async beginResume(t=0){this.resuming=!0,this.setState("reconnecting"),this.clearIceRestart(),this.emit("warning","Reconnecting…","reconnect"),t>0&&(await this.sleep(Math.random()*t),!this.resuming)||await this.reconnect()}async handleDrain(t){if(!this.resuming)return this.isResumeEligible()?void await this.beginResume(Math.max(0,t.reconnect_delay_ms||0)):(this.emitError("Could not resume the call."),void this.disconnectInternal(!0))}async reconnect(){var t,e,i;try{null===(t=this.pc)||void 0===t||t.getSenders().forEach(t=>{var e;t.track&&(null===(e=this.pc)||void 0===e||e.removeTrack(t))})}catch(t){}const s=null===(e=this.localStream)||void 0===e?void 0:e.getAudioTracks()[0];if(!s||"live"!==s.readyState)return this.emitError("Microphone is no longer available."),void this.disconnectInternal(!0);for(this.teardownForReconnect();this.reconnectAttempts<3;){this.reconnectErrorCode=null;try{if(this.config=await this.fetchConfig(),!this.resuming)return;return this.signaling=new d.g(this.wsUrl,this.config.sessionToken,this.handleSignalingMessage.bind(this),this.handleSignalingClose.bind(this),this.handleSignalingError.bind(this)),await this.signaling.connectForReconnect({type:"reconnect",session_id:this.originalSessionID,connection_id:this.originalConnectionID}),await this.buildReconnectPeerConnection(s),this.reconnectAttempts=0,this.resuming=!1,void this.emit("warning-cleared",void 0,"reconnect")}catch(t){const e=this.reconnectErrorCode;if(e&&g.has(e))return this.emitError(null!==(i=m[e])&&void 0!==i?i:"Could not resume the call."),void this.disconnectInternal(!0);if(t instanceof l.Xq)return this.emitError(t.message),void this.disconnectInternal(!0);const s=t instanceof l.PA?t.message:"Reconnecting…";if(this.emit("warning",s,"reconnect"),this.teardownForReconnect(),this.reconnectAttempts++,this.reconnectAttempts>=3)break;if(await this.sleep(500*this.reconnectAttempts),!this.resuming)return}}this.emitError("Could not resume the call."),this.disconnectInternal(!0)}buildReconnectPeerConnection(t){return this.pc=new RTCPeerConnection({iceServers:this.config.iceServers,iceTransportPolicy:this.config.iceTransportPolicy||"relay"}),this.pc.addTrack(t,this.localStream),this.pc.ontrack=this.handleRemoteTrack.bind(this),this.pc.onicecandidate=t=>{var e;t.candidate&&(null===(e=this.signaling)||void 0===e||e.send({type:"ice",candidate:t.candidate.toJSON()}))},this.pc.onconnectionstatechange=this.handleConnectionStateChange.bind(this),this.audioMonitor=new r.h,this.audioMonitor.start(this.localStream,t=>{this.emit("audio-level",t,Number(t))}),new Promise((t,e)=>{const i=setTimeout(()=>{this.connectResolve=null,this.connectReject=null,e(new Error("Reconnect media resume timed out"))},15e3);this.connectResolve=()=>{clearTimeout(i),t()},this.connectReject=t=>{clearTimeout(i),e(t)},(async()=>{var t;try{const t=await this.pc.createOffer();if(!t.sdp)throw new Error("createOffer returned no SDP");await this.pc.setLocalDescription(t),this.signaling.send({type:"offer",sdp:t.sdp})}catch(e){const i=e instanceof Error?e.name:"createOffer";null===(t=this.connectReject)||void 0===t||t.call(this,new Error(p[i]||"Failed to create call offer"))}})()})}teardownForReconnect(){var t,e,i,s,n,r;try{null===(t=this.qualityMonitor)||void 0===t||t.stop(),this.qualityMonitor=null}catch(t){}try{null===(e=this.stallDetector)||void 0===e||e.stop(),this.stallDetector=null}catch(t){}try{null===(i=this.audioMonitor)||void 0===i||i.stop(),this.audioMonitor=null}catch(t){}try{null===(s=this.remoteAudioMonitor)||void 0===s||s.stop(),this.remoteAudioMonitor=null}catch(t){}try{null===(n=this.pc)||void 0===n||n.close(),this.pc=null}catch(t){}try{null===(r=this.signaling)||void 0===r||r.close(o.c,"Resuming"),this.signaling=null}catch(t){}try{this.remoteAudio&&(this.remoteAudio.srcObject=null,this.remoteAudio.remove(),this.remoteAudio=null),this.remoteStream=null}catch(t){}this.clearIceRestart(),this.iceRestartAttempts=0,this.connectResolve=null,this.connectReject=null,this.pendingCandidates=[]}sleep(t){return new Promise(e=>setTimeout(e,t))}async handleAnswer(t){if(this.iceRestartAnswerTimeout&&(clearTimeout(this.iceRestartAnswerTimeout),this.iceRestartAnswerTimeout=null),this.pc)try{await this.pc.setRemoteDescription({type:"answer",sdp:t}),await this.flushPendingCandidates()}catch(t){this.emitError(p.setRemoteDescription)}}async addIceCandidate(t){var e;if(null===(e=this.pc)||void 0===e?void 0:e.remoteDescription)try{await this.pc.addIceCandidate(t)}catch(t){}else this.pendingCandidates.push(t)}async flushPendingCandidates(){for(const t of this.pendingCandidates){if(!this.pc)break;try{await this.pc.addIceCandidate(t)}catch(t){}}this.pendingCandidates=[]}cleanup(){this.disconnect()}cleanupLocalStream(){var t;try{null===(t=this.localStream)||void 0===t||t.getTracks().forEach(t=>t.stop()),this.localStream=null}catch(t){}}setState(t){this.state=t,this.emit("state-change",t,t)}handleBrainResponse(t){const e=t.request_id;if(this.interruptedRequests.has(e))return;if(t.final){const t=this.assembleBrainResponse(e);return void this.emit("brain-response",t,{text:t,request_id:e,final:!0})}let i=this.brainResponseChunks.get(e);i||(i=new Map,this.brainResponseChunks.set(e,i)),i.set(t.index,t.text);const s=this.assembleBrainResponse(e);this.emit("brain-response",s,{text:s,request_id:e,final:!1})}assembleBrainResponse(t){const e=this.brainResponseChunks.get(t);return e?[...e.entries()].sort((t,e)=>t[0]-e[0]).map(([,t])=>t).join(" "):""}handleInterrupt(t){const e=this.interruptedRequests.get(t.request_id),i=void 0===e?t.heard_index:Math.min(e,t.heard_index);this.interruptedRequests.set(t.request_id,i);const s=this.brainResponseChunks.get(t.request_id),n=s?[...s.entries()].sort((t,e)=>t[0]-e[0]):[],o=t=>n.filter(([e])=>t(e)).map(([,t])=>t).join(" "),r=o(t=>t<=i),a=o(t=>t>i);this.emit("interrupt",r,{request_id:t.request_id,heard_index:i,timestamp:t.timestamp,heardText:r,unheardText:a})}emitError(t){this.emit("error",t),this.setState("error")}emit(t,e,i){const s={state:t,message:e,data:i},n=t=>{const e=this.eventListeners.get(t);e&&e.forEach(t=>{try{t(s)}catch(t){}})};n(t),n("any")}}},4587:function(t,e,i){i.d(e,{c:function(){return s}});const s=4001}}]);