@moveo-ai/web-client 0.106.0-true.3 → 0.106.0-true.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/147.min.js.LICENSE.txt +1 -1
- package/dist/329.min.js.LICENSE.txt +1 -1
- package/dist/882.min.js +1 -1
- package/dist/882.min.js.LICENSE.txt +1 -1
- package/dist/882.min.js.map +1 -1
- package/dist/929.min.js.LICENSE.txt +1 -1
- package/dist/954.min.js.LICENSE.txt +1 -1
- package/dist/audio-client.min.js +1 -1
- package/dist/audio-client.min.js.LICENSE.txt +1 -1
- package/dist/audio-client.min.js.map +1 -1
- package/dist/iframe.min.js +1 -1
- package/dist/iframe.min.js.LICENSE.txt +1 -1
- package/dist/iframe.min.js.map +1 -1
- package/dist/iframe.v2.min.js +1 -1
- package/dist/iframe.v2.min.js.LICENSE.txt +1 -1
- package/dist/iframe.v2.min.js.map +1 -1
- package/dist/index.html +1 -1
- package/dist/preview/index.html +2 -2
- package/dist/preview-webrtc/index.html +52 -5
- package/dist/preview.css.min.js.LICENSE.txt +1 -1
- package/dist/public/locales/en.json +4 -0
- package/dist/telnyx-client.min.js +1 -1
- package/dist/telnyx-client.min.js.LICENSE.txt +1 -1
- package/dist/telnyx-client.min.js.map +1 -1
- package/dist/web-client.min.js.LICENSE.txt +1 -1
- package/dist/webrtc-client.min.js +1 -1
- package/dist/webrtc-client.min.js.LICENSE.txt +1 -1
- package/dist/webrtc-client.min.js.map +1 -1
- package/package.json +1 -1
package/dist/882.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see 882.min.js.LICENSE.txt */
|
|
2
|
-
"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}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.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,is_final:t.is_final});break;case"agent_response":this.emit("agent-response",t.text,{text:t.text,message_id:t.message_id});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)}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}}]);
|
|
2
|
+
"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}}]);
|