uneeq-js 3.16.2 → 3.16.4
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/363.index.js +1 -1
- package/dist/363.index.js.map +1 -1
- package/dist/948.index.js +1 -1
- package/dist/948.index.js.map +1 -1
- package/dist/esm/chunks/chunk-KSGM2NAE.js +1 -0
- package/dist/esm/chunks/chunk-MOT3AKDE.js +2 -0
- package/dist/esm/chunks/chunk-WJYCZSEJ.js +1 -0
- package/dist/esm/chunks/chunk-YEJDFRW6.js +2 -0
- package/dist/esm/chunks/deepgram-flux-stt-6DSS2LPY.js +27 -0
- package/dist/esm/chunks/deepgram-flux-stt-BHYXM2EH.js +27 -0
- package/dist/esm/chunks/deepgram-flux-stt-J6S6IOQO.js +27 -0
- package/dist/esm/chunks/deepgram-flux-stt-RQL6OWQ2.js +27 -0
- package/dist/esm/chunks/deepgram-stt-5MWRG5JL.js +1 -0
- package/dist/esm/chunks/deepgram-stt-LHOR4WN6.js +1 -0
- package/dist/esm/chunks/deepgram-stt-QCVIQMXI.js +1 -0
- package/dist/esm/chunks/google-stt-ICGJZD6H.js +2486 -0
- package/dist/esm/chunks/google-stt-JDMN7CZH.js +2486 -0
- package/dist/esm/chunks/google-stt-UNWDYI25.js +2486 -0
- package/dist/esm/index.js +2 -2
- package/dist/google-stt.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -78,10 +78,10 @@ m=`).map((l,c)=>(c>0?"m="+l:l).trim()+`\r
|
|
|
78
78
|
}
|
|
79
79
|
`,n=this.gl.createShader(this.gl.VERTEX_SHADER);this.gl.shaderSource(n,e),this.gl.compileShader(n);let i=this.gl.createShader(this.gl.FRAGMENT_SHADER);this.gl.shaderSource(i,t),this.gl.compileShader(i);let r=this.gl.createProgram();this.gl.attachShader(r,n),this.gl.attachShader(r,i),this.gl.linkProgram(r),this.gl.useProgram(r),this.positionLocation=this.gl.getAttribLocation(r,"a_position"),this.texcoordLocation=this.gl.getAttribLocation(r,"a_texCoord")}updateVideoTexture(){this.videoTexture||(this.videoTexture=this.gl.createTexture(),this.gl.bindTexture(this.gl.TEXTURE_2D,this.videoTexture),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR));let e=this.webRtcController.videoPlayer.getVideoElement().videoHeight,t=this.webRtcController.videoPlayer.getVideoElement().videoWidth;this.prevVideoHeight!=e||this.prevVideoWidth!=t?this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,t,e,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,this.webRtcController.videoPlayer.getVideoElement()):this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,0,0,t,e,this.gl.RGBA,this.gl.UNSIGNED_BYTE,this.webRtcController.videoPlayer.getVideoElement()),this.prevVideoHeight=e,this.prevVideoWidth=t}initBuffers(){this.positionBuffer=this.gl.createBuffer(),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.gl.enableVertexAttribArray(this.positionLocation),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array([-1,1,1,1,-1,-1,-1,-1,1,1,1,-1]),this.gl.STATIC_DRAW),this.gl.vertexAttribPointer(this.positionLocation,2,this.gl.FLOAT,!1,0,0),this.texcoordBuffer=this.gl.createBuffer(),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.texcoordBuffer),this.gl.enableVertexAttribArray(this.texcoordLocation),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),this.gl.STATIC_DRAW),this.gl.vertexAttribPointer(this.texcoordLocation,2,this.gl.FLOAT,!1,0,0)}onXrSessionStarted(e){d.Info("XR Session started"),this.xrSession=e,this.xrSession.addEventListener("end",()=>{this.onXrSessionEnded()}),this.initGL(),this.initShaders(),this.initBuffers(),e.requestReferenceSpace("local").then(t=>{if(this.xrRefSpace=t,this.xrSession.updateRenderState({baseLayer:new XRWebGLLayer(this.xrSession,this.gl)}),this.xrSession.supportedFrameRates)for(let n of this.xrSession.supportedFrameRates)n==90&&e.updateTargetFrameRate(90);this.xrSession.requestAnimationFrame(this.onXrFrame.bind(this))}),this.onSessionStarted.dispatchEvent(new Event("xrSessionStarted"))}areArraysEqual(e,t){return e.length===t.length&&e.every((n,i)=>Math.abs(n-t[i])<=this.EPSILON)}arePointsEqual(e,t){return Math.abs(e.x-t.x)>=this.EPSILON&&Math.abs(e.y-t.y)>=this.EPSILON&&Math.abs(e.z-t.z)>=this.EPSILON}sendXRDataToUE(){if(this.leftView==null||this.rightView==null)return;let e=this.lastSentLeftEyeProj==null||this.lastSentRightEyeProj==null||this.lastSentRelativeLeftEyePos==null||this.lastSentRelativeRightEyePos==null,t=this.leftView.transform.matrix,n=this.leftView.projectionMatrix,i=this.rightView.transform.matrix,r=this.rightView.projectionMatrix,o=this.xrViewerPose.transform.matrix;if(!e&&this.lastSentLeftEyeProj!=null&&this.lastSentRightEyeProj!=null){let c=this.areArraysEqual(n,this.lastSentLeftEyeProj),u=this.areArraysEqual(r,this.lastSentRightEyeProj);e=c==!1||u==!1}let a=new DOMPointReadOnly(this.leftView.transform.position.x-this.xrViewerPose.transform.position.x,this.leftView.transform.position.y-this.xrViewerPose.transform.position.y,this.leftView.transform.position.z-this.xrViewerPose.transform.position.z,1),l=new DOMPointReadOnly(this.leftView.transform.position.x-this.xrViewerPose.transform.position.x,this.leftView.transform.position.y-this.xrViewerPose.transform.position.y,this.leftView.transform.position.z-this.xrViewerPose.transform.position.z,1);if(!e&&this.lastSentRelativeLeftEyePos!=null&&this.lastSentRelativeRightEyePos!=null){let c=this.arePointsEqual(a,this.lastSentRelativeLeftEyePos),u=this.arePointsEqual(l,this.lastSentRelativeRightEyePos);e=c==!1||u==!1}e?(this.webRtcController.streamMessageController.toStreamerHandlers.get("XREyeViews")([t[0],t[4],t[8],t[12],t[1],t[5],t[9],t[13],t[2],t[6],t[10],t[14],t[3],t[7],t[11],t[15],n[0],n[4],n[8],n[12],n[1],n[5],n[9],n[13],n[2],n[6],n[10],n[14],n[3],n[7],n[11],n[15],i[0],i[4],i[8],i[12],i[1],i[5],i[9],i[13],i[2],i[6],i[10],i[14],i[3],i[7],i[11],i[15],r[0],r[4],r[8],r[12],r[1],r[5],r[9],r[13],r[2],r[6],r[10],r[14],r[3],r[7],r[11],r[15],o[0],o[4],o[8],o[12],o[1],o[5],o[9],o[13],o[2],o[6],o[10],o[14],o[3],o[7],o[11],o[15]]),this.lastSentLeftEyeProj=n,this.lastSentRightEyeProj=r,this.lastSentRelativeLeftEyePos=a,this.lastSentRelativeRightEyePos=l):this.webRtcController.streamMessageController.toStreamerHandlers.get("XRHMDTransform")([o[0],o[4],o[8],o[12],o[1],o[5],o[9],o[13],o[2],o[6],o[10],o[14],o[3],o[7],o[11],o[15]])}onXrFrame(e,t){if(this.xrViewerPose=t.getViewerPose(this.xrRefSpace),this.xrViewerPose){if(this.updateViews(),this.leftView==null||this.rightView==null)return;this.sendXRDataToUE(),this.updateVideoTexture(),this.render()}this.webRtcController.config.isFlagEnabled(h.XRControllerInput)&&this.xrSession.inputSources.forEach((n,i,r)=>{this.xrGamepadController.updateStatus(n,t,this.xrRefSpace)},this),this.xrSession.requestAnimationFrame((n,i)=>this.onXrFrame(n,i)),this.onFrame.dispatchEvent(new _t({time:e,frame:t}))}updateViews(){if(this.xrViewerPose)for(let e of this.xrViewerPose.views)e.eye==="left"?this.leftView=e:e.eye==="right"&&(this.rightView=e)}render(){if(!this.gl)return;let e=this.xrSession.renderState.baseLayer;this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,e.framebuffer),this.gl.viewport(0,0,e.framebufferWidth,e.framebufferHeight),this.gl.drawArrays(this.gl.TRIANGLES,0,6)}static isSessionSupported(e){location.protocol!=="https:"&&d.Info("WebXR requires https, if you want WebXR use https.");try{if(navigator.xr)return navigator.xr.isSessionSupported(e)}catch{return Promise.resolve(!1)}return Promise.resolve(!1)}};var Cn=class{constructor(e){this.seq=e.Seq,this.playerSentTimestamp=Date.now(),this.requestFillerSize=e.Filler?e.Filler.length:0}update(e){this.playerReceivedTimestamp=Date.now(),this.streamerReceivedTimestamp=e.ReceivedTimestamp,this.streamerSentTimestamp=e.SentTimestamp,this.responseFillerSize=e.Filler?e.Filler.length:0}};var Mn=class{constructor(e,t){this.intervalHandle=void 0,this.sink=e,this.callback=t,this.records=new Map,this.seq=0}start(e){return this.isRunning()?!1:(this.startTime=Date.now(),this.records.clear(),this.intervalHandle=window.setInterval((()=>{Date.now()-this.startTime>=e.duration?this.stop():this.sendRequest(e.requestSize,e.responseSize)}).bind(this),Math.floor(1e3/e.rps)),!0)}stop(){this.intervalHandle&&(window.clearInterval(this.intervalHandle),this.intervalHandle=void 0,this.callback(this.produceResult()))}produceResult(){let e=new Map(this.records);return{records:e,dataChannelRtt:Math.ceil(Array.from(this.records.values()).reduce((t,n)=>t+(n.playerReceivedTimestamp-n.playerSentTimestamp),0)/this.records.size),playerToStreamerTime:Math.ceil(Array.from(this.records.values()).reduce((t,n)=>t+(n.streamerReceivedTimestamp-n.playerSentTimestamp),0)/this.records.size),streamerToPlayerTime:Math.ceil(Array.from(this.records.values()).reduce((t,n)=>t+(n.playerReceivedTimestamp-n.streamerSentTimestamp),0)/this.records.size),exportLatencyAsCSV:()=>{let t=`Timestamp;RTT;PlayerToStreamer;StreamerToPlayer;
|
|
80
80
|
`;return e.forEach(n=>{t+=n.playerSentTimestamp+";",t+=n.playerReceivedTimestamp-n.playerSentTimestamp+";",t+=n.streamerReceivedTimestamp-n.playerSentTimestamp+";",t+=n.playerReceivedTimestamp-n.streamerSentTimestamp+";",t+=`
|
|
81
|
-
`}),t}}}isRunning(){return!!this.intervalHandle}receive(e){if(!this.isRunning())return;if(!e){d.Error("Undefined response from server");return}let t=this.records.get(e.Seq);t&&t.update(e)}sendRequest(e,t){let n=this.createRequest(e,t),i=new Cn(n);this.records.set(i.seq,i),this.sink(n)}createRequest(e,t){return{Seq:this.seq++,FillResponseSize:t,Filler:e?"A".repeat(e):""}}};var xe=class{constructor(e,t){this.allowConsoleCommands=!1,this.config=e,t?.videoElementParent&&(this._videoElementParent=t.videoElementParent),this._eventEmitter=new $t,this.configureSettings(),this.setWebRtcPlayerController(new bn(this.config,this)),this._webXrController=new wn(this._webRtcController),this._setupWebRtcTCPRelayDetection=this._setupWebRtcTCPRelayDetection.bind(this),this._eventEmitter.addEventListener("webRtcConnected",n=>{this._eventEmitter.addEventListener("statsReceived",this._setupWebRtcTCPRelayDetection)})}get videoElementParent(){return this._videoElementParent||(this._videoElementParent=document.createElement("div"),this._videoElementParent.id="videoElementParent"),this._videoElementParent}configureSettings(){this.config._addOnSettingChangedListener(h.IsQualityController,e=>{e===!0&&!this._webRtcController.isQualityController&&this._webRtcController.sendRequestQualityControlOwnership()}),this.config._addOnSettingChangedListener(h.AFKDetection,e=>{this._webRtcController.setAfkEnabled(e)}),this.config._addOnSettingChangedListener(h.MatchViewportResolution,()=>{this._webRtcController.videoPlayer.updateVideoStreamSize()}),this.config._addOnSettingChangedListener(h.HoveringMouseMode,e=>{this.config.setFlagLabel(h.HoveringMouseMode,`Control Scheme: ${e?"Hovering":"Locked"} Mouse`),this._webRtcController.setMouseInputEnabled(this.config.isFlagEnabled(h.MouseInput))}),this.config._addOnSettingChangedListener(h.KeyboardInput,e=>{this._webRtcController.setKeyboardInputEnabled(e)}),this.config._addOnSettingChangedListener(h.MouseInput,e=>{this._webRtcController.setMouseInputEnabled(e)}),this.config._addOnSettingChangedListener(h.FakeMouseWithTouches,e=>{this._webRtcController.setTouchInputEnabled(this.config.isFlagEnabled(h.TouchInput))}),this.config._addOnSettingChangedListener(h.TouchInput,e=>{this._webRtcController.setTouchInputEnabled(e)}),this.config._addOnSettingChangedListener(h.GamepadInput,e=>{this._webRtcController.setGamePadInputEnabled(e)}),this.config._addOnNumericSettingChangedListener(m.MinQP,e=>{d.Info("-------- Sending MinQP --------"),this._webRtcController.sendEncoderMinQP(e),d.Info("-------------------------------------------");let t=Math.trunc(100*(1-e/51));this.config.setNumericSetting(m.CompatQualityMax,t)}),this.config._addOnNumericSettingChangedListener(m.MaxQP,e=>{d.Info("-------- Sending MaxQP --------"),this._webRtcController.sendEncoderMaxQP(e),d.Info("-------------------------------------------");let t=Math.trunc(100*(1-e/51));this.config.setNumericSetting(m.CompatQualityMin,t)}),this.config._addOnNumericSettingChangedListener(m.MinQuality,e=>{d.Info("-------- Sending MinQuality --------"),this._webRtcController.sendEncoderMinQuality(e),d.Info("-------------------------------------------"),this.config.setNumericSetting(m.CompatQualityMin,e)}),this.config._addOnNumericSettingChangedListener(m.MaxQuality,e=>{d.Info("-------- Sending MaxQuality --------"),this._webRtcController.sendEncoderMaxQuality(e),d.Info("-------------------------------------------"),this.config.setNumericSetting(m.CompatQualityMax,e)}),this.config._addOnNumericSettingChangedListener(m.CompatQualityMin,e=>{e=51-e/100*51,d.Info("-------- Sending MinQP from quality value --------"),this._webRtcController.sendEncoderMaxQP(e),d.Info("-------------------------------------------")}),this.config._addOnNumericSettingChangedListener(m.CompatQualityMax,e=>{e=51-e/100*51,d.Info("-------- Sending MaxQP from quality value --------"),this._webRtcController.sendEncoderMinQP(e),d.Info("-------------------------------------------")}),this.config._addOnNumericSettingChangedListener(m.WebRTCMinBitrate,e=>{d.Info("-------- Sending web rtc settings --------"),this._webRtcController.sendWebRTCMinBitrate(e*1e3),d.Info("-------------------------------------------")}),this.config._addOnNumericSettingChangedListener(m.WebRTCMaxBitrate,e=>{d.Info("-------- Sending web rtc settings --------"),this._webRtcController.sendWebRTCMaxBitrate(e*1e3),d.Info("-------------------------------------------")}),this.config._addOnNumericSettingChangedListener(m.WebRTCFPS,e=>{d.Info("-------- Sending web rtc settings --------"),this._webRtcController.sendWebRTCFps(e),d.Info("-------------------------------------------")}),this.config._addOnOptionSettingChangedListener(M.PreferredCodec,e=>{this._webRtcController&&this._webRtcController.setPreferredCodec(e)}),this.config._registerOnChangeEvents(this._eventEmitter)}_onInputControlOwnership(e){this._inputController=e}setWebRtcPlayerController(e){this._webRtcController=e,this._webRtcController.setPreferredCodec(this.config.getSettingOption(M.PreferredCodec).selected),this._webRtcController.resizePlayerStyle(),this.checkForAutoConnect()}connect(){this._eventEmitter.dispatchEvent(new Mt),this._webRtcController.connectToSignallingServer()}reconnect(){this._eventEmitter.dispatchEvent(new Et),this._webRtcController.tryReconnect("Reconnecting...")}disconnect(){this._eventEmitter.dispatchEvent(new Tt),this._webRtcController.close()}play(){this._onStreamLoading(),this._webRtcController.playStream()}checkForAutoConnect(){this.config.isFlagEnabled(h.AutoConnect)&&(this._onWebRtcAutoConnect(),this._webRtcController.connectToSignallingServer())}unmuteMicrophone(e=!1){if(this.config.isFlagEnabled("UseMic")){this.setMicrophoneMuted(!1);return}if(e){this.config.setFlagEnabled("UseMic",!0),this.reconnect();return}d.Warning("Trying to unmute mic, but PixelStreaming was initialized with no microphone track. Call with forceEnable == true to re-connect with a mic track.")}muteMicrophone(){if(this.config.isFlagEnabled("UseMic")){this.setMicrophoneMuted(!0);return}d.Info("Trying to mute mic, but PixelStreaming has no microphone track, so sending sound is already disabled.")}setMicrophoneMuted(e){var t,n,i,r;for(let o of(r=(i=(n=(t=this._webRtcController)===null||t===void 0?void 0:t.peerConnectionController)===null||n===void 0?void 0:n.peerConnection)===null||i===void 0?void 0:i.getTransceivers())!==null&&r!==void 0?r:[])Z.canTransceiverSendAudio(o)&&(o.sender.track.enabled=!e)}unmuteCamera(e=!1){if(this.config.isFlagEnabled("UseCamera")){this.setCameraMuted(!1);return}if(e){this.config.setFlagEnabled("UseCamera",!0),this.reconnect();return}d.Warning("Trying to unmute video, but PixelStreaming was initialized with no video track. Call with forceEnable == true to re-connect with a video track.")}muteCamera(){if(this.config.isFlagEnabled("UseCamera")){this.setCameraMuted(!0);return}d.Info("Trying to mute camera, but PixelStreaming has no video track, so sending video is already disabled.")}setCameraMuted(e){var t,n,i,r;for(let o of(r=(i=(n=(t=this._webRtcController)===null||t===void 0?void 0:t.peerConnectionController)===null||n===void 0?void 0:n.peerConnection)===null||i===void 0?void 0:i.getTransceivers())!==null&&r!==void 0?r:[])Z.canTransceiverSendVideo(o)&&(o.sender.track.enabled=!e)}_onWebRtcAutoConnect(){this._eventEmitter.dispatchEvent(new pt)}_onWebRtcSdp(){this._eventEmitter.dispatchEvent(new dt)}_onWebRtcSdpOffer(e){this._eventEmitter.dispatchEvent(new ut({sdp:e}))}_onWebRtcSdpAnswer(e){this._eventEmitter.dispatchEvent(new ht({sdp:e}))}_onLatencyCalculated(e){this._eventEmitter.dispatchEvent(new Ft({latencyInfo:e}))}_onStreamLoading(){this._eventEmitter.dispatchEvent(new Ct)}_onDisconnect(e,t){this._eventEmitter.dispatchEvent(new yt({eventString:e,allowClickToReconnect:t}))}_onWebRtcConnecting(){this._eventEmitter.dispatchEvent(new mt)}_onWebRtcConnected(){this._eventEmitter.dispatchEvent(new ft)}_onWebRtcFailed(){this._eventEmitter.dispatchEvent(new gt)}_onVideoInitialized(){this._eventEmitter.dispatchEvent(new wt),this._videoStartTime=Date.now()}_onLatencyTestResult(e){this._eventEmitter.dispatchEvent(new Ot({latencyTimings:e}))}_onDataChannelLatencyTestResponse(e){this._eventEmitter.dispatchEvent(new Nt({response:e}))}_onVideoStats(e){(!this._videoStartTime||this._videoStartTime===void 0)&&(this._videoStartTime=Date.now()),e.handleSessionStatistics(this._videoStartTime,this._inputController,this._webRtcController.videoAvgQp),this._eventEmitter.dispatchEvent(new Pt({aggregatedStats:e}))}_onVideoEncoderAvgQP(e){this._eventEmitter.dispatchEvent(new ct({avgQP:e}))}_onInitialSettings(e){var t;this._eventEmitter.dispatchEvent(new Vt({settings:e})),e.PixelStreamingSettings&&(this.allowConsoleCommands=(t=e.PixelStreamingSettings.AllowPixelStreamingCommands)!==null&&t!==void 0?t:!1,this.allowConsoleCommands===!1&&d.Info("-AllowPixelStreamingCommands=false, sending arbitrary console commands from browser to UE is disabled."));let n=this.config.useUrlParams,i=new ue(window.location.search);d.Info(`using URL parameters ${n}`),e.EncoderSettings&&(e.EncoderSettings.MinQP&&(this.config.setNumericSetting(m.MinQP,n&&i.has(m.MinQP)?Number.parseFloat(i.get(m.MinQP)):e.EncoderSettings.MinQP||0),this.config.setNumericSetting(m.MaxQP,n&&i.has(m.MaxQP)?Number.parseFloat(i.get(m.MaxQP)):e.EncoderSettings.MaxQP||51)),e.EncoderSettings.MinQuality&&(this.config.setNumericSetting(m.MinQuality,n&&i.has(m.MinQuality)?Number.parseFloat(i.get(m.MinQuality)):e.EncoderSettings.MinQuality||0),this.config.setNumericSetting(m.MaxQuality,n&&i.has(m.MaxQuality)?Number.parseFloat(i.get(m.MaxQuality)):e.EncoderSettings.MaxQuality||100)),n&&(i.has(m.CompatQualityMin)&&this.config.setNumericSetting(m.CompatQualityMin,Number.parseFloat(i.get(m.CompatQualityMin))),i.has(m.CompatQualityMax)&&this.config.setNumericSetting(m.CompatQualityMax,Number.parseFloat(i.get(m.CompatQualityMax))))),e.WebRTCSettings&&(this.config.setNumericSetting(m.WebRTCMinBitrate,n&&i.has(m.WebRTCMinBitrate)?Number.parseFloat(i.get(m.WebRTCMinBitrate)):e.WebRTCSettings.MinBitrate/1e3),this.config.setNumericSetting(m.WebRTCMaxBitrate,n&&i.has(m.WebRTCMaxBitrate)?Number.parseFloat(i.get(m.WebRTCMaxBitrate)):e.WebRTCSettings.MaxBitrate/1e3),this.config.setNumericSetting(m.WebRTCFPS,n&&i.has(m.WebRTCFPS)?Number.parseFloat(i.get(m.WebRTCFPS)):e.WebRTCSettings.FPS))}_onQualityControlOwnership(e){this.config.setFlagEnabled(h.IsQualityController,e)}_onPlayerCount(e){this._eventEmitter.dispatchEvent(new Wt({count:e}))}_onSubscribeFailed(e){this._eventEmitter.dispatchEvent(new Bt({message:e}))}_setupWebRtcTCPRelayDetection(e){let t=e.data.aggregatedStats.getActiveCandidatePair();if(t!=null){let n=e.data.aggregatedStats.localCandidates.find(i=>i.id==t.localCandidateId,null);n!=null&&n.candidateType=="relay"&&n.relayProtocol=="tcp"&&this._eventEmitter.dispatchEvent(new Ht),this._eventEmitter.removeEventListener("statsReceived",this._setupWebRtcTCPRelayDetection)}}requestLatencyTest(){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.sendLatencyTest(),!0):!1}requestDataChannelLatencyTest(e){return this._webRtcController.videoPlayer.isVideoReady()?(this._dataChannelLatencyTestController||(this._dataChannelLatencyTestController=new Mn(this._webRtcController.sendDataChannelLatencyTest.bind(this._webRtcController),t=>{this._eventEmitter.dispatchEvent(new Ut({result:t}))}),this.addEventListener("dataChannelLatencyTestResponse",({data:{response:t}})=>{this._dataChannelLatencyTestController.receive(t)})),this._dataChannelLatencyTestController.start(e)):!1}requestShowFps(){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.sendShowFps(),!0):!1}requestIframe(){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.sendIframeRequest(),!0):!1}emitUIInteraction(e){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.emitUIInteraction(e),!0):!1}emitCommand(e){return!this._webRtcController.videoPlayer.isVideoReady()||!this.allowConsoleCommands&&"ConsoleCommand"in e?!1:(this._webRtcController.emitCommand(e),!0)}emitConsoleCommand(e){return!this.allowConsoleCommands||!this._webRtcController.videoPlayer.isVideoReady()?!1:(this._webRtcController.emitConsoleCommand(e),!0)}sendTextboxEntry(e){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.sendTextboxEntry(e),!0):!1}addResponseEventListener(e,t){this._webRtcController.responseController.addResponseEventListener(e,t)}removeResponseEventListener(e){this._webRtcController.responseController.removeResponseEventListener(e)}dispatchEvent(e){return this._eventEmitter.dispatchEvent(e)}addEventListener(e,t){this._eventEmitter.addEventListener(e,t)}removeEventListener(e,t){this._eventEmitter.removeEventListener(e,t)}toggleXR(){this.webXrController.xrClicked()}setSignallingUrlBuilder(e){this._webRtcController.signallingUrlBuilder=e}get webRtcController(){return this._webRtcController}get signallingProtocol(){return this._webRtcController.protocol}get webXrController(){return this._webXrController}registerMessageHandler(e,t,n){if(t===S.FromStreamer&&typeof n>"u"){d.Warning(`Unable to register an undefined handler for ${e}`);return}t===S.ToStreamer&&typeof n>"u"?this._webRtcController.streamMessageController.registerMessageHandler(t,e,i=>this._webRtcController.sendMessageController.sendMessageToStreamer(e,i)):this._webRtcController.streamMessageController.registerMessageHandler(t,e,i=>n(i))}get toStreamerHandlers(){return this._webRtcController.streamMessageController.toStreamerHandlers}isReconnecting(){return this._webRtcController.isReconnecting}};var Tn=class{type=0},En=class{type=1},Rn=class{constructor(e){this.msg=e}msg;type=2};var kn=class{constructor(e){this.stats=e}stats;type=5};var Is="3.16.2";var ur="sessionEndedDueToInactivity",pr="sessionEndedByUser",Ps="sessionEndedDueToConnectionLoss",Ls="sessionEndedDueToVideoPlaybackError",mr="sessionEndedDueToPermissionsError";var Ds="sessionEndedDueToRendererError";var fr=(n=>(n.Good="Good",n.Fair="Fair",n.Poor="Poor",n))(fr||{}),gr=(n=>(n.Always="always",n.WhenDegraded="when-degraded",n.Hidden="hidden",n))(gr||{}),yr=(i=>(i.TopLeft="top-left",i.TopRight="top-right",i.BottomLeft="bottom-left",i.BottomRight="bottom-right",i))(yr||{}),Sr=(n=>(n.Click="click",n.Hover="hover",n.None="none",n))(Sr||{});function Ie(s,e,t){return Math.max(e,Math.min(s,t))}function br(s){let e=s.packetLoss??0,t=s.bufferDelay??50,n=s.roundTripTime??50,i=s.fec??!0,r=s.dtx??!1,o=s.bitrate,a=20+t+n/2,l=100,c=r?8:o?Ie(55-4.6*Math.log(o),0,30):6,u=i?20:10,w=c+(100-c)*(e/(e+u)),v=a*.03+(a>150?.1*(a-150):0),C=Ie(l-w-v,0,100),k=1+.035*C+C*(C-60)*(100-C)*7/1e6;return Ie(Math.round(k*100)/100,1,5)}function vr(s){let e=s.bitrate??0,t=s.roundTripTime??50,n=s.bufferDelay??0,i=s.width||640,r=s.height||480,o=s.frameRate??0,a=s.expectedFrameRate??30,l=s.codec?.toLowerCase();if(o===0)return 1;let c=i*r,u=l==="vp9"?1.2:1,w=n+t/2,v=u*e/c/o,k=Ie(.56*Math.log(v)+5.36,1,5)-1.9*Math.log(a/o)-w*.002;return Ie(Math.round(k*100)/100,1,5)}function xn(s){let e=s?.srcObject;return!!e&&typeof e.getAudioTracks=="function"&&e.getAudioTracks().length>0}var to=3.5,no=2.5,pe=class{constructor(e,t,n){this.stream=e;this.videoElement=t;this.audioElement=n}stream;videoElement;audioElement;previousStats;getPeerConnection(){return this.stream?.webRtcController?.peerConnectionController?.peerConnection}async analyzeAudioStats(){let e=this.getPeerConnection();if(!e){p.error("Stream appears to be down, RTCPeerConnection is not defined");return}let t=await e.getStats(null),n=this.getInboundAudioStats(t);if(!n){p.warn("WebRTC Connection - No inbound audio RTP stats found.");return}let i=n.codecId,r=i?this.getCodecFromStats(t,i):void 0;this.logAudioStats(n,r),this.logElementStatus(r)}async collectNetworkQuality(e){let t=this.getPeerConnection();if(!t)return p.warn("Cannot collect network quality: RTCPeerConnection is not defined"),null;let n=await t.getStats(null),i=this.extractRawStats(n);if(!this.previousStats)return this.previousStats=i,null;let r=this.computeMetrics(i,this.previousStats,e);return this.previousStats=i,r}resetStats(){this.previousStats=void 0}extractRawStats(e){let t={timestamp:Date.now(),audio:{packetsReceived:0,packetsLost:0,bytesReceived:0,jitter:0},video:{packetsReceived:0,packetsLost:0,bytesReceived:0,framesDecoded:0,framesDropped:0,frameWidth:0,frameHeight:0,framesPerSecond:0,jitter:0},connection:{currentRoundTripTime:0}},n,i;if(e.forEach(r=>{r.type==="inbound-rtp"&&r.kind==="audio"?(t.audio.packetsReceived=r.packetsReceived??0,t.audio.packetsLost=r.packetsLost??0,t.audio.bytesReceived=r.bytesReceived??0,t.audio.jitter=r.jitter??0,n=r.codecId):r.type==="inbound-rtp"&&r.kind==="video"?(t.video.packetsReceived=r.packetsReceived??0,t.video.packetsLost=r.packetsLost??0,t.video.bytesReceived=r.bytesReceived??0,t.video.framesDecoded=r.framesDecoded??0,t.video.framesDropped=r.framesDropped??0,t.video.frameWidth=r.frameWidth??0,t.video.frameHeight=r.frameHeight??0,t.video.framesPerSecond=r.framesPerSecond??0,t.video.jitter=r.jitter??0,i=r.codecId):r.type==="candidate-pair"&&r.nominated&&(t.connection.currentRoundTripTime=r.currentRoundTripTime??0)}),n){let r=e.get(n);r&&(t.audio.codecMimeType=r.mimeType)}if(i){let r=e.get(i);r&&(t.video.codecMimeType=r.mimeType)}return t}computeMetrics(e,t,n){let i=(e.timestamp-t.timestamp)/1e3,r=e.audio.packetsReceived-t.audio.packetsReceived,o=e.audio.packetsLost-t.audio.packetsLost,a=r+o,l=a>0?o/a*100:0,c=i>0?(e.audio.bytesReceived-t.audio.bytesReceived)*8/i/1e3:0,u=e.video.packetsReceived-t.video.packetsReceived,w=e.video.packetsLost-t.video.packetsLost,v=u+w,C=v>0?w/v*100:0,k=i>0?(e.video.bytesReceived-t.video.bytesReceived)*8/i/1e3:0,U=e.connection.currentRoundTripTime*1e3,H=br({packetLoss:l,bitrate:c*1e3,roundTripTime:U,bufferDelay:e.audio.jitter*1e3}),A=n.expectedFrameRate??30,Er=e.video.codecMimeType?.toLowerCase()??"",Rr=[["vp9","vp9"],["vp8","vp8"],["h264","h264"],["avc","h264"],["h265","h265"],["hevc","h265"],["av1","av1"]].find(([kr])=>Er.includes(kr))?.[1],As=vr({bitrate:k*1e3,roundTripTime:U,width:e.video.frameWidth,height:e.video.frameHeight,frameRate:e.video.framesPerSecond,expectedFrameRate:A,codec:Rr}),Ns=Math.min(H,As),De;return Ns>=to?De="Good":Ns>=no?De="Fair":De="Poor",{audioPacketLossPercent:Math.round(l*100)/100,videoPacketLossPercent:Math.round(C*100)/100,audioBitrateKbps:Math.round(c),videoBitrateKbps:Math.round(k),frameRate:e.video.framesPerSecond,audioJitterMs:Math.round(e.audio.jitter*1e3*100)/100,videoJitterMs:Math.round(e.video.jitter*1e3*100)/100,roundTripTimeMs:Math.round(U*100)/100,audioMos:H,videoMos:As,qualityLevel:De}}getInboundAudioStats(e){let t=null;return e.forEach(n=>{n.type==="inbound-rtp"&&n.kind==="audio"&&(t=n)}),t}getCodecFromStats(e,t){let n;return e.forEach(i=>{i.type==="codec"&&i.id===t&&(n=i)}),n}logAudioStats(e,t){let{packetsReceived:n,packetsLost:i,bytesReceived:r,jitter:o,audioLevel:a}=e;p.info(`WebRTC Connection - Audio -
|
|
81
|
+
`}),t}}}isRunning(){return!!this.intervalHandle}receive(e){if(!this.isRunning())return;if(!e){d.Error("Undefined response from server");return}let t=this.records.get(e.Seq);t&&t.update(e)}sendRequest(e,t){let n=this.createRequest(e,t),i=new Cn(n);this.records.set(i.seq,i),this.sink(n)}createRequest(e,t){return{Seq:this.seq++,FillResponseSize:t,Filler:e?"A".repeat(e):""}}};var xe=class{constructor(e,t){this.allowConsoleCommands=!1,this.config=e,t?.videoElementParent&&(this._videoElementParent=t.videoElementParent),this._eventEmitter=new $t,this.configureSettings(),this.setWebRtcPlayerController(new bn(this.config,this)),this._webXrController=new wn(this._webRtcController),this._setupWebRtcTCPRelayDetection=this._setupWebRtcTCPRelayDetection.bind(this),this._eventEmitter.addEventListener("webRtcConnected",n=>{this._eventEmitter.addEventListener("statsReceived",this._setupWebRtcTCPRelayDetection)})}get videoElementParent(){return this._videoElementParent||(this._videoElementParent=document.createElement("div"),this._videoElementParent.id="videoElementParent"),this._videoElementParent}configureSettings(){this.config._addOnSettingChangedListener(h.IsQualityController,e=>{e===!0&&!this._webRtcController.isQualityController&&this._webRtcController.sendRequestQualityControlOwnership()}),this.config._addOnSettingChangedListener(h.AFKDetection,e=>{this._webRtcController.setAfkEnabled(e)}),this.config._addOnSettingChangedListener(h.MatchViewportResolution,()=>{this._webRtcController.videoPlayer.updateVideoStreamSize()}),this.config._addOnSettingChangedListener(h.HoveringMouseMode,e=>{this.config.setFlagLabel(h.HoveringMouseMode,`Control Scheme: ${e?"Hovering":"Locked"} Mouse`),this._webRtcController.setMouseInputEnabled(this.config.isFlagEnabled(h.MouseInput))}),this.config._addOnSettingChangedListener(h.KeyboardInput,e=>{this._webRtcController.setKeyboardInputEnabled(e)}),this.config._addOnSettingChangedListener(h.MouseInput,e=>{this._webRtcController.setMouseInputEnabled(e)}),this.config._addOnSettingChangedListener(h.FakeMouseWithTouches,e=>{this._webRtcController.setTouchInputEnabled(this.config.isFlagEnabled(h.TouchInput))}),this.config._addOnSettingChangedListener(h.TouchInput,e=>{this._webRtcController.setTouchInputEnabled(e)}),this.config._addOnSettingChangedListener(h.GamepadInput,e=>{this._webRtcController.setGamePadInputEnabled(e)}),this.config._addOnNumericSettingChangedListener(m.MinQP,e=>{d.Info("-------- Sending MinQP --------"),this._webRtcController.sendEncoderMinQP(e),d.Info("-------------------------------------------");let t=Math.trunc(100*(1-e/51));this.config.setNumericSetting(m.CompatQualityMax,t)}),this.config._addOnNumericSettingChangedListener(m.MaxQP,e=>{d.Info("-------- Sending MaxQP --------"),this._webRtcController.sendEncoderMaxQP(e),d.Info("-------------------------------------------");let t=Math.trunc(100*(1-e/51));this.config.setNumericSetting(m.CompatQualityMin,t)}),this.config._addOnNumericSettingChangedListener(m.MinQuality,e=>{d.Info("-------- Sending MinQuality --------"),this._webRtcController.sendEncoderMinQuality(e),d.Info("-------------------------------------------"),this.config.setNumericSetting(m.CompatQualityMin,e)}),this.config._addOnNumericSettingChangedListener(m.MaxQuality,e=>{d.Info("-------- Sending MaxQuality --------"),this._webRtcController.sendEncoderMaxQuality(e),d.Info("-------------------------------------------"),this.config.setNumericSetting(m.CompatQualityMax,e)}),this.config._addOnNumericSettingChangedListener(m.CompatQualityMin,e=>{e=51-e/100*51,d.Info("-------- Sending MinQP from quality value --------"),this._webRtcController.sendEncoderMaxQP(e),d.Info("-------------------------------------------")}),this.config._addOnNumericSettingChangedListener(m.CompatQualityMax,e=>{e=51-e/100*51,d.Info("-------- Sending MaxQP from quality value --------"),this._webRtcController.sendEncoderMinQP(e),d.Info("-------------------------------------------")}),this.config._addOnNumericSettingChangedListener(m.WebRTCMinBitrate,e=>{d.Info("-------- Sending web rtc settings --------"),this._webRtcController.sendWebRTCMinBitrate(e*1e3),d.Info("-------------------------------------------")}),this.config._addOnNumericSettingChangedListener(m.WebRTCMaxBitrate,e=>{d.Info("-------- Sending web rtc settings --------"),this._webRtcController.sendWebRTCMaxBitrate(e*1e3),d.Info("-------------------------------------------")}),this.config._addOnNumericSettingChangedListener(m.WebRTCFPS,e=>{d.Info("-------- Sending web rtc settings --------"),this._webRtcController.sendWebRTCFps(e),d.Info("-------------------------------------------")}),this.config._addOnOptionSettingChangedListener(M.PreferredCodec,e=>{this._webRtcController&&this._webRtcController.setPreferredCodec(e)}),this.config._registerOnChangeEvents(this._eventEmitter)}_onInputControlOwnership(e){this._inputController=e}setWebRtcPlayerController(e){this._webRtcController=e,this._webRtcController.setPreferredCodec(this.config.getSettingOption(M.PreferredCodec).selected),this._webRtcController.resizePlayerStyle(),this.checkForAutoConnect()}connect(){this._eventEmitter.dispatchEvent(new Mt),this._webRtcController.connectToSignallingServer()}reconnect(){this._eventEmitter.dispatchEvent(new Et),this._webRtcController.tryReconnect("Reconnecting...")}disconnect(){this._eventEmitter.dispatchEvent(new Tt),this._webRtcController.close()}play(){this._onStreamLoading(),this._webRtcController.playStream()}checkForAutoConnect(){this.config.isFlagEnabled(h.AutoConnect)&&(this._onWebRtcAutoConnect(),this._webRtcController.connectToSignallingServer())}unmuteMicrophone(e=!1){if(this.config.isFlagEnabled("UseMic")){this.setMicrophoneMuted(!1);return}if(e){this.config.setFlagEnabled("UseMic",!0),this.reconnect();return}d.Warning("Trying to unmute mic, but PixelStreaming was initialized with no microphone track. Call with forceEnable == true to re-connect with a mic track.")}muteMicrophone(){if(this.config.isFlagEnabled("UseMic")){this.setMicrophoneMuted(!0);return}d.Info("Trying to mute mic, but PixelStreaming has no microphone track, so sending sound is already disabled.")}setMicrophoneMuted(e){var t,n,i,r;for(let o of(r=(i=(n=(t=this._webRtcController)===null||t===void 0?void 0:t.peerConnectionController)===null||n===void 0?void 0:n.peerConnection)===null||i===void 0?void 0:i.getTransceivers())!==null&&r!==void 0?r:[])Z.canTransceiverSendAudio(o)&&(o.sender.track.enabled=!e)}unmuteCamera(e=!1){if(this.config.isFlagEnabled("UseCamera")){this.setCameraMuted(!1);return}if(e){this.config.setFlagEnabled("UseCamera",!0),this.reconnect();return}d.Warning("Trying to unmute video, but PixelStreaming was initialized with no video track. Call with forceEnable == true to re-connect with a video track.")}muteCamera(){if(this.config.isFlagEnabled("UseCamera")){this.setCameraMuted(!0);return}d.Info("Trying to mute camera, but PixelStreaming has no video track, so sending video is already disabled.")}setCameraMuted(e){var t,n,i,r;for(let o of(r=(i=(n=(t=this._webRtcController)===null||t===void 0?void 0:t.peerConnectionController)===null||n===void 0?void 0:n.peerConnection)===null||i===void 0?void 0:i.getTransceivers())!==null&&r!==void 0?r:[])Z.canTransceiverSendVideo(o)&&(o.sender.track.enabled=!e)}_onWebRtcAutoConnect(){this._eventEmitter.dispatchEvent(new pt)}_onWebRtcSdp(){this._eventEmitter.dispatchEvent(new dt)}_onWebRtcSdpOffer(e){this._eventEmitter.dispatchEvent(new ut({sdp:e}))}_onWebRtcSdpAnswer(e){this._eventEmitter.dispatchEvent(new ht({sdp:e}))}_onLatencyCalculated(e){this._eventEmitter.dispatchEvent(new Ft({latencyInfo:e}))}_onStreamLoading(){this._eventEmitter.dispatchEvent(new Ct)}_onDisconnect(e,t){this._eventEmitter.dispatchEvent(new yt({eventString:e,allowClickToReconnect:t}))}_onWebRtcConnecting(){this._eventEmitter.dispatchEvent(new mt)}_onWebRtcConnected(){this._eventEmitter.dispatchEvent(new ft)}_onWebRtcFailed(){this._eventEmitter.dispatchEvent(new gt)}_onVideoInitialized(){this._eventEmitter.dispatchEvent(new wt),this._videoStartTime=Date.now()}_onLatencyTestResult(e){this._eventEmitter.dispatchEvent(new Ot({latencyTimings:e}))}_onDataChannelLatencyTestResponse(e){this._eventEmitter.dispatchEvent(new Nt({response:e}))}_onVideoStats(e){(!this._videoStartTime||this._videoStartTime===void 0)&&(this._videoStartTime=Date.now()),e.handleSessionStatistics(this._videoStartTime,this._inputController,this._webRtcController.videoAvgQp),this._eventEmitter.dispatchEvent(new Pt({aggregatedStats:e}))}_onVideoEncoderAvgQP(e){this._eventEmitter.dispatchEvent(new ct({avgQP:e}))}_onInitialSettings(e){var t;this._eventEmitter.dispatchEvent(new Vt({settings:e})),e.PixelStreamingSettings&&(this.allowConsoleCommands=(t=e.PixelStreamingSettings.AllowPixelStreamingCommands)!==null&&t!==void 0?t:!1,this.allowConsoleCommands===!1&&d.Info("-AllowPixelStreamingCommands=false, sending arbitrary console commands from browser to UE is disabled."));let n=this.config.useUrlParams,i=new ue(window.location.search);d.Info(`using URL parameters ${n}`),e.EncoderSettings&&(e.EncoderSettings.MinQP&&(this.config.setNumericSetting(m.MinQP,n&&i.has(m.MinQP)?Number.parseFloat(i.get(m.MinQP)):e.EncoderSettings.MinQP||0),this.config.setNumericSetting(m.MaxQP,n&&i.has(m.MaxQP)?Number.parseFloat(i.get(m.MaxQP)):e.EncoderSettings.MaxQP||51)),e.EncoderSettings.MinQuality&&(this.config.setNumericSetting(m.MinQuality,n&&i.has(m.MinQuality)?Number.parseFloat(i.get(m.MinQuality)):e.EncoderSettings.MinQuality||0),this.config.setNumericSetting(m.MaxQuality,n&&i.has(m.MaxQuality)?Number.parseFloat(i.get(m.MaxQuality)):e.EncoderSettings.MaxQuality||100)),n&&(i.has(m.CompatQualityMin)&&this.config.setNumericSetting(m.CompatQualityMin,Number.parseFloat(i.get(m.CompatQualityMin))),i.has(m.CompatQualityMax)&&this.config.setNumericSetting(m.CompatQualityMax,Number.parseFloat(i.get(m.CompatQualityMax))))),e.WebRTCSettings&&(this.config.setNumericSetting(m.WebRTCMinBitrate,n&&i.has(m.WebRTCMinBitrate)?Number.parseFloat(i.get(m.WebRTCMinBitrate)):e.WebRTCSettings.MinBitrate/1e3),this.config.setNumericSetting(m.WebRTCMaxBitrate,n&&i.has(m.WebRTCMaxBitrate)?Number.parseFloat(i.get(m.WebRTCMaxBitrate)):e.WebRTCSettings.MaxBitrate/1e3),this.config.setNumericSetting(m.WebRTCFPS,n&&i.has(m.WebRTCFPS)?Number.parseFloat(i.get(m.WebRTCFPS)):e.WebRTCSettings.FPS))}_onQualityControlOwnership(e){this.config.setFlagEnabled(h.IsQualityController,e)}_onPlayerCount(e){this._eventEmitter.dispatchEvent(new Wt({count:e}))}_onSubscribeFailed(e){this._eventEmitter.dispatchEvent(new Bt({message:e}))}_setupWebRtcTCPRelayDetection(e){let t=e.data.aggregatedStats.getActiveCandidatePair();if(t!=null){let n=e.data.aggregatedStats.localCandidates.find(i=>i.id==t.localCandidateId,null);n!=null&&n.candidateType=="relay"&&n.relayProtocol=="tcp"&&this._eventEmitter.dispatchEvent(new Ht),this._eventEmitter.removeEventListener("statsReceived",this._setupWebRtcTCPRelayDetection)}}requestLatencyTest(){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.sendLatencyTest(),!0):!1}requestDataChannelLatencyTest(e){return this._webRtcController.videoPlayer.isVideoReady()?(this._dataChannelLatencyTestController||(this._dataChannelLatencyTestController=new Mn(this._webRtcController.sendDataChannelLatencyTest.bind(this._webRtcController),t=>{this._eventEmitter.dispatchEvent(new Ut({result:t}))}),this.addEventListener("dataChannelLatencyTestResponse",({data:{response:t}})=>{this._dataChannelLatencyTestController.receive(t)})),this._dataChannelLatencyTestController.start(e)):!1}requestShowFps(){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.sendShowFps(),!0):!1}requestIframe(){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.sendIframeRequest(),!0):!1}emitUIInteraction(e){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.emitUIInteraction(e),!0):!1}emitCommand(e){return!this._webRtcController.videoPlayer.isVideoReady()||!this.allowConsoleCommands&&"ConsoleCommand"in e?!1:(this._webRtcController.emitCommand(e),!0)}emitConsoleCommand(e){return!this.allowConsoleCommands||!this._webRtcController.videoPlayer.isVideoReady()?!1:(this._webRtcController.emitConsoleCommand(e),!0)}sendTextboxEntry(e){return this._webRtcController.videoPlayer.isVideoReady()?(this._webRtcController.sendTextboxEntry(e),!0):!1}addResponseEventListener(e,t){this._webRtcController.responseController.addResponseEventListener(e,t)}removeResponseEventListener(e){this._webRtcController.responseController.removeResponseEventListener(e)}dispatchEvent(e){return this._eventEmitter.dispatchEvent(e)}addEventListener(e,t){this._eventEmitter.addEventListener(e,t)}removeEventListener(e,t){this._eventEmitter.removeEventListener(e,t)}toggleXR(){this.webXrController.xrClicked()}setSignallingUrlBuilder(e){this._webRtcController.signallingUrlBuilder=e}get webRtcController(){return this._webRtcController}get signallingProtocol(){return this._webRtcController.protocol}get webXrController(){return this._webXrController}registerMessageHandler(e,t,n){if(t===S.FromStreamer&&typeof n>"u"){d.Warning(`Unable to register an undefined handler for ${e}`);return}t===S.ToStreamer&&typeof n>"u"?this._webRtcController.streamMessageController.registerMessageHandler(t,e,i=>this._webRtcController.sendMessageController.sendMessageToStreamer(e,i)):this._webRtcController.streamMessageController.registerMessageHandler(t,e,i=>n(i))}get toStreamerHandlers(){return this._webRtcController.streamMessageController.toStreamerHandlers}isReconnecting(){return this._webRtcController.isReconnecting}};var Tn=class{type=0},En=class{type=1},Rn=class{constructor(e){this.msg=e}msg;type=2};var kn=class{constructor(e){this.stats=e}stats;type=5};var Is="3.16.4";var ur="sessionEndedDueToInactivity",pr="sessionEndedByUser",Ps="sessionEndedDueToConnectionLoss",Ls="sessionEndedDueToVideoPlaybackError",mr="sessionEndedDueToPermissionsError";var Ds="sessionEndedDueToRendererError";var fr=(n=>(n.Good="Good",n.Fair="Fair",n.Poor="Poor",n))(fr||{}),gr=(n=>(n.Always="always",n.WhenDegraded="when-degraded",n.Hidden="hidden",n))(gr||{}),yr=(i=>(i.TopLeft="top-left",i.TopRight="top-right",i.BottomLeft="bottom-left",i.BottomRight="bottom-right",i))(yr||{}),Sr=(n=>(n.Click="click",n.Hover="hover",n.None="none",n))(Sr||{});function Ie(s,e,t){return Math.max(e,Math.min(s,t))}function br(s){let e=s.packetLoss??0,t=s.bufferDelay??50,n=s.roundTripTime??50,i=s.fec??!0,r=s.dtx??!1,o=s.bitrate,a=20+t+n/2,l=100,c=r?8:o?Ie(55-4.6*Math.log(o),0,30):6,u=i?20:10,w=c+(100-c)*(e/(e+u)),v=a*.03+(a>150?.1*(a-150):0),C=Ie(l-w-v,0,100),k=1+.035*C+C*(C-60)*(100-C)*7/1e6;return Ie(Math.round(k*100)/100,1,5)}function vr(s){let e=s.bitrate??0,t=s.roundTripTime??50,n=s.bufferDelay??0,i=s.width||640,r=s.height||480,o=s.frameRate??0,a=s.expectedFrameRate??30,l=s.codec?.toLowerCase();if(o===0)return 1;let c=i*r,u=l==="vp9"?1.2:1,w=n+t/2,v=u*e/c/o,k=Ie(.56*Math.log(v)+5.36,1,5)-1.9*Math.log(a/o)-w*.002;return Ie(Math.round(k*100)/100,1,5)}function xn(s){let e=s?.srcObject;return!!e&&typeof e.getAudioTracks=="function"&&e.getAudioTracks().length>0}var to=3.5,no=2.5,pe=class{constructor(e,t,n){this.stream=e;this.videoElement=t;this.audioElement=n}stream;videoElement;audioElement;previousStats;getPeerConnection(){return this.stream?.webRtcController?.peerConnectionController?.peerConnection}async analyzeAudioStats(){let e=this.getPeerConnection();if(!e){p.error("Stream appears to be down, RTCPeerConnection is not defined");return}let t=await e.getStats(null),n=this.getInboundAudioStats(t);if(!n){p.warn("WebRTC Connection - No inbound audio RTP stats found.");return}let i=n.codecId,r=i?this.getCodecFromStats(t,i):void 0;this.logAudioStats(n,r),this.logElementStatus(r)}async collectNetworkQuality(e){let t=this.getPeerConnection();if(!t)return p.warn("Cannot collect network quality: RTCPeerConnection is not defined"),null;let n=await t.getStats(null),i=this.extractRawStats(n);if(!this.previousStats)return this.previousStats=i,null;let r=this.computeMetrics(i,this.previousStats,e);return this.previousStats=i,r}resetStats(){this.previousStats=void 0}extractRawStats(e){let t={timestamp:Date.now(),audio:{packetsReceived:0,packetsLost:0,bytesReceived:0,jitter:0},video:{packetsReceived:0,packetsLost:0,bytesReceived:0,framesDecoded:0,framesDropped:0,frameWidth:0,frameHeight:0,framesPerSecond:0,jitter:0},connection:{currentRoundTripTime:0}},n,i;if(e.forEach(r=>{r.type==="inbound-rtp"&&r.kind==="audio"?(t.audio.packetsReceived=r.packetsReceived??0,t.audio.packetsLost=r.packetsLost??0,t.audio.bytesReceived=r.bytesReceived??0,t.audio.jitter=r.jitter??0,n=r.codecId):r.type==="inbound-rtp"&&r.kind==="video"?(t.video.packetsReceived=r.packetsReceived??0,t.video.packetsLost=r.packetsLost??0,t.video.bytesReceived=r.bytesReceived??0,t.video.framesDecoded=r.framesDecoded??0,t.video.framesDropped=r.framesDropped??0,t.video.frameWidth=r.frameWidth??0,t.video.frameHeight=r.frameHeight??0,t.video.framesPerSecond=r.framesPerSecond??0,t.video.jitter=r.jitter??0,i=r.codecId):r.type==="candidate-pair"&&r.nominated&&(t.connection.currentRoundTripTime=r.currentRoundTripTime??0)}),n){let r=e.get(n);r&&(t.audio.codecMimeType=r.mimeType)}if(i){let r=e.get(i);r&&(t.video.codecMimeType=r.mimeType)}return t}computeMetrics(e,t,n){let i=(e.timestamp-t.timestamp)/1e3,r=e.audio.packetsReceived-t.audio.packetsReceived,o=e.audio.packetsLost-t.audio.packetsLost,a=r+o,l=a>0?o/a*100:0,c=i>0?(e.audio.bytesReceived-t.audio.bytesReceived)*8/i/1e3:0,u=e.video.packetsReceived-t.video.packetsReceived,w=e.video.packetsLost-t.video.packetsLost,v=u+w,C=v>0?w/v*100:0,k=i>0?(e.video.bytesReceived-t.video.bytesReceived)*8/i/1e3:0,U=e.connection.currentRoundTripTime*1e3,H=br({packetLoss:l,bitrate:c*1e3,roundTripTime:U,bufferDelay:e.audio.jitter*1e3}),A=n.expectedFrameRate??30,Er=e.video.codecMimeType?.toLowerCase()??"",Rr=[["vp9","vp9"],["vp8","vp8"],["h264","h264"],["avc","h264"],["h265","h265"],["hevc","h265"],["av1","av1"]].find(([kr])=>Er.includes(kr))?.[1],As=vr({bitrate:k*1e3,roundTripTime:U,width:e.video.frameWidth,height:e.video.frameHeight,frameRate:e.video.framesPerSecond,expectedFrameRate:A,codec:Rr}),Ns=Math.min(H,As),De;return Ns>=to?De="Good":Ns>=no?De="Fair":De="Poor",{audioPacketLossPercent:Math.round(l*100)/100,videoPacketLossPercent:Math.round(C*100)/100,audioBitrateKbps:Math.round(c),videoBitrateKbps:Math.round(k),frameRate:e.video.framesPerSecond,audioJitterMs:Math.round(e.audio.jitter*1e3*100)/100,videoJitterMs:Math.round(e.video.jitter*1e3*100)/100,roundTripTimeMs:Math.round(U*100)/100,audioMos:H,videoMos:As,qualityLevel:De}}getInboundAudioStats(e){let t=null;return e.forEach(n=>{n.type==="inbound-rtp"&&n.kind==="audio"&&(t=n)}),t}getCodecFromStats(e,t){let n;return e.forEach(i=>{i.type==="codec"&&i.id===t&&(n=i)}),n}logAudioStats(e,t){let{packetsReceived:n,packetsLost:i,bytesReceived:r,jitter:o,audioLevel:a}=e;p.info(`WebRTC Connection - Audio -
|
|
82
82
|
Codec: ${t?t.mimeType+" ("+t.payloadType+")":"Unknown"},
|
|
83
83
|
Packets received: ${n},
|
|
84
84
|
Packets lost: ${i},
|
|
85
85
|
Bytes received: ${r},
|
|
86
86
|
Jitter: ${o},
|
|
87
|
-
Audio level (0-1): ${a??"N/A"}`),n===0&&p.warn("WebRTC Connection - Audio - No audio packets received \u2014 remote is probably not sending audio."),i>0&&p.warn(`WebRTC Connection - Audio - packet loss detected: ${i} packets lost.`),a===void 0?p.warn("WebRTC Connection - Audio - Audio level not available in stats."):a===0?p.warn("WebRTC Connection - Audio - Audio level is zero \u2014 digital human might not be talking at this exact moment as audio is silent or muted."):a<.02?p.warn("WebRTC Connection - Audio - Audio level is very low \u2014 audio might be too quiet."):p.info("WebRTC Connection - Audio - Audio level looks normal, digital human is likely speaking.")}logElementStatus(e){let t=xn(this.videoElement),n=t?this.videoElement:this.audioElement;p.debug(`Audio plays from ${t?"video":"separate audio"} element (DisableAudioSync=${t?"false":"true"}).`),p.debug(`Video element muted: ${this.videoElement?.muted}, (should be ${t?"false to be able to hear the digital human":"true as part of avoiding auto play restrictions"})`),p.debug(`Playback element muted: ${n?.muted}, (should be false to be able to hear the digital human)`),p.debug(`Playback element volume: ${n?.volume}, (should be greater than zero to be able to hear the digital human)`);let i=e?.mimeType;i&&n&&(p.debug(`Playback element can play webrtc audio codec (${i}) : ${n.canPlayType(i)}, (should be 'probably' or 'maybe)'`),i==="audio/opus"&&p.debug(`Audio codec opus is often known as ogg, so checking can play ogg codec: ${n.canPlayType("audio/ogg")}, (should be 'probably' or 'maybe')`))}};var Pe={good:"#22c55e",fair:"#eab308",poor:"#ef4444",inactive:"#6b7280"},In=class{constructor(e,t){this.videoContainerElement=e;this.visibility=t.visibility??"when-degraded",this.position=t.position??"top-right",this.popupTrigger=t.popupTrigger??"click",this.onClickBound=this.onClick.bind(this),this.onMouseEventBound=n=>n.stopPropagation(),this.onDocumentClickBound=this.onDocumentClick.bind(this),this.onMouseEnterBound=this.onMouseEnter.bind(this),this.onMouseLeaveBound=this.onMouseLeave.bind(this),this.visibility!=="hidden"&&this.createElements()}videoContainerElement;container;panel;bars=[];panelVisible=!1;lastMetrics;visibility;position;popupTrigger;onClickBound;onMouseEventBound;onDocumentClickBound;onMouseEnterBound;onMouseLeaveBound;hoverHideTimeout;originalParentPosition;createElements(){getComputedStyle(this.videoContainerElement).position==="static"&&(this.originalParentPosition=this.videoContainerElement.style.position,this.videoContainerElement.style.position="relative"),this.container=document.createElement("div"),this.container.setAttribute("data-testid","network-indicator"),this.container.setAttribute("role","status"),this.container.setAttribute("aria-live","polite"),this.container.setAttribute("aria-label","Network quality: unknown"),Object.assign(this.container.style,{position:"absolute",zIndex:"1000",cursor:"pointer",padding:"6px 7px",borderRadius:"4px",background:"rgba(0, 0, 0, 0.5)",display:"none",alignItems:"flex-end",gap:"2px",pointerEvents:"auto",...this.getPositionStyles()});let t=[6,12,18];for(let n of t){let i=document.createElement("div");i.setAttribute("data-testid","network-indicator-bar"),Object.assign(i.style,{width:"4px",height:`${n}px`,borderRadius:"1px",background:Pe.inactive,transition:"background 0.3s ease"}),this.bars.push(i),this.container.appendChild(i)}this.container.addEventListener("mousedown",this.onMouseEventBound),this.container.addEventListener("mouseup",this.onMouseEventBound),this.popupTrigger==="click"?this.container.addEventListener("click",this.onClickBound):this.popupTrigger==="hover"&&(this.container.addEventListener("mouseenter",this.onMouseEnterBound),this.container.addEventListener("mouseleave",this.onMouseLeaveBound)),this.popupTrigger==="none"&&(this.container.style.cursor="default"),this.videoContainerElement.appendChild(this.container)}getPositionStyles(){switch(this.position){case"top-left":return{top:"8px",left:"8px"};case"top-right":return{top:"8px",right:"8px"};case"bottom-left":return{bottom:"8px",left:"8px"};case"bottom-right":return{bottom:"8px",right:"8px"};default:return{top:"8px",right:"8px"}}}onClick(e){e.stopPropagation(),this.panelVisible?this.hidePanel():this.showPanel()}onDocumentClick(e){this.panelVisible&&this.container&&!this.container.contains(e.target)&&this.hidePanel()}onMouseEnter(){clearTimeout(this.hoverHideTimeout),this.showPanel()}onMouseLeave(){this.scheduleHoverHide()}scheduleHoverHide(){clearTimeout(this.hoverHideTimeout),this.hoverHideTimeout=setTimeout(()=>this.hidePanel(),50)}showPanel(){!this.container||!this.lastMetrics||(this.panel||(this.panel=document.createElement("div"),this.panel.setAttribute("data-testid","network-indicator-panel"),Object.assign(this.panel.style,{position:"fixed",padding:"10px",borderRadius:"6px",background:"rgba(0, 0, 0, 0.85)",color:"#ffffff",fontSize:"11px",fontFamily:"system-ui, -apple-system, sans-serif",whiteSpace:"nowrap",lineHeight:"1.6",minWidth:"180px",zIndex:"10001",pointerEvents:"auto"}),this.popupTrigger==="hover"&&(this.panel.addEventListener("mouseenter",this.onMouseEnterBound),this.panel.addEventListener("mouseleave",this.onMouseLeaveBound)),document.body.appendChild(this.panel)),this.updatePanel(),this.positionPanel(),this.panel.style.display="block",this.panelVisible=!0,document.addEventListener("click",this.onDocumentClickBound))}hidePanel(){this.panel&&(this.panel.style.display="none"),this.panelVisible=!1,document.removeEventListener("click",this.onDocumentClickBound)}positionPanel(){if(!this.panel||!this.container)return;let e=4,t=4,n=window.innerWidth,i=window.innerHeight,r=this.container.getBoundingClientRect(),o={top:Math.max(0,Math.min(r.top,i)),bottom:Math.max(0,Math.min(r.bottom,i)),left:Math.max(0,Math.min(r.left,n)),right:Math.max(0,Math.min(r.right,n))};this.panel.style.top="",this.panel.style.bottom="",this.panel.style.left="",this.panel.style.right="",this.panel.style.visibility="hidden",this.panel.style.display="block";let{width:a,height:l}=this.panel.getBoundingClientRect();this.panel.style.visibility="";let c=o.top-e,u=i-o.bottom-e,w=o.left-e,v=n-o.right-e,C,k;c>=l||u>=l?(C=u>=l&&(c<l||u>=c)?o.bottom+e:o.top-e-l,k=this.position==="top-left"||this.position==="bottom-left"?o.left:o.right-a):(k=v>=a&&(w<a||v>=w)?o.right+e:o.left-e-a,C=o.bottom-l),k=Math.max(t,Math.min(k,n-a-t)),C=Math.max(0,Math.min(C,i-l-t)),this.panel.style.top=`${C}px`,this.panel.style.left=`${k}px`}updatePanel(){if(!this.panel||!this.lastMetrics)return;let e=this.lastMetrics,t=this.getColor(e.qualityLevel);this.panel.innerHTML=[`<div style="font-weight:600;margin-bottom:4px;color:${t}">${e.qualityLevel} Quality</div>`,this.panelSectionHeader("Quality Score (MOS)"),this.panelRow("Audio",e.audioMos.toFixed(1)+" / 5.0"),this.panelRow("Video",e.videoMos.toFixed(1)+" / 5.0"),this.panelSectionHeader("Connection"),this.panelRow("Round Trip",`${e.roundTripTimeMs} ms`),this.panelRow("Packet Loss",`${e.audioPacketLossPercent}% audio / ${e.videoPacketLossPercent}% video`),this.panelRow("Jitter",`${e.audioJitterMs} ms audio / ${e.videoJitterMs} ms video`),this.panelSectionHeader("Throughput"),this.panelRow("Bitrate",`${e.audioBitrateKbps} audio / ${e.videoBitrateKbps} video kbps`),this.panelRow("Frame Rate",`${e.frameRate} fps`)].join("")}panelSectionHeader(e){return`<div style="color:#6b7280;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;margin-top:6px;margin-bottom:2px">${e}</div>`}panelRow(e,t){return`<div style="display:flex;justify-content:space-between;gap:12px"><span style="color:#9ca3af">${e}</span><span>${t}</span></div>`}getColor(e){switch(e){case"Good":return Pe.good;case"Fair":return Pe.fair;case"Poor":return Pe.poor}}update(e){if(this.lastMetrics=e,!this.container)return;this.container.setAttribute("aria-label",`Network quality: ${e.qualityLevel}`);let t=this.getColor(e.qualityLevel),n=e.qualityLevel==="Good"?3:e.qualityLevel==="Fair"?2:1;this.bars.forEach((i,r)=>{i.style.background=r<n?t:Pe.inactive}),this.visibility==="when-degraded"?this.container.style.display=e.qualityLevel==="Good"?"none":"flex":this.container.style.display="flex",this.panelVisible&&(this.updatePanel(),this.positionPanel())}destroy(){this.container&&(this.container.removeEventListener("click",this.onClickBound),this.container.removeEventListener("mousedown",this.onMouseEventBound),this.container.removeEventListener("mouseup",this.onMouseEventBound),this.container.removeEventListener("mouseenter",this.onMouseEnterBound),this.container.removeEventListener("mouseleave",this.onMouseLeaveBound),this.container.remove(),this.container=void 0),this.originalParentPosition!==void 0&&(this.videoContainerElement.style.position=this.originalParentPosition,this.originalParentPosition=void 0),clearTimeout(this.hoverHideTimeout),this.panel&&(this.panel.removeEventListener("mouseenter",this.onMouseEnterBound),this.panel.removeEventListener("mouseleave",this.onMouseLeaveBound),this.panel.remove(),this.panel=void 0),document.removeEventListener("click",this.onDocumentClickBound),this.bars=[],this.panelVisible=!1,this.lastMetrics=void 0}};var Pn=class{constructor(e,t,n){this.session=e;this.connectionUrl=t;this.videoContainerElement=n;this.config=e.config,this.clientMessages=e.messages,this._audioUpstreamMode=G(this.config.audioUpstreamMode)}session;connectionUrl;videoContainerElement;stream;messages=new io;videoElement;audioElement;videoInitialized=!1;dataChannelOpen=!1;sceneReady=!1;maxReconnectAttempts=4;reconnectionAttempts=0;allowReconnection=!0;reconnectTimeoutId;baseReconnectDelayMs=500;maxReconnectDelayMs=1e4;audioStatsInternal;freezeCount=0;lastDecodedFrames=0;lastCheckTime=Date.now();audioStatsAnalyzer;networkQualityInterval;networkIndicator;config;clientMessages;_audioUpstreamMode;get audioUpstreamMode(){return this._audioUpstreamMode}init(){p.info("Connection config",{connectionUrl:this.connectionUrl,forceTURN:this.config.forceTURN}),this.videoContainerElement||(this.videoContainerElement=document.createElement("div"),document.body.appendChild(this.videoContainerElement)),this.clientMessages?.next(new si);let e=re(this.audioUpstreamMode);this.audioUpstreamMode!=="speech-recognition-service"&&p.info(`audioUpstreamMode='${this.audioUpstreamMode}' is beta; behaviour may change.`);let t=new zt({initialSettings:{AutoConnect:!1,AutoPlayVideo:!1,ForceTURN:this.config.forceTURN,HoveringMouse:!1,KeyboardInput:!1,MaxReconnectAttempts:0,MouseInput:!1,ss:this.connectionUrl,StartVideoMuted:!0,TouchInput:!1,UseMic:e,WaitForStreamer:!0}});this.stream=new xe(t,{videoElementParent:this.videoContainerElement}),d.InitLogging(K.Warning,!1);let n=function(){let i=t.getTextSettingValue($.SignallingServerUrl);return t.isFlagEnabled(h.BrowserSendOffer)&&(i+=(i.includes("?")?"&":"?")+h.BrowserSendOffer+"=true"),i};this.stream.setSignallingUrlBuilder(n),this.addStreamHandlers(),this.stream.connect(),this.addWebSocketHandlers()}addStreamHandlers(){this.stream?.addEventListener("videoInitialized",this.handleVideoInitialized.bind(this)),this.stream?.addEventListener("dataChannelOpen",this.handleDataChannelOpen.bind(this)),this.stream?.addEventListener("webRtcFailed",this.handleWebRtcFailed.bind(this)),this.stream?.addEventListener("webRtcDisconnected",this.handleWebRtcDisconnected.bind(this)),this.stream?.addEventListener("statsReceived",this.handleWebRtcStats.bind(this)),this.stream?.addResponseEventListener("response-listener",this.handleDataChannelMessage.bind(this)),this.stream?.addEventListener("videoEncoderAvgQP",({data:{avgQP:e}})=>{p.trace("WebRTC: VideoEncoderAvgQP - lower is better, ranges from 0 to 51:",e)}),this.stream?.addEventListener("webRtcAutoConnect",()=>{p.debug("WebRTC: AutoConnect triggered")}),this.stream?.addEventListener("webRtcConnected",this.handleWebRtcConnectedMessage.bind(this)),this.stream?.addEventListener("statsReceived",({data:{aggregatedStats:e}})=>{p.trace("WebRTC: StatsReceived",e)}),this.stream?.addEventListener("webRtcTCPRelayDetected",()=>{p.warn("WebRTC: Stream quailty likely degraded due to network enviroment, stream is relayed over TCP.")})}addWebSocketHandlers(){let e=this.stream?.signallingProtocol?.transport;e?.webSocket?.addEventListener("error",this.handleWebSocketError.bind(this)),e?.webSocket?.addEventListener("open",()=>{e.webSocket?.send(JSON.stringify({type:"client_info",uneeqJsSdkVersion:Is}))}),this.stream?.signallingProtocol.on("error",t=>{p.error("Signaling: Received error message from server",t),this.clientMessages?.next(new q(`Signaling server error: ${t}`))}),this.stream?.signallingProtocol.on("index_in_queue",this.handleIndexInQueueMessage.bind(this)),this.stream?.signallingProtocol.on("renderer_taken",this.handleRendererTakenMessage.bind(this)),this.stream?.signallingProtocol.on("renderer_gone",this.handleRendererGoneEvent.bind(this)),this.stream?.signallingProtocol.on("switch_renderer_request",this.handleSwitchRendererRequestEvent.bind(this)),this.stream?.signallingProtocol.on("customer_concurrency_limit_reached",this.handleCustomerConcurrencyLimitReachedMessage.bind(this)),this.stream?.signallingProtocol.on("renderer_error",this.handleRendererErrorMessage.bind(this)),this.stream?.signallingProtocol.on("config",this.checkForStubbedTurnConfig.bind(this))}checkForStubbedTurnConfig(e){let t=e?.peerConnectionOptions?.iceServers??[];p.info("Signaling: Received ice config message with urls:",t.map(i=>({urls:i.urls}))),t.some(i=>i.username?.includes("disabled")&&i.urls?.some(r=>r.includes("0.0.0.0")))&&p.warn("Signaling: TURN server configuration is stubbed (turn:0.0.0.0 with disabled credentials). This should be intentional, is intended for locally run renderers e.g. kiosk, miniprem etc.")}handleWebSocketError(e){p.error("Signaling: WebSocket error",p.serialiseError(e)),this.reconnectIfSafe(e)}handleVideoInitialized(){p.info("Video initialized."),this.videoElement=this.videoContainerElement?.getElementsByTagName("video")[0],this.audioElement=this.stream?.webRtcController?.streamController?.audioElement,this.audioStatsAnalyzer=new pe(this.stream,this.videoElement,this.audioElement);let e=this.getAudioPlaybackElement();if(e&&this.config.speakerDeviceId&&this.setSpeakerDevice(e,this.config.speakerDeviceId),this.videoElement)this.videoElement.muted=!0,this.videoElement.play().then(()=>{this.playAudioElement()}).catch(t=>{if(t instanceof DOMException&&t.name==="NotAllowedError")p.warn("Video autoplay blocked by browser. Requesting user gesture to resume playback."),this.clientMessages?.next(new li);else{let n="Fatal Error: Digital Human video cannot be played.";p.error(n,p.serialiseError(t)),this.clientMessages?.next(new q(n)),this.endSession(Ls,!0)}}),this.videoInitialized=!0,this.messages.next(new Tn),this.reconnectionAttempts=0,this.clearReconnectTimer();else{let t="Fatal Error: Video element not found.";p.error(t),this.clientMessages?.next(new q(t)),this.endSession(Ls,!0)}setTimeout(()=>{this.clientMessages?.next(new ti)},Os)}getAudioPlaybackElement(){return xn(this.videoElement)?this.videoElement:this.audioElement}playAudioElement(){let e=this.getAudioPlaybackElement();if(!e){this.handleMissingAudioElement();return}let t=e===this.videoElement;e.muted=!1,e.play().then(()=>{p.info("Audio playback successfully started."),this.clientMessages?.next(new Kn)}).catch(n=>{p.warn("Audio cannot be played.",n),this.clientMessages?.next(new Fe),t?(e.muted=!0,e.play().then(()=>{this.clientMessages?.next(new Oe)}).catch(i=>{p.warn("Muted video reveal also blocked.",i),this.clientMessages?.next(new q(`Video playback failed: ${i}`))})):this.clientMessages?.next(new Oe)})}resumeVideoPlayback(){if(!this.videoElement){p.warn("resumeVideoPlayback called but no video element available");return}this.videoElement.play().then(()=>{this.playAudioElement()}).catch(e=>{p.error("Video playback failed after user gesture",p.serialiseError(e)),this.clientMessages?.next(new q("Video playback failed after user gesture")),this.endSession(mr,!0)})}pauseAudioElement(){let e=this.getAudioPlaybackElement();if(!e){this.handleMissingAudioElement();return}e===this.videoElement?e.muted=!0:e.pause(),this.clientMessages?.next(new Fe)}muteUpstreamMic(){if(!re(this.audioUpstreamMode)){p.warn(`muteUpstreamMic called in '${this.audioUpstreamMode}' mode \u2014 no PS upstream audio track to mute; ignoring.`);return}if(!this.stream){p.warn("muteUpstreamMic called before PixelStreaming stream is initialised; ignoring.");return}this.stream.muteMicrophone()}unmuteUpstreamMic(){if(!re(this.audioUpstreamMode)){p.warn(`unmuteUpstreamMic called in '${this.audioUpstreamMode}' mode \u2014 no PS upstream audio track to unmute; ignoring.`);return}if(!this.stream){p.warn("unmuteUpstreamMic called before PixelStreaming stream is initialised; ignoring.");return}this.stream.unmuteMicrophone(!1)}setSpeakerDevice(e,t){let n=e;n.setSinkId?n.setSinkId(t).then(()=>{p.info(`Speaker device set to: ${t}`)}).catch(i=>{p.error(`Failed to set speaker device: ${t}`,p.serialiseError(i))}):p.error("setSinkId not supported in this browser, cannot set speaker device")}handleMissingAudioElement(){let e="Error: Digital Human audio element not found, cannot play audio.";p.error(e),this.clientMessages?.next(new q(e))}startAudioStatsMonitor(e=5e3){this.stopAudioStatsMonitor(),p.info("Starting audio stats monitor"),this.audioStatsAnalyzer||(this.audioStatsAnalyzer=new pe(this.stream,this.videoElement,this.audioElement)),this.audioStatsInternal=setInterval(()=>{this.audioStatsAnalyzer?.analyzeAudioStats().catch(t=>{p.error("Error analyzing audio stats",p.serialiseError(t))})},e)}stopAudioStatsMonitor(){this.audioStatsInternal&&clearInterval(this.audioStatsInternal)}startNetworkQualityMonitor(e){this.stopNetworkQualityMonitor(),p.info("Starting network quality monitor"),this.audioStatsAnalyzer||(this.audioStatsAnalyzer=new pe(this.stream,this.videoElement,this.audioElement)),this.videoContainerElement&&e.visibility!=="hidden"&&(this.networkIndicator=new In(this.videoContainerElement,e));let t=e.collectionIntervalMs??3e3;this.networkQualityInterval=setInterval(()=>{this.audioStatsAnalyzer?.collectNetworkQuality(e).then(n=>{n&&(this.networkIndicator?.update(n),this.clientMessages?.next(new ai(n)))}).catch(n=>{p.error("Error collecting network quality",p.serialiseError(n))})},t)}stopNetworkQualityMonitor(){this.networkQualityInterval&&(clearInterval(this.networkQualityInterval),this.networkQualityInterval=void 0),this.networkIndicator&&(this.networkIndicator.destroy(),this.networkIndicator=void 0)}handleDataChannelOpen(){p.info("DataChannelOpen"),this.dataChannelOpen=!0,this.messages.next(new En)}handleWebRtcFailed(e){p.error("WebRTC failed",e),this.reconnectIfSafe(e)}handleWebRtcDisconnected(e){p.warn(`WebRTC disconnected, message: ${e?.data?.eventString}, allowClickToReconnect: ${e?.data?.allowClickToReconnect}`),this.reconnectIfSafe(e)}handleWebRtcStats(e){let t=new kn(e.data.aggregatedStats);this.messages.next(t);let n=e.data.aggregatedStats.inboundVideoStats?.framesDecoded??0;this.checkForFreeze(n)}checkForFreeze(e){let t=Date.now();if(this.lastDecodedFrames===0&&e===0){p.debug("[WebRTC] Waiting for first video frame...");return}if(e===this.lastDecodedFrames){this.freezeCount++;let n=((t-this.lastCheckTime)/1e3).toFixed(1);p.warn(`[WebRTC] Video FROZEN for ${n}s (count=${this.freezeCount})`),this.freezeCount>=3&&(p.error("[WebRTC] Video frozen 3 times in a row, transferring session..."),this.session.sessionTransferManager.transferSession(),this.freezeCount=0)}else this.freezeCount=0,this.lastDecodedFrames=e,this.lastCheckTime=t}clearReconnectTimer(){this.reconnectTimeoutId&&(clearTimeout(this.reconnectTimeoutId),this.reconnectTimeoutId=void 0)}scheduleReconnect(){let e=Math.min(this.baseReconnectDelayMs*Math.pow(2,this.reconnectionAttempts),this.maxReconnectDelayMs);p.info(`Scheduling reconnection attempt ${this.reconnectionAttempts} in ${e}ms`),this.reconnectTimeoutId=setTimeout(()=>{p.info(`Executing reconnection attempt ${this.reconnectionAttempts}`),this.reconnectTimeoutId=void 0,this.videoInitialized=!1,this.dataChannelOpen=!1,this.sceneReady=!1,this.audioStatsAnalyzer?.resetStats(),this.stream?.reconnect()},e)}reconnectIfSafe(e){try{this.allowReconnection&&!this.reconnectTimeoutId?(p.debug("Checking if should attempt reconnection after event",e),this.reconnectionAttempts<this.maxReconnectAttempts?(this.reconnectionAttempts++,this.clientMessages?.next(new ei),this.scheduleReconnect()):(p.info("Max reconnection attempts reached. Ending session."),this.clientMessages?.next(new Zn),this.endSession(Ps,!1))):p.warn("Reconnection already scheduled or reconnecting is disabled")}catch(t){p.error("Error during reconnection attempt",p.serialiseError(t)),this.clientMessages?.next(new q("Error during reconnection attempt")),this.endSession(Ps,!1)}}handleDataChannelMessage(e){p.trace("Signaling: Received data channel message",e);try{let t=JSON.parse(e);if(t.type!==void 0)this.messages.next(new Rn(t));else throw new Error("Signaling: Engine response missing type")}catch(t){p.error("Signaling: Failed to parse engine response",p.serialiseError(t))}}handleIndexInQueueMessage(e){try{let n=Number(e.message);this.clientMessages?.next(new Wn(n))}catch(t){p.error("Signaling: Failed to parse position in queue message",p.serialiseError(t))}}handleRendererTakenMessage(e){try{let t=e;this.clientMessages?.next(new Yn(t.message)),p.info("Signaling: Renderer taken event",t.message)}catch(t){p.error("Signaling: Failed to parse renderer taken message",p.serialiseError(t))}}handleWebRtcConnectedMessage(){this.clientMessages?.next(new ri),p.info("Signaling: WebRTC connected")}handleRendererGoneEvent(e){p.info("Signaling: Renderer gone event",e),this.reconnectIfSafe(e)}handleSwitchRendererRequestEvent(e){p.info("Signaling: Renderer switch renderer request event",e),this.session.sessionTransferManager.transferSession()}handleCustomerConcurrencyLimitReachedMessage(e){p.warn("Signaling: Customer concurrency limit reached message received",e),this.clientMessages?.next(new oi)}handleRendererErrorMessage(e){try{let t=e,n=t.code??-1,i=t.message??"An unknown renderer error occurred";p.error(`Signaling: Renderer error received - code: ${n}, message: ${i}`),this.clientMessages?.next(new Ae(n,i)),this.endSession(Ds,!0)}catch(t){p.error("Signaling: Failed to parse renderer error message",p.serialiseError(t)),this.clientMessages?.next(new Ae(-1,"An unknown renderer error occurred")),this.endSession(Ds,!0)}}socketSend(e){p.trace("Signaling: Sending socket message",e),this.stream?.signallingProtocol?.transport?.webSocket?.send(JSON.stringify(e))}dataSend(e){let t=e.toJSON();if(t.action==="chat_prompt"){let n=t.data?.requestId;p.info(`Signaling: Sending data channel message \u2014 action=chat_prompt, requestId=${n??"unknown"}`),(!(e instanceof se)||e.shouldEmitPromptRequest)&&this.clientMessages?.next(new Gn(t.data))}else p.info("Signaling: Sending data channel message",JSON.stringify(t));this.stream?.emitUIInteraction(e)}dataSendBinary(e){p.info("Signaling: Sending data channel binary message");let t=this.uint8ToBase64(e);this.stream?.emitUIInteraction(t)}uint8ToBase64(e){let t="",n=e.byteLength;for(let i=0;i<n;i++)t+=String.fromCharCode(e[i]);return btoa(t)}endSession(e=pr,t=!0){p.info("Signaling: Ending session"),this.clearReconnectTimer(),this.stopNetworkQualityMonitor(),this.socketSend({message:e,type:"client_gone",sessionId:this.config.sessionId}),this.streamDisconnect(),p.info("Session has ended, reason: "+e),t&&this.clientMessages?.next(new qn(e))}streamDisconnect(){p.info("Signaling: Disconnecting stream"),this.stopNetworkQualityMonitor(),this.stopAudioStatsMonitor(),this.allowReconnection=!1,this.clearReconnectTimer();let e=this.stream?.webRtcController?.statsTimerHandle;e&&window.clearInterval(e);let t=this.stream?.webRtcController?.peerConnectionController;if(t?.peerConnection){t.peerConnection.getReceivers=()=>[];let n=t.peerConnection;Object.defineProperty(t,"peerConnection",{get:()=>n,set:()=>{},configurable:!0})}this.stream?.disconnect(),this.dataChannelOpen=!1,this.videoInitialized=!1,this.sceneReady=!1}startSoftSwitch(){p.info("Signaling: Start soft switching"),this.clientMessages?.next(new ni)}stopSoftSwitch(){p.info("Signaling: Stop soft switching"),this.clientMessages?.next(new ii)}};import{Subject as so}from"rxjs";var wr=(o=>(o.CloseUp="close_up",o.LooseCloseUp="loose_close_up",o.TightMediumShot="tight_medium_shot",o.MediumShot="medium_shot",o.MediumFullShot="medium_full_shot",o.FullShot="full_shot",o))(wr||{}),Cr=(i=>(i.Left="left",i.Right="right",i.Center="center",i.Centre="centre",i))(Cr||{}),Le=class{constructor(e,t=2e3,n=z()){this.position=e;this.duration=t;this.requestId=n}position;duration;requestId;toJSON(){return{action:"camera_to_anchor",data:{requestId:this.requestId,position:this.position,transition_duration_ms:this.duration}}}};var Ln=class{constructor(e,t=z()){this.avatarId=e;this.requestId=t}avatarId;requestId;toJSON(){return{action:"change_avatar",data:{id:this.avatarId,requestId:this.requestId}}}};var Dn=class{constructor(e,t=z()){this.url=e;this.requestId=t}url;requestId;toJSON(){return{action:"load_background",data:{url:this.url,requestId:this.requestId}}}};var On=class{constructor(e,t=z()){this.actionName=e;this.requestId=t}actionName;requestId;toJSON(){return{action:"trigger_action",data:{action_name:this.actionName,requestId:this.requestId}}}};var Fn=class{constructor(e){this.session=e;this.addTransferSessionListener()}session;isTransferSessionInProgress=!1;addTransferSessionListener(){this.isTransferSessionInProgress=!1,document.addEventListener("keydown",e=>{e.ctrlKey&&e.shiftKey&&e.key.toLowerCase()==="y"&&(p.info("Session transfer via keyboard shortcut triggered"),this.transferSession())})}transferSession(){if(this.isTransferSessionInProgress){p.warn("Transfer already in progress, skipping");return}this.isTransferSessionInProgress=!0,p.info("Beginning session transfer"),this.session.config.videoContainerElement&&(this.session.config.videoContainerElement.querySelectorAll("#freezeFrame,#streamingVideo").forEach(n=>{n.remove()}),this.session.signaling&&this.session.signaling.streamDisconnect()),this.session.createSignaling(this.session.config.videoContainerElement??document.createElement("div")).init()}switchLiveVideo(e,t){p.info("New signaling video is ready for transfer"),this.session.signaling&&e&&t.videoElement&&(t.videoElement.classList.add("incoming-video"),this.session.signaling.videoElement&&t.videoElement&&e?.appendChild(t.videoElement),this.session.signaling.startSoftSwitch(),setTimeout(()=>{this.session.signaling?.streamDisconnect(),this.session.signaling=t,this.isTransferSessionInProgress=!1,this.session.signaling?.stopSoftSwitch(),p.info("Session transfer complete")},1e3))}};var Mr=[1103,1200,1402];var Os=750,An=class{constructor(e){this.config=e;this.sessionTransferManager=new Fn(this),this._audioUpstreamMode=G(this.config.audioUpstreamMode)}config;id;signaling;messages=new so;speechRec;promptMetadata={};audioStreamId;sessionTransferManager;jwt;welcomeRequested=!1;resolutionLogged=!1;sttPausedByHost=!1;_audioUpstreamMode;get audioUpstreamMode(){return this._audioUpstreamMode}updatePromptMetadata(e){try{JSON.parse(JSON.stringify(e)),this.promptMetadata.custom=e,this.messages.next(new Qn(this.promptMetadata))}catch(t){p.error("Error parsing custom metadata",e,p.serialiseError(t))}}setEnableMicrophone(e){let t=this.audioUpstreamMode;this.config.enableMicrophone=e,this.sttPausedByHost=!1;let n=!1;J(t)&&(this.speechRec?(e?this.speechRec.startRecognition():this.speechRec.stopRecognition(),n=!0):p.warn("setEnableMicrophone: STT leg is configured but speech recognition is not initialised yet")),re(t)&&(this.signaling?(e?this.signaling.unmuteUpstreamMic():this.signaling.muteUpstreamMic(),n=!0,J(t)||this.messages.next(new jn(e))):p.warn("setEnableMicrophone: PS leg is configured but signaling is not initialised yet")),n||p.warn(`setEnableMicrophone(${e}) had nothing to do in mode '${t}' \u2014 session not ready?`)}pauseSpeechRecognition(){return this.sttPausedByHost=!0,this.speechRec?this.speechRec.pause():(p.warn("pauseSpeechRecognition: pause intent recorded, but speech recognition is not initialised yet \u2014 nothing to pause"),!1)}resumeSpeechRecognition(){return this.sttPausedByHost=!1,this.speechRec?this.speechRec.resume():(p.warn("resumeSpeechRecognition: pause intent cleared, but speech recognition is not initialised yet \u2014 nothing to resume"),!1)}setCameraAnchorDistance(e,t=0,n=this.signaling){this.config.cameraAnchorDistance=e,n?.dataSend(new Le(e,t))}setCameraAnchorHorizontal(e,t=0,n=this.signaling){this.config.cameraAnchorHorizontal=e,n?.dataSend(new Le(e,t))}changeAvatar(e,t=this.signaling){t?.dataSend(new Ln(e))}loadBackground(e,t=this.signaling){t?.dataSend(new Dn(e))}userStartSpeaking(e=this.signaling){e?.dataSend(new ci("start"))}userStopSpeaking(e=this.signaling){e?.dataSend(new ci("stop"))}triggerAction(e,t=this.signaling){t?.dataSend(new On(e))}resumeVideoPlayback(){this.signaling?.resumeVideoPlayback()}createSession(){this.messages.subscribe(e=>{if(this.config.messageHandler&&this.config.messageHandler(e),e.uneeqMessageType==="SoftSwitchFinished"||e.uneeqMessageType==="SessionReconnectingFinished"){if(!J(this.audioUpstreamMode))return;if(this.config.enableMicrophone&&!this.sttPausedByHost)e.uneeqMessageType==="SessionReconnectingFinished"?(p.info("Session, resuming speech recognition after reconnect"),this.speechRec?.resume()):(p.info("Session, restarting speech recognition after soft switch"),this.speechRec?.startRecognition());else{let t=e.uneeqMessageType==="SoftSwitchFinished"?"soft switch":"reconnect",n=this.sttPausedByHost?"paused by host":"microphone disabled";p.info(`Session, skipping speech recognition restart after ${t} (${n})`)}}}),this.id=this.config.sessionId,this.jwt=this.config.sessionToken,p.info("Session created with id: "+this.id),this.updatePromptMetadata(this.config.customMetadata||{}),this.promptMetadata=this.initMetadata(),this.listenForTabClosure(),this.signaling=this.createSignaling(this.config.videoContainerElement),this.signaling.init()}createSignaling(e=document.createElement("div")){let t=new URLSearchParams({token:this.jwt});this.config.backgroundUrl&&t.append("backgroundUrl",this.config.backgroundUrl);let n=(this.config.connectionUrl+`/session-service/v1/ws/session?${t.toString()}`).replace("http://","ws://").replace("https://","wss://");p.debug("Socket URL:",n);let i=new Pn(this,n,e);return i.messages.subscribe(r=>{this.signalingEventHandler(r,i)}),i}signalingEventHandler(e,t){switch(e.type){case 0:{this.handleSessionReady(t);break}case 1:{this.handleSessionReady(t);break}case 2:{this.handleDataChannelMessage(e,t);break}case 5:{let n=e.stats;!this.resolutionLogged&&n.inboundVideoStats?.frameWidth&&n.inboundVideoStats?.frameHeight&&(p.info("Video resolution:",`${n.inboundVideoStats.frameWidth}x${n.inboundVideoStats.frameHeight}`),this.resolutionLogged=!0),this.config.webRtcStatsEmitMessages&&this.messages.next(new Hn(n)),this.config.webRtcStatsLogMessages&&p.info("WebRTC stats",n);break}}}handleSessionReady(e){p.debug(`Session ready check - videoInitialized: ${e.videoInitialized}, dataChannelOpen: ${e.dataChannelOpen}, sceneReady: ${e.sceneReady}`),e.videoInitialized&&e.dataChannelOpen&&e.sceneReady&&(e.reconnectionAttempts=0,this.setCameraAnchorDistance(this.config.cameraAnchorDistance,0,e),this.setCameraAnchorHorizontal(this.config.cameraAnchorHorizontal,0,e),setTimeout(()=>{this.sessionTransferManager.isTransferSessionInProgress&&this.config.videoContainerElement?this.sessionTransferManager.switchLiveVideo(this.config.videoContainerElement,e):(this.initSpeechRecognition(this.jwt),this.sendWelcomePrompt(),document.body.classList.add("uneeq-streaming-live")),this.messages.next(new _n(this.id)),this.config.networkIndicator&&e.startNetworkQualityMonitor(this.config.networkIndicator),this.config.webRtcStatsLogMessages&&e.startAudioStatsMonitor()},Os))}async initSpeechRecognition(e){if(!J(this.audioUpstreamMode)){p.info(`[STT] audioUpstreamMode='${this.audioUpstreamMode}' \u2014 skipping STT provider initialisation (no STT leg in this mode).`);return}if(this.speechRec){p.warn("Speech recognition already initialized");return}let t=this.config.speechRecognitionProvider||"google";p.info(`[STT] Config speechRecognitionProvider: "${this.config.speechRecognitionProvider}", resolved provider: "${t}"`),t!=="google"&&t!=="deepgram"&&(p.warn(`Invalid speechRecognitionProvider value: "${String(t)}". Supported values are "google" or "deepgram". Defaulting to "google".`),t="google",this.config.speechRecognitionProvider="google"),p.info(`[STT] Using provider: ${t}`);try{this.speechRec=await(t==="deepgram"?this.createDeepgramSTT(e):this.createGoogleSTT(e))}catch(n){p.error("[STT] Failed to initialise speech recognition provider",p.serialiseError(n));return}this.config.enableMicrophone&&!this.sttPausedByHost&&this.speechRec&&this.speechRec.startRecognition()}async createGoogleSTT(e){let t=this.getSpeechOptions(e);p.debug("Initializing Google STT (speech-recognition-service)");let{GoogleSTT:n}=await import("./chunks/google-stt-AOUGMCIB.js");return new n(t)}async createDeepgramSTT(e){let t=this.config.deepgramConfig||{};if(this.isFluxModel(t.model))return this.createDeepgramFluxSTT(e);p.warn("Deepgram STT is currently in beta, is subject to change, and is not suitable for production use"),p.debug("Initializing Deepgram STT");let n={connectionUrl:this.config.connectionUrl,jwtToken:e,sessionId:this.id,model:t.model,language:t.language,smartFormat:t.smartFormat,interimResults:t.interimResults,utteranceEndMs:t.utteranceEndMs,vadEvents:t.vadEvents,encoding:t.encoding,sampleRate:t.sampleRate,channels:t.channels,fillerWords:t.fillerWords,endpointing:t.endpointing,interruptionWordThreshold:t.interruptionWordThreshold,echoCancellation:t.microphone?.echoCancellation,noiseSuppression:t.microphone?.noiseSuppression,autoGainControl:t.microphone?.autoGainControl,microphoneDeviceId:this.config.microphoneDeviceId,promptMetadata:this.promptMetadata,messages:this.messages,sendMessage:r=>{this.signaling?.dataSend(r)},enableInterrupt:this.config.enableInterruptBySpeech,safetyNetTimeoutMs:t.safetyNetTimeoutMs,keyterms:t.keyterms,noDelay:t.noDelay},{DeepgramSTT:i}=await import("./chunks/deepgram-stt-Y67Z46KN.js");return new i(n)}isFluxModel(e){return e!==void 0&&e.toLowerCase().startsWith("flux")}async createDeepgramFluxSTT(e){p.debug("Initializing Deepgram Flux STT (v2 API)");let t=this.config.deepgramConfig||{},n={connectionUrl:this.config.connectionUrl,jwtToken:e,sessionId:this.id,model:t.model,language:t.language,eotThreshold:t.eotThreshold,eagerEotThreshold:t.eagerEotThreshold,eotTimeoutMs:t.eotTimeoutMs,eagerMaxTurnDurationMs:t.eagerMaxTurnDurationMs,keyterms:t.keyterms,safetyNetTimeoutMs:t.safetyNetTimeoutMs,echoCancellation:t.microphone?.echoCancellation,noiseSuppression:t.microphone?.noiseSuppression,autoGainControl:t.microphone?.autoGainControl,microphoneDeviceId:this.config.microphoneDeviceId,promptMetadata:this.promptMetadata,messages:this.messages,sendMessage:r=>{this.signaling?.dataSend(r)}},{DeepgramFluxSTT:i}=await import("./chunks/deepgram-flux-stt-NOTQ2K35.js");return new i(n)}getSpeechOptions(e){return{apiUrl:this.config.connectionUrl,assetBasePath:this.config.assetBasePath,enableInterrupt:this.config.enableInterruptBySpeech,enableVad:this.config.enableVad,jwtToken:e,hintPhrases:this.config.speechRecognitionHintPhrases,hintPhrasesBoost:this.config.speechRecognitionHintPhrasesBoost,locales:this.config.speechRecognitionLocales,messages:this.messages,promptMetadata:this.promptMetadata,sessionId:this.id,sendMessage:t=>{this.signaling?.dataSend(t)},microphoneDeviceId:this.config.microphoneDeviceId}}initMetadata(){return{userSpokenLocale:"",browserDetectedLocales:this.config.speechRecognitionLocales,userTimezone:Intl.DateTimeFormat().resolvedOptions().timeZone,userScreenWidth:window.screen.availWidth,userScreenHeight:window.screen.availHeight,userAgent:navigator.userAgent,personaId:this.config.personaId,custom:this.config.customMetadata}}handleDataChannelMessage(e,t){switch(p.debug("Processing data channel message",e),e.msg.type){case"nlp_prompt_result":this.messages.next(new Jn(e.msg));break;case"avatar_started_speaking":{this.messages.next(new Bn);break}case"avatar_stopped_speaking":{this.messages.next(new Vn);break}case"error":{p.error(`an error has occurred - ${JSON.stringify(e.msg)}`),this.handleChannelMessageError(e.msg);break}case"scene_ready":{p.debug("Scene is ready"),t.sceneReady=!0,this.handleSessionReady(t),this.messages.next(new Xn);break}case"speech_event":{this.messages.next(new zn(e.msg));break}case"session_ended":{let n=e.msg.reason==="UserInactivity"?ur:e.msg.reason;this.signaling?.endSession(n),this.signaling=void 0;break}case"speech_stream_opened":{this.audioStreamId=e.msg.streamId;break}case"speech_stream_closed":{e.msg.streamId===this.audioStreamId?this.audioStreamId=void 0:p.warn("Received SpeechStreamClosed message for unexpected streamId",e.msg.streamId);break}}}handleChannelMessageError(e){let t=e?.message?.trim()||"An unknown error occurred";e&&Mr.includes(e.code)?this.messages.next(new $n(e)):this.messages.next(new q(t))}sendWelcomePrompt(){p.debug("Checking if the welcome prompt should be sent. Welcome requested already = "+this.welcomeRequested+". Prompt = ",this.config.welcomePrompt),this.config.welcomePrompt&&this.config.welcomePrompt.length>0&&!this.welcomeRequested&&(this.welcomeRequested=!0,this.signaling?.dataSend(new se(this.config.welcomePrompt,this.promptMetadata)))}listenForTabClosure(){window.addEventListener("beforeunload",()=>{p.info("Window unload detected, ending session."),this.signaling?.endSession(),this.signaling=void 0})}};var Nn=class{constructor(e,t=z()){this.prompt=e;this.requestId=t}prompt;requestId;toJSON(){return{action:"speak",data:{requestId:this.requestId,prompt:this.prompt}}}};var me=class{constructor(e,t,n={},i=z()){this.action=e;this.streamId=t;this.metadata=n;this.requestId=i}action;streamId;metadata;requestId;toJSON(){return{action:"speech_stream",data:{requestId:this.requestId,action:this.action,streamId:this.streamId,metadata:this.metadata}}}};var Un=class{constructor(e,t,n,i){this.command=e;this.enabled=t;this.category=n;this.verbosity=i}command;enabled;category;verbosity;toJSON(){let e={command:this.command,enabled:this.enabled};return this.category!==void 0&&(e.category=this.category),this.verbosity!==void 0&&(e.verbosity=this.verbosity),{action:"execute_command",data:e}}};async function Tr(s,e){try{if(s?.audioStreamId===void 0){p.warn("Audio stream is not open | Call openAudioStream() first");return}let t;if(typeof e=="string"){let o=typeof atob<"u"?atob(e):Buffer.from(e,"base64").toString("binary");t=new Uint8Array(o.length);for(let a=0;a<o.length;a++)t[a]=o.charCodeAt(a)}else if(e instanceof Uint8Array)t=e;else if(typeof Blob<"u"&&e instanceof Blob){let o=await e.arrayBuffer();t=new Uint8Array(o)}else{p.error("speakAudio: Unsupported audio type",e);return}let n=Uint8Array.from([1]),i=Uint8Array.from([s.audioStreamId]),r=new Uint8Array(2+t.length);r.set(n,0),r.set(i,1),r.set(t,2),s.signaling?.dataSendBinary(r)}catch(t){p.error("speakAudioSend: Error sending audio",t)}}var Fs=class{constructor(e){this.config=e;p.setLevel(e.logLevel??"info")}config;session;messageSubscription;init(){if(this.session){let e="Cannot initialize: session already active. Call endSession() first.";throw p.warn(e),new Error(e)}if(this.config.audioUpstreamMode!==void 0&&!_s(this.config.audioUpstreamMode)){let e=`Invalid audioUpstreamMode: '${String(this.config.audioUpstreamMode)}'. Allowed: 'speech-recognition-service' | 'pixel-streaming' | 'both'.`;throw p.error(e),new Error(e)}p.info(`Initializing Uneeq with config:', ${JSON.stringify(this.config)}, for UserAgent: ${navigator.userAgent}`),this.session=new An(this.config),this.session.createSession(),this.messageSubscription=this.session.messages.subscribe(e=>{e.uneeqMessageType==="SessionEnded"&&(p.info("Session ended, resetting session state"),this.resetSessionState())})}isSessionActive(){return this.session!==void 0}ensureSessionExists(){return this.session?.id?!0:(p.warn("Cannot perform action, session has not started."),!1)}chatPrompt(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.signaling?.dataSend(new se(e,this.session?.promptMetadata))}speak(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.signaling?.dataSend(new Nn(e))}openAudioStream(){let e=this.session;this.ensureSessionExists()&&e?.signaling?.dataSend(new me("open",e?.audioStreamId))}closeAudioStream(){let e=this.session;this.ensureSessionExists()&&e?.audioStreamId!==void 0&&e.signaling?.dataSend(new me("close",e.audioStreamId))}interruptAudioStream(){let e=this.session;this.ensureSessionExists()&&e?.audioStreamId!==void 0&&e.signaling?.dataSend(new me("interrupt",e.audioStreamId))}async speakAudio(e){this.ensureSessionExists()&&await Tr(this.session,e)}cameraAnchorDistance(e,t){this.ensureSessionExists()&&this.session?.setCameraAnchorDistance(e,t)}cameraAnchorHorizontal(e,t){this.ensureSessionExists()&&this.session?.setCameraAnchorHorizontal(e,t)}changeAvatar(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.changeAvatar(e)}loadBackground(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.loadBackground(e)}userStartSpeaking(){this.ensureSessionExists()&&this.session?.userStartSpeaking()}userStopSpeaking(){this.ensureSessionExists()&&this.session?.userStopSpeaking()}triggerAction(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.triggerAction(e)}resumeVideoPlayback(){this.session?.resumeVideoPlayback()}executeCommand(e,t,n,i){this.ensureSessionExists()&&this.session?.signaling?.dataSend(new Un(e,t,n,i))}endSession(){this.ensureSessionExists()&&(this.session?.signaling?.endSession(),this.resetSessionState())}resetSessionState(){this.messageSubscription?.unsubscribe(),this.messageSubscription=void 0,this.session=void 0}unmuteDigitalHuman(){this.ensureSessionExists()&&(this.session?.signaling?.playAudioElement(),p.debug("Unmuted digital human."))}muteDigitalHuman(){this.ensureSessionExists()&&(this.session?.signaling?.pauseAudioElement(),p.debug("Muted digital human."))}stopSpeaking(){this.ensureSessionExists()&&this.session?.signaling?.dataSend(new Vs)}setCustomPromptMetadata(e){this.ensureSessionExists()&&this.session?.updatePromptMetadata(e)}enableMicrophone(e=!0){this.ensureSessionExists()&&this.session?.setEnableMicrophone(e)}pauseSpeechRecognition(){if(!this.ensureSessionExists())return!1;let e=G(this.config.audioUpstreamMode);if(!J(e))return p.warn(`pauseSpeechRecognition called in '${e}' mode \u2014 no STT leg to pause; ignoring. Use muteUpstreamMic() to silence the PS mic track.`),!1;let t=this.session?.pauseSpeechRecognition()??!1;return t instanceof Promise?!0:t}resumeSpeechRecognition(){if(!this.ensureSessionExists())return!1;let e=G(this.config.audioUpstreamMode);if(!J(e))return p.warn(`resumeSpeechRecognition called in '${e}' mode \u2014 no STT leg to resume; ignoring. Use unmuteUpstreamMic() to re-enable the PS mic track.`),!1;let t=this.session?.resumeSpeechRecognition()??!1;return t instanceof Promise?!0:t}muteUpstreamMic(){this.ensureSessionExists()&&this.session?.signaling?.muteUpstreamMic()}unmuteUpstreamMic(){this.ensureSessionExists()&&this.session?.signaling?.unmuteUpstreamMic()}setWebRtcStatsEnabled(e,t){this.session?.config&&(this.session.config.webRtcStatsEmitMessages=e,this.session.config.webRtcStatsLogMessages=t,p.info(`Setting up WebRtcStats: webRtcStatsEmitMessages: ${this.session.config.webRtcStatsEmitMessages}, webRtcStatsLogMessages: ${this.session.config.webRtcStatsLogMessages}`),t?this.session.signaling?.startAudioStatsMonitor():this.session.signaling?.stopAudioStatsMonitor())}setNetworkIndicatorEnabled(e){this.ensureSessionExists()&&(e?this.session?.signaling?.startNetworkQualityMonitor(e):this.session?.signaling?.stopNetworkQualityMonitor())}};export{Dr as AvatarAnswerMessage,Ur as AvatarInterruptedMessage,Bn as AvatarStartedSpeakingMessage,Vn as AvatarStoppedSpeakingMessage,wr as CameraAnchorDistance,Cr as CameraAnchorHorizontal,Qn as CustomMetadataUpdated,oi as CustomerConcurrencyLimitReachedMessage,Lr as DeviceErrorMessage,Fe as DigitalHumanMuted,Oe as DigitalHumanPlayedInMutedModeSuccess,Kn as DigitalHumanUnmuted,jn as EnableMicrophoneUpdatedMessage,Pr as LogLevel,Sr as NetworkIndicatorPopupTrigger,yr as NetworkIndicatorPosition,gr as NetworkIndicatorVisibility,fr as NetworkQualityLevel,ai as NetworkQualityMessage,Gn as PromptRequestMessage,Jn as PromptResultMessage,Ae as RendererErrorMessage,Xn as SceneReadyMessage,$n as SessionBackendErrorMessage,Yn as SessionConnectingMessage,Zn as SessionDisconnectedMessage,qn as SessionEndedMessage,q as SessionErrorMessage,_n as SessionLiveMessage,ti as SessionReconnectingFinishedMessage,ei as SessionReconnectingMessage,ni as SoftSwitchStartingMessage,ii as SoftSwitchStoppingMessage,zn as SpeechEventMessage,di as SpeechRecognitionProvider,Br as SpeechRecognitionTransientErrorMessage,Or as SpeechTranscriptionMessage,Is as UNEEQ_JS_SDK_VERSION,Fs as Uneeq,Bs as UneeqMessageType,Ar as UserStartedSpeakingMessage,Nr as UserStoppedSpeakingMessage,Fr as VadInterruptionAllowedMessage,li as VideoAutoplayBlockedMessage,si as VideoLayoutConfiguringMessage,Wn as WaitingInQueueMessage,ri as WebRtcConnectedMessage,Hn as WebRtcStatsMessage,G as resolveAudioUpstreamMode};
|
|
87
|
+
Audio level (0-1): ${a??"N/A"}`),n===0&&p.warn("WebRTC Connection - Audio - No audio packets received \u2014 remote is probably not sending audio."),i>0&&p.warn(`WebRTC Connection - Audio - packet loss detected: ${i} packets lost.`),a===void 0?p.warn("WebRTC Connection - Audio - Audio level not available in stats."):a===0?p.warn("WebRTC Connection - Audio - Audio level is zero \u2014 digital human might not be talking at this exact moment as audio is silent or muted."):a<.02?p.warn("WebRTC Connection - Audio - Audio level is very low \u2014 audio might be too quiet."):p.info("WebRTC Connection - Audio - Audio level looks normal, digital human is likely speaking.")}logElementStatus(e){let t=xn(this.videoElement),n=t?this.videoElement:this.audioElement;p.debug(`Audio plays from ${t?"video":"separate audio"} element (DisableAudioSync=${t?"false":"true"}).`),p.debug(`Video element muted: ${this.videoElement?.muted}, (should be ${t?"false to be able to hear the digital human":"true as part of avoiding auto play restrictions"})`),p.debug(`Playback element muted: ${n?.muted}, (should be false to be able to hear the digital human)`),p.debug(`Playback element volume: ${n?.volume}, (should be greater than zero to be able to hear the digital human)`);let i=e?.mimeType;i&&n&&(p.debug(`Playback element can play webrtc audio codec (${i}) : ${n.canPlayType(i)}, (should be 'probably' or 'maybe)'`),i==="audio/opus"&&p.debug(`Audio codec opus is often known as ogg, so checking can play ogg codec: ${n.canPlayType("audio/ogg")}, (should be 'probably' or 'maybe')`))}};var Pe={good:"#22c55e",fair:"#eab308",poor:"#ef4444",inactive:"#6b7280"},In=class{constructor(e,t){this.videoContainerElement=e;this.visibility=t.visibility??"when-degraded",this.position=t.position??"top-right",this.popupTrigger=t.popupTrigger??"click",this.onClickBound=this.onClick.bind(this),this.onMouseEventBound=n=>n.stopPropagation(),this.onDocumentClickBound=this.onDocumentClick.bind(this),this.onMouseEnterBound=this.onMouseEnter.bind(this),this.onMouseLeaveBound=this.onMouseLeave.bind(this),this.visibility!=="hidden"&&this.createElements()}videoContainerElement;container;panel;bars=[];panelVisible=!1;lastMetrics;visibility;position;popupTrigger;onClickBound;onMouseEventBound;onDocumentClickBound;onMouseEnterBound;onMouseLeaveBound;hoverHideTimeout;originalParentPosition;createElements(){getComputedStyle(this.videoContainerElement).position==="static"&&(this.originalParentPosition=this.videoContainerElement.style.position,this.videoContainerElement.style.position="relative"),this.container=document.createElement("div"),this.container.setAttribute("data-testid","network-indicator"),this.container.setAttribute("role","status"),this.container.setAttribute("aria-live","polite"),this.container.setAttribute("aria-label","Network quality: unknown"),Object.assign(this.container.style,{position:"absolute",zIndex:"1000",cursor:"pointer",padding:"6px 7px",borderRadius:"4px",background:"rgba(0, 0, 0, 0.5)",display:"none",alignItems:"flex-end",gap:"2px",pointerEvents:"auto",...this.getPositionStyles()});let t=[6,12,18];for(let n of t){let i=document.createElement("div");i.setAttribute("data-testid","network-indicator-bar"),Object.assign(i.style,{width:"4px",height:`${n}px`,borderRadius:"1px",background:Pe.inactive,transition:"background 0.3s ease"}),this.bars.push(i),this.container.appendChild(i)}this.container.addEventListener("mousedown",this.onMouseEventBound),this.container.addEventListener("mouseup",this.onMouseEventBound),this.popupTrigger==="click"?this.container.addEventListener("click",this.onClickBound):this.popupTrigger==="hover"&&(this.container.addEventListener("mouseenter",this.onMouseEnterBound),this.container.addEventListener("mouseleave",this.onMouseLeaveBound)),this.popupTrigger==="none"&&(this.container.style.cursor="default"),this.videoContainerElement.appendChild(this.container)}getPositionStyles(){switch(this.position){case"top-left":return{top:"8px",left:"8px"};case"top-right":return{top:"8px",right:"8px"};case"bottom-left":return{bottom:"8px",left:"8px"};case"bottom-right":return{bottom:"8px",right:"8px"};default:return{top:"8px",right:"8px"}}}onClick(e){e.stopPropagation(),this.panelVisible?this.hidePanel():this.showPanel()}onDocumentClick(e){this.panelVisible&&this.container&&!this.container.contains(e.target)&&this.hidePanel()}onMouseEnter(){clearTimeout(this.hoverHideTimeout),this.showPanel()}onMouseLeave(){this.scheduleHoverHide()}scheduleHoverHide(){clearTimeout(this.hoverHideTimeout),this.hoverHideTimeout=setTimeout(()=>this.hidePanel(),50)}showPanel(){!this.container||!this.lastMetrics||(this.panel||(this.panel=document.createElement("div"),this.panel.setAttribute("data-testid","network-indicator-panel"),Object.assign(this.panel.style,{position:"fixed",padding:"10px",borderRadius:"6px",background:"rgba(0, 0, 0, 0.85)",color:"#ffffff",fontSize:"11px",fontFamily:"system-ui, -apple-system, sans-serif",whiteSpace:"nowrap",lineHeight:"1.6",minWidth:"180px",zIndex:"10001",pointerEvents:"auto"}),this.popupTrigger==="hover"&&(this.panel.addEventListener("mouseenter",this.onMouseEnterBound),this.panel.addEventListener("mouseleave",this.onMouseLeaveBound)),document.body.appendChild(this.panel)),this.updatePanel(),this.positionPanel(),this.panel.style.display="block",this.panelVisible=!0,document.addEventListener("click",this.onDocumentClickBound))}hidePanel(){this.panel&&(this.panel.style.display="none"),this.panelVisible=!1,document.removeEventListener("click",this.onDocumentClickBound)}positionPanel(){if(!this.panel||!this.container)return;let e=4,t=4,n=window.innerWidth,i=window.innerHeight,r=this.container.getBoundingClientRect(),o={top:Math.max(0,Math.min(r.top,i)),bottom:Math.max(0,Math.min(r.bottom,i)),left:Math.max(0,Math.min(r.left,n)),right:Math.max(0,Math.min(r.right,n))};this.panel.style.top="",this.panel.style.bottom="",this.panel.style.left="",this.panel.style.right="",this.panel.style.visibility="hidden",this.panel.style.display="block";let{width:a,height:l}=this.panel.getBoundingClientRect();this.panel.style.visibility="";let c=o.top-e,u=i-o.bottom-e,w=o.left-e,v=n-o.right-e,C,k;c>=l||u>=l?(C=u>=l&&(c<l||u>=c)?o.bottom+e:o.top-e-l,k=this.position==="top-left"||this.position==="bottom-left"?o.left:o.right-a):(k=v>=a&&(w<a||v>=w)?o.right+e:o.left-e-a,C=o.bottom-l),k=Math.max(t,Math.min(k,n-a-t)),C=Math.max(0,Math.min(C,i-l-t)),this.panel.style.top=`${C}px`,this.panel.style.left=`${k}px`}updatePanel(){if(!this.panel||!this.lastMetrics)return;let e=this.lastMetrics,t=this.getColor(e.qualityLevel);this.panel.innerHTML=[`<div style="font-weight:600;margin-bottom:4px;color:${t}">${e.qualityLevel} Quality</div>`,this.panelSectionHeader("Quality Score (MOS)"),this.panelRow("Audio",e.audioMos.toFixed(1)+" / 5.0"),this.panelRow("Video",e.videoMos.toFixed(1)+" / 5.0"),this.panelSectionHeader("Connection"),this.panelRow("Round Trip",`${e.roundTripTimeMs} ms`),this.panelRow("Packet Loss",`${e.audioPacketLossPercent}% audio / ${e.videoPacketLossPercent}% video`),this.panelRow("Jitter",`${e.audioJitterMs} ms audio / ${e.videoJitterMs} ms video`),this.panelSectionHeader("Throughput"),this.panelRow("Bitrate",`${e.audioBitrateKbps} audio / ${e.videoBitrateKbps} video kbps`),this.panelRow("Frame Rate",`${e.frameRate} fps`)].join("")}panelSectionHeader(e){return`<div style="color:#6b7280;font-size:10px;text-transform:uppercase;letter-spacing:0.5px;margin-top:6px;margin-bottom:2px">${e}</div>`}panelRow(e,t){return`<div style="display:flex;justify-content:space-between;gap:12px"><span style="color:#9ca3af">${e}</span><span>${t}</span></div>`}getColor(e){switch(e){case"Good":return Pe.good;case"Fair":return Pe.fair;case"Poor":return Pe.poor}}update(e){if(this.lastMetrics=e,!this.container)return;this.container.setAttribute("aria-label",`Network quality: ${e.qualityLevel}`);let t=this.getColor(e.qualityLevel),n=e.qualityLevel==="Good"?3:e.qualityLevel==="Fair"?2:1;this.bars.forEach((i,r)=>{i.style.background=r<n?t:Pe.inactive}),this.visibility==="when-degraded"?this.container.style.display=e.qualityLevel==="Good"?"none":"flex":this.container.style.display="flex",this.panelVisible&&(this.updatePanel(),this.positionPanel())}destroy(){this.container&&(this.container.removeEventListener("click",this.onClickBound),this.container.removeEventListener("mousedown",this.onMouseEventBound),this.container.removeEventListener("mouseup",this.onMouseEventBound),this.container.removeEventListener("mouseenter",this.onMouseEnterBound),this.container.removeEventListener("mouseleave",this.onMouseLeaveBound),this.container.remove(),this.container=void 0),this.originalParentPosition!==void 0&&(this.videoContainerElement.style.position=this.originalParentPosition,this.originalParentPosition=void 0),clearTimeout(this.hoverHideTimeout),this.panel&&(this.panel.removeEventListener("mouseenter",this.onMouseEnterBound),this.panel.removeEventListener("mouseleave",this.onMouseLeaveBound),this.panel.remove(),this.panel=void 0),document.removeEventListener("click",this.onDocumentClickBound),this.bars=[],this.panelVisible=!1,this.lastMetrics=void 0}};var Pn=class{constructor(e,t,n){this.session=e;this.connectionUrl=t;this.videoContainerElement=n;this.config=e.config,this.clientMessages=e.messages,this._audioUpstreamMode=G(this.config.audioUpstreamMode)}session;connectionUrl;videoContainerElement;stream;messages=new io;videoElement;audioElement;videoInitialized=!1;dataChannelOpen=!1;sceneReady=!1;maxReconnectAttempts=4;reconnectionAttempts=0;allowReconnection=!0;reconnectTimeoutId;baseReconnectDelayMs=500;maxReconnectDelayMs=1e4;audioStatsInternal;freezeCount=0;lastDecodedFrames=0;lastCheckTime=Date.now();audioStatsAnalyzer;networkQualityInterval;networkIndicator;config;clientMessages;_audioUpstreamMode;get audioUpstreamMode(){return this._audioUpstreamMode}init(){p.info("Connection config",{connectionUrl:this.connectionUrl,forceTURN:this.config.forceTURN}),this.videoContainerElement||(this.videoContainerElement=document.createElement("div"),document.body.appendChild(this.videoContainerElement)),this.clientMessages?.next(new si);let e=re(this.audioUpstreamMode);this.audioUpstreamMode!=="speech-recognition-service"&&p.info(`audioUpstreamMode='${this.audioUpstreamMode}' is beta; behaviour may change.`);let t=new zt({initialSettings:{AutoConnect:!1,AutoPlayVideo:!1,ForceTURN:this.config.forceTURN,HoveringMouse:!1,KeyboardInput:!1,MaxReconnectAttempts:0,MouseInput:!1,ss:this.connectionUrl,StartVideoMuted:!0,TouchInput:!1,UseMic:e,WaitForStreamer:!0}});this.stream=new xe(t,{videoElementParent:this.videoContainerElement}),d.InitLogging(K.Warning,!1);let n=function(){let i=t.getTextSettingValue($.SignallingServerUrl);return t.isFlagEnabled(h.BrowserSendOffer)&&(i+=(i.includes("?")?"&":"?")+h.BrowserSendOffer+"=true"),i};this.stream.setSignallingUrlBuilder(n),this.addStreamHandlers(),this.stream.connect(),this.addWebSocketHandlers()}addStreamHandlers(){this.stream?.addEventListener("videoInitialized",this.handleVideoInitialized.bind(this)),this.stream?.addEventListener("dataChannelOpen",this.handleDataChannelOpen.bind(this)),this.stream?.addEventListener("webRtcFailed",this.handleWebRtcFailed.bind(this)),this.stream?.addEventListener("webRtcDisconnected",this.handleWebRtcDisconnected.bind(this)),this.stream?.addEventListener("statsReceived",this.handleWebRtcStats.bind(this)),this.stream?.addResponseEventListener("response-listener",this.handleDataChannelMessage.bind(this)),this.stream?.addEventListener("videoEncoderAvgQP",({data:{avgQP:e}})=>{p.trace("WebRTC: VideoEncoderAvgQP - lower is better, ranges from 0 to 51:",e)}),this.stream?.addEventListener("webRtcAutoConnect",()=>{p.debug("WebRTC: AutoConnect triggered")}),this.stream?.addEventListener("webRtcConnected",this.handleWebRtcConnectedMessage.bind(this)),this.stream?.addEventListener("statsReceived",({data:{aggregatedStats:e}})=>{p.trace("WebRTC: StatsReceived",e)}),this.stream?.addEventListener("webRtcTCPRelayDetected",()=>{p.warn("WebRTC: Stream quailty likely degraded due to network enviroment, stream is relayed over TCP.")})}addWebSocketHandlers(){let e=this.stream?.signallingProtocol?.transport;e?.webSocket?.addEventListener("error",this.handleWebSocketError.bind(this)),e?.webSocket?.addEventListener("open",()=>{e.webSocket?.send(JSON.stringify({type:"client_info",uneeqJsSdkVersion:Is}))}),this.stream?.signallingProtocol.on("error",t=>{p.error("Signaling: Received error message from server",t),this.clientMessages?.next(new q(`Signaling server error: ${t}`))}),this.stream?.signallingProtocol.on("index_in_queue",this.handleIndexInQueueMessage.bind(this)),this.stream?.signallingProtocol.on("renderer_taken",this.handleRendererTakenMessage.bind(this)),this.stream?.signallingProtocol.on("renderer_gone",this.handleRendererGoneEvent.bind(this)),this.stream?.signallingProtocol.on("switch_renderer_request",this.handleSwitchRendererRequestEvent.bind(this)),this.stream?.signallingProtocol.on("customer_concurrency_limit_reached",this.handleCustomerConcurrencyLimitReachedMessage.bind(this)),this.stream?.signallingProtocol.on("renderer_error",this.handleRendererErrorMessage.bind(this)),this.stream?.signallingProtocol.on("config",this.checkForStubbedTurnConfig.bind(this))}checkForStubbedTurnConfig(e){let t=e?.peerConnectionOptions?.iceServers??[];p.info("Signaling: Received ice config message with urls:",t.map(i=>({urls:i.urls}))),t.some(i=>i.username?.includes("disabled")&&i.urls?.some(r=>r.includes("0.0.0.0")))&&p.warn("Signaling: TURN server configuration is stubbed (turn:0.0.0.0 with disabled credentials). This should be intentional, is intended for locally run renderers e.g. kiosk, miniprem etc.")}handleWebSocketError(e){p.error("Signaling: WebSocket error",p.serialiseError(e)),this.reconnectIfSafe(e)}handleVideoInitialized(){p.info("Video initialized."),this.videoElement=this.videoContainerElement?.getElementsByTagName("video")[0],this.audioElement=this.stream?.webRtcController?.streamController?.audioElement,this.audioStatsAnalyzer=new pe(this.stream,this.videoElement,this.audioElement);let e=this.getAudioPlaybackElement();if(e&&this.config.speakerDeviceId&&this.setSpeakerDevice(e,this.config.speakerDeviceId),this.videoElement)this.videoElement.muted=!0,this.videoElement.play().then(()=>{this.playAudioElement()}).catch(t=>{if(t instanceof DOMException&&t.name==="NotAllowedError")p.warn("Video autoplay blocked by browser. Requesting user gesture to resume playback."),this.clientMessages?.next(new li);else{let n="Fatal Error: Digital Human video cannot be played.";p.error(n,p.serialiseError(t)),this.clientMessages?.next(new q(n)),this.endSession(Ls,!0)}}),this.videoInitialized=!0,"mediaSession"in navigator&&(navigator.mediaSession.setActionHandler("play",()=>this.playAudioElement()),navigator.mediaSession.setActionHandler("pause",()=>this.pauseAudioElement())),this.messages.next(new Tn),this.reconnectionAttempts=0,this.clearReconnectTimer();else{let t="Fatal Error: Video element not found.";p.error(t),this.clientMessages?.next(new q(t)),this.endSession(Ls,!0)}setTimeout(()=>{this.clientMessages?.next(new ti)},Os)}getAudioPlaybackElement(){return xn(this.videoElement)?this.videoElement:this.audioElement}playAudioElement(){let e=this.getAudioPlaybackElement();if(!e){this.handleMissingAudioElement();return}let t=e===this.videoElement;e.muted=!1,e.play().then(()=>{p.info("Audio playback successfully started."),this.clientMessages?.next(new Kn),"mediaSession"in navigator&&(navigator.mediaSession.playbackState="playing")}).catch(n=>{p.warn("Audio cannot be played.",n),this.clientMessages?.next(new Fe),t?(e.muted=!0,e.play().then(()=>{this.clientMessages?.next(new Oe)}).catch(i=>{p.warn("Muted video reveal also blocked.",i),this.clientMessages?.next(new q(`Video playback failed: ${i}`))})):this.clientMessages?.next(new Oe)})}resumeVideoPlayback(){if(!this.videoElement){p.warn("resumeVideoPlayback called but no video element available");return}this.videoElement.play().then(()=>{this.playAudioElement()}).catch(e=>{p.error("Video playback failed after user gesture",p.serialiseError(e)),this.clientMessages?.next(new q("Video playback failed after user gesture")),this.endSession(mr,!0)})}pauseAudioElement(){let e=this.getAudioPlaybackElement();if(!e){this.handleMissingAudioElement();return}e===this.videoElement?e.muted=!0:e.pause(),this.clientMessages?.next(new Fe),"mediaSession"in navigator&&(navigator.mediaSession.playbackState="paused")}muteUpstreamMic(){if(!re(this.audioUpstreamMode)){p.warn(`muteUpstreamMic called in '${this.audioUpstreamMode}' mode \u2014 no PS upstream audio track to mute; ignoring.`);return}if(!this.stream){p.warn("muteUpstreamMic called before PixelStreaming stream is initialised; ignoring.");return}this.stream.muteMicrophone()}unmuteUpstreamMic(){if(!re(this.audioUpstreamMode)){p.warn(`unmuteUpstreamMic called in '${this.audioUpstreamMode}' mode \u2014 no PS upstream audio track to unmute; ignoring.`);return}if(!this.stream){p.warn("unmuteUpstreamMic called before PixelStreaming stream is initialised; ignoring.");return}this.stream.unmuteMicrophone(!1)}setSpeakerDevice(e,t){let n=e;n.setSinkId?n.setSinkId(t).then(()=>{p.info(`Speaker device set to: ${t}`)}).catch(i=>{p.error(`Failed to set speaker device: ${t}`,p.serialiseError(i))}):p.error("setSinkId not supported in this browser, cannot set speaker device")}handleMissingAudioElement(){let e="Error: Digital Human audio element not found, cannot play audio.";p.error(e),this.clientMessages?.next(new q(e))}startAudioStatsMonitor(e=5e3){this.stopAudioStatsMonitor(),p.info("Starting audio stats monitor"),this.audioStatsAnalyzer||(this.audioStatsAnalyzer=new pe(this.stream,this.videoElement,this.audioElement)),this.audioStatsInternal=setInterval(()=>{this.audioStatsAnalyzer?.analyzeAudioStats().catch(t=>{p.error("Error analyzing audio stats",p.serialiseError(t))})},e)}stopAudioStatsMonitor(){this.audioStatsInternal&&clearInterval(this.audioStatsInternal)}startNetworkQualityMonitor(e){this.stopNetworkQualityMonitor(),p.info("Starting network quality monitor"),this.audioStatsAnalyzer||(this.audioStatsAnalyzer=new pe(this.stream,this.videoElement,this.audioElement)),this.videoContainerElement&&e.visibility!=="hidden"&&(this.networkIndicator=new In(this.videoContainerElement,e));let t=e.collectionIntervalMs??3e3;this.networkQualityInterval=setInterval(()=>{this.audioStatsAnalyzer?.collectNetworkQuality(e).then(n=>{n&&(this.networkIndicator?.update(n),this.clientMessages?.next(new ai(n)))}).catch(n=>{p.error("Error collecting network quality",p.serialiseError(n))})},t)}stopNetworkQualityMonitor(){this.networkQualityInterval&&(clearInterval(this.networkQualityInterval),this.networkQualityInterval=void 0),this.networkIndicator&&(this.networkIndicator.destroy(),this.networkIndicator=void 0)}handleDataChannelOpen(){p.info("DataChannelOpen"),this.dataChannelOpen=!0,this.messages.next(new En)}handleWebRtcFailed(e){p.error("WebRTC failed",e),this.reconnectIfSafe(e)}handleWebRtcDisconnected(e){p.warn(`WebRTC disconnected, message: ${e?.data?.eventString}, allowClickToReconnect: ${e?.data?.allowClickToReconnect}`),this.reconnectIfSafe(e)}handleWebRtcStats(e){let t=new kn(e.data.aggregatedStats);this.messages.next(t);let n=e.data.aggregatedStats.inboundVideoStats?.framesDecoded??0;this.checkForFreeze(n)}checkForFreeze(e){let t=Date.now();if(this.lastDecodedFrames===0&&e===0){p.debug("[WebRTC] Waiting for first video frame...");return}if(e===this.lastDecodedFrames){this.freezeCount++;let n=((t-this.lastCheckTime)/1e3).toFixed(1);p.warn(`[WebRTC] Video FROZEN for ${n}s (count=${this.freezeCount})`),this.freezeCount>=3&&(p.error("[WebRTC] Video frozen 3 times in a row, transferring session..."),this.session.sessionTransferManager.transferSession(),this.freezeCount=0)}else this.freezeCount=0,this.lastDecodedFrames=e,this.lastCheckTime=t}clearReconnectTimer(){this.reconnectTimeoutId&&(clearTimeout(this.reconnectTimeoutId),this.reconnectTimeoutId=void 0)}scheduleReconnect(){let e=Math.min(this.baseReconnectDelayMs*Math.pow(2,this.reconnectionAttempts),this.maxReconnectDelayMs);p.info(`Scheduling reconnection attempt ${this.reconnectionAttempts} in ${e}ms`),this.reconnectTimeoutId=setTimeout(()=>{p.info(`Executing reconnection attempt ${this.reconnectionAttempts}`),this.reconnectTimeoutId=void 0,this.videoInitialized=!1,this.dataChannelOpen=!1,this.sceneReady=!1,this.audioStatsAnalyzer?.resetStats(),this.stream?.reconnect()},e)}reconnectIfSafe(e){try{this.allowReconnection&&!this.reconnectTimeoutId?(p.debug("Checking if should attempt reconnection after event",e),this.reconnectionAttempts<this.maxReconnectAttempts?(this.reconnectionAttempts++,this.clientMessages?.next(new ei),this.scheduleReconnect()):(p.info("Max reconnection attempts reached. Ending session."),this.clientMessages?.next(new Zn),this.endSession(Ps,!1))):p.warn("Reconnection already scheduled or reconnecting is disabled")}catch(t){p.error("Error during reconnection attempt",p.serialiseError(t)),this.clientMessages?.next(new q("Error during reconnection attempt")),this.endSession(Ps,!1)}}handleDataChannelMessage(e){p.trace("Signaling: Received data channel message",e);try{let t=JSON.parse(e);if(t.type!==void 0)this.messages.next(new Rn(t));else throw new Error("Signaling: Engine response missing type")}catch(t){p.error("Signaling: Failed to parse engine response",p.serialiseError(t))}}handleIndexInQueueMessage(e){try{let n=Number(e.message);this.clientMessages?.next(new Wn(n))}catch(t){p.error("Signaling: Failed to parse position in queue message",p.serialiseError(t))}}handleRendererTakenMessage(e){try{let t=e;this.clientMessages?.next(new Yn(t.message)),p.info("Signaling: Renderer taken event",t.message)}catch(t){p.error("Signaling: Failed to parse renderer taken message",p.serialiseError(t))}}handleWebRtcConnectedMessage(){this.clientMessages?.next(new ri),p.info("Signaling: WebRTC connected")}handleRendererGoneEvent(e){p.info("Signaling: Renderer gone event",e),this.reconnectIfSafe(e)}handleSwitchRendererRequestEvent(e){p.info("Signaling: Renderer switch renderer request event",e),this.session.sessionTransferManager.transferSession()}handleCustomerConcurrencyLimitReachedMessage(e){p.warn("Signaling: Customer concurrency limit reached message received",e),this.clientMessages?.next(new oi)}handleRendererErrorMessage(e){try{let t=e,n=t.code??-1,i=t.message??"An unknown renderer error occurred";p.error(`Signaling: Renderer error received - code: ${n}, message: ${i}`),this.clientMessages?.next(new Ae(n,i)),this.endSession(Ds,!0)}catch(t){p.error("Signaling: Failed to parse renderer error message",p.serialiseError(t)),this.clientMessages?.next(new Ae(-1,"An unknown renderer error occurred")),this.endSession(Ds,!0)}}socketSend(e){p.trace("Signaling: Sending socket message",e),this.stream?.signallingProtocol?.transport?.webSocket?.send(JSON.stringify(e))}dataSend(e){let t=e.toJSON();if(t.action==="chat_prompt"){let n=t.data?.requestId;p.info(`Signaling: Sending data channel message \u2014 action=chat_prompt, requestId=${n??"unknown"}`),(!(e instanceof se)||e.shouldEmitPromptRequest)&&this.clientMessages?.next(new Gn(t.data))}else p.info("Signaling: Sending data channel message",JSON.stringify(t));this.stream?.emitUIInteraction(e)}dataSendBinary(e){p.info("Signaling: Sending data channel binary message");let t=this.uint8ToBase64(e);this.stream?.emitUIInteraction(t)}uint8ToBase64(e){let t="",n=e.byteLength;for(let i=0;i<n;i++)t+=String.fromCharCode(e[i]);return btoa(t)}endSession(e=pr,t=!0){p.info("Signaling: Ending session"),this.clearReconnectTimer(),this.stopNetworkQualityMonitor(),this.socketSend({message:e,type:"client_gone",sessionId:this.config.sessionId}),this.streamDisconnect(),p.info("Session has ended, reason: "+e),t&&this.clientMessages?.next(new qn(e))}streamDisconnect(){p.info("Signaling: Disconnecting stream"),this.stopNetworkQualityMonitor(),this.stopAudioStatsMonitor(),this.allowReconnection=!1,this.clearReconnectTimer();let e=this.stream?.webRtcController?.statsTimerHandle;e&&window.clearInterval(e);let t=this.stream?.webRtcController?.peerConnectionController;if(t?.peerConnection){t.peerConnection.getReceivers=()=>[];let n=t.peerConnection;Object.defineProperty(t,"peerConnection",{get:()=>n,set:()=>{},configurable:!0})}this.stream?.disconnect(),this.dataChannelOpen=!1,this.videoInitialized=!1,this.sceneReady=!1,"mediaSession"in navigator&&(navigator.mediaSession.setActionHandler("play",null),navigator.mediaSession.setActionHandler("pause",null),navigator.mediaSession.playbackState="none")}startSoftSwitch(){p.info("Signaling: Start soft switching"),this.clientMessages?.next(new ni)}stopSoftSwitch(){p.info("Signaling: Stop soft switching"),this.clientMessages?.next(new ii)}};import{Subject as so}from"rxjs";var wr=(o=>(o.CloseUp="close_up",o.LooseCloseUp="loose_close_up",o.TightMediumShot="tight_medium_shot",o.MediumShot="medium_shot",o.MediumFullShot="medium_full_shot",o.FullShot="full_shot",o))(wr||{}),Cr=(i=>(i.Left="left",i.Right="right",i.Center="center",i.Centre="centre",i))(Cr||{}),Le=class{constructor(e,t=2e3,n=z()){this.position=e;this.duration=t;this.requestId=n}position;duration;requestId;toJSON(){return{action:"camera_to_anchor",data:{requestId:this.requestId,position:this.position,transition_duration_ms:this.duration}}}};var Ln=class{constructor(e,t=z()){this.avatarId=e;this.requestId=t}avatarId;requestId;toJSON(){return{action:"change_avatar",data:{id:this.avatarId,requestId:this.requestId}}}};var Dn=class{constructor(e,t=z()){this.url=e;this.requestId=t}url;requestId;toJSON(){return{action:"load_background",data:{url:this.url,requestId:this.requestId}}}};var On=class{constructor(e,t=z()){this.actionName=e;this.requestId=t}actionName;requestId;toJSON(){return{action:"trigger_action",data:{action_name:this.actionName,requestId:this.requestId}}}};var Fn=class{constructor(e){this.session=e;this.addTransferSessionListener()}session;isTransferSessionInProgress=!1;addTransferSessionListener(){this.isTransferSessionInProgress=!1,document.addEventListener("keydown",e=>{e.ctrlKey&&e.shiftKey&&e.key.toLowerCase()==="y"&&(p.info("Session transfer via keyboard shortcut triggered"),this.transferSession())})}transferSession(){if(this.isTransferSessionInProgress){p.warn("Transfer already in progress, skipping");return}this.isTransferSessionInProgress=!0,p.info("Beginning session transfer"),this.session.config.videoContainerElement&&(this.session.config.videoContainerElement.querySelectorAll("#freezeFrame,#streamingVideo").forEach(n=>{n.remove()}),this.session.signaling&&this.session.signaling.streamDisconnect()),this.session.createSignaling(this.session.config.videoContainerElement??document.createElement("div")).init()}switchLiveVideo(e,t){p.info("New signaling video is ready for transfer"),this.session.signaling&&e&&t.videoElement&&(t.videoElement.classList.add("incoming-video"),this.session.signaling.videoElement&&t.videoElement&&e?.appendChild(t.videoElement),this.session.signaling.startSoftSwitch(),setTimeout(()=>{this.session.signaling?.streamDisconnect(),this.session.signaling=t,this.isTransferSessionInProgress=!1,this.session.signaling?.stopSoftSwitch(),p.info("Session transfer complete")},1e3))}};var Mr=[1103,1200,1402];var Os=750,An=class{constructor(e){this.config=e;this.sessionTransferManager=new Fn(this),this._audioUpstreamMode=G(this.config.audioUpstreamMode)}config;id;signaling;messages=new so;speechRec;promptMetadata={};audioStreamId;sessionTransferManager;jwt;welcomeRequested=!1;resolutionLogged=!1;sttPausedByHost=!1;_audioUpstreamMode;get audioUpstreamMode(){return this._audioUpstreamMode}updatePromptMetadata(e){try{JSON.parse(JSON.stringify(e)),this.promptMetadata.custom=e,this.messages.next(new Qn(this.promptMetadata))}catch(t){p.error("Error parsing custom metadata",e,p.serialiseError(t))}}setEnableMicrophone(e){let t=this.audioUpstreamMode;this.config.enableMicrophone=e,this.sttPausedByHost=!1;let n=!1;J(t)&&(this.speechRec?(e?this.speechRec.startRecognition():this.speechRec.stopRecognition(),n=!0):p.warn("setEnableMicrophone: STT leg is configured but speech recognition is not initialised yet")),re(t)&&(this.signaling?(e?this.signaling.unmuteUpstreamMic():this.signaling.muteUpstreamMic(),n=!0,J(t)||this.messages.next(new jn(e))):p.warn("setEnableMicrophone: PS leg is configured but signaling is not initialised yet")),n||p.warn(`setEnableMicrophone(${e}) had nothing to do in mode '${t}' \u2014 session not ready?`)}pauseSpeechRecognition(){return this.sttPausedByHost=!0,this.speechRec?this.speechRec.pause():(p.warn("pauseSpeechRecognition: pause intent recorded, but speech recognition is not initialised yet \u2014 nothing to pause"),!1)}resumeSpeechRecognition(){return this.sttPausedByHost=!1,this.speechRec?this.speechRec.resume():(p.warn("resumeSpeechRecognition: pause intent cleared, but speech recognition is not initialised yet \u2014 nothing to resume"),!1)}setCameraAnchorDistance(e,t=0,n=this.signaling){this.config.cameraAnchorDistance=e,n?.dataSend(new Le(e,t))}setCameraAnchorHorizontal(e,t=0,n=this.signaling){this.config.cameraAnchorHorizontal=e,n?.dataSend(new Le(e,t))}changeAvatar(e,t=this.signaling){t?.dataSend(new Ln(e))}loadBackground(e,t=this.signaling){t?.dataSend(new Dn(e))}userStartSpeaking(e=this.signaling){e?.dataSend(new ci("start"))}userStopSpeaking(e=this.signaling){e?.dataSend(new ci("stop"))}triggerAction(e,t=this.signaling){t?.dataSend(new On(e))}resumeVideoPlayback(){this.signaling?.resumeVideoPlayback()}createSession(){this.messages.subscribe(e=>{if(this.config.messageHandler&&this.config.messageHandler(e),e.uneeqMessageType==="SoftSwitchFinished"||e.uneeqMessageType==="SessionReconnectingFinished"){if(!J(this.audioUpstreamMode))return;if(this.config.enableMicrophone&&!this.sttPausedByHost)e.uneeqMessageType==="SessionReconnectingFinished"?(p.info("Session, resuming speech recognition after reconnect"),this.speechRec?.resume()):(p.info("Session, restarting speech recognition after soft switch"),this.speechRec?.startRecognition());else{let t=e.uneeqMessageType==="SoftSwitchFinished"?"soft switch":"reconnect",n=this.sttPausedByHost?"paused by host":"microphone disabled";p.info(`Session, skipping speech recognition restart after ${t} (${n})`)}}}),this.id=this.config.sessionId,this.jwt=this.config.sessionToken,p.info("Session created with id: "+this.id),this.updatePromptMetadata(this.config.customMetadata||{}),this.promptMetadata=this.initMetadata(),this.listenForTabClosure(),this.signaling=this.createSignaling(this.config.videoContainerElement),this.signaling.init()}createSignaling(e=document.createElement("div")){let t=new URLSearchParams({token:this.jwt});this.config.backgroundUrl&&t.append("backgroundUrl",this.config.backgroundUrl);let n=(this.config.connectionUrl+`/session-service/v1/ws/session?${t.toString()}`).replace("http://","ws://").replace("https://","wss://");p.debug("Socket URL:",n);let i=new Pn(this,n,e);return i.messages.subscribe(r=>{this.signalingEventHandler(r,i)}),i}signalingEventHandler(e,t){switch(e.type){case 0:{this.handleSessionReady(t);break}case 1:{this.handleSessionReady(t);break}case 2:{this.handleDataChannelMessage(e,t);break}case 5:{let n=e.stats;!this.resolutionLogged&&n.inboundVideoStats?.frameWidth&&n.inboundVideoStats?.frameHeight&&(p.info("Video resolution:",`${n.inboundVideoStats.frameWidth}x${n.inboundVideoStats.frameHeight}`),this.resolutionLogged=!0),this.config.webRtcStatsEmitMessages&&this.messages.next(new Hn(n)),this.config.webRtcStatsLogMessages&&p.info("WebRTC stats",n);break}}}handleSessionReady(e){p.debug(`Session ready check - videoInitialized: ${e.videoInitialized}, dataChannelOpen: ${e.dataChannelOpen}, sceneReady: ${e.sceneReady}`),e.videoInitialized&&e.dataChannelOpen&&e.sceneReady&&(e.reconnectionAttempts=0,this.setCameraAnchorDistance(this.config.cameraAnchorDistance,0,e),this.setCameraAnchorHorizontal(this.config.cameraAnchorHorizontal,0,e),setTimeout(()=>{this.sessionTransferManager.isTransferSessionInProgress&&this.config.videoContainerElement?this.sessionTransferManager.switchLiveVideo(this.config.videoContainerElement,e):(this.initSpeechRecognition(this.jwt),this.sendWelcomePrompt(),document.body.classList.add("uneeq-streaming-live")),this.messages.next(new _n(this.id)),this.config.networkIndicator&&e.startNetworkQualityMonitor(this.config.networkIndicator),this.config.webRtcStatsLogMessages&&e.startAudioStatsMonitor()},Os))}async initSpeechRecognition(e){if(!J(this.audioUpstreamMode)){p.info(`[STT] audioUpstreamMode='${this.audioUpstreamMode}' \u2014 skipping STT provider initialisation (no STT leg in this mode).`);return}if(this.speechRec){p.warn("Speech recognition already initialized");return}let t=this.config.speechRecognitionProvider||"google";p.info(`[STT] Config speechRecognitionProvider: "${this.config.speechRecognitionProvider}", resolved provider: "${t}"`),t!=="google"&&t!=="deepgram"&&(p.warn(`Invalid speechRecognitionProvider value: "${String(t)}". Supported values are "google" or "deepgram". Defaulting to "google".`),t="google",this.config.speechRecognitionProvider="google"),p.info(`[STT] Using provider: ${t}`);try{this.speechRec=await(t==="deepgram"?this.createDeepgramSTT(e):this.createGoogleSTT(e))}catch(n){p.error("[STT] Failed to initialise speech recognition provider",p.serialiseError(n));return}this.config.enableMicrophone&&!this.sttPausedByHost&&this.speechRec&&this.speechRec.startRecognition()}async createGoogleSTT(e){let t=this.getSpeechOptions(e);p.debug("Initializing Google STT (speech-recognition-service)");let{GoogleSTT:n}=await import("./chunks/google-stt-JDMN7CZH.js");return new n(t)}async createDeepgramSTT(e){let t=this.config.deepgramConfig||{};if(this.isFluxModel(t.model))return this.createDeepgramFluxSTT(e);p.warn("Deepgram STT is currently in beta, is subject to change, and is not suitable for production use"),p.debug("Initializing Deepgram STT");let n={connectionUrl:this.config.connectionUrl,jwtToken:e,sessionId:this.id,model:t.model,language:t.language,smartFormat:t.smartFormat,interimResults:t.interimResults,utteranceEndMs:t.utteranceEndMs,vadEvents:t.vadEvents,encoding:t.encoding,sampleRate:t.sampleRate,channels:t.channels,fillerWords:t.fillerWords,endpointing:t.endpointing,interruptionWordThreshold:t.interruptionWordThreshold,echoCancellation:t.microphone?.echoCancellation,noiseSuppression:t.microphone?.noiseSuppression,autoGainControl:t.microphone?.autoGainControl,microphoneDeviceId:this.config.microphoneDeviceId,promptMetadata:this.promptMetadata,messages:this.messages,sendMessage:r=>{this.signaling?.dataSend(r)},enableInterrupt:this.config.enableInterruptBySpeech,safetyNetTimeoutMs:t.safetyNetTimeoutMs,keyterms:t.keyterms,noDelay:t.noDelay},{DeepgramSTT:i}=await import("./chunks/deepgram-stt-Y67Z46KN.js");return new i(n)}isFluxModel(e){return e!==void 0&&e.toLowerCase().startsWith("flux")}async createDeepgramFluxSTT(e){p.debug("Initializing Deepgram Flux STT (v2 API)");let t=this.config.deepgramConfig||{},n={connectionUrl:this.config.connectionUrl,jwtToken:e,sessionId:this.id,model:t.model,language:t.language,eotThreshold:t.eotThreshold,eagerEotThreshold:t.eagerEotThreshold,eotTimeoutMs:t.eotTimeoutMs,eagerMaxTurnDurationMs:t.eagerMaxTurnDurationMs,keyterms:t.keyterms,safetyNetTimeoutMs:t.safetyNetTimeoutMs,echoCancellation:t.microphone?.echoCancellation,noiseSuppression:t.microphone?.noiseSuppression,autoGainControl:t.microphone?.autoGainControl,microphoneDeviceId:this.config.microphoneDeviceId,promptMetadata:this.promptMetadata,messages:this.messages,sendMessage:r=>{this.signaling?.dataSend(r)}},{DeepgramFluxSTT:i}=await import("./chunks/deepgram-flux-stt-BHYXM2EH.js");return new i(n)}getSpeechOptions(e){return{apiUrl:this.config.connectionUrl,assetBasePath:this.config.assetBasePath,enableInterrupt:this.config.enableInterruptBySpeech,enableVad:this.config.enableVad,jwtToken:e,hintPhrases:this.config.speechRecognitionHintPhrases,hintPhrasesBoost:this.config.speechRecognitionHintPhrasesBoost,locales:this.config.speechRecognitionLocales,messages:this.messages,promptMetadata:this.promptMetadata,sessionId:this.id,sendMessage:t=>{this.signaling?.dataSend(t)},microphoneDeviceId:this.config.microphoneDeviceId}}initMetadata(){return{userSpokenLocale:"",browserDetectedLocales:this.config.speechRecognitionLocales,userTimezone:Intl.DateTimeFormat().resolvedOptions().timeZone,userScreenWidth:window.screen.availWidth,userScreenHeight:window.screen.availHeight,userAgent:navigator.userAgent,personaId:this.config.personaId,custom:this.config.customMetadata}}handleDataChannelMessage(e,t){switch(p.debug("Processing data channel message",e),e.msg.type){case"nlp_prompt_result":this.messages.next(new Jn(e.msg));break;case"avatar_started_speaking":{this.messages.next(new Bn);break}case"avatar_stopped_speaking":{this.messages.next(new Vn);break}case"error":{p.error(`an error has occurred - ${JSON.stringify(e.msg)}`),this.handleChannelMessageError(e.msg);break}case"scene_ready":{p.debug("Scene is ready"),t.sceneReady=!0,this.handleSessionReady(t),this.messages.next(new Xn);break}case"speech_event":{this.messages.next(new zn(e.msg));break}case"session_ended":{let n=e.msg.reason==="UserInactivity"?ur:e.msg.reason;this.signaling?.endSession(n),this.signaling=void 0;break}case"speech_stream_opened":{this.audioStreamId=e.msg.streamId;break}case"speech_stream_closed":{e.msg.streamId===this.audioStreamId?this.audioStreamId=void 0:p.warn("Received SpeechStreamClosed message for unexpected streamId",e.msg.streamId);break}}}handleChannelMessageError(e){let t=e?.message?.trim()||"An unknown error occurred";e&&Mr.includes(e.code)?this.messages.next(new $n(e)):this.messages.next(new q(t))}sendWelcomePrompt(){p.debug("Checking if the welcome prompt should be sent. Welcome requested already = "+this.welcomeRequested+". Prompt = ",this.config.welcomePrompt),this.config.welcomePrompt&&this.config.welcomePrompt.length>0&&!this.welcomeRequested&&(this.welcomeRequested=!0,this.signaling?.dataSend(new se(this.config.welcomePrompt,this.promptMetadata)))}listenForTabClosure(){window.addEventListener("beforeunload",()=>{p.info("Window unload detected, ending session."),this.signaling?.endSession(),this.signaling=void 0})}};var Nn=class{constructor(e,t=z()){this.prompt=e;this.requestId=t}prompt;requestId;toJSON(){return{action:"speak",data:{requestId:this.requestId,prompt:this.prompt}}}};var me=class{constructor(e,t,n={},i=z()){this.action=e;this.streamId=t;this.metadata=n;this.requestId=i}action;streamId;metadata;requestId;toJSON(){return{action:"speech_stream",data:{requestId:this.requestId,action:this.action,streamId:this.streamId,metadata:this.metadata}}}};var Un=class{constructor(e,t,n,i){this.command=e;this.enabled=t;this.category=n;this.verbosity=i}command;enabled;category;verbosity;toJSON(){let e={command:this.command,enabled:this.enabled};return this.category!==void 0&&(e.category=this.category),this.verbosity!==void 0&&(e.verbosity=this.verbosity),{action:"execute_command",data:e}}};async function Tr(s,e){try{if(s?.audioStreamId===void 0){p.warn("Audio stream is not open | Call openAudioStream() first");return}let t;if(typeof e=="string"){let o=typeof atob<"u"?atob(e):Buffer.from(e,"base64").toString("binary");t=new Uint8Array(o.length);for(let a=0;a<o.length;a++)t[a]=o.charCodeAt(a)}else if(e instanceof Uint8Array)t=e;else if(typeof Blob<"u"&&e instanceof Blob){let o=await e.arrayBuffer();t=new Uint8Array(o)}else{p.error("speakAudio: Unsupported audio type",e);return}let n=Uint8Array.from([1]),i=Uint8Array.from([s.audioStreamId]),r=new Uint8Array(2+t.length);r.set(n,0),r.set(i,1),r.set(t,2),s.signaling?.dataSendBinary(r)}catch(t){p.error("speakAudioSend: Error sending audio",t)}}var Fs=class{constructor(e){this.config=e;p.setLevel(e.logLevel??"info")}config;session;messageSubscription;init(){if(this.session){let e="Cannot initialize: session already active. Call endSession() first.";throw p.warn(e),new Error(e)}if(this.config.audioUpstreamMode!==void 0&&!_s(this.config.audioUpstreamMode)){let e=`Invalid audioUpstreamMode: '${String(this.config.audioUpstreamMode)}'. Allowed: 'speech-recognition-service' | 'pixel-streaming' | 'both'.`;throw p.error(e),new Error(e)}p.info(`Initializing Uneeq with config:', ${JSON.stringify(this.config)}, for UserAgent: ${navigator.userAgent}`),this.session=new An(this.config),this.session.createSession(),this.messageSubscription=this.session.messages.subscribe(e=>{e.uneeqMessageType==="SessionEnded"&&(p.info("Session ended, resetting session state"),this.resetSessionState())})}isSessionActive(){return this.session!==void 0}ensureSessionExists(){return this.session?.id?!0:(p.warn("Cannot perform action, session has not started."),!1)}chatPrompt(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.signaling?.dataSend(new se(e,this.session?.promptMetadata))}speak(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.signaling?.dataSend(new Nn(e))}openAudioStream(){let e=this.session;this.ensureSessionExists()&&e?.signaling?.dataSend(new me("open",e?.audioStreamId))}closeAudioStream(){let e=this.session;this.ensureSessionExists()&&e?.audioStreamId!==void 0&&e.signaling?.dataSend(new me("close",e.audioStreamId))}interruptAudioStream(){let e=this.session;this.ensureSessionExists()&&e?.audioStreamId!==void 0&&e.signaling?.dataSend(new me("interrupt",e.audioStreamId))}async speakAudio(e){this.ensureSessionExists()&&await Tr(this.session,e)}cameraAnchorDistance(e,t){this.ensureSessionExists()&&this.session?.setCameraAnchorDistance(e,t)}cameraAnchorHorizontal(e,t){this.ensureSessionExists()&&this.session?.setCameraAnchorHorizontal(e,t)}changeAvatar(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.changeAvatar(e)}loadBackground(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.loadBackground(e)}userStartSpeaking(){this.ensureSessionExists()&&this.session?.userStartSpeaking()}userStopSpeaking(){this.ensureSessionExists()&&this.session?.userStopSpeaking()}triggerAction(e){e&&e.trim()!==""&&this.ensureSessionExists()&&this.session?.triggerAction(e)}resumeVideoPlayback(){this.session?.resumeVideoPlayback()}executeCommand(e,t,n,i){this.ensureSessionExists()&&this.session?.signaling?.dataSend(new Un(e,t,n,i))}endSession(){this.ensureSessionExists()&&(this.session?.signaling?.endSession(),this.resetSessionState())}resetSessionState(){this.messageSubscription?.unsubscribe(),this.messageSubscription=void 0,this.session=void 0}unmuteDigitalHuman(){this.ensureSessionExists()&&(this.session?.signaling?.playAudioElement(),p.debug("Unmuted digital human."))}muteDigitalHuman(){this.ensureSessionExists()&&(this.session?.signaling?.pauseAudioElement(),p.debug("Muted digital human."))}stopSpeaking(){this.ensureSessionExists()&&this.session?.signaling?.dataSend(new Vs)}setCustomPromptMetadata(e){this.ensureSessionExists()&&this.session?.updatePromptMetadata(e)}enableMicrophone(e=!0){this.ensureSessionExists()&&this.session?.setEnableMicrophone(e)}pauseSpeechRecognition(){if(!this.ensureSessionExists())return!1;let e=G(this.config.audioUpstreamMode);if(!J(e))return p.warn(`pauseSpeechRecognition called in '${e}' mode \u2014 no STT leg to pause; ignoring. Use muteUpstreamMic() to silence the PS mic track.`),!1;let t=this.session?.pauseSpeechRecognition()??!1;return t instanceof Promise?!0:t}resumeSpeechRecognition(){if(!this.ensureSessionExists())return!1;let e=G(this.config.audioUpstreamMode);if(!J(e))return p.warn(`resumeSpeechRecognition called in '${e}' mode \u2014 no STT leg to resume; ignoring. Use unmuteUpstreamMic() to re-enable the PS mic track.`),!1;let t=this.session?.resumeSpeechRecognition()??!1;return t instanceof Promise?!0:t}muteUpstreamMic(){this.ensureSessionExists()&&this.session?.signaling?.muteUpstreamMic()}unmuteUpstreamMic(){this.ensureSessionExists()&&this.session?.signaling?.unmuteUpstreamMic()}setWebRtcStatsEnabled(e,t){this.session?.config&&(this.session.config.webRtcStatsEmitMessages=e,this.session.config.webRtcStatsLogMessages=t,p.info(`Setting up WebRtcStats: webRtcStatsEmitMessages: ${this.session.config.webRtcStatsEmitMessages}, webRtcStatsLogMessages: ${this.session.config.webRtcStatsLogMessages}`),t?this.session.signaling?.startAudioStatsMonitor():this.session.signaling?.stopAudioStatsMonitor())}setNetworkIndicatorEnabled(e){this.ensureSessionExists()&&(e?this.session?.signaling?.startNetworkQualityMonitor(e):this.session?.signaling?.stopNetworkQualityMonitor())}};export{Dr as AvatarAnswerMessage,Ur as AvatarInterruptedMessage,Bn as AvatarStartedSpeakingMessage,Vn as AvatarStoppedSpeakingMessage,wr as CameraAnchorDistance,Cr as CameraAnchorHorizontal,Qn as CustomMetadataUpdated,oi as CustomerConcurrencyLimitReachedMessage,Lr as DeviceErrorMessage,Fe as DigitalHumanMuted,Oe as DigitalHumanPlayedInMutedModeSuccess,Kn as DigitalHumanUnmuted,jn as EnableMicrophoneUpdatedMessage,Pr as LogLevel,Sr as NetworkIndicatorPopupTrigger,yr as NetworkIndicatorPosition,gr as NetworkIndicatorVisibility,fr as NetworkQualityLevel,ai as NetworkQualityMessage,Gn as PromptRequestMessage,Jn as PromptResultMessage,Ae as RendererErrorMessage,Xn as SceneReadyMessage,$n as SessionBackendErrorMessage,Yn as SessionConnectingMessage,Zn as SessionDisconnectedMessage,qn as SessionEndedMessage,q as SessionErrorMessage,_n as SessionLiveMessage,ti as SessionReconnectingFinishedMessage,ei as SessionReconnectingMessage,ni as SoftSwitchStartingMessage,ii as SoftSwitchStoppingMessage,zn as SpeechEventMessage,di as SpeechRecognitionProvider,Br as SpeechRecognitionTransientErrorMessage,Or as SpeechTranscriptionMessage,Is as UNEEQ_JS_SDK_VERSION,Fs as Uneeq,Bs as UneeqMessageType,Ar as UserStartedSpeakingMessage,Nr as UserStoppedSpeakingMessage,Fr as VadInterruptionAllowedMessage,li as VideoAutoplayBlockedMessage,si as VideoLayoutConfiguringMessage,Wn as WaitingInQueueMessage,ri as WebRtcConnectedMessage,Hn as WebRtcStatsMessage,G as resolveAudioUpstreamMode};
|
package/dist/google-stt.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export declare class GoogleSTT implements SpeechRecognitionInterface {
|
|
|
23
23
|
private isTemporarilyPaused;
|
|
24
24
|
private vadInitialising;
|
|
25
25
|
private pausedDuringVadInit;
|
|
26
|
+
private micInitialising;
|
|
27
|
+
private vadInitGeneration;
|
|
26
28
|
private isSignalingReconnecting;
|
|
27
29
|
stream?: MediaStream;
|
|
28
30
|
micVad: MicVAD;
|