@sanseng/livekit-ws-sdk 1.0.0 → 1.0.2
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/README.md +0 -2
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +1 -1
- package/dist/index.full.umd.js +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("livekit-client")):"function"==typeof define&&define.amd?define(["exports","livekit-client"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LivekitSDK={},e.LivekitClient)}(this,function(e,t){"use strict";var i,s,n;!function(e){e.SDK_AUTH_TOKEN_FAILED="SDK_AUTH_TOKEN_FAILED",e.SDK_GET_LIVEKIT_CONFIG_FAILED="SDK_GET_LIVEKIT_CONFIG_FAILED",e.SDK_SWITCH_VIDEO_FAILED="SDK_SWITCH_VIDEO_FAILED",e.SDK_INTERRUPT_CONVERSATION_FAILED="SDK_INTERRUPT_CONVERSATION_FAILED",e.HTTP_CONTROLLER_NOT_AVAILABLE="HTTP_CONTROLLER_NOT_AVAILABLE",e.SDK_PRECONNECT_FAILED="SDK_PRECONNECT_FAILED",e.SDK_CONNECT_FAILED="SDK_CONNECT_FAILED",e.SDK_INITIALIZATION_FAILED="SDK_INITIALIZATION_FAILED",e.SDK_DISCONNECT_FAILED="SDK_DISCONNECT_FAILED",e.SDK_RECONNECT_FAILED="SDK_RECONNECT_FAILED",e.SDK_NOT_CONNECTED="SDK_NOT_CONNECTED",e.SDK_INVALID_STATE_TRANSITION="SDK_INVALID_STATE_TRANSITION",e.SDK_ERROR="SDK_ERROR",e.LIVEKIT_CONNECT_FAILED="LIVEKIT_CONNECT_FAILED",e.AUDIO_CAPTURE_START_FAILED="AUDIO_CAPTURE_START_FAILED",e.AUDIO_CAPTURE_FAILED="AUDIO_CAPTURE_FAILED",e.AUDIO_INVALID_SAMPLE_RATE="AUDIO_INVALID_SAMPLE_RATE",e.AUDIO_INVALID_CHANNEL="AUDIO_INVALID_CHANNEL",e.AUDIO_INVALID_HEADER_LENGTH="AUDIO_INVALID_HEADER_LENGTH",e.AUDIO_INVALID_TYPE="AUDIO_INVALID_TYPE",e.AUDIO_INVALID_RESERVED="AUDIO_INVALID_RESERVED",e.AUDIO_CONTROLLER_NOT_AVAILABLE="AUDIO_CONTROLLER_NOT_AVAILABLE",e.CAMERA_CONTROLLER_NOT_AVAILABLE="CAMERA_CONTROLLER_NOT_AVAILABLE",e.CONVERSATION_CONTROLLER_NOT_AVAILABLE="CONVERSATION_CONTROLLER_NOT_AVAILABLE",e.STATE_MACHINE_INVALID_STATE_TRANSITION="STATE_MACHINE_INVALID_STATE_TRANSITION",e.OBJECT_DISPOSED="OBJECT_DISPOSED",e.AUDIO_INVALID_CODEC="AUDIO_INVALID_CODEC",e.LIVEKIT_SEND_VIDEO_AVAILABLE_STATE_FAILED="LIVEKIT_SEND_VIDEO_AVAILABLE_STATE_FAILED",e.LIVEKIT_SEND_TEXT_DATA_FAILED="LIVEKIT_SEND_TEXT_DATA_FAILED",e.LIVEKIT_DATA_MESSAGE_PARSE_ERROR="LIVEKIT_DATA_MESSAGE_PARSE_ERROR",e.LIVEKIT_UNPUBLISH_MICROPHONE_FAILED="LIVEKIT_UNPUBLISH_MICROPHONE_FAILED",e.NO_AVATARID="NO_AVATARID",e.NO_AUTH_TOKEN="NO_AUTH_TOKEN",e.INVALID_CONNECT_CONFIG="INVALID_CONNECT_CONFIG"}(i||(i={}));class r extends Error{constructor(e,t,i){super(t),this.name="SDKError",this.code=e,this.cause=i,Object.setPrototypeOf(this,r.prototype)}static fromError(e,t){return e instanceof r?e:e instanceof Error?new r(t||i.SDK_ERROR,e.message,e):"string"==typeof e?new r(t||i.SDK_ERROR,e):new r(t||i.SDK_ERROR,"Unknown error",e)}}class o{constructor(){this._disposed=!1}get isDisposed(){return this._disposed}dispose(){this._disposed||(this.onDispose(),this._disposed=!0)}ensureNotDisposed(){if(this._disposed)throw new r(i.OBJECT_DISPOSED,"Object has been disposed")}}e.LogLevel=void 0,(s=e.LogLevel||(e.LogLevel={}))[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.NONE=4]="NONE";class a{static setLevel(e){this._level=e}static setPrefix(e){this._prefix=e}static debug(t,...i){this._level<=e.LogLevel.DEBUG&&console.debug(`${this._prefix} [DEBUG]`,t,...i)}static info(t,...i){this._level<=e.LogLevel.INFO&&console.info(`${this._prefix} [INFO]`,t,...i)}static warn(t,...i){this._level<=e.LogLevel.WARN&&console.warn(`${this._prefix} [WARN]`,t,...i)}static error(t,...i){this._level<=e.LogLevel.ERROR&&console.error(`${this._prefix} [ERROR]`,t,...i)}}a._level=e.LogLevel.ERROR,a._prefix="[SDK]";class c extends o{constructor(){super(...arguments),this._listeners=new Map}on(e,t){this.ensureNotDisposed(),this._listeners.has(e)||this._listeners.set(e,new Set);const i=this._listeners.get(e);return i.add(t),a.debug(`Event listener added for: ${String(e)}`),()=>{i.delete(t),a.debug(`Event listener removed for: ${String(e)}`)}}once(e,t){this.ensureNotDisposed();const i=s=>{t(s),this.off(e,i)};return this.on(e,i)}off(e,t){this.ensureNotDisposed();const i=this._listeners.get(e);i&&i.delete(t)}emit(e,t){this.ensureNotDisposed();const i=this._listeners.get(e);i&&i.size>0&&(a.debug(`Emitting event: ${String(e)}`,t),i.forEach(i=>{try{i(t)}catch(t){a.error(`Error in event listener for ${String(e)}:`,t)}}))}removeAllListeners(){this._listeners.clear(),a.debug("All event listeners removed")}listenerCount(e){const t=this._listeners.get(e);return t?t.size:0}onDispose(){this.removeAllListeners()}}e.SessionStatus=void 0,(n=e.SessionStatus||(e.SessionStatus={})).IDLE="idle",n.CONNECTING="connecting",n.CONNECTED="connected",n.PARTIAL="partial",n.DISCONNECTED="disconnected",n.RECONNECTING="reconnecting",n.DISCONNECTING="disconnecting",n.ERROR="error",n.DISPOSED="disposed";class h{constructor(){this.status=e.SessionStatus.DISCONNECTED,this.state=e.SessionStatus.DISCONNECTED,this.isConnected=!1}reset(){this.status=e.SessionStatus.DISCONNECTED,this.state=e.SessionStatus.DISCONNECTED,this.isConnected=!1}}const d=1e3,l=24e3;var _;!function(e){e.NO_VIDEO_TRACK="NO_VIDEO_TRACK",e.TRACK_MUTED="TRACK_MUTED",e.TRACK_ENDED="TRACK_ENDED"}(_||(_={}));const u=.7;class p{constructor(){this._active=null}get active(){return this._active}tryBegin(e){return(null===this._active||this._active===e)&&(this._active=e,!0)}end(e){this._active===e&&(this._active=null)}reset(){this._active=null}}class m{constructor(e){this._connectionStateGetter=null,this.options=e,this._livekitUrl="",this._wsUrl="",this.eventBus=new c,this.sessionState=new h,this.mediaAudioCaptureState=new p,this._token="auth"===e.connectConfig.type&&e.connectConfig.config.authToken||"",e.debug&&a.setLevel(0),a.info("SDK Context initialized")}setLivekitConfig(e,t,i){this._livekitUrl=e||"wss://api.newportai.com/s2/livekit-lisbon",this._token=t,this._roomId=i}setAuthToken(e){this._httpToken=e}get authToken(){return this._httpToken}emitError(e,t){const i=r.fromError(e,t);return this.eventBus.emit("inner:sdk:error",{error:i}),i}setVideoOptions(e){this.options.video=Object.assign({},e,this.options.video||{})}get wsUrl(){return this._wsUrl}get livekitUrl(){return this._livekitUrl}get token(){return this._token}get roomId(){return this._roomId}getLivekitConfig(){return{livekitUrl:this._livekitUrl,token:this._token}}bindConnectionState(e){this._connectionStateGetter=e}get connectionState(){return this._connectionStateGetter?.()}clearConnectionStateBinding(){this._connectionStateGetter=null}dispose(){this.clearConnectionStateBinding(),this.mediaAudioCaptureState.reset(),this.eventBus.dispose(),this.sessionState.reset(),a.info("SDK Context disposed")}}class v extends o{setContext(e){this._context=e}}function g(e){return{http:{connected:!1},rtc:{connected:!1,hasVideoTrack:!1},overall:{state:e}}}function E(e){return Object.freeze({http:Object.freeze({...e.http}),rtc:Object.freeze({...e.rtc}),overall:Object.freeze({...e.overall})})}class f{constructor(){this._transitionMap=null}get transitionMap(){if(!this._transitionMap){const e=new Map;for(const t of this.transitionTable)e.set(t.from,new Set(t.to));this._transitionMap=e}return this._transitionMap}getCurrentState(){return this._currentState}transitionTo(e,t){const s=this._currentState;if(!this.canTransition(s,e)){const n=this.transitionMap.get(s),o=n?Array.from(n).join(", "):"none";throw t?.error??new r(i.STATE_MACHINE_INVALID_STATE_TRANSITION,`Invalid state transition: cannot transition from "${s}" to "${e}". Current state: "${s}". Allowed transitions: [${o}]`)}this._currentState=e}canTransition(e,t){if(e===t)return!1;const i=this.transitionMap.get(e);return i?.has(t)??!1}reset(){throw new Error("Method not implemented.")}}class C extends f{constructor(){super(...arguments),this._currentState="idle",this.transitionTable=[{from:"idle",to:["connecting","disposed"]},{from:"connecting",to:["connected","partial","error","idle","disposed"]},{from:"connected",to:["disconnecting","partial","reconnecting:auto","reconnecting:manual","error","disposed"]},{from:"partial",to:["connected","disconnecting","reconnecting:auto","reconnecting:manual","error","disposed"]},{from:"reconnecting:auto",to:["connected","partial","error","idle","disposed"]},{from:"reconnecting:manual",to:["connected","partial","error","idle","disposed"]},{from:"disconnecting",to:["disconnected","error","disposed"]},{from:"disconnected",to:["reconnecting:manual","reconnecting:auto","idle","disposed"]},{from:"error",to:["reconnecting:manual","reconnecting:auto","idle","disposed"]},{from:"disposed",to:[]}]}reset(){this._currentState="idle"}}class T extends v{constructor(){super(),this._unsubscribes=[],this._fsm=new C,this._snapshot=g("idle")}start(){this.ensureNotDisposed();const e=this._context.eventBus,t=e.on("inner:rtc:connected",()=>{this._snapshot.rtc.connected=!0,this._context.eventBus.emit("inner:sdk:connected",{source:"livekit"}),this._onFactsChanged()}),i=e.on("inner:rtc:disconnected",e=>{this._snapshot.rtc.connected=!1,this._snapshot.rtc.hasVideoTrack=!1,this._context.eventBus.emit("inner:sdk:disconnected",{source:"livekit",reason:e?.reason}),this._onFactsChanged()}),s=e.on("inner:rtc:video:available",()=>{this._snapshot.rtc.hasVideoTrack=!0}),n=e.on("inner:rtc:video:unavailable",()=>{this._snapshot.rtc.hasVideoTrack=!1}),r=e.on("inner:sdk:connected",e=>{"http"===e.source&&(this._snapshot.http.connected=!0,this._onFactsChanged())}),o=e.on("inner:sdk:disconnected",e=>{"http"===e.source&&(this._snapshot.http.connected=!1,this._onFactsChanged())});this._unsubscribes=[t,i,s,n,r,o],this._syncHttpFromContext(),this._onFactsChanged()}startConnecting(){this._transitionTo("connecting")}startDisconnecting(){this._transitionTo("disconnecting")}completeDisconnecting(){this._snapshot.http.connected=!1,this._snapshot.rtc.connected=!1,this._snapshot.rtc.hasVideoTrack=!1,this._transitionTo("disconnected")}captureSnapshotAndStartReconnectingManual(){const e=this.getSnapshot();return this._transitionTo("reconnecting:manual"),e}transitionToIdle(){this._snapshot.http.connected=!1,this._snapshot.rtc.connected=!1,this._snapshot.rtc.hasVideoTrack=!1,this._transitionTo("idle")}transitionToDisposed(){this._transitionTo("disposed")}getSnapshot(){return E(this._snapshot)}getState(){return this._fsm.getCurrentState()}canStartReconnectingManual(){const e=this._fsm.getCurrentState();return"connected"===e||"partial"===e||"disconnected"===e||"error"===e}_factsFullyConnected(){return("direct"===this._context.options.connectConfig.type||this._snapshot.http.connected)&&this._snapshot.rtc.connected}_factsAnyCritical(){return"direct"===this._context.options.connectConfig.type?this._snapshot.rtc.connected:this._snapshot.http.connected||this._snapshot.rtc.connected}_syncHttpFromContext(){this._snapshot.http.connected=Boolean(this._context.token)}_onFactsChanged(){const e=this._fsm.getCurrentState(),t=this._factsFullyConnected(),i=this._factsAnyCritical();if("connecting"===e||"reconnecting:auto"===e||"reconnecting:manual"===e){if(t)return void this._transitionTo("connected");if(i)return void this._transitionTo("partial")}if("connected"===e||"partial"===e){if(!i)return void this._transitionTo("disconnected");if(!t)return void this._transitionTo("partial");if(t&&"partial"===e)return void this._transitionTo("connected")}}_transitionTo(e){this._fsm.canTransition(this._fsm.getCurrentState(),e)&&(this._fsm.transitionTo(e),this._snapshot.overall.state=this._fsm.getCurrentState(),this._syncSessionState())}_syncSessionState(){const t=this._fsm.getCurrentState();this._context.sessionState.status=function(t){switch(t){case"idle":return e.SessionStatus.IDLE;case"connecting":return e.SessionStatus.CONNECTING;case"connected":return e.SessionStatus.CONNECTED;case"partial":return e.SessionStatus.PARTIAL;case"disconnecting":return e.SessionStatus.DISCONNECTING;case"disconnected":case"error":default:return e.SessionStatus.DISCONNECTED;case"reconnecting:auto":case"reconnecting:manual":return e.SessionStatus.RECONNECTING;case"disposed":return e.SessionStatus.DISPOSED}}(t),this._context.sessionState.state=this._context.sessionState.status,this._context.sessionState.isConnected="connected"===t}onDispose(){this._unsubscribes.forEach(e=>e()),this._unsubscribes=[]}}class S extends o{get trackId(){return this._trackId}get participantId(){return this._participantId}get track(){return this._track}constructor(){super(),this._trackId=null,this._participantId=null,this._track=null,this._stream=null,this._videoElement=document.createElement("video"),this._videoElement.autoplay=!0,this._videoElement.playsInline=!0,this._videoElement.muted=!0,this._videoElement.crossOrigin="anonymous",this._videoElement.style.display="none",a.info("Video Source initialized with internal video element")}getInternalElement(){return this._videoElement}setTrack(e,t,i){this.ensureNotDisposed(),this._track&&this._track.stop(),this._track=e,this._trackId=t,this._participantId=i,this._stream||(this._stream=new MediaStream);const s=this._stream.getTracks();for(const t of s)if(t!==e)try{this._stream.removeTrack(t)}catch(e){a.warn("Failed to remove track from stream",e)}if(!this._stream.getTracks().includes(e))try{this._stream.addTrack(e)}catch(e){a.error("Failed to add track to media stream:",e)}a.info("Video track ready")}clearTrack(){if(this._videoElement&&(this._videoElement.srcObject=null),this._stream){const e=this._stream.getTracks();for(const t of e)try{this._stream.removeTrack(t)}catch(e){a.warn("Failed to remove track from stream",e)}}this._track&&(this._track.stop(),this._track=null),this._trackId=null,this._participantId=null,a.info("Video track cleared")}get hasTrack(){return null!==this._track&&"live"===this._track.readyState}onDispose(){this.clearTrack(),this._videoElement&&(this._videoElement.srcObject=null,this._videoElement.parentElement&&this._videoElement.parentElement.removeChild(this._videoElement)),this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),a.info("Video Source disposed")}}class A extends o{constructor(){super(...arguments),this._renderer=null}getRenderer(){return this._renderer}setRenderer(e){this._renderer&&this._renderer.dispose(),this._renderer=e,a.debug("Raw render strategy renderer set")}getProcessors(){return[]}setProcessors(e){a.warn("Raw render strategy does not support processors")}attachToContainer(e){if(this._renderer){if("getElement"in this._renderer&&"function"==typeof this._renderer.getElement){const t=this._renderer.getElement();t instanceof HTMLVideoElement&&(t.parentElement&&t.parentElement!==e&&t.parentElement.removeChild(t),t.parentElement!==e&&(e.appendChild(t),t.style.display="",a.debug("Video element attached to container in raw mode")))}}else a.warn("No renderer available to attach to container")}onDispose(){this._renderer&&(this._renderer.dispose(),this._renderer=null),a.info("Raw Render Strategy disposed")}}class D{create(){return new A}}class R extends o{constructor(e,t){if(super(),this._canvas=null,this._ctx=null,this._videoElement=null,this._parentElement=null,this._resizeObserver=null,this._animationFrameId=null,this._isRendering=!1,this._renderLoop=()=>{if(this._isRendering&&this._videoElement&&this._canvas&&this._ctx){try{this._syncCanvasSize(),this._ctx.drawImage(this._videoElement,0,0,this._canvas.width,this._canvas.height)}catch(e){a.error("Error rendering from video to canvas:",e)}this._animationFrameId=requestAnimationFrame(this._renderLoop)}},e){if(this._canvas=e,this._ctx=e.getContext("2d"),!this._ctx)throw new Error("Failed to get 2D context from canvas")}else{if(!t)throw new Error("CanvasRenderer requires either canvas or videoElement");this._videoElement=t,this._createCanvasFromVideo()}a.info("Canvas Renderer created")}_createCanvasFromVideo(){if(!this._videoElement)return;if(this._parentElement=this._videoElement.parentElement,!this._parentElement)throw new Error("Video element must have a parent element");if("static"===window.getComputedStyle(this._parentElement).position&&(this._parentElement.style.position="relative"),this._canvas=document.createElement("canvas"),this._ctx=this._canvas.getContext("2d"),!this._ctx)throw new Error("Failed to get 2D context from canvas");this._canvas.style.position="absolute",this._canvas.style.top="0",this._canvas.style.left="0",this._canvas.style.width="100%",this._canvas.style.height="100%",this._canvas.style.pointerEvents="none",this._parentElement.appendChild(this._canvas),this._syncCanvasSize(),this._setupResizeObserver()}_syncCanvasSize(){if(!this._canvas||!this._videoElement||!this._ctx)return;const e=this._videoElement.videoWidth,t=this._videoElement.videoHeight,i=this._videoElement.clientWidth,s=this._videoElement.clientHeight;if(e>0&&t>0&&i>0&&s>0){const n=e/t;let r,o;n>i/s?(r=i,o=i/n):(r=s*n,o=s),this._canvas.style.width=`${r}px`,this._canvas.style.height=`${o}px`;const a=(i-r)/2,c=(s-o)/2;this._canvas.style.left=`${a}px`,this._canvas.style.top=`${c}px`,this._canvas.width=e,this._canvas.height=t}}_setupResizeObserver(){this._videoElement&&"undefined"!=typeof ResizeObserver&&(this._resizeObserver=new ResizeObserver(()=>{this._syncCanvasSize()}),this._resizeObserver.observe(this._videoElement))}startRenderingFromVideo(){!this._isRendering&&this._videoElement&&this._canvas&&this._ctx&&(this._isRendering=!0,this._renderLoop())}stopRenderingFromVideo(){this._isRendering=!1,null!==this._animationFrameId&&(cancelAnimationFrame(this._animationFrameId),this._animationFrameId=null)}setFitMode(e){this._canvas&&(this._canvas.style.width="100%",this._canvas.style.height="100%",this._canvas.style.objectFit=e)}render(e){if(this.ensureNotDisposed(),this._ctx&&this._canvas)try{const t=e.displayWidth,i=e.displayHeight;this._videoElement?this._syncCanvasSize():this._canvas.width===t&&this._canvas.height===i||(this._canvas.width=t,this._canvas.height=i);const s=e instanceof VideoFrame?e.displayWidth:e.videoWidth,n=e instanceof VideoFrame?e.displayHeight:e.videoHeight;s>0&&n>0&&(this._canvas.width===s&&this._canvas.height===n||(this._canvas.width=s,this._canvas.height=n)),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._ctx.drawImage(e,0,0,this._canvas.width,this._canvas.height)}catch(e){a.error("Error rendering video frame to canvas:",e)}}getCanvas(){return this._canvas}getContext(){return this._ctx}onDispose(){this.stopRenderingFromVideo(),this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._canvas&&this._parentElement&&this._canvas.parentElement===this._parentElement&&this._parentElement.removeChild(this._canvas),this._canvas=null,this._ctx=null,this._videoElement=null,this._parentElement=null,a.info("Canvas Renderer disposed")}}class I extends o{constructor(e){super(),this._element=null,this._stream=null,this._track=null,this._element=e,a.info("Video Element Renderer created")}setTrack(e){if(this.ensureNotDisposed(),this._track=e,!this._element)return void a.warn("No video element available to set track");this._stream||(this._stream=new MediaStream,this._element.srcObject=this._stream);const t=this._stream.getTracks();for(const i of t)if(i!==e)try{this._stream.removeTrack(i)}catch(e){a.error("Failed to remove track from media stream:",e)}if(!this._stream.getTracks().includes(e))try{this._stream.addTrack(e)}catch(e){a.error("Failed to add track to media stream:",e)}this._element.play().catch(e=>{a.error("Error playing video:",e)}),a.debug("Video track set to element (stream reused)")}setOpacity(e){this._element&&(this._element.style.opacity=String(e))}getElement(){return this._element}setFitMode(e){this._element&&(this._element.style.width="100%",this._element.style.height="100%",this._element.style.objectFit=e)}render(e){a.debug("Render called in direct mode (no-op)")}onDispose(){this._element&&(this._element.srcObject=null),this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._track&&(this._track.stop(),this._track=null),a.info("Video Element Renderer disposed")}clearTrack(){if(this._stream){const e=this._stream.getTracks();for(const t of e)try{this._stream.removeTrack(t)}catch(e){a.error("Failed to remove track from media stream:",e)}}this._track=null}}class y extends o{constructor(){super(...arguments),this._renderer=null,this._processors=[],this._videoElementRenderer=null,this._canvasRenderer=null,this._videoFrameCallbackId=null,this._animationFrameId=null,this._isProcessing=!1,this._processVideoFrame=()=>{if(!this._isProcessing||!this._videoElementRenderer||!this._canvasRenderer)return;const e=this._videoElementRenderer.getElement();if(!e||e.readyState<2)this._isProcessing&&e&&(this._videoFrameCallbackId=e.requestVideoFrameCallback(this._processVideoFrame));else{try{let t=new VideoFrame(e,{timestamp:1e3*performance.now()});for(const e of this._processors){const i=e.process(t);i&&i!==t&&(t instanceof VideoFrame&&t.close(),t=i)}t instanceof ImageData?this._renderImageData(t):this._canvasRenderer.render(t),t instanceof VideoFrame&&t.close()}catch(e){a.error("Error processing video frame:",e)}this._isProcessing&&e&&(this._videoFrameCallbackId=e.requestVideoFrameCallback(this._processVideoFrame))}},this._processVideoFrameFallback=()=>{if(!this._isProcessing||!this._canvasRenderer||!this._videoElementRenderer)return;const e=this._videoElementRenderer.getElement();if(!e||e.readyState<2||e.paused){const e=this._canvasRenderer.getContext(),t=this._canvasRenderer.getCanvas();return e&&t&&e.clearRect(0,0,t.width,t.height),void(this._animationFrameId=requestAnimationFrame(this._processVideoFrameFallback))}const t=e.videoWidth,i=e.videoHeight,s=this._canvasRenderer.getCanvas();t>0&&s&&(s.width!==t||s.height!==i)&&(s.width=t,s.height=i);let n=new VideoFrame(e);try{for(const e of this._processors){const t=e.process(n);t&&t!==n&&(n instanceof VideoFrame&&n.close(),n=t)}n instanceof ImageData?this._renderImageData(n):this._canvasRenderer.render(n)}finally{n instanceof VideoFrame&&n.close()}this._isProcessing&&(this._animationFrameId=requestAnimationFrame(this._processVideoFrameFallback))}}getRenderer(){return this._renderer}setRenderer(e){if(this._renderer&&this._renderer.dispose(),this._renderer=e,e instanceof I){if(this._videoElementRenderer=e,!this._canvasRenderer){const e=this._videoElementRenderer.getElement();if(e)try{e.parentElement&&(this._canvasRenderer=new R(void 0,e),this._renderer=this._canvasRenderer,a.debug("Canvas renderer created in setRenderer (processed mode)"))}catch(e){a.warn("Failed to create CanvasRenderer in setRenderer, will retry in attachToContainer:",e)}}this._setupProcessingPipeline()}else this._videoElementRenderer=null,this._stopProcessingPipeline();a.debug("Processed render strategy renderer set")}addProcessor(e,t){void 0!==t&&t>=0&&t<this._processors.length?this._processors.splice(t,0,e):this._processors.push(e),this._setupProcessingPipeline()}getProcessors(){return this._processors}setProcessors(e){this._processors.forEach(e=>e.dispose()),this._processors=e,this._setupProcessingPipeline(),a.debug("Processed render strategy processor set")}attachToContainer(e){if(this._canvasRenderer){const t=this._canvasRenderer.getCanvas();if(t&&(t.parentElement&&t.parentElement!==e&&t.parentElement.removeChild(t),t.parentElement!==e&&(e.appendChild(t),a.debug("Canvas element attached to container in processed mode"))),this._videoElementRenderer){const e=this._videoElementRenderer.getElement();e&&(e.parentElement&&e.parentElement.removeChild(e),e.style.display="none")}}else if(this._videoElementRenderer){const t=this._videoElementRenderer.getElement();if(t){const i=null!==t.parentElement;i||e.appendChild(t);try{this._canvasRenderer=new R(void 0,t),this._renderer=this._canvasRenderer,i||t.parentElement!==e||e.removeChild(t),t.style.display="none";const s=this._canvasRenderer.getCanvas();s&&s.parentElement!==e&&e.appendChild(s),this._startProcessingLoop(),a.debug("Canvas created and attached to container in processed mode")}catch(s){a.error("Failed to create CanvasRenderer in attachToContainer:",s),i||t.parentElement!==e||e.removeChild(t),t.parentElement!==e&&(e.appendChild(t),t.style.display="")}}}}_setupProcessingPipeline(){if(!this._videoElementRenderer)return;const e=this._videoElementRenderer.getElement();if(e){if(e.parentElement&&e.parentElement.removeChild(e),e.style.display="none",e.readyState<2){const t=()=>{this._setupProcessingPipeline(),e.removeEventListener("loadedmetadata",t)};return void e.addEventListener("loadedmetadata",t)}this._canvasRenderer&&(this._startProcessingLoop(),a.info("Processing pipeline setup completed"))}else a.warn("Video element not available for processing")}_stopProcessingPipeline(){this._stopProcessingLoop(),this._canvasRenderer&&(this._canvasRenderer.dispose(),this._canvasRenderer=null),this._videoElementRenderer&&(this._renderer=this._videoElementRenderer)}_startProcessingLoop(){if(this._isProcessing||!this._videoElementRenderer||!this._canvasRenderer)return;this._videoElementRenderer.getElement()&&(this._isProcessing=!0,"requestVideoFrameCallback"in HTMLVideoElement.prototype?this._processVideoFrame():this._processVideoFrameFallback())}_stopProcessingLoop(){this._isProcessing=!1;const e=this._videoElementRenderer?.getElement();null!==this._videoFrameCallbackId&&e&&"cancelVideoFrameCallback"in e&&(e.cancelVideoFrameCallback(this._videoFrameCallbackId),this._videoFrameCallbackId=null),null!==this._animationFrameId&&(cancelAnimationFrame(this._animationFrameId),this._animationFrameId=null)}_renderImageData(e){if(!this._canvasRenderer)return;const t=this._canvasRenderer.getContext(),i=this._canvasRenderer.getCanvas();t&&i&&(i.width===e.width&&i.height===e.height||(i.width=e.width,i.height=e.height),t.clearRect(0,0,i.width,i.height),t.putImageData(e,0,0))}onDispose(){this._stopProcessingPipeline(),this._renderer&&(this._renderer.dispose(),this._renderer=null),this._processors.forEach(e=>e.dispose()),this._processors=[],this._videoElementRenderer=null,this._canvasRenderer=null,a.info("Processed Render Strategy disposed")}}class b{create(){return new y}}class k{static getFactory(e){return"processed"===e?new b:new D}}class w extends o{constructor(e,t){super(),this._videoElementRenderer=null,this._containerElement=null,this._source=e;const i=t?.renderMode||"raw";this._containerElement=t?.containerElement||null,this._strategyFactory=k.getFactory(i),this._strategy=this._strategyFactory.create();const s=this._source.getInternalElement(),n=new I(s);this._videoElementRenderer=n,this._strategy.setRenderer(n),this._containerElement&&(this._strategy.attachToContainer(this._containerElement),a.info("Renderer elements attached to container via strategy")),a.info("Video Pipeline created")}setRenderMode(e){this.ensureNotDisposed();const t=k.getFactory(e);if(this._strategyFactory.constructor===t.constructor)return;const i=this._strategy.getRenderer(),s=this._strategy.getProcessors();this._strategy.dispose(),this._strategyFactory=t,this._strategy=this._strategyFactory.create(),i&&this._strategy.setRenderer(i),s.length>0&&this._strategy.setProcessors(s),this._containerElement&&this._strategy.attachToContainer(this._containerElement),a.info(`Video render mode changed to: ${e}`)}setRenderFitMode(e){this.ensureNotDisposed();const t=this._strategy.getRenderer();t?.setFitMode(e),a.info(`Video render fit mode changed to: ${e}`)}setProcessor(e){this.ensureNotDisposed(),this._strategy.setProcessors(e?[e]:[])}setRenderer(e){this.ensureNotDisposed(),this._strategy.setRenderer(e)}get strategy(){return this._strategy}get videoElementRenderer(){return this._videoElementRenderer}onDispose(){if(this._strategy.dispose(),this._videoElementRenderer){const e=this._videoElementRenderer.getElement();e&&e.parentElement&&e.parentElement.removeChild(e),this._videoElementRenderer.dispose(),this._videoElementRenderer=null}a.info("Video Pipeline disposed")}}class N extends o{onDispose(){}}class x extends N{constructor(e){super(),this._program=null,this._texture=null,this._lastProcessedTimestamp=null,this._options=e,this._canvas=document.createElement("canvas");const t=this._canvas.getContext("webgl",{premultipliedAlpha:!1,preserveDrawingBuffer:!0});if(!t)throw new Error("WebGL not supported");this._gl=t,this._initGL(),a.info("WebGL Green Screen Processor initialized")}_initGL(){const e=this._gl;this._program=this._createProgram("\n attribute vec2 aPosition;\n attribute vec2 aTexCoord;\n varying vec2 vTexCoord;\n void main() {\n gl_Position = vec4(aPosition, 0, 1);\n vTexCoord = aTexCoord;\n }","\n precision mediump float;\n varying vec2 vTexCoord;\n uniform sampler2D uSampler;\n uniform vec3 uChromaKey; // greenScreen target color: RGB\n uniform float uSimilarity; // greenScreen similarity\n uniform float uSmoothness; // greenScreen smoothness\n uniform float uSpill; // greenScreen despill strength\n\n // convert RGB to YCbCr space, separate luminance and chrominance\n vec3 rgbToYcbcr(vec3 rgb) {\n float y = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b;\n float cb = 0.564 * (rgb.b - y) + 0.5;\n float cr = 0.713 * (rgb.r - y) + 0.5;\n return vec3(y, cb, cr);\n }\n\n void main() {\n vec4 color = texture2D(uSampler, vTexCoord);\n vec3 rgb = color.rgb;\n \n vec3 ycbcr = rgbToYcbcr(rgb);\n vec3 targetYcbcr = rgbToYcbcr(uChromaKey);\n \n // 核心改进:只计算 Cb 和 Cr 的欧式距离,忽略亮度 Y\n // 这能确保深色褶皱(Y低)因为 Cb/Cr 不变而不被扣除\n float dist = distance(ycbcr.yz, targetYcbcr.yz);\n \n // 使用 smoothstep 生成丝滑边缘\n float alpha = smoothstep(uSimilarity, uSimilarity + uSmoothness, dist);\n alpha = pow(alpha, 1.2);\n\n // 增强型 Despill (去溢出)\n float maxRB = max(rgb.r, rgb.b);\n if (rgb.g > maxRB) {\n float edgeFactor = 1.0 - alpha; // 边缘像素更强去绿\n float diff = (rgb.g - maxRB) * uSpill * edgeFactor;\n rgb.g -= diff;\n rgb.rb += diff * 0.15;\n }\n\n // rgb = mix(vec3(dot(rgb, vec3(0.333))), rgb, alpha);\n float luma = dot(rgb, vec3(0.299, 0.587, 0.114));\n rgb = mix(vec3(luma), rgb, alpha);\n\n gl_FragColor = vec4(rgb, alpha * color.a);\n }\n "),this._texture=e.createTexture();const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,i),e.bufferData(e.ARRAY_BUFFER,t,e.STATIC_DRAW);const s=e.getAttribLocation(this._program,"aPosition"),n=e.getAttribLocation(this._program,"aTexCoord");e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,16,0),e.enableVertexAttribArray(n),e.vertexAttribPointer(n,2,e.FLOAT,!1,16,8)}process(e){if(!this._options.enabled)return e;const{displayWidth:t,displayHeight:i,timestamp:s}=e;this._canvas.width===t&&this._canvas.height===i||(this._canvas.width=t,this._canvas.height=i,this._gl.viewport(0,0,t,i));const n=this._gl;n.useProgram(this._program),n.activeTexture(n.TEXTURE0),n.bindTexture(n.TEXTURE_2D,this._texture),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,n.RGBA,n.UNSIGNED_BYTE,e),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR);const r=this._options.chromaKey||[0,255,0];n.uniform3f(n.getUniformLocation(this._program,"uChromaKey"),r[0]/255,r[1]/255,r[2]/255),n.uniform1f(n.getUniformLocation(this._program,"uSimilarity"),this._options.similarity??.3),n.uniform1f(n.getUniformLocation(this._program,"uSmoothness"),this._options.smoothness??.25),n.uniform1f(n.getUniformLocation(this._program,"uSpill"),this._options.despillStrength??1.15),n.drawArrays(n.TRIANGLE_STRIP,0,4);const o=new VideoFrame(this._canvas,{timestamp:s,duration:e.duration??void 0});return e.close(),o}_createProgram(e,t){const i=this._gl,s=(e,t)=>{const s=i.createShader(e);return i.shaderSource(s,t),i.compileShader(s),s},n=i.createProgram();return i.attachShader(n,s(i.VERTEX_SHADER,e)),i.attachShader(n,s(i.FRAGMENT_SHADER,t)),i.linkProgram(n),n}onDispose(){const e=this._gl;this._texture&&e.deleteTexture(this._texture),this._program&&e.deleteProgram(this._program),a.info("WebGL Green Screen Processor disposed")}updateOptions(e){this._options={...this._options,...e}}}class L extends v{constructor(e){if(super(),this._source=new S,this._pipeline=new w(this._source,e),"processed"===e?.renderMode&&e?.greenScreen?.enabled){const t=new x(e.greenScreen);this._pipeline.setProcessor(t),a.info("Green screen processor enabled")}this._pipeline.setRenderFitMode(e?.fitMode||"contain"),a.info("Video Controller created")}setTrack(e,t,i){this.ensureNotDisposed(),this._source.setTrack(e,t,i)}removeTrack(e){this.ensureNotDisposed(),this._source.trackId===e&&this._source.clearTrack()}setRenderMode(e){this.ensureNotDisposed(),this._pipeline.setRenderMode(e),this._context.eventBus.emit("inner:video:render:mode:changed",{mode:e})}setRenderFitMode(e){this.ensureNotDisposed(),this._pipeline.setRenderFitMode(e)}getSource(){return this.ensureNotDisposed(),this._source}onDispose(){this._source.dispose(),this._pipeline.dispose(),a.info("Video Controller disposed")}}class O extends o{process(e,t){return this.ensureNotDisposed(),e}onDispose(){}}class P extends o{set onProcessedAudio(e){this._onProcessedAudio=e}constructor(e){super(),this._processors=[],this._processingStrategy=new O,a.info("Input Audio Pipeline created")}setProcessingStrategy(e){this.ensureNotDisposed(),this._processingStrategy&&this._processingStrategy.dispose(),this._processingStrategy=e,a.debug("Audio processing strategy set")}get processingStrategy(){return this._processingStrategy}addProcessor(e){this.ensureNotDisposed(),this._processors.push(e),a.debug(`Audio processor added. Total: ${this._processors.length}`)}removeProcessor(e){this.ensureNotDisposed();const t=this._processors.indexOf(e);t>=0&&(this._processors.splice(t,1),a.debug(`Audio processor removed. Total: ${this._processors.length}`))}process(e,t){this.ensureNotDisposed();let i=e;try{i=this._processingStrategy.process(i,t)}catch(e){a.error("Error in audio processing strategy:",e)}for(const e of this._processors)try{i=e.process(i,t)}catch(e){a.error("Error in audio processor:",e);continue}this._onProcessedAudio&&this._onProcessedAudio(i,t)}onDispose(){if(this._processingStrategy)try{this._processingStrategy.dispose()}catch(e){a.error("Error disposing audio processing strategy:",e)}this._processors.forEach(e=>{try{e.dispose()}catch(e){a.error("Error disposing audio processor:",e)}}),this._processors.length=0,this._onProcessedAudio=void 0,a.info("Input Audio Pipeline disposed")}}class F extends o{constructor(){super(),this._audioElement=null,this._stream=null,this._track=null,this._volume=1,this._isMuted=!1,this._audioElement=document.createElement("audio"),this._audioElement.autoplay=!0,this._audioElement.volume=this._volume,this._audioElement.muted=this._isMuted,a.info("Output Audio Pipeline created")}getAudioElement(){if(!this._audioElement)throw new r(i.SDK_ERROR,"Audio element not found");return this._audioElement}setTrack(e){this.ensureNotDisposed(),this._track&&this._track!==e&&this._track.stop(),this._track=e,this._audioElement&&(this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._stream=new MediaStream([e]),this._audioElement.volume=this._volume,this._audioElement.muted=this._isMuted,a.debug("Audio track set to output pipeline"))}removeTrack(){this.ensureNotDisposed(),this._audioElement&&(this._audioElement.srcObject=null),this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._track&&(this._track.stop(),this._track=null),a.debug("Audio track removed from output pipeline")}setVolume(e){this.ensureNotDisposed(),this._volume=Math.max(0,Math.min(1,e)),this._audioElement&&(this._audioElement.volume=this._volume),a.debug(`Audio output volume set to: ${this._volume}`)}getVolume(){return this._volume}mute(){this.ensureNotDisposed(),this._isMuted=!0,this._audioElement&&(this._audioElement.muted=!0),a.debug("Audio output muted")}unmute(){this.ensureNotDisposed(),this._isMuted=!1,this._audioElement&&(this._audioElement.muted=!1),a.debug("Audio output unmuted")}isMuted(){return this._isMuted}onDispose(){if(this.removeTrack(),this._audioElement){try{this._audioElement.pause(),this._audioElement.srcObject=null}catch{}this._audioElement=null}a.info("Output Audio Pipeline disposed")}}class M extends o{emitAudioData(e,t){if(this.onAudioData)try{this.onAudioData(e,t)}catch(e){a.error("Error in audio data callback:",e)}}}class V extends M{constructor(e){super(),this.options=e,this._stream=null,this._audioContext=null,this._sourceNode=null,this._workletNode=null,this._targetSampleRate=l,this._bitDepth=16,this._channels=1;const t=e?.input;this._targetSampleRate=t?.sampleRate||l,this._bitDepth=t?.bitDepth||16,this._channels=t?.channels||1}async start(){this.ensureNotDisposed(),(this._stream||this._audioContext||this._sourceNode||this._workletNode)&&this.stop();try{const e=this.options?.input,t={audio:e?.constraints?e.constraints:{channelCount:this._channels}};this._stream=await navigator.mediaDevices.getUserMedia(t);const i=this._stream.getAudioTracks()[0],s=i.getSettings().sampleRate||44100;this._audioContext=new AudioContext({sampleRate:s});const n=function(){const e=new Blob(["\nclass AudioResamplerProcessor extends AudioWorkletProcessor {\n constructor(options) {\n super();\n this.targetSampleRate = options.processorOptions?.targetSampleRate || 24000;\n this.bitDepth = options.processorOptions?.bitDepth || 16;\n this.channels = options.processorOptions?.channels || 1;\n \n // Resampling related\n // sampleRate is a global in AudioWorkletProcessor representing the AudioContext's sample rate\n this.resampleRatio = this.targetSampleRate / sampleRate;\n \n // Timestamp tracking\n this.frameCount = 0;\n }\n\n process(inputs, outputs, parameters) {\n const input = inputs[0];\n if (!input || input.length === 0 || !input[0] || input[0].length === 0) {\n return true;\n }\n\n const inputData = input[0]; // mono input\n const inputLength = inputData.length;\n \n // Linear resampling\n const outputLength = Math.floor(inputLength * this.resampleRatio);\n const resampledData = new Float32Array(outputLength);\n \n for (let i = 0; i < outputLength; i++) {\n const srcIndex = i / this.resampleRatio;\n const srcIndexFloor = Math.floor(srcIndex);\n const srcIndexCeil = Math.min(srcIndexFloor + 1, inputLength - 1);\n const fraction = srcIndex - srcIndexFloor;\n \n // Linear interpolation\n resampledData[i] = inputData[srcIndexFloor] * (1 - fraction) + inputData[srcIndexCeil] * fraction;\n }\n \n // Post the resampled data\n this.port.postMessage({\n type: 'audioData',\n data: resampledData,\n sampleRate: this.targetSampleRate,\n bitDepth: this.bitDepth,\n frameCount: this.frameCount,\n });\n \n this.frameCount += outputLength;\n \n return true;\n }\n}\n\nregisterProcessor('audio-resampler', AudioResamplerProcessor);\n"],{type:"text/javascript"});return URL.createObjectURL(e)}();await this._audioContext.audioWorklet.addModule(n),this._sourceNode=this._audioContext.createMediaStreamSource(this._stream),this._workletNode=new AudioWorkletNode(this._audioContext,"audio-resampler",{processorOptions:{targetSampleRate:this._targetSampleRate,bitDepth:this._bitDepth,channels:this._channels},numberOfInputs:1,numberOfOutputs:0}),this._workletNode.port.onmessage=e=>{const{type:t,data:i,sampleRate:s}=e.data;"audioData"===t&&i&&this.emitAudioData(i,s)},this._sourceNode.connect(this._workletNode),a.info(`Audio capture started: input=${s}Hz -> output=${this._targetSampleRate}Hz, ${this._bitDepth}bit`)}catch(e){throw r.fromError(e,i.AUDIO_CAPTURE_FAILED)}}stop(){this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._workletNode&&(this._workletNode.port.onmessage=null,this._workletNode.disconnect(),this._workletNode=null),this._sourceNode&&(this._sourceNode.disconnect(),this._sourceNode=null),this._audioContext&&(this._audioContext.close(),this._audioContext=null),a.info("Audio capture stopped")}onDispose(){this.stop()}}class K{create(e){return new V(e)}}class U extends v{constructor(e,t){super(),this._source=null,this._isWsCapturing=!1,this._currentOutputTrackId=null,this._inputPipeline=new P(e),this._outputPipeline=new F,this._sourceFactory=t||new K,a.info("Audio Controller created")}setContext(e){super.setContext(e),this._wireLocalInputToEventBus()}_wireLocalInputToEventBus(){this._inputPipeline.onProcessedAudio=(e,t)=>{this._context.eventBus.emit("inner:audio:frame:received",{data:e,sampleRate:t})}}async startWsCapture(){if(this.ensureNotDisposed(),this._isWsCapturing)a.warn("Audio capture already started");else{if(!this._context.mediaAudioCaptureState.tryBegin("ws"))throw new r(i.SDK_INVALID_STATE_TRANSITION,"RTC audio capture is active");try{this._source||(this._source=this._sourceFactory.create(this._context.options.audio),this._source.onAudioData=(e,t)=>{this._inputPipeline.process(e,t)}),await this._source.start(),this._isWsCapturing=!0,this._context.eventBus.emit("inner:audio:input:started",void 0),a.info("Audio capture started (ws)")}catch(e){throw this._context.mediaAudioCaptureState.end("ws"),this._context.emitError(e,i.AUDIO_CAPTURE_START_FAILED)}}}stopWsCapture(){this.ensureNotDisposed(),this._isWsCapturing&&(this._source&&this._source.stop(),this._isWsCapturing=!1,this._context.mediaAudioCaptureState.end("ws"),this._context.eventBus.emit("inner:audio:input:stopped",void 0),a.info("Audio capture stopped (ws)"))}get isWsCapturing(){return this._isWsCapturing}setOutputTrack(e,t,i){this.ensureNotDisposed(),this._outputPipeline.setTrack(e),this._currentOutputTrackId=t,this._context.eventBus.emit("inner:audio:track:added",{trackId:t,participantId:i}),a.info("Audio output track ready")}removeOutputTrack(e){this.ensureNotDisposed(),this._currentOutputTrackId===e&&(this._outputPipeline.removeTrack(),this._currentOutputTrackId=null,this._context.eventBus.emit("inner:audio:track:removed",{trackId:e}),a.info("Audio output track removed"))}setVolume(e){this.ensureNotDisposed(),this._outputPipeline.setVolume(e),this._context.eventBus.emit("inner:audio:volume:changed",{volume:e}),a.debug(`Audio volume set to: ${e}`)}getVolume(){return this._outputPipeline.getVolume()}mute(){this.ensureNotDisposed(),this._outputPipeline.mute(),this._context.eventBus.emit("inner:audio:muted",void 0),a.debug("Audio muted")}unmute(){this.ensureNotDisposed(),this._outputPipeline.unmute(),this._context.eventBus.emit("inner:audio:unmuted",void 0),a.debug("Audio unmuted")}getOutputElement(){return this._outputPipeline.getAudioElement()}isMuted(){return this._outputPipeline.isMuted()}onDispose(){this.stopWsCapture(),this._source&&(this._source.dispose(),this._source=null),this._inputPipeline.dispose(),this._outputPipeline.dispose(),a.info("Audio Controller disposed")}}class B extends o{constructor(){super(...arguments),this._stream=null,this._videoElement=null}async start(){if(this.ensureNotDisposed(),this._stream)a.warn("Camera capture already started");else try{const e=await navigator.mediaDevices.getUserMedia({video:!0});if(this._stream=e,!this._videoElement){const e=document.createElement("video");e.autoplay=!0,e.muted=!0,e.playsInline=!0,e.style.position="fixed",e.style.opacity="0",e.style.pointerEvents="none",e.style.width="0",e.style.height="0",e.style.zIndex="-1","undefined"!=typeof document&&document.body&&document.body.appendChild(e),this._videoElement=e}this._videoElement.srcObject=this._stream,this._videoElement.play().catch(e=>{a.error("Failed to start camera video playback",e)})}catch(e){throw r.fromError(e,i.SDK_ERROR)}}stop(){if(this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._videoElement){this._videoElement.srcObject=null;const e=this._videoElement.parentNode;e&&e.removeChild(this._videoElement),this._videoElement=null}a.info("Camera capture stopped")}getStream(){return this.ensureNotDisposed(),this._stream}getVideoElement(){return this.ensureNotDisposed(),this._videoElement}getTrack(){if(this.ensureNotDisposed(),!this._stream)return null;const e=this._stream.getVideoTracks();return e.length>0?e[0]:null}onDispose(){this.stop()}}const q=640,H=360;class $ extends o{constructor(e,t){super(),this._videoElement=null,this._canvas=null,this._videoElement=e,this._onFrame=t,this._handleServerCommand=this._onServerCommand.bind(this)}setContext(e){this._context=e}setVideoElement(e){this._videoElement=e}start(){this.ensureNotDisposed(),this._canvas||("undefined"!=typeof OffscreenCanvas?this._canvas=new OffscreenCanvas(q,H):(this._canvas=document.createElement("canvas"),this._canvas.width=q,this._canvas.height=H)),this._context.eventBus.on("inner:conversation:server:command",this._handleServerCommand)}_onServerCommand({code:e}){500===e&&this._captureFrame()}stop(){this._context.eventBus.off("inner:conversation:server:command",this._handleServerCommand)}_captureFrame(){const e=this._videoElement,t=this._canvas;if(!e||!t)return;if(e.readyState<2||0===e.videoWidth||0===e.videoHeight)return;const i=t.getContext("2d");if(!i)return;const s=e.videoWidth,n=e.videoHeight;let r=q,o=q*n/s;o>H&&(o=H,r=H*s/n),t.width!==r&&(t.width=r),t.height!==o&&(t.height=o),i.clearRect(0,0,t.width,t.height),i.drawImage(e,0,0,s,n,0,0,r,o),"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas&&"function"==typeof t.convertToBlob?t.convertToBlob({type:"image/jpeg",quality:u}).then(e=>{if(e)try{this._onFrame(e,r,o,0,u)}catch(e){a.error("ScreenshotScheduler onFrame callback error",e)}}).catch(e=>{a.error("ScreenshotScheduler convertToBlob error",e)}):t instanceof HTMLCanvasElement&&t.toBlob(e=>{if(e)try{this._onFrame(e,r,o,0,u)}catch(e){a.error("ScreenshotScheduler onFrame callback error",e)}},"image/jpeg",u)}onDispose(){this.stop(),this._canvas=null,this._videoElement=null}}const G=4294967295;function W(e){const t=Math.floor(e);return t<0?0:t>65535?65535:t}function z(e){const t=new ArrayBuffer(12),i=new DataView(t),s=128|15&function(e){const t=Math.floor(e);return t<0?0:t>4?4:t}(e.format);return i.setUint8(0,s),i.setUint8(1,function(e){const t=Math.floor(e);return t<0?0:t>255?255:t}(e.quality)),i.setUint16(2,W(e.id),!1),i.setUint16(4,W(e.width),!1),i.setUint16(6,W(e.height),!1),i.setUint32(8,function(e){const t=Math.floor(e);return t<0?0:t>G?G:t}(e.payloadLength),!1),new Uint8Array(t)}class j extends o{constructor(){super(...arguments),this._wsSender=null,this._imageId=0}send(e,t){if(this.ensureNotDisposed(),!this._wsSender||!this._wsSender.isConnected())return;const i=e.byteLength,s=z({format:t.format,quality:t.quality,id:this._nextId(),width:t.width,height:t.height,payloadLength:i}),n=new Uint8Array(s.byteLength+i);n.set(s,0),n.set(e,s.byteLength),this._wsSender.sendBinary(n)}_nextId(){const e=this._imageId;return this._imageId=this._imageId>=65535?0:this._imageId+1,e}onDispose(){this._wsSender=null}}class Q extends v{constructor(){super(),this._isRunning=!1,this._source=new B,this._sender=new j;this._scheduler=new $(null,(e,t,i,s,n=.7)=>{(async function(e,t){const i=await e.arrayBuffer();return{data:new Uint8Array(i),width:t.width,height:t.height,format:t.format,quality:t.quality}})(e,{width:t,height:i,format:s,quality:n}).then(e=>{this._sender.send(e.data,{width:e.width,height:e.height,format:e.format,quality:e.quality})})})}setContext(e){super.setContext(e),this._scheduler.setContext(e)}async startCamera(){if(this.ensureNotDisposed(),this._isRunning)return void a.warn("Camera already running");await this._source.start();const e=this._source.getVideoElement();this._scheduler.setVideoElement(e),this._scheduler.start(),this._isRunning=!0,this._context.eventBus.emit("inner:camera:started",void 0),a.info("Camera started")}stopCamera(){this.ensureNotDisposed(),this._isRunning&&(this._scheduler.stop(),this._source.stop(),this._isRunning=!1,this._context.eventBus.emit("inner:camera:stopped",void 0),a.info("Camera stopped"))}isCameraRunning(){return this._isRunning}getStream(){return this.ensureNotDisposed(),this._source.getStream()}getTrack(){return this.ensureNotDisposed(),this._source.getTrack()}attachTo(e){this.ensureNotDisposed();const t=this._source.getStream();t&&(e.srcObject=t,e.play().catch(e=>a.error("attachTo play failed",e)))}onDispose(){this.stopCamera(),this._source.dispose(),this._scheduler.dispose(),this._sender.dispose()}}var Y;e.ConversationStateType=void 0,(Y=e.ConversationStateType||(e.ConversationStateType={})).IDLE="idle",Y.WAITING="waiting",Y.STREAMING="streaming",Y.COMPLETED="completed",Y.ERROR="error";class X extends f{constructor(){super(...arguments),this._currentState=e.ConversationStateType.IDLE,this.transitionTable=[{from:e.ConversationStateType.IDLE,to:[e.ConversationStateType.WAITING,e.ConversationStateType.ERROR]},{from:e.ConversationStateType.WAITING,to:[e.ConversationStateType.STREAMING,e.ConversationStateType.ERROR]},{from:e.ConversationStateType.STREAMING,to:[e.ConversationStateType.COMPLETED,e.ConversationStateType.ERROR]},{from:e.ConversationStateType.COMPLETED,to:[e.ConversationStateType.IDLE,e.ConversationStateType.WAITING,e.ConversationStateType.ERROR]},{from:e.ConversationStateType.ERROR,to:[e.ConversationStateType.IDLE]}]}reset(){this._currentState=e.ConversationStateType.IDLE}}class J extends o{constructor(e){super(),this._currentQuestion=null,this._currentAnswer=null,this._sessionId=e,this._stateMachine=new X,a.info(`Conversation session created: ${e}`)}get sessionId(){return this._sessionId}get state(){return this._stateMachine.getCurrentState()}_setQuestion(t){this._currentQuestion=t,this._stateMachine.transitionTo(e.ConversationStateType.WAITING),this._syncContextState()}get currentQuestion(){return this._currentQuestion}_startAnswer(t){this._currentAnswer={questionId:t,text:"",isComplete:!1,timestamp:Date.now()},this._stateMachine.transitionTo(e.ConversationStateType.STREAMING),this._syncContextState()}_appendAnswerChunk(e){this._currentAnswer&&(this._currentAnswer.text+=e)}_completeAnswer(){this._currentAnswer&&(this._currentAnswer.isComplete=!0,this._currentAnswer.completedAt=Date.now()),this._stateMachine.transitionTo(e.ConversationStateType.COMPLETED),this._syncContextState()}get currentAnswer(){return this._currentAnswer}_setError(t){this._stateMachine.transitionTo(e.ConversationStateType.ERROR),this._syncContextState()}_syncContextState(){}handleEvent(t){const i=this._stateMachine.getCurrentState();switch(t.type){case"QUESTION":if(i!==e.ConversationStateType.IDLE&&i!==e.ConversationStateType.COMPLETED)return void a.warn(`Ignoring QUESTION event in invalid state: ${i}`);this._setQuestion(t.payload);break;case"ANSWER_START":if(i!==e.ConversationStateType.WAITING)return void a.warn(`Ignoring ANSWER_START event in invalid state: ${i}. Expected: WAITING`);this._startAnswer(t.payload);break;case"ANSWER_CHUNK":if(i!==e.ConversationStateType.STREAMING)return void a.warn(`Ignoring ANSWER_CHUNK event in invalid state: ${i}. Expected: STREAMING`);this._appendAnswerChunk(t.payload&&t.payload.chunk||""),t.payload&&t.payload.isComplete&&this._completeAnswer();break;case"ANSWER_COMPLETE":if(i!==e.ConversationStateType.STREAMING)return void a.warn(`Ignoring ANSWER_COMPLETE event in invalid state: ${i}. Expected: STREAMING`);this._completeAnswer();break;case"ERROR":this._setError(t.payload);break;default:a.warn(`Unknown event type: ${t.type}`)}}reset(){this._stateMachine.reset(),this._currentQuestion=null,this._currentAnswer=null}onDispose(){this.reset(),a.info(`Conversation session disposed: ${this._sessionId}`)}}class Z extends o{constructor(){super(...arguments),this._buffers=new Map}appendChunk(e,t){this.ensureNotDisposed();const i=(this._buffers.get(e)||"")+t;return this._buffers.set(e,i),a.debug(`Message chunk appended for question ${e}, length: ${i.length}`),i}getMessage(e){return this._buffers.get(e)||null}complete(e){const t=this.getMessage(e)||"";return this._buffers.delete(e),a.debug(`Message assembly completed for question ${e}, length: ${t.length}`),t}clear(e){this._buffers.delete(e)}onDispose(){this._buffers.clear(),a.info("Message Assembler disposed")}}class ee{generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}generateQuestionId(){return Math.random().toString(36).substring(2,6)}}class te extends v{constructor(e){super(),this._rtcTextSender=null,this._sessions=new Map,this._assembler=new Z,this._idService=new ee,a.info("Conversation Manager created")}setRtcTextSender(e){this._rtcTextSender=e}async sendQuestion(e,t={speed:100,mood:0,vol:50}){this.ensureNotDisposed();const i=this._idService.generateQuestionId(),s={id:i,text:e,timestamp:Date.now(),inputMode:"text"},n=this._idService.generateSessionId(),r=new J(n);return r.handleEvent({type:"QUESTION",payload:s}),this._sessions.set(i,r),await this._dispatchServerTextUplink(i,e,t,r),this._context.eventBus.emit("inner:conversation:question:sent",{questionId:i,text:e}),this._context.eventBus.emit("inner:conversation:answer:waiting",{questionId:i}),a.info(`Question sent: ${i}`),i}async sendSystemEvent(e,t){if(this.ensureNotDisposed(),this._rtcTextSender)try{await this._rtcTextSender.sendSystemEvent(e,t)}catch(e){a.error("Error sending video avaliable state:",e)}}async _dispatchServerTextUplink(e,t,s,n){if(this._rtcTextSender)try{await this._rtcTextSender.sendTextData(e,t,"input.text",s)}catch(e){throw a.error("Error sending question via RTC:",e),n.handleEvent({type:"ERROR",payload:"Failed to send question"}),this._context.eventBus.emit("inner:sdk:error",{error:r.fromError(e,i.LIVEKIT_SEND_TEXT_DATA_FAILED)}),e}else a.warn("RTC text sender not set, question not sent")}handleServerPong(){this.ensureNotDisposed()}willDisconnect(){this.ensureNotDisposed()}handleAnswerChunk(t,i,s){this.ensureNotDisposed();const n=this._sessions.get(t);if(!n)return void a.warn(`No active session for answer chunk: ${t}`);if(n.state===e.ConversationStateType.WAITING&&n.handleEvent({type:"ANSWER_START",payload:t}),s){n.handleEvent({type:"ANSWER_COMPLETE"});const e=this._assembler.complete(t);this._context.eventBus.emit("inner:conversation:answer:completed",{questionId:t,fullAnswer:e});try{n.dispose()}catch(e){a.error("Error disposing session:",e)}this._sessions.delete(t)}else n.handleEvent({type:"ANSWER_CHUNK",payload:{uid:t,chunk:i,isComplete:s}}),this._assembler.appendChunk(t,i),this._context.eventBus.emit("inner:conversation:answer:chunk",{questionId:t,chunk:i,isComplete:s})}handleServerInitiatedMessage(e,t){this.ensureNotDisposed();const i=e??this._idService.generateQuestionId();this._context.eventBus.emit("inner:conversation:server:message",{questionId:i,message:t,type:"text"})}handleAsrTextReceived(e,t,i,s){this.ensureNotDisposed();const n=this._idService.generateSessionId(),r=new J(n);r.handleEvent({type:"QUESTION",payload:{id:e,text:t,timestamp:Date.now(),inputMode:"voice"}}),this._sessions.set(e,r),i?this._context.eventBus.emit("inner:conversation:asr:chunk",{questionId:e,text:t,isComplete:s??!1}):this._context.eventBus.emit("inner:conversation:asr:received",{questionId:e,text:t})}handleServerCommand(e,t){this.ensureNotDisposed(),this._context.eventBus.emit("inner:conversation:server:command",{code:e,command:t})}onDispose(){for(const e of this._sessions.values())try{e.dispose()}catch(e){a.error("Error disposing session:",e)}this._sessions.clear(),this._assembler.dispose(),a.info("Conversation Manager disposed")}}class ie extends v{constructor(e){super(),this._eventUnsubscribers=[],this._manager=new te(e),a.info("Conversation Controller created")}setContext(e){super.setContext(e),this._manager.setContext(e),this._bindEventBus()}get manager(){return this._manager}setRtcTextSender(e){this._manager.setRtcTextSender(e)}async sendQuestion(e,t){return this.ensureNotDisposed(),this._manager.sendQuestion(e,t)}async interrupt(){return this.ensureNotDisposed(),this._manager.sendSystemEvent("control.interrupt")}_clearEventListeners(){this._eventUnsubscribers.forEach(e=>{try{e()}catch(e){a.error("Performance monitor unsubscribe failed",e)}}),this._eventUnsubscribers=[]}_bindEventBus(){this._eventUnsubscribers.push(this._context.eventBus.on("inner:rtc:video:available",()=>{this.sendVideoAvaliableState()}))}async sendVideoAvaliableState(){return this.ensureNotDisposed(),this._manager.sendSystemEvent("scene.ready")}onDispose(){this._clearEventListeners(),this._manager.dispose(),a.info("Conversation Controller disposed")}}class se extends o{constructor(){super(...arguments),this._tracks=new Map,this._participants=new Map,this._trackEndedHandlers=new Map}register(e,t,i){this.ensureNotDisposed(),this._tracks.set(e,t),this._participants.has(i)||this._participants.set(i,new Set),this._participants.get(i).add(e);const s=()=>{a.debug(`Track ended: ${e}`),this.unregister(e)};this._trackEndedHandlers.set(e,s),t.on("ended",s),a.debug(`Track registered: ${e} from participant ${i}`)}unregister(e){const t=this._tracks.get(e);if(t){const i=this._trackEndedHandlers.get(e);i&&(t.off("ended",i),this._trackEndedHandlers.delete(e)),t.stop(),this._tracks.delete(e);for(const[t,i]of this._participants.entries())if(i.has(e)){i.delete(e),0===i.size&&this._participants.delete(t);break}a.debug(`Track unregistered: ${e}`)}}getTrack(e){return this._tracks.get(e)||null}getParticipantTracks(e){const t=this._participants.get(e);return t?Array.from(t):[]}getAllTrackIds(){return Array.from(this._tracks.keys())}getVideoAvailability(){let e=!1,t=!1,i=!1;for(const s of this._tracks.values()){const n=s.mediaStreamTrack;if("video"===n.kind&&(e=!0,"live"===n.readyState&&(t=!0),n.enabled&&(i=!0),"live"===n.readyState&&n.enabled))return{available:!0}}return e?t?i?{available:!1,reason:_.NO_VIDEO_TRACK}:{available:!1,reason:_.TRACK_MUTED}:{available:!1,reason:_.TRACK_ENDED}:{available:!1,reason:_.NO_VIDEO_TRACK}}clear(){const e=Array.from(this._tracks.keys());for(const t of e)this.unregister(t);a.info("All tracks cleared")}onDispose(){this.clear()}}class ne extends v{constructor(e){super(),this._videoController=null,this._room=null,this._trackRegistry=e,this._loosTrackTimer=null,a.info("Video Track Handler created")}setRoom(e){this._room=e}setVideoController(e){this._videoController=e}handleTrackSubscribed(e,t,i){this.ensureNotDisposed(),this._loosTrackTimer&&clearTimeout(this._loosTrackTimer),this._trackRegistry.register(t,e,i),this._videoController&&e.attach(this._videoController.getSource().getInternalElement()),e.on("videoPlaybackStarted",()=>{a.info("inner:rtc:video:available"),this._context.eventBus.emit("inner:rtc:video:available",void 0)}),this._context.eventBus.emit("inner:video:track:added",{trackId:t,participantId:i}),a.debug(`Video track subscribed: ${t}`)}handleTrackUnsubscribed(e,t,i){this.ensureNotDisposed(),this._videoController&&e.detach(this._videoController.getSource().getInternalElement()),e.removeAllListeners(),this._context.eventBus.emit("inner:video:track:removed",{trackId:t,participantId:i}),this._loosTrackTimer&&clearTimeout(this._loosTrackTimer),this._loosTrackTimer=setTimeout(()=>{this._context.eventBus.emit("inner:rtc:video:unavailable",void 0)},5e3),this._trackRegistry.unregister(t),a.debug(`Video track unsubscribed: ${t}`)}supports(e){return"video"===e.mediaStreamTrack.kind}onDispose(){this._loosTrackTimer&&(clearTimeout(this._loosTrackTimer),this._loosTrackTimer=null),a.info("Video Track Handler disposed")}}class re extends v{constructor(e){super(),this._audioController=null,this._room=null,this._trackRegistry=e,a.info("Audio Track Handler created")}setRoom(e){this._room=e}setAudioController(e){this._audioController=e}handleTrackSubscribed(e,t,i){this.ensureNotDisposed(),this._trackRegistry.register(t,e,i),this._audioController?e.attach(this._audioController.getOutputElement()):this._context.eventBus.emit("inner:audio:track:added",{trackId:t,participantId:i}),a.debug(`Audio track subscribed: ${t}`)}handleTrackUnsubscribed(e,t,i){this.ensureNotDisposed(),this._audioController?(this._audioController.removeOutputTrack(t),e.detach(this._audioController.getOutputElement())):this._context.eventBus.emit("inner:audio:track:removed",{trackId:t}),this._trackRegistry.unregister(t),a.debug(`Audio track unsubscribed: ${t}`)}supports(e){return"audio"===e.mediaStreamTrack.kind}onDispose(){a.info("Audio Track Handler disposed")}}class oe extends v{constructor(e){super(),this._handlers=[],this._room=null,this._trackRegistry=e,a.info("LiveKit Event Adapter created")}setContext(e){if(super.setContext(e),0===this._handlers.length){const t=new ne(this._trackRegistry),i=new re(this._trackRegistry);t.setContext(e),i.setContext(e),this._handlers.push(t,i),this._room&&(t.setRoom(this._room),i.setRoom(this._room))}}setRoom(e){this._room=e,this._handlers.forEach(t=>{t.setRoom(e)}),a.info("LiveKit room set:",this._room)}setVideoController(e){const t=this._handlers.find(e=>e instanceof ne);t&&t.setVideoController(e)}setAudioController(e){const t=this._handlers.find(e=>e instanceof re);t&&t.setAudioController(e)}handleTrackSubscribed(e,t,i){this.ensureNotDisposed();const s=this._findHandler(e);s?s.handleTrackSubscribed(e,t,i):a.warn(`No handler found for track, trackId: ${t}`)}handleTrackUnsubscribed(e,t){this.ensureNotDisposed();const i=this._trackRegistry.getTrack(e);if(i){const s=this._findHandler(i);s?s.handleTrackUnsubscribed(i,e,t):(this._trackRegistry.unregister(e),a.warn(`No handler found for track, trackId: ${e}`))}}_findHandler(e){return this._handlers.find(t=>t.supports(e))||null}onDispose(){this._handlers.forEach(e=>{try{e.dispose()}catch(e){a.error("Error disposing track handler:",e)}}),this._handlers.length=0,a.info("LiveKit Event Adapter disposed")}}class ae extends v{constructor(){super(),this._room=null,this._rtcRoom=null,this._micTrack=null,this._cameraVideoTrack=null,this._protocolDispatch=null,this._maxAttempts=3,this._maxDelay=1e4,this._speakingHandlers=new Map,this._trackRegistry=new se,this._eventAdapter=new oe(this._trackRegistry),a.info("LiveKit Service created")}setContext(e){super.setContext(e),this._maxAttempts=e.options.reconnect?.maxAttempts||3,this._maxDelay=(e.options.reconnect?.delay??10)*d,this._eventAdapter.setContext(e)}async connect(e,s,n,o){if(this.ensureNotDisposed(),this._rtcRoom&&this._rtcRoom.state===t.ConnectionState.Connected)return void a.warn("Already connected to LiveKit room");let c;try{await this._tearDownStaleRoom(),a.info(`Connecting to LiveKit room: ${n} at ${e}`),c=new t.Room({reconnectPolicy:{nextRetryDelayInMs:e=>e.elapsedMs<this._maxDelay?Math.min(d*Math.pow(2,e.retryCount),this._maxDelay):null}}),c.prepareConnection(e,s),this._registerRoomListeners(c),a.info("Connecting to LiveKit room..."),await c.connect(e,s,{autoSubscribe:!0,maxRetries:this._context.options.reconnect?.maxAttempts||3}),this._eventAdapter.setRoom(c),this._rtcRoom=c,this._room=c}catch(e){if(c){try{c.removeAllListeners()}catch{}try{await c.disconnect()}catch{}}throw this._rtcRoom=null,this._room=null,r.fromError(e,i.LIVEKIT_CONNECT_FAILED)}}_registerRoomListeners(e){e.on(t.RoomEvent.TrackSubscribed,(e,t,i)=>{this._handleTrackSubscribed(e,t,i)}),e.on(t.RoomEvent.TrackUnsubscribed,(e,t,i)=>{this._handleTrackUnsubscribed(e,t,i)}),e.on(t.RoomEvent.TrackMuted,(e,t)=>{this._handleTrackMuted(e,t)}),e.on(t.RoomEvent.TrackUnmuted,(e,t)=>{this._handleTrackUnmuted(e,t)}),e.on(t.RoomEvent.Connected,()=>{a.info("Connected to LiveKit room"),this._context.eventBus.emit("inner:rtc:connected",void 0)}),e.on(t.RoomEvent.Disconnected,e=>{e?a.info(`LiveKit room disconnected: ${e}`):a.info("LiveKit room disconnected"),e!==t.DisconnectReason.CLIENT_INITIATED&&(this._context.eventBus.emit("inner:rtc:disconnected",{reason:e?String(e):void 0}),this._context.emitError(new r(i.LIVEKIT_CONNECT_FAILED,e?`LiveKit disconnected: ${String(e)}`:"LiveKit disconnected"),i.LIVEKIT_CONNECT_FAILED)),this._micTrack?.stop(),this._micTrack=null,this._cameraVideoTrack?.stop(),this._cameraVideoTrack=null,this._clearSpeakingHandlers(),this._context.mediaAudioCaptureState.end("rtc"),this._room=null,this._rtcRoom=null}),e.on(t.RoomEvent.DataReceived,e=>{this._onRoomDataReceived(e)})}async _tearDownStaleRoom(){if(!this._rtcRoom)return;await this.stopMicrophone(),await this.stopCamera(),this._clearSpeakingHandlers();const e=this._rtcRoom;this._rtcRoom=null,this._room=null;try{e.removeAllListeners()}catch{}try{await e.disconnect()}catch{}}_clearSpeakingHandlers(){if(this._rtcRoom){for(const[e,i]of this._speakingHandlers.entries()){const s=this._findRemoteParticipantByIdentity(e);try{s?.off(t.ParticipantEvent.IsSpeakingChanged,i)}catch{}}this._speakingHandlers.clear()}else this._speakingHandlers.clear()}_findRemoteParticipantByIdentity(e){const t=this._rtcRoom;if(t)for(const i of t.remoteParticipants.values())if(i.identity===e)return i}_removeSpeakingListenerIfNoAudioTracks(e){const i=this._speakingHandlers.get(e);if(!i)return;const s=this._trackRegistry.getParticipantTracks(e);for(const e of s){const t=this._trackRegistry.getTrack(e);if("audio"===t?.kind)return}const n=this._findRemoteParticipantByIdentity(e);try{n?.off(t.ParticipantEvent.IsSpeakingChanged,i)}catch{}this._speakingHandlers.delete(e)}async startMicrophone(){this.ensureNotDisposed();const e=this._rtcRoom;if(!e||!this.isConnected())throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit is not connected");if(!this._context.mediaAudioCaptureState.tryBegin("rtc"))throw new r(i.SDK_INVALID_STATE_TRANSITION,"WebSocket audio capture is active");try{if(this._micTrack)return void a.warn("Microphone already published");const i=await t.createLocalAudioTrack(this._context.options.audio?.input??{});await e.localParticipant.publishTrack(i),this._micTrack=i,a.info("Microphone published (rtc)")}catch(e){throw this._context.mediaAudioCaptureState.end("rtc"),this._context.emitError(e,i.AUDIO_CAPTURE_START_FAILED)}}async stopMicrophone(){const e=this._rtcRoom,t=this._micTrack;if(t&&e)try{await e.localParticipant.unpublishTrack(t,!0)}catch(e){throw this._context.emitError(e,i.LIVEKIT_UNPUBLISH_MICROPHONE_FAILED)}this._micTrack?.stop(),this._micTrack=null,this._context.mediaAudioCaptureState.end("rtc"),a.info("Microphone stopped (rtc)")}isMicrophoneActive(){return!!this._micTrack}async sendTextData(e,t,s,n){this.ensureNotDisposed();const o=this._rtcRoom;if(!o||!this.isConnected())throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit is not connected");try{const i={event:s,requestId:e,data:{...n,text:t}},r=(new TextEncoder).encode(JSON.stringify(i));await o.localParticipant.publishData(r,{reliable:!0}),a.debug("Text message sent via RTC data:",e)}catch(e){throw this._context.emitError(e,i.LIVEKIT_SEND_TEXT_DATA_FAILED)}}async sendSystemEvent(e,t){this.ensureNotDisposed();const s=this._rtcRoom;if(!s||!this.isConnected())throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit is not connected");try{const i={event:e,data:t??{}},n=(new TextEncoder).encode(JSON.stringify(i));await s.localParticipant.publishData(n,{reliable:!0}),a.debug("System event :",e,"sent via RTC data")}catch(e){throw this._context.emitError(e,i.LIVEKIT_SEND_TEXT_DATA_FAILED)}}setProtocolMessageDispatcher(e){this._protocolDispatch=e}async startCamera(){this.ensureNotDisposed();const e=this._rtcRoom;if(!e||!this.isConnected())throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit is not connected");if(this._cameraVideoTrack)a.warn("RTC camera already published");else try{const i=await t.createLocalVideoTrack({});await e.localParticipant.publishTrack(i),this._cameraVideoTrack=i,a.info("Camera published (rtc)")}catch(e){throw this._context.emitError(e,i.LIVEKIT_CONNECT_FAILED)}}async stopCamera(){const e=this._rtcRoom,t=this._cameraVideoTrack;if(t&&e)try{await e.localParticipant.unpublishTrack(t,!0)}catch(e){a.error("Error unpublishing RTC camera:",e)}this._cameraVideoTrack?.stop(),this._cameraVideoTrack=null,a.info("Camera stopped (rtc)")}attachCameraTo(e){if(this.ensureNotDisposed(),!this._cameraVideoTrack)throw new r(i.LIVEKIT_CONNECT_FAILED,"Camera track is not published");this._cameraVideoTrack.attach(e)}detachCameraFrom(e){if(this.ensureNotDisposed(),!this._cameraVideoTrack)throw new r(i.LIVEKIT_CONNECT_FAILED,"Camera track is not published");this._cameraVideoTrack.detach(e)}isRtcCameraActive(){return null!==this._cameraVideoTrack}_onRoomDataReceived(e){if(this._protocolDispatch&&0!==e.length)try{const t=(new TextDecoder).decode(e),i=JSON.parse(t);if(!i||"object"!=typeof i)return;a.debug("RTC data message received:",t),this._protocolDispatch(i)}catch(e){a.error("RTC data message parse error:",e),this._context.emitError(e,i.LIVEKIT_DATA_MESSAGE_PARSE_ERROR)}}_handleTrackSubscribed(e,i,s){try{if(!e.mediaStreamTrack)return void a.warn("Track does not have MediaStreamTrack");if("audio"===e.kind){const e=s.identity;if(!this._speakingHandlers.has(e)){const i=t=>{this._context.eventBus.emit("inner:audio:speaking:changed",{participantId:e,isSpeaking:t}),a.info(`Participant ${e} is speaking: ${t}`)};s.on(t.ParticipantEvent.IsSpeakingChanged,i),this._speakingHandlers.set(e,i)}}const n=i.trackSid,r=s.identity;this._eventAdapter.handleTrackSubscribed(e,n,r)}catch(e){a.error("Error handling track subscribed:",e)}}_handleTrackUnsubscribed(e,t,i){try{const e=i,s=t.trackSid,n=e.identity,r=this._trackRegistry.getTrack(s),o="audio"===r?.kind;"video"===r?.kind&&this._context.eventBus.emit("inner:rtc:video:unavailable",void 0),this._eventAdapter.handleTrackUnsubscribed(s,n),o&&this._removeSpeakingListenerIfNoAudioTracks(n)}catch(e){a.error("Error handling track unsubscribed:",e)}}_handleTrackMuted(e,t){try{"video"===e.kind&&this._context.eventBus.emit("inner:rtc:video:unavailable",void 0)}catch(e){a.error("Error handling track muted:",e)}}_handleTrackUnmuted(e,t){try{"video"===e.kind&&this._context.eventBus.emit("inner:rtc:video:available",void 0)}catch(e){a.error("Error handling track unmuted:",e)}}async disconnect(){await this.stopMicrophone(),await this.stopCamera(),this._clearSpeakingHandlers();const e=this._rtcRoom;if(e)try{try{e.removeAllListeners()}catch{}await e.disconnect(),this._room=null,this._rtcRoom=null,this._context.eventBus.emit("inner:rtc:disconnected",{reason:"Disconnected from LiveKit room"}),a.info("Disconnected from LiveKit room")}catch(e){a.error("Error disconnecting from LiveKit room:",e),this._room=null,this._rtcRoom=null}else this._room=null}isConnected(){return!!this._room&&this._room.state===t.ConnectionState.Connected}getTrackRegistry(){return this._trackRegistry}get trackRegistry(){return this._trackRegistry}getEventAdapter(){return this._eventAdapter}onDispose(){this._protocolDispatch=null,this.disconnect(),this._trackRegistry.dispose(),this._eventAdapter.dispose(),a.info("LiveKit Service disposed")}}class ce extends v{constructor(){super(),this._conversationManager=null,a.info("ProtocolMessageDispatcher created")}setConversationManager(e){this._conversationManager=e,a.debug("Conversation manager set in ProtocolMessageDispatcher")}dispatch(e){this.ensureNotDisposed();try{if(e.event)return void this._handleLivekitServerResponseMessage(e)}catch(e){a.error("Error dispatching protocol message:",e)}}_handleLivekitServerResponseMessage(e){switch(e.event){case"response.chunk":this._conversationManager?.handleAnswerChunk(e.requestId,e.data.text,!1);break;case"response.done":this._conversationManager?.handleAnswerChunk(e.requestId,"",!0);break;case"input.asr.partial":this._conversationManager?.handleAsrTextReceived(e.requestId,e.data.text,!0,e.data.final??!1);break;case"input.asr.final":this._conversationManager?.handleAsrTextReceived(e.requestId,e.data.text,!1,!0);break;case"system.prompt":this._conversationManager?.handleServerInitiatedMessage(void 0,e.data.text);break;case"session.closing":break;case"input.voice.start":this._context.eventBus.emit("inner:conversation:voice:start",{requestId:e.requestId});break;case"input.voice.finish":this._context.eventBus.emit("inner:conversation:voice:finish",{requestId:e.requestId});break;default:a.warn("Unknown event:",e.event)}}onDispose(){this._conversationManager=null,a.info("ProtocolMessageDispatcher disposed")}}const he=["sdk:connected","sdk:disconnected","sdk:error","media:video:available","media:video:unavailable","media:video:trackAdded","media:video:trackRemoved","media:audio:trackAdded","media:audio:trackRemoved","media:audio:captureStarted","media:audio:captureStopped","media:camera:started","media:camera:stopped","media:audio:volumeChanged","media:audio:muted","media:audio:unmuted","conversation:question:sent","conversation:answer:waiting","conversation:server:message","conversation:asr:received","conversation:asr:chunk","conversation:answer:chunk","conversation:answer:completed"],de=/^[a-z]+:[a-zA-z]+(:[a-zA-Z]+)?$/;class le{constructor(e){this.inner=e,this.listeners=new Map,this.forwardedVideoTrackIds=new Set,this.livekitConnected=!1,this.httpConnected=!1,this.internalMap={"inner:sdk:error":{public:"sdk:error",sanitizer:e=>({message:e?.error?.message,code:e?.error?.code})},"inner:rtc:video:available":{public:"media:video:available"},"inner:rtc:video:unavailable":{public:"media:video:unavailable"},"inner:video:track:added":{public:"media:video:trackAdded"},"inner:video:track:removed":{public:"media:video:trackRemoved"},"inner:audio:track:added":{public:"media:audio:trackAdded"},"inner:audio:track:removed":{public:"media:audio:trackRemoved"},"inner:audio:input:started":{public:"media:audio:captureStarted"},"inner:audio:input:stopped":{public:"media:audio:captureStopped"},"inner:camera:started":{public:"media:camera:started"},"inner:camera:stopped":{public:"media:camera:stopped"},"inner:audio:volume:changed":{public:"media:audio:volumeChanged",sanitizer:e=>({volume:e?.volume})},"inner:audio:muted":{public:"media:audio:muted"},"inner:audio:unmuted":{public:"media:audio:unmuted"},"inner:conversation:question:sent":{public:"conversation:question:sent",sanitizer:e=>({questionId:e?.questionId,text:String(e?.text||"")})},"inner:conversation:answer:waiting":{public:"conversation:answer:waiting",sanitizer:e=>({questionId:e?.questionId})},"inner:conversation:server:message":{public:"conversation:server:message",sanitizer:e=>({questionId:e?.questionId,message:String(e?.message||""),type:String(e?.type||"")})},"inner:conversation:asr:received":{public:"conversation:asr:received",sanitizer:e=>({questionId:e?.questionId,text:String(e?.text||"")})},"inner:conversation:asr:chunk":{public:"conversation:asr:chunk",sanitizer:e=>({questionId:e?.questionId,text:String(e?.text||""),isComplete:e?.isComplete??!1})},"inner:conversation:answer:chunk":{public:"conversation:answer:chunk",sanitizer:e=>({questionId:e?.questionId,chunk:String(e?.chunk||"")})},"inner:conversation:answer:completed":{public:"conversation:answer:completed",sanitizer:e=>({questionId:e?.questionId,fullAnswer:String(e?.fullAnswer||"")})}},Object.keys(this.internalMap).forEach(e=>{this.inner.on(e,t=>this.handleInternalEvent(e,t))}),this.inner.on("inner:sdk:connected",e=>this.handleConnected(e,!0)),this.inner.on("inner:sdk:disconnected",e=>this.handleConnected(e,!1)),he.forEach(e=>{this.inner.on(e,t=>this.handlePublicEvent(e,t))})}publicAPI(){return{on:this.on.bind(this),off:this.off.bind(this),once:this.once.bind(this)}}on(e,t){const i=String(e);return this.assertAllowed(i),this.listeners.has(i)||this.listeners.set(i,new Set),this.listeners.get(i).add(t),()=>this.off(e,t)}once(e,t){const i=String(e);this.assertAllowed(i);const s=i=>{try{t(i)}finally{this.off(e,s)}};return this.on(e,s)}off(e,t){const i=String(e);this.assertAllowed(i);const s=this.listeners.get(i);s&&(s.delete(t),0===s.size&&this.listeners.delete(i))}handleInternalEvent(e,t){const i=this.internalMap[e];if(!i)return;const s=i.public;if(-1===he.indexOf(s))return;if("media:video:trackAdded"===s){const e=t?.trackId||t?.id;if("string"==typeof e){if(this.forwardedVideoTrackIds.has(e))return;this.forwardedVideoTrackIds.add(e)}}const n=i.sanitizer?i.sanitizer(t):t;if(!de.test(s))return;const r=this.listeners.get(s);r&&0!==r.size&&r.forEach(e=>{try{e(n)}catch(e){a.error("PublicEventEmitter listener error",e)}})}handlePublicEvent(e,t){if(-1===he.indexOf(e))return;const i=Object.values(this.internalMap).find(t=>t.public===e),s=i&&i.sanitizer?i.sanitizer(t):t;if("media:video:trackAdded"===e){const e=t?.trackId||t?.id;if("string"==typeof e){if(this.forwardedVideoTrackIds.has(e))return;this.forwardedVideoTrackIds.add(e)}}const n=this.listeners.get(e);n&&0!==n.size&&n.forEach(e=>{try{e(s)}catch(e){a.error("PublicEventEmitter listener error",e)}})}handleConnected(e,t){"livekit"===e.source?this.livekitConnected=t:"http"===e.source&&(this.httpConnected=t),this.maybeEmitSdkConnected(t?"connected":"disconnected")}maybeEmitSdkConnected(e){const t="connected"===e,i=t?!!this.livekitConnected:!this.livekitConnected,s=t?!!this.httpConnected:!this.httpConnected,n={livekit:i,http:s,all:i&&s},r=JSON.stringify(n);this.lastConnectedPayloadJson!==r&&(this.lastConnectedPayloadJson=r,this.inner.emit(`sdk:${e}`,n))}assertAllowed(e){if(-1===he.indexOf(e))throw new Error(`Event "${e}" is not allowed for public consumers`);if(!de.test(e))throw new Error(`Event name "${e}" does not follow namespace:domain[:action] naming`)}}class _e extends o{constructor(e,t){super(),this._requestCounter=0,this._baseURL=e||"",this._defaultHeaders=t||{},a.info(`HTTP Service created with baseURL: ${this._baseURL||"none"}`)}setAuthToken(e){this._defaultHeaders.Authorization=`Bearer ${e}`}request(e){this.ensureNotDisposed();const t=e.requestId||`req_${Date.now()}_${++this._requestCounter}`,i=this._buildURL(e.url,e.params),s=this._mergeHeaders(e.headers),n={method:e.method||"GET",headers:s};void 0!==e.data&&"GET"!==(e.method||"GET")&&("string"==typeof e.data?n.body=e.data:(n.body=JSON.stringify(e.data),s["Content-Type"]||s["content-type"]||(s["Content-Type"]="application/json")));const r=e.timeout||3e4,o=new AbortController;return n.signal=o.signal,new Promise((s,c)=>{const h=setTimeout(()=>o.abort(),r);fetch(i,n).then(async n=>{clearTimeout(h);const r={};let o;n.headers.forEach((e,t)=>{r[t]=e});const c=n.headers.get("content-type");o=c&&c.includes("application/json")?await n.json():await n.text();const d={requestId:t,status:n.status,headers:r,data:o,config:e};a.debug(`HTTP request succeeded: ${e.method} ${i} [${t}]`),s(d)}).catch(s=>{clearTimeout(h);const n=s&&"AbortError"===s.name,r={requestId:t,status:s&&s.status||void 0,message:n?"Request aborted (timeout)":s&&s.message||"HTTP request failed",error:s,config:e};a.error(`HTTP request failed: ${e.method} ${i} [${t}]`,s),c(r)})})}get(e,t,i){return this.request({...i,url:e,method:"GET",params:t})}post(e,t,i){return this.request({...i,url:e,method:"POST",data:t})}put(e,t,i){return this.request({...i,url:e,method:"PUT",data:t})}delete(e,t){return this.request({...t,url:e,method:"DELETE"})}patch(e,t,i){return this.request({...i,url:e,method:"PATCH",data:t})}_buildURL(e,t){if(e.startsWith("http://")||e.startsWith("https://"))return this._appendParams(e,t);let i=this._baseURL;return!i||i.endsWith("/")||e.startsWith("/")?i&&i.endsWith("/")&&e.startsWith("/")&&(i=i.slice(0,-1)):i+="/",i+=e,this._appendParams(i,t)}_appendParams(e,t){if(!t||0===Object.keys(t).length)return e;const i=new URLSearchParams;for(const[e,s]of Object.entries(t))i.append(e,String(s));const s=e.includes("?")?"&":"?";return`${e}${s}${i.toString()}`}_mergeHeaders(e){const t={...this._defaultHeaders};return e&&Object.assign(t,e),t}onDispose(){a.info("HTTP Service disposed")}}function ue(e,t="https"){if(e.includes("://"))return e;return`${t.replace(/:$/,"")}://${e}`}class pe extends v{constructor(e,t){super(),this._httpService=new _e(e||"https://api.newportai.com/s2/aigc/api/vih_dispatcher",t)}getAuthToken(){if(this.ensureNotDisposed(),this._context.authToken)return this._httpService?.setAuthToken(this._context.authToken),Promise.resolve();throw this._context.emitError("Auth token not found",i.SDK_AUTH_TOKEN_FAILED)}async fetchConnectionConfig(){this.ensureNotDisposed();const e=await this._httpService.request({url:"/v1/session/start",method:"POST",data:{avatarId:"auth"===this._context.options.connectConfig.type?this._context.options.connectConfig.config.avatarId:"",voice:"auth"===this._context.options.connectConfig.type&&this._context.options.connectConfig.config.avatarVoice||""},headers:this._context.options.sandbox?{"X-Env-Sandbox":"true"}:void 0}).catch(e=>{throw this._context.emitError(e,i.SDK_GET_LIVEKIT_CONFIG_FAILED)});if(0!==e.data.code||!e.data.data)throw this._context.emitError(new r(i.SDK_GET_LIVEKIT_CONFIG_FAILED,e.data.msg||"LiveKit config response invalid"),i.SDK_GET_LIVEKIT_CONFIG_FAILED);return{roomId:"",roomToken:e.data.data.userToken,livekitUrl:ue(e.data.data.sfuUrl,"wss")}}onDispose(){this._httpService.dispose()}}class me extends v{constructor(e,t){super(),this._connectStartAt=null,this._hasReportedFirstFrame=!1,this._videoElement=null,this._videoFirstFrameHandler=null,this._pendingTextResponse=new Map,this._pendingTextAudioQueue=[],this._pendingTextAudioStartAt=new Map,this._pendingNoSpeechStartAt=null,this._eventUnsubscribers=[],this._reporter=e??null,this._now=t??(()=>Date.now())}setReporter(e){this._reporter=e??null}startConnectMeasurement(){this._connectStartAt=this._now(),this._hasReportedFirstFrame=!1}bindVideoElement(e){this._unbindVideoElement(),this._videoElement=e,this._videoFirstFrameHandler=this._handleVideoFirstFrame.bind(this),this._videoElement.addEventListener("loadeddata",this._videoFirstFrameHandler,{once:!1})}setContext(e){super.setContext(e),this._bindEventBus()}_bindEventBus(){this._clearEventListeners(),this._subscribeConversationMetrics(),this._subscribeAudioMetrics()}_subscribeConversationMetrics(){this._eventUnsubscribers.push(this._context.eventBus.on("inner:conversation:question:sent",({questionId:e})=>{const t=this._now();this._pendingTextResponse.set(e,t),this._pendingTextAudioQueue.push(e),this._pendingTextAudioStartAt.set(e,t)})),this._eventUnsubscribers.push(this._context.eventBus.on("inner:conversation:answer:chunk",({questionId:e})=>{this._tryCompleteTextResponse(e)})),this._eventUnsubscribers.push(this._context.eventBus.on("inner:conversation:answer:completed",({questionId:e})=>{this._tryCompleteTextResponse(e)})),this._eventUnsubscribers.push(this._context.eventBus.on("inner:conversation:server:message",({questionId:e})=>{this._tryCompleteTextResponse(e)}))}_subscribeAudioMetrics(){this._eventUnsubscribers.push(this._context.eventBus.on("inner:audio:speaking:changed",({isSpeaking:e})=>{e&&(this._tryCompleteTextToAudio(),this._tryCompleteNoSpeechToAudio())})),this._eventUnsubscribers.push(this._context.eventBus.on("inner:audio:no_speech:reported",({timestamp:e})=>{null===this._pendingNoSpeechStartAt&&(this._pendingNoSpeechStartAt=e)}))}_handleVideoFirstFrame(){this._hasReportedFirstFrame||null===this._connectStartAt||(this._hasReportedFirstFrame=!0,this._report({metric:"connect_to_first_frame_ms",durationMs:this._now()-this._connectStartAt,startedAt:this._connectStartAt,endedAt:this._now()}))}_tryCompleteTextResponse(e){const t=this._pendingTextResponse.get(e);if(void 0===t)return;this._pendingTextResponse.delete(e);const i=this._now();this._report({metric:"text_send_to_text_response_ms",durationMs:i-t,startedAt:t,endedAt:i,questionId:e})}_tryCompleteTextToAudio(){let e;for(;this._pendingTextAudioQueue.length>0;){const t=this._pendingTextAudioQueue.shift();if(t&&this._pendingTextAudioStartAt.has(t)){e=t;break}}if(!e)return;const t=this._pendingTextAudioStartAt.get(e);if(void 0===t)return;this._pendingTextAudioStartAt.delete(e);const i=this._now();this._report({metric:"text_send_to_audio_response_ms",durationMs:i-t,startedAt:t,endedAt:i,questionId:e})}_tryCompleteNoSpeechToAudio(){if(null===this._pendingNoSpeechStartAt)return;const e=this._pendingNoSpeechStartAt;this._pendingNoSpeechStartAt=null;const t=this._now();this._report({metric:"no_speech_report_to_audio_response_ms",durationMs:t-e,startedAt:e,endedAt:t})}_report(e){const t=this._reporter??this._defaultReporter;try{t(e)}catch(e){a.error("Performance metric reporter failed",e)}}_defaultReporter(e){a.info("[performance-metric]",e)}_unbindVideoElement(){this._videoElement&&this._videoFirstFrameHandler&&this._videoElement.removeEventListener("loadeddata",this._videoFirstFrameHandler),this._videoElement=null,this._videoFirstFrameHandler=null}_clearEventListeners(){this._eventUnsubscribers.forEach(e=>{try{e()}catch(e){a.error("Performance monitor unsubscribe failed",e)}}),this._eventUnsubscribers=[]}onDispose(){this._unbindVideoElement(),this._clearEventListeners(),this._pendingTextResponse.clear(),this._pendingTextAudioQueue.length=0,this._pendingTextAudioStartAt.clear(),this._pendingNoSpeechStartAt=null,this._reporter=null}}class ve extends v{constructor(e,t=6e4){super(),this._cachedConfig=null,this._cachedAt=null,this._inflightPromise=null,this._nextDirectConfig=null,this._httpController=e,this._ttlMs=t}async preConnect(){this.ensureNotDisposed();const e=this.getValidConfig();return e||(this._inflightPromise||(this._inflightPromise=this._fetchConfig().finally(()=>{this._inflightPromise=null})),this._inflightPromise)}getValidConfig(){return this.ensureNotDisposed(),this._cachedConfig&&null!==this._cachedAt?Date.now()-this._cachedAt>=this._ttlMs?null:this._cachedConfig:null}async refreshConfig(){return this.ensureNotDisposed(),this._cachedConfig=null,this._cachedAt=null,this._inflightPromise||(this._inflightPromise=this._fetchConfig().finally(()=>{this._inflightPromise=null})),this._inflightPromise}replaceDirectConfig(e){this.ensureNotDisposed();const t=this._validateDirectConfig(e);this._nextDirectConfig=t,this._cachedConfig=null,this._cachedAt=null}async _fetchConfig(){const e=this._context.options.connectConfig;if("direct"===e.type){const t=this._nextDirectConfig??this._validateDirectConfig(e.config),i={livekitUrl:t.sfuUrl,token:t.clientToken};return this._cache(i),this._nextDirectConfig=null,i}return this._fetchAuthConfigWithRetry(e.config.authToken||"")}_fromAuthPayload(e){if(!e.livekitUrl||!e.roomToken)throw this._context.emitError("Invalid connection config payload",i.SDK_GET_LIVEKIT_CONFIG_FAILED);return{livekitUrl:e.livekitUrl,token:e.roomToken,roomId:e.roomId,videoOptions:{renderMode:e.greenScreen?.enabled?"processed":"raw",greenScreen:{enabled:Boolean(e.greenScreen?.enabled),...e.greenScreen}}}}_cache(e){this._cachedConfig=e,this._cachedAt=Date.now()}async _fetchAuthConfigWithRetry(e){let t=null;for(let i=1;i<=ve.AUTH_RETRY_MAX_ATTEMPTS;i++)try{const t=this._context.authToken||e;this._context.setAuthToken(t),await this._httpController.getAuthToken();const i=await this._httpController.fetchConnectionConfig(),s=this._fromAuthPayload(i);return this._cache(s),s}catch(e){if(t=e,i>=ve.AUTH_RETRY_MAX_ATTEMPTS)break;await this._delay(ve.AUTH_RETRY_BASE_DELAY_MS*i)}throw this._context.emitError(t||"Failed to fetch auth connection config",i.SDK_GET_LIVEKIT_CONFIG_FAILED)}_delay(e){return new Promise(t=>setTimeout(t,e))}_validateDirectConfig(e){const t=(e.sfuUrl||"").trim(),s=(e.clientToken||"").trim();if(!t||!s)throw this._context.emitError("Invalid direct connection config",i.SDK_PRECONNECT_FAILED);return{sfuUrl:t,clientToken:s}}onDispose(){this._cachedConfig=null,this._cachedAt=null,this._inflightPromise=null,this._nextDirectConfig=null}}ve.AUTH_RETRY_MAX_ATTEMPTS=2,ve.AUTH_RETRY_BASE_DELAY_MS=300;class ge extends o{constructor(e){super(),this._videoController=null,this._audioController=null,this._conversationController=null,this._cameraController=null,this._liveKitService=null,this._connectionCoordinator=null,this._httpController=null,this._configManager=null,this._performanceMonitor=null,this._pendingDirectConfig=null,this._isReconnectInProgress=!1,this._reconnectPromise=null,this._liveKitProtocolDispatcher=null,this._context=new m(e),a.info("SDK Client created")}get events(){return this.ensureNotDisposed(),this._publicEventAPI||(this._publicEmitter=new le(this._context.eventBus),this._publicEventAPI=this._publicEmitter.publicAPI()),this._publicEventAPI}sendTextQuestion(e){if(this.ensureNotDisposed(),this._ensureConnected(),this._conversationController)return this._conversationController.sendQuestion(e);throw new r(i.CONVERSATION_CONTROLLER_NOT_AVAILABLE,"Conversation controller is not available")}async interrupt(){if(this.ensureNotDisposed(),this._ensureConnected(),this._conversationController)return this._conversationController.interrupt();throw new r(i.CONVERSATION_CONTROLLER_NOT_AVAILABLE,"Conversation controller is not available")}setPerformanceMetricReporter(e){if(this.ensureNotDisposed(),!this._performanceMonitor)return this._performanceMonitor=new me(e),void this._performanceMonitor.setContext(this._context);this._performanceMonitor.setReporter(e)}setRenderFitMode(e){this.ensureNotDisposed(),this._ensureConnected(),this._videoController&&this._videoController.setRenderFitMode(e)}async startAudioCapture(){this.ensureNotDisposed(),this._ensureConnected(),await this._startAudioCaptureRtc()}async stopAudioCapture(){this.ensureNotDisposed(),this._ensureConnected(),await this._stopAudioCaptureRtc()}setVolume(e){this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().setVolume(e)}getVolume(){return this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().getVolume()||1}mute(){this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().mute()}unmute(){this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().unmute()}get isMuted(){return this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().isMuted()}get isAudioCapturing(){return this.ensureNotDisposed(),this._ensureConnected(),this._liveKitService?.isMicrophoneActive()??!1}setAuthToken(e){this.ensureNotDisposed(),this._context.setAuthToken(e),this._httpController&&this._httpController.getAuthToken()}updateConnectionConfig(e){if(this.ensureNotDisposed(),"direct"!==this._context.options.connectConfig.type)throw this._context.emitError(new r(i.SDK_INVALID_STATE_TRANSITION,"updateConnectionConfig is only available in direct mode"),i.SDK_INVALID_STATE_TRANSITION);this._pendingDirectConfig=this._validateDirectConnectionConfig(e)}async startCamera(){this.ensureNotDisposed(),this._ensureConnected(),await this._requireLiveKitService().startCamera()}stopCamera(){this.ensureNotDisposed(),this._ensureConnected(),this._liveKitService?.stopCamera()}getCameraStream(){return this.ensureNotDisposed(),this._ensureConnected(),this._cameraController?.getStream()??null}getCameraTrack(){return this.ensureNotDisposed(),this._ensureConnected(),this._cameraController?.getTrack()??null}attachCameraTo(e){this.ensureNotDisposed(),this._ensureConnected(),this._requireLiveKitService().attachCameraTo(e)}async preConnect(){this.ensureNotDisposed();try{this._ensureConfigManagerReady();const e=await this._configManager.preConnect();return this._applyConnectionConfig(e),!0}catch(e){throw this._context.emitError(e,i.SDK_PRECONNECT_FAILED)}}async connect(){if(this.ensureNotDisposed(),this._ensurePerformanceMonitorReady(),this._performanceMonitor?.startConnectMeasurement(),this._connectionCoordinator&&this._context.sessionState.isConnected)a.warn("SDK already initialized");else{try{this._ensureConfigManagerReady();const e=this._configManager.getValidConfig();if(e)this._applyConnectionConfig(e);else{if(!await this.preConnect())throw new r(i.SDK_CONNECT_FAILED,"PreConnect failed without explicit error")}}catch(e){throw this._context.emitError(e,i.SDK_CONNECT_FAILED)}try{await this._disposeConnectionRuntimeBeforeConnect(),a.info("Initializing SDK..."),this._connectionCoordinator=new T,this._connectionCoordinator.setContext(this._context),this._context.bindConnectionState(()=>this._connectionCoordinator.getState()),this._connectionCoordinator.start(),this._connectionCoordinator.startConnecting(),this._bootstrapDomainControllers(),this._bootstrapLiveKitService(),this._wireLiveKitEventAdapterToControllers(),this._setupRtcProtocolDispatcher(),await this._establishMediaAndSessionTransports(),a.info("SDK initialized and connected")}catch(e){throw this._connectionCoordinator&&this._connectionCoordinator.transitionToIdle(),await this._cleanup(),this._context.emitError(e,i.SDK_INITIALIZATION_FAILED)}}}async disconnect(){if(this.ensureNotDisposed(),this._connectionCoordinator&&"idle"!==this._connectionCoordinator.getState()&&"disposed"!==this._connectionCoordinator.getState()){a.info("Disconnecting SDK..."),this._connectionCoordinator.startDisconnecting();try{this._audioController&&this._audioController.stopWsCapture(),this._liveKitService&&(await this._liveKitService.sendSystemEvent("session.stop"),await this._liveKitService.disconnect()),this._cameraController&&this._cameraController.stopCamera(),this._connectionCoordinator.completeDisconnecting(),a.info("SDK disconnected")}catch(e){throw a.error("Error during disconnect:",e),this._context.emitError(e,i.SDK_DISCONNECT_FAILED)}}}async reconnect(){if(this.ensureNotDisposed(),this._reconnectPromise)return this._reconnectPromise;const e=this._connectionCoordinator;if(!e?.canStartReconnectingManual()){const t=e?e.getSnapshot():this.connectionSnapshot;return a.warn("SDK reconnect not allowed in current state, returning current snapshot"),t}const t=e.captureSnapshotAndStartReconnectingManual();return this._reconnectPromise=(async()=>{this._isReconnectInProgress=!0;try{return await this.disconnect(),this._stageDirectConfigForNextReconnect(),await this._refreshConnectionConfigForReconnect(),await this.connect(),t}catch(e){throw a.error("Error during reconnect:",e),this._context.emitError(e,i.SDK_RECONNECT_FAILED)}finally{this._isReconnectInProgress=!1,this._reconnectPromise=null}})(),this._reconnectPromise}get connectionSnapshot(){return this.ensureNotDisposed(),this._connectionCoordinator?this._connectionCoordinator.getSnapshot():E(g("idle"))}async _cleanup(){if(this._conversationController?.setRtcTextSender(null),this._liveKitService?.setProtocolMessageDispatcher(null),this._liveKitProtocolDispatcher&&(this._liveKitProtocolDispatcher.dispose(),this._liveKitProtocolDispatcher=null),this._audioController&&this._audioController.stopWsCapture(),this._liveKitService)try{await this._liveKitService.disconnect()}catch(e){a.error("Error disconnecting LiveKit:",e)}this._cameraController&&this._cameraController.stopCamera()}async _disposeConnectionRuntimeBeforeConnect(){await this._cleanup(),this._conversationController?.setRtcTextSender(null),this._liveKitService?.setProtocolMessageDispatcher(null),this._liveKitProtocolDispatcher&&(this._liveKitProtocolDispatcher.dispose(),this._liveKitProtocolDispatcher=null),this._videoController?.dispose(),this._videoController=null,this._audioController?.dispose(),this._audioController=null,this._cameraController?.dispose(),this._cameraController=null,this._conversationController?.dispose(),this._conversationController=null,this._liveKitService?.dispose(),this._liveKitService=null,this._connectionCoordinator?.dispose(),this._connectionCoordinator=null}_bootstrapDomainControllers(){this._videoController=new L(this._context.options.video),this._videoController.setContext(this._context),this._performanceMonitor?.bindVideoElement(this._videoController.getSource().getInternalElement()),this._audioController=new U(this._context.options.audio),this._audioController.setContext(this._context),this._cameraController=new Q,this._cameraController.setContext(this._context),this._conversationController=new ie,this._conversationController.setContext(this._context)}_bootstrapLiveKitService(){this._liveKitService=new ae,this._liveKitService.setContext(this._context)}_wireLiveKitEventAdapterToControllers(){if(this._liveKitService&&this._videoController&&this._audioController){const e=this._liveKitService.getEventAdapter();e&&("function"==typeof e.setVideoController&&e.setVideoController(this._videoController),"function"==typeof e.setAudioController&&e.setAudioController(this._audioController))}}_setupRtcProtocolDispatcher(){this._liveKitProtocolDispatcher&&(this._liveKitProtocolDispatcher.dispose(),this._liveKitProtocolDispatcher=null),this._liveKitProtocolDispatcher=new ce,this._liveKitProtocolDispatcher.setContext(this._context),this._liveKitProtocolDispatcher.setConversationManager(this._conversationController.manager),this._liveKitService.setProtocolMessageDispatcher(e=>{this._liveKitProtocolDispatcher.dispatch(e)}),this._conversationController.setRtcTextSender(this._liveKitService)}async _establishMediaAndSessionTransports(){await this._liveKitService.connect(this._context.livekitUrl,this._context.token,"auth"===this._context.options.connectConfig.type?this._context.options.connectConfig.config.avatarId:"")}async _refreshConnectionConfigForReconnect(){this._ensureConfigManagerReady();const e=await this._configManager.refreshConfig();this._applyConnectionConfig(e)}_ensureConfigManagerReady(){a.info("Creating HTTP controller..."),this._httpController=this._httpController??new pe(this._context.options.http?.baseURL,this._context.options.http?.headers),this._httpController.setContext(this._context),this._configManager=this._configManager??new ve(this._httpController),this._configManager.setContext(this._context)}_applyConnectionConfig(e){this._context.setLivekitConfig(e.livekitUrl,e.token,e.roomId||""),e.videoOptions&&this._context.setVideoOptions(e.videoOptions),"auth"===this._context.options.connectConfig.type&&this._context.eventBus.emit("inner:sdk:connected",{source:"http"})}_stageDirectConfigForNextReconnect(){"direct"===this._context.options.connectConfig.type&&this._pendingDirectConfig&&(this._ensureConfigManagerReady(),this._configManager.replaceDirectConfig(this._pendingDirectConfig),this._pendingDirectConfig=null)}_validateDirectConnectionConfig(e){const t=(e?.sfuUrl||"").trim(),s=(e?.clientToken||"").trim();if(!t||!s)throw this._context.emitError(new r(i.SDK_PRECONNECT_FAILED,"Invalid direct connection config"),i.SDK_PRECONNECT_FAILED);return{sfuUrl:t,clientToken:s}}_ensurePerformanceMonitorReady(){const e=this._context.options.performanceMonitor;if(!(!1!==e?.enabled))return this._performanceMonitor?.dispose(),void(this._performanceMonitor=null);this._performanceMonitor?this._performanceMonitor.setReporter(e?.reporter):(this._performanceMonitor=new me(e?.reporter),this._performanceMonitor.setContext(this._context))}get isConnected(){return this.ensureNotDisposed(),this._context.sessionState.isConnected}_ensureConnected(){if(!this._context.sessionState.isConnected)throw new r(i.SDK_NOT_CONNECTED,"SDK is not connected. Call connect() first.")}async _startAudioCaptureRtc(){await this._requireLiveKitService().startMicrophone()}async _stopAudioCaptureRtc(){await this._requireLiveKitService().stopMicrophone()}_requireAudioController(){if(!this._audioController)throw new r(i.AUDIO_CONTROLLER_NOT_AVAILABLE,"Audio controller is not available");return this._audioController}_requireLiveKitService(){if(!this._liveKitService)throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit service is not available");return this._liveKitService}onDispose(){this.disconnect().catch(e=>{a.error("Error during disconnect in dispose:",e)}),this._videoController&&(this._videoController.dispose(),this._videoController=null),this._audioController&&(this._audioController.dispose(),this._audioController=null),this._cameraController&&(this._cameraController.dispose(),this._cameraController=null),this._conversationController?.setRtcTextSender(null),this._liveKitService?.setProtocolMessageDispatcher(null),this._liveKitProtocolDispatcher&&(this._liveKitProtocolDispatcher.dispose(),this._liveKitProtocolDispatcher=null),this._conversationController&&(this._conversationController.dispose(),this._conversationController=null),this._liveKitService&&(this._liveKitService.dispose(),this._liveKitService=null),this._httpController&&(this._httpController.dispose(),this._httpController=null),this._configManager&&(this._configManager.dispose(),this._configManager=null),this._performanceMonitor&&(this._performanceMonitor.dispose(),this._performanceMonitor=null),this._connectionCoordinator&&(this._connectionCoordinator.transitionToDisposed(),this._connectionCoordinator.dispose(),this._connectionCoordinator=null),this._context.dispose(),a.info("SDK Client disposed")}}class Ee extends o{constructor(e,t){super(),this._videoElement=null,this._videoUrl=null,this._isPlaying=!1,this._frameCallbackId=null,this._videoUrl=e,t?this._videoElement=t:(this._videoElement=document.createElement("video"),this._videoElement.style.opacity="0",this._videoElement.muted=!0,this._videoElement.playsInline=!0,this._videoElement.loop=!0,document.querySelector("#video-container")?.appendChild(this._videoElement)),a.info("Local Video Debug Source created")}get videoElement(){return this._videoElement}async load(){if(!this._videoElement)throw new Error("Video element or URL not set");return new Promise((e,t)=>{const i=this._videoElement,s=()=>{i.removeEventListener("loadedmetadata",s),i.removeEventListener("error",n),a.info(`Video loaded: ${i.videoWidth}x${i.videoHeight}`),e()},n=e=>{i.removeEventListener("loadedmetadata",s),i.removeEventListener("error",n),t(new Error(`Failed to load video: ${e}`))};i.addEventListener("loadedmetadata",s),i.addEventListener("error",n),i.src=this._videoUrl||"",i.load()})}async play(){if(!this._videoElement)throw new Error("Video element not set");if(!this._isPlaying)try{await this._videoElement.play(),this._videoElement.style.opacity="0",this._videoElement.setAttribute("loop","true"),this._isPlaying=!0,a.info("Video playback started")}catch(e){throw a.error("Failed to play video:",e),e}}pause(){this._videoElement&&this._isPlaying&&(this._videoElement.pause(),this._isPlaying=!1,a.info("Video playback paused"))}stop(){this._videoElement&&(this._videoElement.pause(),this._videoElement.currentTime=0,this._isPlaying=!1,a.info("Video playback stopped"))}get isPlaying(){return this._isPlaying&&null!==this._videoElement&&!this._videoElement.paused}get videoWidth(){return this._videoElement?.videoWidth||0}get videoHeight(){return this._videoElement?.videoHeight||0}async captureFrame(){if(!this._videoElement||this._videoElement.readyState<2)return null;try{if("VideoFrame"in window&&"function"==typeof window.VideoFrame)try{return new VideoFrame(this._videoElement,{timestamp:1e6*this._videoElement.currentTime})}catch(e){a.error("",e)}const e=await createImageBitmap(this._videoElement),t=new VideoFrame(e,{timestamp:1e6*this._videoElement.currentTime});return e.close(),t}catch(e){return a.error("Failed to capture video frame:",e),null}}onFrame(e){if(!this._videoElement)return;this.offFrame();const t=this._videoElement;if("requestVideoFrameCallback"in t){const i=(s,n)=>{this._isPlaying&&this._videoElement&&this.captureFrame().then(s=>{s&&(e(s),s.close()),this._isPlaying&&this._videoElement&&(this._frameCallbackId=t.requestVideoFrameCallback(i))}).catch(e=>{a.error("Error in frame callback:",e)})};this._frameCallbackId=t.requestVideoFrameCallback(i)}else{const t=()=>{this._isPlaying&&this._videoElement&&this.captureFrame().then(i=>{i&&(e(i),i.close()),this._isPlaying&&this._videoElement&&(this._frameCallbackId=requestAnimationFrame(t))}).catch(e=>{a.error("Error in frame callback:",e)})};this._frameCallbackId=requestAnimationFrame(t)}}offFrame(){null!==this._frameCallbackId&&(this._videoElement&&"cancelVideoFrameCallback"in this._videoElement?this._videoElement.cancelVideoFrameCallback(this._frameCallbackId):cancelAnimationFrame(this._frameCallbackId),this._frameCallbackId=null)}onDispose(){this.stop(),this.offFrame(),this._videoElement&&this._videoElement.parentElement===document.body&&document.body.removeChild(this._videoElement),this._videoElement=null,this._videoUrl=null,a.info("Local Video Debug Source disposed")}}class fe extends o{constructor(e,t,i){super(),this._outputCanvas=null,this._outputRenderer=null,this._source=new S;const s={...e,renderMode:"processed"};this._pipeline=new w(this._source,s),this._outputRenderer=new R(i,t),this._pipeline.setRenderer(this._outputRenderer),this._outputCanvas=this._outputRenderer.getCanvas(),a.info("Video Pipeline Runner created")}get outputCanvas(){return this._outputCanvas}get processor(){return this._pipeline.strategy.getProcessors()[0]||null}setProcessor(e){this._pipeline.setProcessor(e),a.info("Processor set on pipeline")}async processFrame(e){if(this.ensureNotDisposed(),!this._outputRenderer)return a.error("Output renderer not available"),void e.close();try{const t=this._pipeline.strategy.getProcessors()[0]||null;let i=null;if(t){try{i=t.process(e)}catch(t){a.error("Error processing frame:",t),i=e}if(null===i&&"getImageData"in t){const i=t.getImageData();if(i&&this._outputCanvas&&this._outputRenderer.getContext()){const e=this._outputRenderer.getContext();e&&(this._outputCanvas.width===i.width&&this._outputCanvas.height===i.height||(this._outputCanvas.width=i.width,this._outputCanvas.height=i.height),e.putImageData(i,0,0))}return void e.close()}i&&i!==e?(this._outputRenderer.render(i),e.close()):i===e?this._outputRenderer.render(e):e.close()}else this._outputRenderer.render(e)}catch(t){a.error("Error in processFrame:",t),e.close()}}setOutputSize(e,t){this._outputCanvas&&(this._outputCanvas.width=e,this._outputCanvas.height=t,a.info(`Output canvas size set to ${e}x${t}`))}onDispose(){this._pipeline.dispose(),this._outputRenderer&&(this._outputRenderer.dispose(),this._outputRenderer=null),this._outputCanvas&&this._outputCanvas.parentElement===document.body&&document.body.removeChild(this._outputCanvas),this._outputCanvas=null,a.info("Video Pipeline Runner disposed")}}e.DEFAULT_AUDIO_BUFFER_SIZE=4096,e.DEFAULT_AUDIO_CHANNELS=1,e.DEFAULT_AUDIO_SAMPLE_RATE=l,e.DEFAULT_RECONNECT_ATTEMPTS=3,e.DEFAULT_RECONNECT_DELAY=10,e.DEFAULT_WS_TIMEOUT=1e4,e.Disposable=o,e.EventBus=c,e.Logger=a,e.SDKClient=ge,e.SDKError=r,e.SessionState=h,e.StandaloneVideoDebugger=class extends o{constructor(e,t,i,s){if(super(),this._isRunning=!1,this._videoSource=new Ee(e,t),this._options={renderMode:"processed",containerElement:t,...s},this._pipelineRunner=new fe(this._options,t,i),this._options.greenScreen?.enabled){const e=new x(this._options.greenScreen);this._pipelineRunner.setProcessor(e),a.info("Green screen processor enabled in debugger")}a.info("Standalone Video Debugger created")}async switchSource(e,t){this.ensureNotDisposed();const i=this._videoSource,s=this._isRunning,n=new Ee(e,t);try{await n.load(),s&&await n.play(),n.onFrame(e=>{this._pipelineRunner.processFrame(e).catch(e=>{a.error("Error processing frame:",e)})}),this._videoSource=n;try{i.offFrame(),i.stop(),i.dispose()}catch(e){a.warn("Error disposing old video source during switch:",e)}const e=this._videoSource.videoWidth,t=this._videoSource.videoHeight;e>0&&t>0&&this._pipelineRunner.setOutputSize(e,t)}catch(e){a.error("Failed to switch video source:",e);try{n.dispose()}catch(e){a.warn("Error disposing new video source after failed switch:",e)}throw e}}get outputCanvas(){return this._pipelineRunner.outputCanvas}get videoSource(){return this._videoSource}get processor(){return this._pipelineRunner.processor}setProcessor(e){this._pipelineRunner.setProcessor(e)}updateGreenScreenOptions(e){const t=this._pipelineRunner.processor;if(t&&"updateOptions"in t&&"function"==typeof t.updateOptions)t.updateOptions(e),a.info("Green screen options updated");else{const t=this._options.greenScreen||{enabled:!1},i={...t,...e,enabled:void 0!==e.enabled?e.enabled:t.enabled},s=new x(i);this._pipelineRunner.setProcessor(s),this._options.greenScreen=i,a.info("Green screen processor recreated with new options")}}async initialize(){this.ensureNotDisposed();try{await this._videoSource.load();const e=this._videoSource.videoWidth,t=this._videoSource.videoHeight;e>0&&t>0&&this._pipelineRunner.setOutputSize(e,t),a.info("Video debugger initialized")}catch(e){throw a.error("Failed to initialize video debugger:",e),e}}async start(){if(this.ensureNotDisposed(),this._isRunning)a.warn("Debugger is already running");else try{0===this._videoSource.videoWidth&&await this.initialize(),await this._videoSource.play(),this._videoSource.onFrame(e=>{this._pipelineRunner.processFrame(e).catch(e=>{a.error("Error processing frame:",e)})}),this._isRunning=!0,a.info("Video debugger started")}catch(e){throw a.error("Failed to start video debugger:",e),e}}stop(){this._isRunning&&(this._videoSource.stop(),this._videoSource.offFrame(),this._isRunning=!1,a.info("Video debugger stopped"))}pause(){this._isRunning&&(this._videoSource.pause(),a.info("Video debugger paused"))}async resume(){this._isRunning&&(await this._videoSource.play(),a.info("Video debugger resumed"))}get isRunning(){return this._isRunning}onDispose(){this.stop(),this._videoSource.dispose(),this._pipelineRunner.dispose(),a.info("Standalone Video Debugger disposed")}},e.createClient=function(e){const t=e.connectConfig;if(!("direct"!==t.type||t.config.sfuUrl&&t.config.clientToken))throw new r(i.INVALID_CONNECT_CONFIG,"Invalid direct connect config");if("auth"===t.type&&!t.config.avatarId)throw new r(i.NO_AVATARID,"avatarId is required");return new ge(e)}});
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("livekit-client")):"function"==typeof define&&define.amd?define(["exports","livekit-client"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LivekitSDK={},e.LivekitClient)}(this,function(e,t){"use strict";var i,s,n;!function(e){e.SDK_AUTH_TOKEN_FAILED="SDK_AUTH_TOKEN_FAILED",e.SDK_GET_LIVEKIT_CONFIG_FAILED="SDK_GET_LIVEKIT_CONFIG_FAILED",e.SDK_SWITCH_VIDEO_FAILED="SDK_SWITCH_VIDEO_FAILED",e.SDK_INTERRUPT_CONVERSATION_FAILED="SDK_INTERRUPT_CONVERSATION_FAILED",e.HTTP_CONTROLLER_NOT_AVAILABLE="HTTP_CONTROLLER_NOT_AVAILABLE",e.SDK_PRECONNECT_FAILED="SDK_PRECONNECT_FAILED",e.SDK_CONNECT_FAILED="SDK_CONNECT_FAILED",e.SDK_INITIALIZATION_FAILED="SDK_INITIALIZATION_FAILED",e.SDK_DISCONNECT_FAILED="SDK_DISCONNECT_FAILED",e.SDK_RECONNECT_FAILED="SDK_RECONNECT_FAILED",e.SDK_NOT_CONNECTED="SDK_NOT_CONNECTED",e.SDK_INVALID_STATE_TRANSITION="SDK_INVALID_STATE_TRANSITION",e.SDK_ERROR="SDK_ERROR",e.LIVEKIT_CONNECT_FAILED="LIVEKIT_CONNECT_FAILED",e.AUDIO_CAPTURE_START_FAILED="AUDIO_CAPTURE_START_FAILED",e.AUDIO_CAPTURE_FAILED="AUDIO_CAPTURE_FAILED",e.AUDIO_INVALID_SAMPLE_RATE="AUDIO_INVALID_SAMPLE_RATE",e.AUDIO_INVALID_CHANNEL="AUDIO_INVALID_CHANNEL",e.AUDIO_INVALID_HEADER_LENGTH="AUDIO_INVALID_HEADER_LENGTH",e.AUDIO_INVALID_TYPE="AUDIO_INVALID_TYPE",e.AUDIO_INVALID_RESERVED="AUDIO_INVALID_RESERVED",e.AUDIO_CONTROLLER_NOT_AVAILABLE="AUDIO_CONTROLLER_NOT_AVAILABLE",e.CAMERA_CONTROLLER_NOT_AVAILABLE="CAMERA_CONTROLLER_NOT_AVAILABLE",e.CONVERSATION_CONTROLLER_NOT_AVAILABLE="CONVERSATION_CONTROLLER_NOT_AVAILABLE",e.STATE_MACHINE_INVALID_STATE_TRANSITION="STATE_MACHINE_INVALID_STATE_TRANSITION",e.OBJECT_DISPOSED="OBJECT_DISPOSED",e.AUDIO_INVALID_CODEC="AUDIO_INVALID_CODEC",e.LIVEKIT_SEND_VIDEO_AVAILABLE_STATE_FAILED="LIVEKIT_SEND_VIDEO_AVAILABLE_STATE_FAILED",e.LIVEKIT_SEND_TEXT_DATA_FAILED="LIVEKIT_SEND_TEXT_DATA_FAILED",e.LIVEKIT_DATA_MESSAGE_PARSE_ERROR="LIVEKIT_DATA_MESSAGE_PARSE_ERROR",e.LIVEKIT_UNPUBLISH_MICROPHONE_FAILED="LIVEKIT_UNPUBLISH_MICROPHONE_FAILED",e.NO_AVATARID="NO_AVATARID",e.NO_AUTH_TOKEN="NO_AUTH_TOKEN",e.INVALID_CONNECT_CONFIG="INVALID_CONNECT_CONFIG"}(i||(i={}));class r extends Error{constructor(e,t,i){super(t),this.name="SDKError",this.code=e,this.cause=i,Object.setPrototypeOf(this,r.prototype)}static fromError(e,t){return e instanceof r?e:e instanceof Error?new r(t||i.SDK_ERROR,e.message,e):"string"==typeof e?new r(t||i.SDK_ERROR,e):new r(t||i.SDK_ERROR,"Unknown error",e)}}class o{constructor(){this._disposed=!1}get isDisposed(){return this._disposed}dispose(){this._disposed||(this.onDispose(),this._disposed=!0)}ensureNotDisposed(){if(this._disposed)throw new r(i.OBJECT_DISPOSED,"Object has been disposed")}}e.LogLevel=void 0,(s=e.LogLevel||(e.LogLevel={}))[s.DEBUG=0]="DEBUG",s[s.INFO=1]="INFO",s[s.WARN=2]="WARN",s[s.ERROR=3]="ERROR",s[s.NONE=4]="NONE";class a{static setLevel(e){this._level=e}static setPrefix(e){this._prefix=e}static debug(t,...i){this._level<=e.LogLevel.DEBUG&&console.debug(`${this._prefix} [DEBUG]`,t,...i)}static info(t,...i){this._level<=e.LogLevel.INFO&&console.info(`${this._prefix} [INFO]`,t,...i)}static warn(t,...i){this._level<=e.LogLevel.WARN&&console.warn(`${this._prefix} [WARN]`,t,...i)}static error(t,...i){this._level<=e.LogLevel.ERROR&&console.error(`${this._prefix} [ERROR]`,t,...i)}}a._level=e.LogLevel.ERROR,a._prefix="[SDK]";class c extends o{constructor(){super(...arguments),this._listeners=new Map}on(e,t){this.ensureNotDisposed(),this._listeners.has(e)||this._listeners.set(e,new Set);const i=this._listeners.get(e);return i.add(t),a.debug(`Event listener added for: ${String(e)}`),()=>{i.delete(t),a.debug(`Event listener removed for: ${String(e)}`)}}once(e,t){this.ensureNotDisposed();const i=s=>{t(s),this.off(e,i)};return this.on(e,i)}off(e,t){this.ensureNotDisposed();const i=this._listeners.get(e);i&&i.delete(t)}emit(e,t){this.ensureNotDisposed();const i=this._listeners.get(e);i&&i.size>0&&(a.debug(`Emitting event: ${String(e)}`,t),i.forEach(i=>{try{i(t)}catch(t){a.error(`Error in event listener for ${String(e)}:`,t)}}))}removeAllListeners(){this._listeners.clear(),a.debug("All event listeners removed")}listenerCount(e){const t=this._listeners.get(e);return t?t.size:0}onDispose(){this.removeAllListeners()}}e.SessionStatus=void 0,(n=e.SessionStatus||(e.SessionStatus={})).IDLE="idle",n.CONNECTING="connecting",n.CONNECTED="connected",n.PARTIAL="partial",n.DISCONNECTED="disconnected",n.RECONNECTING="reconnecting",n.DISCONNECTING="disconnecting",n.ERROR="error",n.DISPOSED="disposed";class h{constructor(){this.status=e.SessionStatus.DISCONNECTED,this.state=e.SessionStatus.DISCONNECTED,this.isConnected=!1}reset(){this.status=e.SessionStatus.DISCONNECTED,this.state=e.SessionStatus.DISCONNECTED,this.isConnected=!1}}const d=1e3,l=24e3;var _;!function(e){e.NO_VIDEO_TRACK="NO_VIDEO_TRACK",e.TRACK_MUTED="TRACK_MUTED",e.TRACK_ENDED="TRACK_ENDED"}(_||(_={}));const u=.7;class p{constructor(){this._active=null}get active(){return this._active}tryBegin(e){return(null===this._active||this._active===e)&&(this._active=e,!0)}end(e){this._active===e&&(this._active=null)}reset(){this._active=null}}class m{constructor(e){this._connectionStateGetter=null,this.options=e,this._livekitUrl="",this._wsUrl="",this.eventBus=new c,this.sessionState=new h,this.mediaAudioCaptureState=new p,this._token="auth"===e.connectConfig.type&&e.connectConfig.config.authToken||"",e.debug&&a.setLevel(0),a.info("SDK Context initialized")}setLivekitConfig(e,t,i){this._livekitUrl=e||"wss://api.newportai.com/s2/livekit-lisbon",this._token=t,this._roomId=i}setAuthToken(e){this._httpToken=e}get authToken(){return this._httpToken}emitError(e,t){const i=r.fromError(e,t);return this.eventBus.emit("inner:sdk:error",{error:i}),i}setVideoOptions(e){this.options.video=Object.assign({},e,this.options.video||{})}get wsUrl(){return this._wsUrl}get livekitUrl(){return this._livekitUrl}get token(){return this._token}get roomId(){return this._roomId}getLivekitConfig(){return{livekitUrl:this._livekitUrl,token:this._token}}bindConnectionState(e){this._connectionStateGetter=e}get connectionState(){return this._connectionStateGetter?.()}clearConnectionStateBinding(){this._connectionStateGetter=null}dispose(){this.clearConnectionStateBinding(),this.mediaAudioCaptureState.reset(),this.eventBus.dispose(),this.sessionState.reset(),a.info("SDK Context disposed")}}class v extends o{setContext(e){this._context=e}}function g(e){return{http:{connected:!1},rtc:{connected:!1,hasVideoTrack:!1},overall:{state:e}}}function E(e){return Object.freeze({http:Object.freeze({...e.http}),rtc:Object.freeze({...e.rtc}),overall:Object.freeze({...e.overall})})}class f{constructor(){this._transitionMap=null}get transitionMap(){if(!this._transitionMap){const e=new Map;for(const t of this.transitionTable)e.set(t.from,new Set(t.to));this._transitionMap=e}return this._transitionMap}getCurrentState(){return this._currentState}transitionTo(e,t){const s=this._currentState;if(!this.canTransition(s,e)){const n=this.transitionMap.get(s),o=n?Array.from(n).join(", "):"none";throw t?.error??new r(i.STATE_MACHINE_INVALID_STATE_TRANSITION,`Invalid state transition: cannot transition from "${s}" to "${e}". Current state: "${s}". Allowed transitions: [${o}]`)}this._currentState=e}canTransition(e,t){if(e===t)return!1;const i=this.transitionMap.get(e);return i?.has(t)??!1}reset(){throw new Error("Method not implemented.")}}class C extends f{constructor(){super(...arguments),this._currentState="idle",this.transitionTable=[{from:"idle",to:["connecting","disposed"]},{from:"connecting",to:["connected","partial","error","idle","disposed"]},{from:"connected",to:["disconnecting","partial","reconnecting:auto","reconnecting:manual","error","disposed"]},{from:"partial",to:["connected","disconnecting","reconnecting:auto","reconnecting:manual","error","disposed"]},{from:"reconnecting:auto",to:["connected","partial","error","idle","disposed"]},{from:"reconnecting:manual",to:["connected","partial","error","idle","disposed"]},{from:"disconnecting",to:["disconnected","error","disposed"]},{from:"disconnected",to:["reconnecting:manual","reconnecting:auto","idle","disposed"]},{from:"error",to:["reconnecting:manual","reconnecting:auto","idle","disposed"]},{from:"disposed",to:[]}]}reset(){this._currentState="idle"}}class T extends v{constructor(){super(),this._unsubscribes=[],this._fsm=new C,this._snapshot=g("idle")}start(){this.ensureNotDisposed();const e=this._context.eventBus,t=e.on("inner:rtc:connected",()=>{this._snapshot.rtc.connected=!0,this._context.eventBus.emit("inner:sdk:connected",{source:"livekit"}),this._onFactsChanged()}),i=e.on("inner:rtc:disconnected",e=>{this._snapshot.rtc.connected=!1,this._snapshot.rtc.hasVideoTrack=!1,this._context.eventBus.emit("inner:sdk:disconnected",{source:"livekit",reason:e?.reason}),this._onFactsChanged()}),s=e.on("inner:rtc:video:available",()=>{this._snapshot.rtc.hasVideoTrack=!0}),n=e.on("inner:rtc:video:unavailable",()=>{this._snapshot.rtc.hasVideoTrack=!1}),r=e.on("inner:sdk:connected",e=>{"http"===e.source&&(this._snapshot.http.connected=!0,this._onFactsChanged())}),o=e.on("inner:sdk:disconnected",e=>{"http"===e.source&&(this._snapshot.http.connected=!1,this._onFactsChanged())});this._unsubscribes=[t,i,s,n,r,o],this._syncHttpFromContext(),this._onFactsChanged()}startConnecting(){this._transitionTo("connecting")}startDisconnecting(){this._transitionTo("disconnecting")}completeDisconnecting(){this._snapshot.http.connected=!1,this._snapshot.rtc.connected=!1,this._snapshot.rtc.hasVideoTrack=!1,this._transitionTo("disconnected")}captureSnapshotAndStartReconnectingManual(){const e=this.getSnapshot();return this._transitionTo("reconnecting:manual"),e}transitionToIdle(){this._snapshot.http.connected=!1,this._snapshot.rtc.connected=!1,this._snapshot.rtc.hasVideoTrack=!1,this._transitionTo("idle")}transitionToDisposed(){this._transitionTo("disposed")}getSnapshot(){return E(this._snapshot)}getState(){return this._fsm.getCurrentState()}canStartReconnectingManual(){const e=this._fsm.getCurrentState();return"connected"===e||"partial"===e||"disconnected"===e||"error"===e}_factsFullyConnected(){return("direct"===this._context.options.connectConfig.type||this._snapshot.http.connected)&&this._snapshot.rtc.connected}_factsAnyCritical(){return"direct"===this._context.options.connectConfig.type?this._snapshot.rtc.connected:this._snapshot.http.connected||this._snapshot.rtc.connected}_syncHttpFromContext(){this._snapshot.http.connected=Boolean(this._context.token)}_onFactsChanged(){const e=this._fsm.getCurrentState(),t=this._factsFullyConnected(),i=this._factsAnyCritical();if("connecting"===e||"reconnecting:auto"===e||"reconnecting:manual"===e){if(t)return void this._transitionTo("connected");if(i)return void this._transitionTo("partial")}if("connected"===e||"partial"===e){if(!i)return void this._transitionTo("disconnected");if(!t)return void this._transitionTo("partial");if(t&&"partial"===e)return void this._transitionTo("connected")}}_transitionTo(e){this._fsm.canTransition(this._fsm.getCurrentState(),e)&&(this._fsm.transitionTo(e),this._snapshot.overall.state=this._fsm.getCurrentState(),this._syncSessionState())}_syncSessionState(){const t=this._fsm.getCurrentState();this._context.sessionState.status=function(t){switch(t){case"idle":return e.SessionStatus.IDLE;case"connecting":return e.SessionStatus.CONNECTING;case"connected":return e.SessionStatus.CONNECTED;case"partial":return e.SessionStatus.PARTIAL;case"disconnecting":return e.SessionStatus.DISCONNECTING;case"disconnected":case"error":default:return e.SessionStatus.DISCONNECTED;case"reconnecting:auto":case"reconnecting:manual":return e.SessionStatus.RECONNECTING;case"disposed":return e.SessionStatus.DISPOSED}}(t),this._context.sessionState.state=this._context.sessionState.status,this._context.sessionState.isConnected="connected"===t}onDispose(){this._unsubscribes.forEach(e=>e()),this._unsubscribes=[]}}class S extends o{get trackId(){return this._trackId}get participantId(){return this._participantId}get track(){return this._track}constructor(){super(),this._trackId=null,this._participantId=null,this._track=null,this._stream=null,this._videoElement=document.createElement("video"),this._videoElement.autoplay=!0,this._videoElement.playsInline=!0,this._videoElement.muted=!0,this._videoElement.crossOrigin="anonymous",this._videoElement.style.display="none",a.info("Video Source initialized with internal video element")}getInternalElement(){return this._videoElement}setTrack(e,t,i){this.ensureNotDisposed(),this._track&&this._track.stop(),this._track=e,this._trackId=t,this._participantId=i,this._stream||(this._stream=new MediaStream);const s=this._stream.getTracks();for(const t of s)if(t!==e)try{this._stream.removeTrack(t)}catch(e){a.warn("Failed to remove track from stream",e)}if(!this._stream.getTracks().includes(e))try{this._stream.addTrack(e)}catch(e){a.error("Failed to add track to media stream:",e)}a.info("Video track ready")}clearTrack(){if(this._videoElement&&(this._videoElement.srcObject=null),this._stream){const e=this._stream.getTracks();for(const t of e)try{this._stream.removeTrack(t)}catch(e){a.warn("Failed to remove track from stream",e)}}this._track&&(this._track.stop(),this._track=null),this._trackId=null,this._participantId=null,a.info("Video track cleared")}get hasTrack(){return null!==this._track&&"live"===this._track.readyState}onDispose(){this.clearTrack(),this._videoElement&&(this._videoElement.srcObject=null,this._videoElement.parentElement&&this._videoElement.parentElement.removeChild(this._videoElement)),this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),a.info("Video Source disposed")}}class A extends o{constructor(){super(...arguments),this._renderer=null}getRenderer(){return this._renderer}setRenderer(e){this._renderer&&this._renderer.dispose(),this._renderer=e,a.debug("Raw render strategy renderer set")}getProcessors(){return[]}setProcessors(e){a.warn("Raw render strategy does not support processors")}attachToContainer(e){if(this._renderer){if("getElement"in this._renderer&&"function"==typeof this._renderer.getElement){const t=this._renderer.getElement();t instanceof HTMLVideoElement&&(t.parentElement&&t.parentElement!==e&&t.parentElement.removeChild(t),t.parentElement!==e&&(e.appendChild(t),t.style.display="",a.debug("Video element attached to container in raw mode")))}}else a.warn("No renderer available to attach to container")}onDispose(){this._renderer&&(this._renderer.dispose(),this._renderer=null),a.info("Raw Render Strategy disposed")}}class D{create(){return new A}}class R extends o{constructor(e,t){if(super(),this._canvas=null,this._ctx=null,this._videoElement=null,this._parentElement=null,this._resizeObserver=null,this._animationFrameId=null,this._isRendering=!1,this._renderLoop=()=>{if(this._isRendering&&this._videoElement&&this._canvas&&this._ctx){try{this._syncCanvasSize(),this._ctx.drawImage(this._videoElement,0,0,this._canvas.width,this._canvas.height)}catch(e){a.error("Error rendering from video to canvas:",e)}this._animationFrameId=requestAnimationFrame(this._renderLoop)}},e){if(this._canvas=e,this._ctx=e.getContext("2d"),!this._ctx)throw new Error("Failed to get 2D context from canvas")}else{if(!t)throw new Error("CanvasRenderer requires either canvas or videoElement");this._videoElement=t,this._createCanvasFromVideo()}a.info("Canvas Renderer created")}_createCanvasFromVideo(){if(!this._videoElement)return;if(this._parentElement=this._videoElement.parentElement,!this._parentElement)throw new Error("Video element must have a parent element");if("static"===window.getComputedStyle(this._parentElement).position&&(this._parentElement.style.position="relative"),this._canvas=document.createElement("canvas"),this._ctx=this._canvas.getContext("2d"),!this._ctx)throw new Error("Failed to get 2D context from canvas");this._canvas.style.position="absolute",this._canvas.style.top="0",this._canvas.style.left="0",this._canvas.style.width="100%",this._canvas.style.height="100%",this._canvas.style.pointerEvents="none",this._parentElement.appendChild(this._canvas),this._syncCanvasSize(),this._setupResizeObserver()}_syncCanvasSize(){if(!this._canvas||!this._videoElement||!this._ctx)return;const e=this._videoElement.videoWidth,t=this._videoElement.videoHeight,i=this._videoElement.clientWidth,s=this._videoElement.clientHeight;if(e>0&&t>0&&i>0&&s>0){const n=e/t;let r,o;n>i/s?(r=i,o=i/n):(r=s*n,o=s),this._canvas.style.width=`${r}px`,this._canvas.style.height=`${o}px`;const a=(i-r)/2,c=(s-o)/2;this._canvas.style.left=`${a}px`,this._canvas.style.top=`${c}px`,this._canvas.width=e,this._canvas.height=t}}_setupResizeObserver(){this._videoElement&&"undefined"!=typeof ResizeObserver&&(this._resizeObserver=new ResizeObserver(()=>{this._syncCanvasSize()}),this._resizeObserver.observe(this._videoElement))}startRenderingFromVideo(){!this._isRendering&&this._videoElement&&this._canvas&&this._ctx&&(this._isRendering=!0,this._renderLoop())}stopRenderingFromVideo(){this._isRendering=!1,null!==this._animationFrameId&&(cancelAnimationFrame(this._animationFrameId),this._animationFrameId=null)}setFitMode(e){this._canvas&&(this._canvas.style.width="100%",this._canvas.style.height="100%",this._canvas.style.objectFit=e)}render(e){if(this.ensureNotDisposed(),this._ctx&&this._canvas)try{const t=e.displayWidth,i=e.displayHeight;this._videoElement?this._syncCanvasSize():this._canvas.width===t&&this._canvas.height===i||(this._canvas.width=t,this._canvas.height=i);const s=e instanceof VideoFrame?e.displayWidth:e.videoWidth,n=e instanceof VideoFrame?e.displayHeight:e.videoHeight;s>0&&n>0&&(this._canvas.width===s&&this._canvas.height===n||(this._canvas.width=s,this._canvas.height=n)),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._ctx.drawImage(e,0,0,this._canvas.width,this._canvas.height)}catch(e){a.error("Error rendering video frame to canvas:",e)}}getCanvas(){return this._canvas}getContext(){return this._ctx}onDispose(){this.stopRenderingFromVideo(),this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._canvas&&this._parentElement&&this._canvas.parentElement===this._parentElement&&this._parentElement.removeChild(this._canvas),this._canvas=null,this._ctx=null,this._videoElement=null,this._parentElement=null,a.info("Canvas Renderer disposed")}}class I extends o{constructor(e){super(),this._element=null,this._stream=null,this._track=null,this._element=e,a.info("Video Element Renderer created")}setTrack(e){if(this.ensureNotDisposed(),this._track=e,!this._element)return void a.warn("No video element available to set track");this._stream||(this._stream=new MediaStream,this._element.srcObject=this._stream);const t=this._stream.getTracks();for(const i of t)if(i!==e)try{this._stream.removeTrack(i)}catch(e){a.error("Failed to remove track from media stream:",e)}if(!this._stream.getTracks().includes(e))try{this._stream.addTrack(e)}catch(e){a.error("Failed to add track to media stream:",e)}this._element.play().catch(e=>{a.error("Error playing video:",e)}),a.debug("Video track set to element (stream reused)")}setOpacity(e){this._element&&(this._element.style.opacity=String(e))}getElement(){return this._element}setFitMode(e){this._element&&(this._element.style.width="100%",this._element.style.height="100%",this._element.style.objectFit=e)}render(e){a.debug("Render called in direct mode (no-op)")}onDispose(){this._element&&(this._element.srcObject=null),this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._track&&(this._track.stop(),this._track=null),a.info("Video Element Renderer disposed")}clearTrack(){if(this._stream){const e=this._stream.getTracks();for(const t of e)try{this._stream.removeTrack(t)}catch(e){a.error("Failed to remove track from media stream:",e)}}this._track=null}}class y extends o{constructor(){super(...arguments),this._renderer=null,this._processors=[],this._videoElementRenderer=null,this._canvasRenderer=null,this._videoFrameCallbackId=null,this._animationFrameId=null,this._isProcessing=!1,this._processVideoFrame=()=>{if(!this._isProcessing||!this._videoElementRenderer||!this._canvasRenderer)return;const e=this._videoElementRenderer.getElement();if(!e||e.readyState<2)this._isProcessing&&e&&(this._videoFrameCallbackId=e.requestVideoFrameCallback(this._processVideoFrame));else{try{let t=new VideoFrame(e,{timestamp:1e3*performance.now()});for(const e of this._processors){const i=e.process(t);i&&i!==t&&(t instanceof VideoFrame&&t.close(),t=i)}t instanceof ImageData?this._renderImageData(t):this._canvasRenderer.render(t),t instanceof VideoFrame&&t.close()}catch(e){a.error("Error processing video frame:",e)}this._isProcessing&&e&&(this._videoFrameCallbackId=e.requestVideoFrameCallback(this._processVideoFrame))}},this._processVideoFrameFallback=()=>{if(!this._isProcessing||!this._canvasRenderer||!this._videoElementRenderer)return;const e=this._videoElementRenderer.getElement();if(!e||e.readyState<2||e.paused){const e=this._canvasRenderer.getContext(),t=this._canvasRenderer.getCanvas();return e&&t&&e.clearRect(0,0,t.width,t.height),void(this._animationFrameId=requestAnimationFrame(this._processVideoFrameFallback))}const t=e.videoWidth,i=e.videoHeight,s=this._canvasRenderer.getCanvas();t>0&&s&&(s.width!==t||s.height!==i)&&(s.width=t,s.height=i);let n=new VideoFrame(e);try{for(const e of this._processors){const t=e.process(n);t&&t!==n&&(n instanceof VideoFrame&&n.close(),n=t)}n instanceof ImageData?this._renderImageData(n):this._canvasRenderer.render(n)}finally{n instanceof VideoFrame&&n.close()}this._isProcessing&&(this._animationFrameId=requestAnimationFrame(this._processVideoFrameFallback))}}getRenderer(){return this._renderer}setRenderer(e){if(this._renderer&&this._renderer.dispose(),this._renderer=e,e instanceof I){if(this._videoElementRenderer=e,!this._canvasRenderer){const e=this._videoElementRenderer.getElement();if(e)try{e.parentElement&&(this._canvasRenderer=new R(void 0,e),this._renderer=this._canvasRenderer,a.debug("Canvas renderer created in setRenderer (processed mode)"))}catch(e){a.warn("Failed to create CanvasRenderer in setRenderer, will retry in attachToContainer:",e)}}this._setupProcessingPipeline()}else this._videoElementRenderer=null,this._stopProcessingPipeline();a.debug("Processed render strategy renderer set")}addProcessor(e,t){void 0!==t&&t>=0&&t<this._processors.length?this._processors.splice(t,0,e):this._processors.push(e),this._setupProcessingPipeline()}getProcessors(){return this._processors}setProcessors(e){this._processors.forEach(e=>e.dispose()),this._processors=e,this._setupProcessingPipeline(),a.debug("Processed render strategy processor set")}attachToContainer(e){if(this._canvasRenderer){const t=this._canvasRenderer.getCanvas();if(t&&(t.parentElement&&t.parentElement!==e&&t.parentElement.removeChild(t),t.parentElement!==e&&(e.appendChild(t),a.debug("Canvas element attached to container in processed mode"))),this._videoElementRenderer){const e=this._videoElementRenderer.getElement();e&&(e.parentElement&&e.parentElement.removeChild(e),e.style.display="none")}}else if(this._videoElementRenderer){const t=this._videoElementRenderer.getElement();if(t){const i=null!==t.parentElement;i||e.appendChild(t);try{this._canvasRenderer=new R(void 0,t),this._renderer=this._canvasRenderer,i||t.parentElement!==e||e.removeChild(t),t.style.display="none";const s=this._canvasRenderer.getCanvas();s&&s.parentElement!==e&&e.appendChild(s),this._startProcessingLoop(),a.debug("Canvas created and attached to container in processed mode")}catch(s){a.error("Failed to create CanvasRenderer in attachToContainer:",s),i||t.parentElement!==e||e.removeChild(t),t.parentElement!==e&&(e.appendChild(t),t.style.display="")}}}}_setupProcessingPipeline(){if(!this._videoElementRenderer)return;const e=this._videoElementRenderer.getElement();if(e){if(e.parentElement&&e.parentElement.removeChild(e),e.style.display="none",e.readyState<2){const t=()=>{this._setupProcessingPipeline(),e.removeEventListener("loadedmetadata",t)};return void e.addEventListener("loadedmetadata",t)}this._canvasRenderer&&(this._startProcessingLoop(),a.info("Processing pipeline setup completed"))}else a.warn("Video element not available for processing")}_stopProcessingPipeline(){this._stopProcessingLoop(),this._canvasRenderer&&(this._canvasRenderer.dispose(),this._canvasRenderer=null),this._videoElementRenderer&&(this._renderer=this._videoElementRenderer)}_startProcessingLoop(){if(this._isProcessing||!this._videoElementRenderer||!this._canvasRenderer)return;this._videoElementRenderer.getElement()&&(this._isProcessing=!0,"requestVideoFrameCallback"in HTMLVideoElement.prototype?this._processVideoFrame():this._processVideoFrameFallback())}_stopProcessingLoop(){this._isProcessing=!1;const e=this._videoElementRenderer?.getElement();null!==this._videoFrameCallbackId&&e&&"cancelVideoFrameCallback"in e&&(e.cancelVideoFrameCallback(this._videoFrameCallbackId),this._videoFrameCallbackId=null),null!==this._animationFrameId&&(cancelAnimationFrame(this._animationFrameId),this._animationFrameId=null)}_renderImageData(e){if(!this._canvasRenderer)return;const t=this._canvasRenderer.getContext(),i=this._canvasRenderer.getCanvas();t&&i&&(i.width===e.width&&i.height===e.height||(i.width=e.width,i.height=e.height),t.clearRect(0,0,i.width,i.height),t.putImageData(e,0,0))}onDispose(){this._stopProcessingPipeline(),this._renderer&&(this._renderer.dispose(),this._renderer=null),this._processors.forEach(e=>e.dispose()),this._processors=[],this._videoElementRenderer=null,this._canvasRenderer=null,a.info("Processed Render Strategy disposed")}}class b{create(){return new y}}class k{static getFactory(e){return"processed"===e?new b:new D}}class w extends o{constructor(e,t){super(),this._videoElementRenderer=null,this._containerElement=null,this._source=e;const i=t?.renderMode||"raw";this._containerElement=t?.containerElement||null,this._strategyFactory=k.getFactory(i),this._strategy=this._strategyFactory.create();const s=this._source.getInternalElement(),n=new I(s);this._videoElementRenderer=n,this._strategy.setRenderer(n),this._containerElement&&(this._strategy.attachToContainer(this._containerElement),a.info("Renderer elements attached to container via strategy")),a.info("Video Pipeline created")}setRenderMode(e){this.ensureNotDisposed();const t=k.getFactory(e);if(this._strategyFactory.constructor===t.constructor)return;const i=this._strategy.getRenderer(),s=this._strategy.getProcessors();this._strategy.dispose(),this._strategyFactory=t,this._strategy=this._strategyFactory.create(),i&&this._strategy.setRenderer(i),s.length>0&&this._strategy.setProcessors(s),this._containerElement&&this._strategy.attachToContainer(this._containerElement),a.info(`Video render mode changed to: ${e}`)}setRenderFitMode(e){this.ensureNotDisposed();const t=this._strategy.getRenderer();t?.setFitMode(e),a.info(`Video render fit mode changed to: ${e}`)}setProcessor(e){this.ensureNotDisposed(),this._strategy.setProcessors(e?[e]:[])}setRenderer(e){this.ensureNotDisposed(),this._strategy.setRenderer(e)}get strategy(){return this._strategy}get videoElementRenderer(){return this._videoElementRenderer}onDispose(){if(this._strategy.dispose(),this._videoElementRenderer){const e=this._videoElementRenderer.getElement();e&&e.parentElement&&e.parentElement.removeChild(e),this._videoElementRenderer.dispose(),this._videoElementRenderer=null}a.info("Video Pipeline disposed")}}class N extends o{onDispose(){}}class x extends N{constructor(e){super(),this._program=null,this._texture=null,this._lastProcessedTimestamp=null,this._options=e,this._canvas=document.createElement("canvas");const t=this._canvas.getContext("webgl",{premultipliedAlpha:!1,preserveDrawingBuffer:!0});if(!t)throw new Error("WebGL not supported");this._gl=t,this._initGL(),a.info("WebGL Green Screen Processor initialized")}_initGL(){const e=this._gl;this._program=this._createProgram("\n attribute vec2 aPosition;\n attribute vec2 aTexCoord;\n varying vec2 vTexCoord;\n void main() {\n gl_Position = vec4(aPosition, 0, 1);\n vTexCoord = aTexCoord;\n }","\n precision mediump float;\n varying vec2 vTexCoord;\n uniform sampler2D uSampler;\n uniform vec3 uChromaKey; // greenScreen target color: RGB\n uniform float uSimilarity; // greenScreen similarity\n uniform float uSmoothness; // greenScreen smoothness\n uniform float uSpill; // greenScreen despill strength\n\n // convert RGB to YCbCr space, separate luminance and chrominance\n vec3 rgbToYcbcr(vec3 rgb) {\n float y = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b;\n float cb = 0.564 * (rgb.b - y) + 0.5;\n float cr = 0.713 * (rgb.r - y) + 0.5;\n return vec3(y, cb, cr);\n }\n\n void main() {\n vec4 color = texture2D(uSampler, vTexCoord);\n vec3 rgb = color.rgb;\n \n vec3 ycbcr = rgbToYcbcr(rgb);\n vec3 targetYcbcr = rgbToYcbcr(uChromaKey);\n \n // 核心改进:只计算 Cb 和 Cr 的欧式距离,忽略亮度 Y\n // 这能确保深色褶皱(Y低)因为 Cb/Cr 不变而不被扣除\n float dist = distance(ycbcr.yz, targetYcbcr.yz);\n \n // 使用 smoothstep 生成丝滑边缘\n float alpha = smoothstep(uSimilarity, uSimilarity + uSmoothness, dist);\n alpha = pow(alpha, 1.2);\n\n // 增强型 Despill (去溢出)\n float maxRB = max(rgb.r, rgb.b);\n if (rgb.g > maxRB) {\n float edgeFactor = 1.0 - alpha; // 边缘像素更强去绿\n float diff = (rgb.g - maxRB) * uSpill * edgeFactor;\n rgb.g -= diff;\n rgb.rb += diff * 0.15;\n }\n\n // rgb = mix(vec3(dot(rgb, vec3(0.333))), rgb, alpha);\n float luma = dot(rgb, vec3(0.299, 0.587, 0.114));\n rgb = mix(vec3(luma), rgb, alpha);\n\n gl_FragColor = vec4(rgb, alpha * color.a);\n }\n "),this._texture=e.createTexture();const t=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,1,1,1,0]),i=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,i),e.bufferData(e.ARRAY_BUFFER,t,e.STATIC_DRAW);const s=e.getAttribLocation(this._program,"aPosition"),n=e.getAttribLocation(this._program,"aTexCoord");e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,16,0),e.enableVertexAttribArray(n),e.vertexAttribPointer(n,2,e.FLOAT,!1,16,8)}process(e){if(!this._options.enabled)return e;const{displayWidth:t,displayHeight:i,timestamp:s}=e;this._canvas.width===t&&this._canvas.height===i||(this._canvas.width=t,this._canvas.height=i,this._gl.viewport(0,0,t,i));const n=this._gl;n.useProgram(this._program),n.activeTexture(n.TEXTURE0),n.bindTexture(n.TEXTURE_2D,this._texture),n.texImage2D(n.TEXTURE_2D,0,n.RGBA,n.RGBA,n.UNSIGNED_BYTE,e),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR);const r=this._options.chromaKey||[0,255,0];n.uniform3f(n.getUniformLocation(this._program,"uChromaKey"),r[0]/255,r[1]/255,r[2]/255),n.uniform1f(n.getUniformLocation(this._program,"uSimilarity"),this._options.similarity??.3),n.uniform1f(n.getUniformLocation(this._program,"uSmoothness"),this._options.smoothness??.25),n.uniform1f(n.getUniformLocation(this._program,"uSpill"),this._options.despillStrength??1.15),n.drawArrays(n.TRIANGLE_STRIP,0,4);const o=new VideoFrame(this._canvas,{timestamp:s,duration:e.duration??void 0});return e.close(),o}_createProgram(e,t){const i=this._gl,s=(e,t)=>{const s=i.createShader(e);return i.shaderSource(s,t),i.compileShader(s),s},n=i.createProgram();return i.attachShader(n,s(i.VERTEX_SHADER,e)),i.attachShader(n,s(i.FRAGMENT_SHADER,t)),i.linkProgram(n),n}onDispose(){const e=this._gl;this._texture&&e.deleteTexture(this._texture),this._program&&e.deleteProgram(this._program),a.info("WebGL Green Screen Processor disposed")}updateOptions(e){this._options={...this._options,...e}}}class L extends v{constructor(e){if(super(),this._source=new S,this._pipeline=new w(this._source,e),"processed"===e?.renderMode&&e?.greenScreen?.enabled){const t=new x(e.greenScreen);this._pipeline.setProcessor(t),a.info("Green screen processor enabled")}this._pipeline.setRenderFitMode(e?.fitMode||"contain"),a.info("Video Controller created")}setTrack(e,t,i){this.ensureNotDisposed(),this._source.setTrack(e,t,i)}removeTrack(e){this.ensureNotDisposed(),this._source.trackId===e&&this._source.clearTrack()}setRenderMode(e){this.ensureNotDisposed(),this._pipeline.setRenderMode(e),this._context.eventBus.emit("inner:video:render:mode:changed",{mode:e})}setRenderFitMode(e){this.ensureNotDisposed(),this._pipeline.setRenderFitMode(e)}getSource(){return this.ensureNotDisposed(),this._source}onDispose(){this._source.dispose(),this._pipeline.dispose(),a.info("Video Controller disposed")}}class O extends o{process(e,t){return this.ensureNotDisposed(),e}onDispose(){}}class P extends o{set onProcessedAudio(e){this._onProcessedAudio=e}constructor(e){super(),this._processors=[],this._processingStrategy=new O,a.info("Input Audio Pipeline created")}setProcessingStrategy(e){this.ensureNotDisposed(),this._processingStrategy&&this._processingStrategy.dispose(),this._processingStrategy=e,a.debug("Audio processing strategy set")}get processingStrategy(){return this._processingStrategy}addProcessor(e){this.ensureNotDisposed(),this._processors.push(e),a.debug(`Audio processor added. Total: ${this._processors.length}`)}removeProcessor(e){this.ensureNotDisposed();const t=this._processors.indexOf(e);t>=0&&(this._processors.splice(t,1),a.debug(`Audio processor removed. Total: ${this._processors.length}`))}process(e,t){this.ensureNotDisposed();let i=e;try{i=this._processingStrategy.process(i,t)}catch(e){a.error("Error in audio processing strategy:",e)}for(const e of this._processors)try{i=e.process(i,t)}catch(e){a.error("Error in audio processor:",e);continue}this._onProcessedAudio&&this._onProcessedAudio(i,t)}onDispose(){if(this._processingStrategy)try{this._processingStrategy.dispose()}catch(e){a.error("Error disposing audio processing strategy:",e)}this._processors.forEach(e=>{try{e.dispose()}catch(e){a.error("Error disposing audio processor:",e)}}),this._processors.length=0,this._onProcessedAudio=void 0,a.info("Input Audio Pipeline disposed")}}class F extends o{constructor(){super(),this._audioElement=null,this._stream=null,this._track=null,this._volume=1,this._isMuted=!1,this._audioElement=document.createElement("audio"),this._audioElement.autoplay=!0,this._audioElement.volume=this._volume,this._audioElement.muted=this._isMuted,a.info("Output Audio Pipeline created")}getAudioElement(){if(!this._audioElement)throw new r(i.SDK_ERROR,"Audio element not found");return this._audioElement}setTrack(e){this.ensureNotDisposed(),this._track&&this._track!==e&&this._track.stop(),this._track=e,this._audioElement&&(this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._stream=new MediaStream([e]),this._audioElement.volume=this._volume,this._audioElement.muted=this._isMuted,a.debug("Audio track set to output pipeline"))}removeTrack(){this.ensureNotDisposed(),this._audioElement&&(this._audioElement.srcObject=null),this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._track&&(this._track.stop(),this._track=null),a.debug("Audio track removed from output pipeline")}setVolume(e){this.ensureNotDisposed(),this._volume=Math.max(0,Math.min(1,e)),this._audioElement&&(this._audioElement.volume=this._volume),a.debug(`Audio output volume set to: ${this._volume}`)}getVolume(){return this._volume}mute(){this.ensureNotDisposed(),this._isMuted=!0,this._audioElement&&(this._audioElement.muted=!0),a.debug("Audio output muted")}unmute(){this.ensureNotDisposed(),this._isMuted=!1,this._audioElement&&(this._audioElement.muted=!1),a.debug("Audio output unmuted")}isMuted(){return this._isMuted}onDispose(){if(this.removeTrack(),this._audioElement){try{this._audioElement.pause(),this._audioElement.srcObject=null}catch{}this._audioElement=null}a.info("Output Audio Pipeline disposed")}}class M extends o{emitAudioData(e,t){if(this.onAudioData)try{this.onAudioData(e,t)}catch(e){a.error("Error in audio data callback:",e)}}}class V extends M{constructor(e){super(),this.options=e,this._stream=null,this._audioContext=null,this._sourceNode=null,this._workletNode=null,this._targetSampleRate=l,this._bitDepth=16,this._channels=1;const t=e?.input;this._targetSampleRate=t?.sampleRate||l,this._bitDepth=t?.bitDepth||16,this._channels=t?.channels||1}async start(){this.ensureNotDisposed(),(this._stream||this._audioContext||this._sourceNode||this._workletNode)&&this.stop();try{const e=this.options?.input,t={audio:e?.constraints?e.constraints:{channelCount:this._channels}};this._stream=await navigator.mediaDevices.getUserMedia(t);const i=this._stream.getAudioTracks()[0],s=i.getSettings().sampleRate||44100;this._audioContext=new AudioContext({sampleRate:s});const n=function(){const e=new Blob(["\nclass AudioResamplerProcessor extends AudioWorkletProcessor {\n constructor(options) {\n super();\n this.targetSampleRate = options.processorOptions?.targetSampleRate || 24000;\n this.bitDepth = options.processorOptions?.bitDepth || 16;\n this.channels = options.processorOptions?.channels || 1;\n \n // Resampling related\n // sampleRate is a global in AudioWorkletProcessor representing the AudioContext's sample rate\n this.resampleRatio = this.targetSampleRate / sampleRate;\n \n // Timestamp tracking\n this.frameCount = 0;\n }\n\n process(inputs, outputs, parameters) {\n const input = inputs[0];\n if (!input || input.length === 0 || !input[0] || input[0].length === 0) {\n return true;\n }\n\n const inputData = input[0]; // mono input\n const inputLength = inputData.length;\n \n // Linear resampling\n const outputLength = Math.floor(inputLength * this.resampleRatio);\n const resampledData = new Float32Array(outputLength);\n \n for (let i = 0; i < outputLength; i++) {\n const srcIndex = i / this.resampleRatio;\n const srcIndexFloor = Math.floor(srcIndex);\n const srcIndexCeil = Math.min(srcIndexFloor + 1, inputLength - 1);\n const fraction = srcIndex - srcIndexFloor;\n \n // Linear interpolation\n resampledData[i] = inputData[srcIndexFloor] * (1 - fraction) + inputData[srcIndexCeil] * fraction;\n }\n \n // Post the resampled data\n this.port.postMessage({\n type: 'audioData',\n data: resampledData,\n sampleRate: this.targetSampleRate,\n bitDepth: this.bitDepth,\n frameCount: this.frameCount,\n });\n \n this.frameCount += outputLength;\n \n return true;\n }\n}\n\nregisterProcessor('audio-resampler', AudioResamplerProcessor);\n"],{type:"text/javascript"});return URL.createObjectURL(e)}();await this._audioContext.audioWorklet.addModule(n),this._sourceNode=this._audioContext.createMediaStreamSource(this._stream),this._workletNode=new AudioWorkletNode(this._audioContext,"audio-resampler",{processorOptions:{targetSampleRate:this._targetSampleRate,bitDepth:this._bitDepth,channels:this._channels},numberOfInputs:1,numberOfOutputs:0}),this._workletNode.port.onmessage=e=>{const{type:t,data:i,sampleRate:s}=e.data;"audioData"===t&&i&&this.emitAudioData(i,s)},this._sourceNode.connect(this._workletNode),a.info(`Audio capture started: input=${s}Hz -> output=${this._targetSampleRate}Hz, ${this._bitDepth}bit`)}catch(e){throw r.fromError(e,i.AUDIO_CAPTURE_FAILED)}}stop(){this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._workletNode&&(this._workletNode.port.onmessage=null,this._workletNode.disconnect(),this._workletNode=null),this._sourceNode&&(this._sourceNode.disconnect(),this._sourceNode=null),this._audioContext&&(this._audioContext.close(),this._audioContext=null),a.info("Audio capture stopped")}onDispose(){this.stop()}}class K{create(e){return new V(e)}}class U extends v{constructor(e,t){super(),this._source=null,this._isWsCapturing=!1,this._currentOutputTrackId=null,this._inputPipeline=new P(e),this._outputPipeline=new F,this._sourceFactory=t||new K,a.info("Audio Controller created")}setContext(e){super.setContext(e),this._wireLocalInputToEventBus()}_wireLocalInputToEventBus(){this._inputPipeline.onProcessedAudio=(e,t)=>{this._context.eventBus.emit("inner:audio:frame:received",{data:e,sampleRate:t})}}async startWsCapture(){if(this.ensureNotDisposed(),this._isWsCapturing)a.warn("Audio capture already started");else{if(!this._context.mediaAudioCaptureState.tryBegin("ws"))throw new r(i.SDK_INVALID_STATE_TRANSITION,"RTC audio capture is active");try{this._source||(this._source=this._sourceFactory.create(this._context.options.audio),this._source.onAudioData=(e,t)=>{this._inputPipeline.process(e,t)}),await this._source.start(),this._isWsCapturing=!0,this._context.eventBus.emit("inner:audio:input:started",void 0),a.info("Audio capture started (ws)")}catch(e){throw this._context.mediaAudioCaptureState.end("ws"),this._context.emitError(e,i.AUDIO_CAPTURE_START_FAILED)}}}stopWsCapture(){this.ensureNotDisposed(),this._isWsCapturing&&(this._source&&this._source.stop(),this._isWsCapturing=!1,this._context.mediaAudioCaptureState.end("ws"),this._context.eventBus.emit("inner:audio:input:stopped",void 0),a.info("Audio capture stopped (ws)"))}get isWsCapturing(){return this._isWsCapturing}setOutputTrack(e,t,i){this.ensureNotDisposed(),this._outputPipeline.setTrack(e),this._currentOutputTrackId=t,this._context.eventBus.emit("inner:audio:track:added",{trackId:t,participantId:i}),a.info("Audio output track ready")}removeOutputTrack(e){this.ensureNotDisposed(),this._currentOutputTrackId===e&&(this._outputPipeline.removeTrack(),this._currentOutputTrackId=null,this._context.eventBus.emit("inner:audio:track:removed",{trackId:e}),a.info("Audio output track removed"))}setVolume(e){this.ensureNotDisposed(),this._outputPipeline.setVolume(e),this._context.eventBus.emit("inner:audio:volume:changed",{volume:e}),a.debug(`Audio volume set to: ${e}`)}getVolume(){return this._outputPipeline.getVolume()}mute(){this.ensureNotDisposed(),this._outputPipeline.mute(),this._context.eventBus.emit("inner:audio:muted",void 0),a.debug("Audio muted")}unmute(){this.ensureNotDisposed(),this._outputPipeline.unmute(),this._context.eventBus.emit("inner:audio:unmuted",void 0),a.debug("Audio unmuted")}getOutputElement(){return this._outputPipeline.getAudioElement()}isMuted(){return this._outputPipeline.isMuted()}onDispose(){this.stopWsCapture(),this._source&&(this._source.dispose(),this._source=null),this._inputPipeline.dispose(),this._outputPipeline.dispose(),a.info("Audio Controller disposed")}}class B extends o{constructor(){super(...arguments),this._stream=null,this._videoElement=null}async start(){if(this.ensureNotDisposed(),this._stream)a.warn("Camera capture already started");else try{const e=await navigator.mediaDevices.getUserMedia({video:!0});if(this._stream=e,!this._videoElement){const e=document.createElement("video");e.autoplay=!0,e.muted=!0,e.playsInline=!0,e.style.position="fixed",e.style.opacity="0",e.style.pointerEvents="none",e.style.width="0",e.style.height="0",e.style.zIndex="-1","undefined"!=typeof document&&document.body&&document.body.appendChild(e),this._videoElement=e}this._videoElement.srcObject=this._stream,this._videoElement.play().catch(e=>{a.error("Failed to start camera video playback",e)})}catch(e){throw r.fromError(e,i.SDK_ERROR)}}stop(){if(this._stream&&(this._stream.getTracks().forEach(e=>e.stop()),this._stream=null),this._videoElement){this._videoElement.srcObject=null;const e=this._videoElement.parentNode;e&&e.removeChild(this._videoElement),this._videoElement=null}a.info("Camera capture stopped")}getStream(){return this.ensureNotDisposed(),this._stream}getVideoElement(){return this.ensureNotDisposed(),this._videoElement}getTrack(){if(this.ensureNotDisposed(),!this._stream)return null;const e=this._stream.getVideoTracks();return e.length>0?e[0]:null}onDispose(){this.stop()}}const q=640,H=360;class $ extends o{constructor(e,t){super(),this._videoElement=null,this._canvas=null,this._videoElement=e,this._onFrame=t,this._handleServerCommand=this._onServerCommand.bind(this)}setContext(e){this._context=e}setVideoElement(e){this._videoElement=e}start(){this.ensureNotDisposed(),this._canvas||("undefined"!=typeof OffscreenCanvas?this._canvas=new OffscreenCanvas(q,H):(this._canvas=document.createElement("canvas"),this._canvas.width=q,this._canvas.height=H)),this._context.eventBus.on("inner:conversation:server:command",this._handleServerCommand)}_onServerCommand({code:e}){500===e&&this._captureFrame()}stop(){this._context.eventBus.off("inner:conversation:server:command",this._handleServerCommand)}_captureFrame(){const e=this._videoElement,t=this._canvas;if(!e||!t)return;if(e.readyState<2||0===e.videoWidth||0===e.videoHeight)return;const i=t.getContext("2d");if(!i)return;const s=e.videoWidth,n=e.videoHeight;let r=q,o=q*n/s;o>H&&(o=H,r=H*s/n),t.width!==r&&(t.width=r),t.height!==o&&(t.height=o),i.clearRect(0,0,t.width,t.height),i.drawImage(e,0,0,s,n,0,0,r,o),"undefined"!=typeof OffscreenCanvas&&t instanceof OffscreenCanvas&&"function"==typeof t.convertToBlob?t.convertToBlob({type:"image/jpeg",quality:u}).then(e=>{if(e)try{this._onFrame(e,r,o,0,u)}catch(e){a.error("ScreenshotScheduler onFrame callback error",e)}}).catch(e=>{a.error("ScreenshotScheduler convertToBlob error",e)}):t instanceof HTMLCanvasElement&&t.toBlob(e=>{if(e)try{this._onFrame(e,r,o,0,u)}catch(e){a.error("ScreenshotScheduler onFrame callback error",e)}},"image/jpeg",u)}onDispose(){this.stop(),this._canvas=null,this._videoElement=null}}const G=4294967295;function W(e){const t=Math.floor(e);return t<0?0:t>65535?65535:t}function z(e){const t=new ArrayBuffer(12),i=new DataView(t),s=128|15&function(e){const t=Math.floor(e);return t<0?0:t>4?4:t}(e.format);return i.setUint8(0,s),i.setUint8(1,function(e){const t=Math.floor(e);return t<0?0:t>255?255:t}(e.quality)),i.setUint16(2,W(e.id),!1),i.setUint16(4,W(e.width),!1),i.setUint16(6,W(e.height),!1),i.setUint32(8,function(e){const t=Math.floor(e);return t<0?0:t>G?G:t}(e.payloadLength),!1),new Uint8Array(t)}class j extends o{constructor(){super(...arguments),this._wsSender=null,this._imageId=0}send(e,t){if(this.ensureNotDisposed(),!this._wsSender||!this._wsSender.isConnected())return;const i=e.byteLength,s=z({format:t.format,quality:t.quality,id:this._nextId(),width:t.width,height:t.height,payloadLength:i}),n=new Uint8Array(s.byteLength+i);n.set(s,0),n.set(e,s.byteLength),this._wsSender.sendBinary(n)}_nextId(){const e=this._imageId;return this._imageId=this._imageId>=65535?0:this._imageId+1,e}onDispose(){this._wsSender=null}}class Q extends v{constructor(){super(),this._isRunning=!1,this._source=new B,this._sender=new j;this._scheduler=new $(null,(e,t,i,s,n=.7)=>{(async function(e,t){const i=await e.arrayBuffer();return{data:new Uint8Array(i),width:t.width,height:t.height,format:t.format,quality:t.quality}})(e,{width:t,height:i,format:s,quality:n}).then(e=>{this._sender.send(e.data,{width:e.width,height:e.height,format:e.format,quality:e.quality})})})}setContext(e){super.setContext(e),this._scheduler.setContext(e)}async startCamera(){if(this.ensureNotDisposed(),this._isRunning)return void a.warn("Camera already running");await this._source.start();const e=this._source.getVideoElement();this._scheduler.setVideoElement(e),this._scheduler.start(),this._isRunning=!0,this._context.eventBus.emit("inner:camera:started",void 0),a.info("Camera started")}stopCamera(){this.ensureNotDisposed(),this._isRunning&&(this._scheduler.stop(),this._source.stop(),this._isRunning=!1,this._context.eventBus.emit("inner:camera:stopped",void 0),a.info("Camera stopped"))}isCameraRunning(){return this._isRunning}getStream(){return this.ensureNotDisposed(),this._source.getStream()}getTrack(){return this.ensureNotDisposed(),this._source.getTrack()}attachTo(e){this.ensureNotDisposed();const t=this._source.getStream();t&&(e.srcObject=t,e.play().catch(e=>a.error("attachTo play failed",e)))}onDispose(){this.stopCamera(),this._source.dispose(),this._scheduler.dispose(),this._sender.dispose()}}var Y;e.ConversationStateType=void 0,(Y=e.ConversationStateType||(e.ConversationStateType={})).IDLE="idle",Y.WAITING="waiting",Y.STREAMING="streaming",Y.COMPLETED="completed",Y.ERROR="error";class X extends f{constructor(){super(...arguments),this._currentState=e.ConversationStateType.IDLE,this.transitionTable=[{from:e.ConversationStateType.IDLE,to:[e.ConversationStateType.WAITING,e.ConversationStateType.ERROR]},{from:e.ConversationStateType.WAITING,to:[e.ConversationStateType.STREAMING,e.ConversationStateType.ERROR]},{from:e.ConversationStateType.STREAMING,to:[e.ConversationStateType.COMPLETED,e.ConversationStateType.ERROR]},{from:e.ConversationStateType.COMPLETED,to:[e.ConversationStateType.IDLE,e.ConversationStateType.WAITING,e.ConversationStateType.ERROR]},{from:e.ConversationStateType.ERROR,to:[e.ConversationStateType.IDLE]}]}reset(){this._currentState=e.ConversationStateType.IDLE}}class J extends o{constructor(e){super(),this._currentQuestion=null,this._currentAnswer=null,this._sessionId=e,this._stateMachine=new X,a.info(`Conversation session created: ${e}`)}get sessionId(){return this._sessionId}get state(){return this._stateMachine.getCurrentState()}_setQuestion(t){this._currentQuestion=t,this._stateMachine.transitionTo(e.ConversationStateType.WAITING),this._syncContextState()}get currentQuestion(){return this._currentQuestion}_startAnswer(t){this._currentAnswer={questionId:t,text:"",isComplete:!1,timestamp:Date.now()},this._stateMachine.transitionTo(e.ConversationStateType.STREAMING),this._syncContextState()}_appendAnswerChunk(e){this._currentAnswer&&(this._currentAnswer.text+=e)}_completeAnswer(){this._currentAnswer&&(this._currentAnswer.isComplete=!0,this._currentAnswer.completedAt=Date.now()),this._stateMachine.transitionTo(e.ConversationStateType.COMPLETED),this._syncContextState()}get currentAnswer(){return this._currentAnswer}_setError(t){this._stateMachine.transitionTo(e.ConversationStateType.ERROR),this._syncContextState()}_syncContextState(){}handleEvent(t){const i=this._stateMachine.getCurrentState();switch(t.type){case"QUESTION":if(i!==e.ConversationStateType.IDLE&&i!==e.ConversationStateType.COMPLETED)return void a.warn(`Ignoring QUESTION event in invalid state: ${i}`);this._setQuestion(t.payload);break;case"ANSWER_START":if(i!==e.ConversationStateType.WAITING)return void a.warn(`Ignoring ANSWER_START event in invalid state: ${i}. Expected: WAITING`);this._startAnswer(t.payload);break;case"ANSWER_CHUNK":if(i!==e.ConversationStateType.STREAMING)return void a.warn(`Ignoring ANSWER_CHUNK event in invalid state: ${i}. Expected: STREAMING`);this._appendAnswerChunk(t.payload&&t.payload.chunk||""),t.payload&&t.payload.isComplete&&this._completeAnswer();break;case"ANSWER_COMPLETE":if(i!==e.ConversationStateType.STREAMING)return void a.warn(`Ignoring ANSWER_COMPLETE event in invalid state: ${i}. Expected: STREAMING`);this._completeAnswer();break;case"ERROR":this._setError(t.payload);break;default:a.warn(`Unknown event type: ${t.type}`)}}reset(){this._stateMachine.reset(),this._currentQuestion=null,this._currentAnswer=null}onDispose(){this.reset(),a.info(`Conversation session disposed: ${this._sessionId}`)}}class Z extends o{constructor(){super(...arguments),this._buffers=new Map}appendChunk(e,t){this.ensureNotDisposed();const i=(this._buffers.get(e)||"")+t;return this._buffers.set(e,i),a.debug(`Message chunk appended for question ${e}, length: ${i.length}`),i}getMessage(e){return this._buffers.get(e)||null}complete(e){const t=this.getMessage(e)||"";return this._buffers.delete(e),a.debug(`Message assembly completed for question ${e}, length: ${t.length}`),t}clear(e){this._buffers.delete(e)}onDispose(){this._buffers.clear(),a.info("Message Assembler disposed")}}class ee{generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}generateQuestionId(){return Math.random().toString(36).substring(2,6)}}class te extends v{constructor(e){super(),this._rtcTextSender=null,this._sessions=new Map,this._assembler=new Z,this._idService=new ee,a.info("Conversation Manager created")}setRtcTextSender(e){this._rtcTextSender=e}async sendQuestion(e,t={speed:100,mood:0,vol:50}){this.ensureNotDisposed();const i=this._idService.generateQuestionId(),s={id:i,text:e,timestamp:Date.now(),inputMode:"text"},n=this._idService.generateSessionId(),r=new J(n);return r.handleEvent({type:"QUESTION",payload:s}),this._sessions.set(i,r),await this._dispatchServerTextUplink(i,e,t,r),this._context.eventBus.emit("inner:conversation:question:sent",{questionId:i,text:e}),this._context.eventBus.emit("inner:conversation:answer:waiting",{questionId:i}),a.info(`Question sent: ${i}`),i}async sendSystemEvent(e,t){if(this.ensureNotDisposed(),this._rtcTextSender)try{await this._rtcTextSender.sendSystemEvent(e,t)}catch(e){a.error("Error sending video avaliable state:",e)}}async _dispatchServerTextUplink(e,t,s,n){if(this._rtcTextSender)try{await this._rtcTextSender.sendTextData(e,t,"input.text",s)}catch(e){throw a.error("Error sending question via RTC:",e),n.handleEvent({type:"ERROR",payload:"Failed to send question"}),this._context.eventBus.emit("inner:sdk:error",{error:r.fromError(e,i.LIVEKIT_SEND_TEXT_DATA_FAILED)}),e}else a.warn("RTC text sender not set, question not sent")}handleServerPong(){this.ensureNotDisposed()}willDisconnect(){this.ensureNotDisposed()}handleAnswerChunk(t,i,s){this.ensureNotDisposed();const n=this._sessions.get(t);if(!n)return void a.warn(`No active session for answer chunk: ${t}`);if(n.state===e.ConversationStateType.WAITING&&n.handleEvent({type:"ANSWER_START",payload:t}),s){n.handleEvent({type:"ANSWER_COMPLETE"});const e=this._assembler.complete(t);this._context.eventBus.emit("inner:conversation:answer:completed",{questionId:t,fullAnswer:e});try{n.dispose()}catch(e){a.error("Error disposing session:",e)}this._sessions.delete(t)}else n.handleEvent({type:"ANSWER_CHUNK",payload:{uid:t,chunk:i,isComplete:s}}),this._assembler.appendChunk(t,i),this._context.eventBus.emit("inner:conversation:answer:chunk",{questionId:t,chunk:i,isComplete:s})}handleServerInitiatedMessage(e,t){this.ensureNotDisposed();const i=e??this._idService.generateQuestionId();this._context.eventBus.emit("inner:conversation:server:message",{questionId:i,message:t,type:"text"})}handleAsrTextReceived(e,t,i,s){this.ensureNotDisposed();const n=this._idService.generateSessionId(),r=new J(n);r.handleEvent({type:"QUESTION",payload:{id:e,text:t,timestamp:Date.now(),inputMode:"voice"}}),this._sessions.set(e,r),i?this._context.eventBus.emit("inner:conversation:asr:chunk",{questionId:e,text:t,isComplete:s??!1}):this._context.eventBus.emit("inner:conversation:asr:received",{questionId:e,text:t})}handleServerCommand(e,t){this.ensureNotDisposed(),this._context.eventBus.emit("inner:conversation:server:command",{code:e,command:t})}onDispose(){for(const e of this._sessions.values())try{e.dispose()}catch(e){a.error("Error disposing session:",e)}this._sessions.clear(),this._assembler.dispose(),a.info("Conversation Manager disposed")}}class ie extends v{constructor(e){super(),this._eventUnsubscribers=[],this._manager=new te(e),a.info("Conversation Controller created")}setContext(e){super.setContext(e),this._manager.setContext(e),this._bindEventBus()}get manager(){return this._manager}setRtcTextSender(e){this._manager.setRtcTextSender(e)}async sendQuestion(e,t){return this.ensureNotDisposed(),this._manager.sendQuestion(e,t)}async interrupt(){return this.ensureNotDisposed(),this._manager.sendSystemEvent("control.interrupt")}_clearEventListeners(){this._eventUnsubscribers.forEach(e=>{try{e()}catch(e){a.error("Performance monitor unsubscribe failed",e)}}),this._eventUnsubscribers=[]}_bindEventBus(){this._eventUnsubscribers.push(this._context.eventBus.on("inner:rtc:video:available",()=>{this.sendVideoAvaliableState()}))}async sendVideoAvaliableState(){return this.ensureNotDisposed(),this._manager.sendSystemEvent("scene.ready")}onDispose(){this._clearEventListeners(),this._manager.dispose(),a.info("Conversation Controller disposed")}}class se extends o{constructor(){super(...arguments),this._tracks=new Map,this._participants=new Map,this._trackEndedHandlers=new Map}register(e,t,i){this.ensureNotDisposed(),this._tracks.set(e,t),this._participants.has(i)||this._participants.set(i,new Set),this._participants.get(i).add(e);const s=()=>{a.debug(`Track ended: ${e}`),this.unregister(e)};this._trackEndedHandlers.set(e,s),t.on("ended",s),a.debug(`Track registered: ${e} from participant ${i}`)}unregister(e){const t=this._tracks.get(e);if(t){const i=this._trackEndedHandlers.get(e);i&&(t.off("ended",i),this._trackEndedHandlers.delete(e)),t.stop(),this._tracks.delete(e);for(const[t,i]of this._participants.entries())if(i.has(e)){i.delete(e),0===i.size&&this._participants.delete(t);break}a.debug(`Track unregistered: ${e}`)}}getTrack(e){return this._tracks.get(e)||null}getParticipantTracks(e){const t=this._participants.get(e);return t?Array.from(t):[]}getAllTrackIds(){return Array.from(this._tracks.keys())}getVideoAvailability(){let e=!1,t=!1,i=!1;for(const s of this._tracks.values()){const n=s.mediaStreamTrack;if("video"===n.kind&&(e=!0,"live"===n.readyState&&(t=!0),n.enabled&&(i=!0),"live"===n.readyState&&n.enabled))return{available:!0}}return e?t?i?{available:!1,reason:_.NO_VIDEO_TRACK}:{available:!1,reason:_.TRACK_MUTED}:{available:!1,reason:_.TRACK_ENDED}:{available:!1,reason:_.NO_VIDEO_TRACK}}clear(){const e=Array.from(this._tracks.keys());for(const t of e)this.unregister(t);a.info("All tracks cleared")}onDispose(){this.clear()}}class ne extends v{constructor(e){super(),this._videoController=null,this._room=null,this._trackRegistry=e,this._loosTrackTimer=null,a.info("Video Track Handler created")}setRoom(e){this._room=e}setVideoController(e){this._videoController=e}handleTrackSubscribed(e,t,i){this.ensureNotDisposed(),this._loosTrackTimer&&clearTimeout(this._loosTrackTimer),this._trackRegistry.register(t,e,i),this._videoController&&e.attach(this._videoController.getSource().getInternalElement()),e.on("videoPlaybackStarted",()=>{a.info("inner:rtc:video:available"),this._context.eventBus.emit("inner:rtc:video:available",void 0)}),this._context.eventBus.emit("inner:video:track:added",{trackId:t,participantId:i}),a.debug(`Video track subscribed: ${t}`)}handleTrackUnsubscribed(e,t,i){this.ensureNotDisposed(),this._videoController&&e.detach(this._videoController.getSource().getInternalElement()),e.removeAllListeners(),this._context.eventBus.emit("inner:video:track:removed",{trackId:t,participantId:i}),this._loosTrackTimer&&clearTimeout(this._loosTrackTimer),this._loosTrackTimer=setTimeout(()=>{this._context.eventBus.emit("inner:rtc:video:unavailable",void 0)},5e3),this._trackRegistry.unregister(t),a.debug(`Video track unsubscribed: ${t}`)}supports(e){return"video"===e.mediaStreamTrack.kind}onDispose(){this._loosTrackTimer&&(clearTimeout(this._loosTrackTimer),this._loosTrackTimer=null),a.info("Video Track Handler disposed")}}class re extends v{constructor(e){super(),this._audioController=null,this._room=null,this._trackRegistry=e,a.info("Audio Track Handler created")}setRoom(e){this._room=e}setAudioController(e){this._audioController=e}handleTrackSubscribed(e,t,i){this.ensureNotDisposed(),this._trackRegistry.register(t,e,i),this._audioController?e.attach(this._audioController.getOutputElement()):this._context.eventBus.emit("inner:audio:track:added",{trackId:t,participantId:i}),a.debug(`Audio track subscribed: ${t}`)}handleTrackUnsubscribed(e,t,i){this.ensureNotDisposed(),this._audioController?(this._audioController.removeOutputTrack(t),e.detach(this._audioController.getOutputElement())):this._context.eventBus.emit("inner:audio:track:removed",{trackId:t}),this._trackRegistry.unregister(t),a.debug(`Audio track unsubscribed: ${t}`)}supports(e){return"audio"===e.mediaStreamTrack.kind}onDispose(){a.info("Audio Track Handler disposed")}}class oe extends v{constructor(e){super(),this._handlers=[],this._room=null,this._trackRegistry=e,a.info("LiveKit Event Adapter created")}setContext(e){if(super.setContext(e),0===this._handlers.length){const t=new ne(this._trackRegistry),i=new re(this._trackRegistry);t.setContext(e),i.setContext(e),this._handlers.push(t,i),this._room&&(t.setRoom(this._room),i.setRoom(this._room))}}setRoom(e){this._room=e,this._handlers.forEach(t=>{t.setRoom(e)}),a.info("LiveKit room set:",this._room)}setVideoController(e){const t=this._handlers.find(e=>e instanceof ne);t&&t.setVideoController(e)}setAudioController(e){const t=this._handlers.find(e=>e instanceof re);t&&t.setAudioController(e)}handleTrackSubscribed(e,t,i){this.ensureNotDisposed();const s=this._findHandler(e);s?s.handleTrackSubscribed(e,t,i):a.warn(`No handler found for track, trackId: ${t}`)}handleTrackUnsubscribed(e,t){this.ensureNotDisposed();const i=this._trackRegistry.getTrack(e);if(i){const s=this._findHandler(i);s?s.handleTrackUnsubscribed(i,e,t):(this._trackRegistry.unregister(e),a.warn(`No handler found for track, trackId: ${e}`))}}_findHandler(e){return this._handlers.find(t=>t.supports(e))||null}onDispose(){this._handlers.forEach(e=>{try{e.dispose()}catch(e){a.error("Error disposing track handler:",e)}}),this._handlers.length=0,a.info("LiveKit Event Adapter disposed")}}class ae extends v{constructor(){super(),this._room=null,this._rtcRoom=null,this._micTrack=null,this._cameraVideoTrack=null,this._protocolDispatch=null,this._maxAttempts=3,this._maxDelay=1e4,this._speakingHandlers=new Map,this._trackRegistry=new se,this._eventAdapter=new oe(this._trackRegistry),a.info("LiveKit Service created")}setContext(e){super.setContext(e),this._maxAttempts=e.options.reconnect?.maxAttempts||3,this._maxDelay=(e.options.reconnect?.delay??10)*d,this._eventAdapter.setContext(e)}async connect(e,s,n,o){if(this.ensureNotDisposed(),this._rtcRoom&&this._rtcRoom.state===t.ConnectionState.Connected)return void a.warn("Already connected to LiveKit room");let c;try{await this._tearDownStaleRoom(),a.info(`Connecting to LiveKit room: ${n} at ${e}`),c=new t.Room({reconnectPolicy:{nextRetryDelayInMs:e=>e.elapsedMs<this._maxDelay?Math.min(d*Math.pow(2,e.retryCount),this._maxDelay):null}}),c.prepareConnection(e,s),this._registerRoomListeners(c),a.info("Connecting to LiveKit room..."),await c.connect(e,s,{autoSubscribe:!0,maxRetries:this._context.options.reconnect?.maxAttempts||3}),this._eventAdapter.setRoom(c),this._rtcRoom=c,this._room=c}catch(e){if(c){try{c.removeAllListeners()}catch{}try{await c.disconnect()}catch{}}throw this._rtcRoom=null,this._room=null,r.fromError(e,i.LIVEKIT_CONNECT_FAILED)}}_registerRoomListeners(e){e.on(t.RoomEvent.TrackSubscribed,(e,t,i)=>{this._handleTrackSubscribed(e,t,i)}),e.on(t.RoomEvent.TrackUnsubscribed,(e,t,i)=>{this._handleTrackUnsubscribed(e,t,i)}),e.on(t.RoomEvent.TrackMuted,(e,t)=>{this._handleTrackMuted(e,t)}),e.on(t.RoomEvent.TrackUnmuted,(e,t)=>{this._handleTrackUnmuted(e,t)}),e.on(t.RoomEvent.Connected,()=>{a.info("Connected to LiveKit room"),this._context.eventBus.emit("inner:rtc:connected",void 0)}),e.on(t.RoomEvent.Disconnected,e=>{e?a.info(`LiveKit room disconnected: ${e}`):a.info("LiveKit room disconnected"),e!==t.DisconnectReason.CLIENT_INITIATED&&(this._context.eventBus.emit("inner:rtc:disconnected",{reason:e?String(e):void 0}),this._context.emitError(new r(i.LIVEKIT_CONNECT_FAILED,e?`LiveKit disconnected: ${String(e)}`:"LiveKit disconnected"),i.LIVEKIT_CONNECT_FAILED)),this._micTrack?.stop(),this._micTrack=null,this._cameraVideoTrack?.stop(),this._cameraVideoTrack=null,this._clearSpeakingHandlers(),this._context.mediaAudioCaptureState.end("rtc"),this._room=null,this._rtcRoom=null}),e.on(t.RoomEvent.DataReceived,e=>{this._onRoomDataReceived(e)})}async _tearDownStaleRoom(){if(!this._rtcRoom)return;await this.stopMicrophone(),await this.stopCamera(),this._clearSpeakingHandlers();const e=this._rtcRoom;this._rtcRoom=null,this._room=null;try{e.removeAllListeners()}catch{}try{await e.disconnect()}catch{}}_clearSpeakingHandlers(){if(this._rtcRoom){for(const[e,i]of this._speakingHandlers.entries()){const s=this._findRemoteParticipantByIdentity(e);try{s?.off(t.ParticipantEvent.IsSpeakingChanged,i)}catch{}}this._speakingHandlers.clear()}else this._speakingHandlers.clear()}_findRemoteParticipantByIdentity(e){const t=this._rtcRoom;if(t)for(const i of t.remoteParticipants.values())if(i.identity===e)return i}_removeSpeakingListenerIfNoAudioTracks(e){const i=this._speakingHandlers.get(e);if(!i)return;const s=this._trackRegistry.getParticipantTracks(e);for(const e of s){const t=this._trackRegistry.getTrack(e);if("audio"===t?.kind)return}const n=this._findRemoteParticipantByIdentity(e);try{n?.off(t.ParticipantEvent.IsSpeakingChanged,i)}catch{}this._speakingHandlers.delete(e)}async startMicrophone(){this.ensureNotDisposed();const e=this._rtcRoom;if(!e||!this.isConnected())throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit is not connected");if(!this._context.mediaAudioCaptureState.tryBegin("rtc"))throw new r(i.SDK_INVALID_STATE_TRANSITION,"WebSocket audio capture is active");try{if(this._micTrack)return void a.warn("Microphone already published");const i=await t.createLocalAudioTrack(this._context.options.audio?.input??{});await e.localParticipant.publishTrack(i),this._micTrack=i,a.info("Microphone published (rtc)")}catch(e){throw this._context.mediaAudioCaptureState.end("rtc"),this._context.emitError(e,i.AUDIO_CAPTURE_START_FAILED)}}async stopMicrophone(){const e=this._rtcRoom,t=this._micTrack;if(t&&e)try{await e.localParticipant.unpublishTrack(t,!0)}catch(e){throw this._context.emitError(e,i.LIVEKIT_UNPUBLISH_MICROPHONE_FAILED)}this._micTrack?.stop(),this._micTrack=null,this._context.mediaAudioCaptureState.end("rtc"),a.info("Microphone stopped (rtc)")}isMicrophoneActive(){return!!this._micTrack}async sendTextData(e,t,s,n){this.ensureNotDisposed();const o=this._rtcRoom;if(!o||!this.isConnected())throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit is not connected");try{const i={event:s,requestId:e,data:{...n,text:t}},r=(new TextEncoder).encode(JSON.stringify(i));await o.localParticipant.publishData(r,{reliable:!0}),a.debug("Text message sent via RTC data:",e)}catch(e){throw this._context.emitError(e,i.LIVEKIT_SEND_TEXT_DATA_FAILED)}}async sendSystemEvent(e,t){this.ensureNotDisposed();const s=this._rtcRoom;if(!s||!this.isConnected())throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit is not connected");try{const i={event:e,data:t??{}},n=(new TextEncoder).encode(JSON.stringify(i));await s.localParticipant.publishData(n,{reliable:!0}),a.debug("System event :",e,"sent via RTC data")}catch(e){throw this._context.emitError(e,i.LIVEKIT_SEND_TEXT_DATA_FAILED)}}setProtocolMessageDispatcher(e){this._protocolDispatch=e}async startCamera(){this.ensureNotDisposed();const e=this._rtcRoom;if(!e||!this.isConnected())throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit is not connected");if(this._cameraVideoTrack)a.warn("RTC camera already published");else try{const i=await t.createLocalVideoTrack({});await e.localParticipant.publishTrack(i),this._cameraVideoTrack=i,a.info("Camera published (rtc)")}catch(e){throw this._context.emitError(e,i.LIVEKIT_CONNECT_FAILED)}}async stopCamera(){const e=this._rtcRoom,t=this._cameraVideoTrack;if(t&&e)try{await e.localParticipant.unpublishTrack(t,!0)}catch(e){a.error("Error unpublishing RTC camera:",e)}this._cameraVideoTrack?.stop(),this._cameraVideoTrack=null,a.info("Camera stopped (rtc)")}attachCameraTo(e){if(this.ensureNotDisposed(),!this._cameraVideoTrack)throw new r(i.LIVEKIT_CONNECT_FAILED,"Camera track is not published");this._cameraVideoTrack.attach(e)}detachCameraFrom(e){if(this.ensureNotDisposed(),!this._cameraVideoTrack)throw new r(i.LIVEKIT_CONNECT_FAILED,"Camera track is not published");this._cameraVideoTrack.detach(e)}isRtcCameraActive(){return null!==this._cameraVideoTrack}_onRoomDataReceived(e){if(this._protocolDispatch&&0!==e.length)try{const t=(new TextDecoder).decode(e),i=JSON.parse(t);if(!i||"object"!=typeof i)return;a.debug("RTC data message received:",t),this._protocolDispatch(i)}catch(e){a.error("RTC data message parse error:",e),this._context.emitError(e,i.LIVEKIT_DATA_MESSAGE_PARSE_ERROR)}}_handleTrackSubscribed(e,i,s){try{if(!e.mediaStreamTrack)return void a.warn("Track does not have MediaStreamTrack");if("audio"===e.kind){const e=s.identity;if(!this._speakingHandlers.has(e)){const i=t=>{this._context.eventBus.emit("inner:audio:speaking:changed",{participantId:e,isSpeaking:t}),a.info(`Participant ${e} is speaking: ${t}`)};s.on(t.ParticipantEvent.IsSpeakingChanged,i),this._speakingHandlers.set(e,i)}}const n=i.trackSid,r=s.identity;this._eventAdapter.handleTrackSubscribed(e,n,r)}catch(e){a.error("Error handling track subscribed:",e)}}_handleTrackUnsubscribed(e,t,i){try{const e=i,s=t.trackSid,n=e.identity,r=this._trackRegistry.getTrack(s),o="audio"===r?.kind;"video"===r?.kind&&this._context.eventBus.emit("inner:rtc:video:unavailable",void 0),this._eventAdapter.handleTrackUnsubscribed(s,n),o&&this._removeSpeakingListenerIfNoAudioTracks(n)}catch(e){a.error("Error handling track unsubscribed:",e)}}_handleTrackMuted(e,t){try{"video"===e.kind&&this._context.eventBus.emit("inner:rtc:video:unavailable",void 0)}catch(e){a.error("Error handling track muted:",e)}}_handleTrackUnmuted(e,t){try{"video"===e.kind&&this._context.eventBus.emit("inner:rtc:video:available",void 0)}catch(e){a.error("Error handling track unmuted:",e)}}async disconnect(){await this.stopMicrophone(),await this.stopCamera(),this._clearSpeakingHandlers();const e=this._rtcRoom;if(e)try{try{e.removeAllListeners()}catch{}await e.disconnect(),this._room=null,this._rtcRoom=null,this._context.eventBus.emit("inner:rtc:disconnected",{reason:"Disconnected from LiveKit room"}),a.info("Disconnected from LiveKit room")}catch(e){a.error("Error disconnecting from LiveKit room:",e),this._room=null,this._rtcRoom=null}else this._room=null}isConnected(){return!!this._room&&this._room.state===t.ConnectionState.Connected}getTrackRegistry(){return this._trackRegistry}get trackRegistry(){return this._trackRegistry}getEventAdapter(){return this._eventAdapter}onDispose(){this._protocolDispatch=null,this.disconnect(),this._trackRegistry.dispose(),this._eventAdapter.dispose(),a.info("LiveKit Service disposed")}}class ce extends v{constructor(){super(),this._conversationManager=null,a.info("ProtocolMessageDispatcher created")}setConversationManager(e){this._conversationManager=e,a.debug("Conversation manager set in ProtocolMessageDispatcher")}dispatch(e){this.ensureNotDisposed();try{if(e.event)return void this._handleLivekitServerResponseMessage(e)}catch(e){a.error("Error dispatching protocol message:",e)}}_handleLivekitServerResponseMessage(e){switch(e.event){case"response.chunk":this._conversationManager?.handleAnswerChunk(e.requestId,e.data.text,!1);break;case"response.done":this._conversationManager?.handleAnswerChunk(e.requestId,"",!0);break;case"input.asr.partial":this._conversationManager?.handleAsrTextReceived(e.requestId,e.data.text,!0,e.data.final??!1);break;case"input.asr.final":this._conversationManager?.handleAsrTextReceived(e.requestId,e.data.text,!1,!0);break;case"system.prompt":this._conversationManager?.handleServerInitiatedMessage(void 0,e.data.text);break;case"session.closing":break;case"input.voice.start":this._context.eventBus.emit("inner:conversation:voice:start",{requestId:e.requestId});break;case"input.voice.finish":this._context.eventBus.emit("inner:conversation:voice:finish",{requestId:e.requestId});break;default:a.warn("Unknown event:",e.event)}}onDispose(){this._conversationManager=null,a.info("ProtocolMessageDispatcher disposed")}}const he=["sdk:connected","sdk:disconnected","sdk:error","media:video:available","media:video:unavailable","media:video:trackAdded","media:video:trackRemoved","media:audio:trackAdded","media:audio:trackRemoved","media:audio:captureStarted","media:audio:captureStopped","media:camera:started","media:camera:stopped","media:audio:volumeChanged","media:audio:muted","media:audio:unmuted","conversation:question:sent","conversation:answer:waiting","conversation:server:message","conversation:asr:received","conversation:asr:chunk","conversation:answer:chunk","conversation:answer:completed"],de=/^[a-z]+:[a-zA-z]+(:[a-zA-Z]+)?$/;class le{constructor(e){this.inner=e,this.listeners=new Map,this.forwardedVideoTrackIds=new Set,this.livekitConnected=!1,this.httpConnected=!1,this.internalMap={"inner:sdk:error":{public:"sdk:error",sanitizer:e=>({message:e?.error?.message,code:e?.error?.code})},"inner:rtc:video:available":{public:"media:video:available"},"inner:rtc:video:unavailable":{public:"media:video:unavailable"},"inner:video:track:added":{public:"media:video:trackAdded"},"inner:video:track:removed":{public:"media:video:trackRemoved"},"inner:audio:track:added":{public:"media:audio:trackAdded"},"inner:audio:track:removed":{public:"media:audio:trackRemoved"},"inner:audio:input:started":{public:"media:audio:captureStarted"},"inner:audio:input:stopped":{public:"media:audio:captureStopped"},"inner:camera:started":{public:"media:camera:started"},"inner:camera:stopped":{public:"media:camera:stopped"},"inner:audio:volume:changed":{public:"media:audio:volumeChanged",sanitizer:e=>({volume:e?.volume})},"inner:audio:muted":{public:"media:audio:muted"},"inner:audio:unmuted":{public:"media:audio:unmuted"},"inner:conversation:question:sent":{public:"conversation:question:sent",sanitizer:e=>({questionId:e?.questionId,text:String(e?.text||"")})},"inner:conversation:answer:waiting":{public:"conversation:answer:waiting",sanitizer:e=>({questionId:e?.questionId})},"inner:conversation:server:message":{public:"conversation:server:message",sanitizer:e=>({questionId:e?.questionId,message:String(e?.message||""),type:String(e?.type||"")})},"inner:conversation:asr:received":{public:"conversation:asr:received",sanitizer:e=>({questionId:e?.questionId,text:String(e?.text||"")})},"inner:conversation:asr:chunk":{public:"conversation:asr:chunk",sanitizer:e=>({questionId:e?.questionId,text:String(e?.text||""),isComplete:e?.isComplete??!1})},"inner:conversation:answer:chunk":{public:"conversation:answer:chunk",sanitizer:e=>({questionId:e?.questionId,chunk:String(e?.chunk||"")})},"inner:conversation:answer:completed":{public:"conversation:answer:completed",sanitizer:e=>({questionId:e?.questionId,fullAnswer:String(e?.fullAnswer||"")})}},Object.keys(this.internalMap).forEach(e=>{this.inner.on(e,t=>this.handleInternalEvent(e,t))}),this.inner.on("inner:sdk:connected",e=>this.handleConnected(e,!0)),this.inner.on("inner:sdk:disconnected",e=>this.handleConnected(e,!1)),he.forEach(e=>{this.inner.on(e,t=>this.handlePublicEvent(e,t))})}publicAPI(){return{on:this.on.bind(this),off:this.off.bind(this),once:this.once.bind(this)}}on(e,t){const i=String(e);return this.assertAllowed(i),this.listeners.has(i)||this.listeners.set(i,new Set),this.listeners.get(i).add(t),()=>this.off(e,t)}once(e,t){const i=String(e);this.assertAllowed(i);const s=i=>{try{t(i)}finally{this.off(e,s)}};return this.on(e,s)}off(e,t){const i=String(e);this.assertAllowed(i);const s=this.listeners.get(i);s&&(s.delete(t),0===s.size&&this.listeners.delete(i))}handleInternalEvent(e,t){const i=this.internalMap[e];if(!i)return;const s=i.public;if(-1===he.indexOf(s))return;if("media:video:trackAdded"===s){const e=t?.trackId||t?.id;if("string"==typeof e){if(this.forwardedVideoTrackIds.has(e))return;this.forwardedVideoTrackIds.add(e)}}const n=i.sanitizer?i.sanitizer(t):t;if(!de.test(s))return;const r=this.listeners.get(s);r&&0!==r.size&&r.forEach(e=>{try{e(n)}catch(e){a.error("PublicEventEmitter listener error",e)}})}handlePublicEvent(e,t){if(-1===he.indexOf(e))return;const i=Object.values(this.internalMap).find(t=>t.public===e),s=i&&i.sanitizer?i.sanitizer(t):t;if("media:video:trackAdded"===e){const e=t?.trackId||t?.id;if("string"==typeof e){if(this.forwardedVideoTrackIds.has(e))return;this.forwardedVideoTrackIds.add(e)}}const n=this.listeners.get(e);n&&0!==n.size&&n.forEach(e=>{try{e(s)}catch(e){a.error("PublicEventEmitter listener error",e)}})}handleConnected(e,t){"livekit"===e.source?this.livekitConnected=t:"http"===e.source&&(this.httpConnected=t),this.maybeEmitSdkConnected(t?"connected":"disconnected")}maybeEmitSdkConnected(e){const t="connected"===e,i=t?!!this.livekitConnected:!this.livekitConnected,s=t?!!this.httpConnected:!this.httpConnected,n={livekit:i,http:s,all:i&&s},r=JSON.stringify(n);this.lastConnectedPayloadJson!==r&&(this.lastConnectedPayloadJson=r,this.inner.emit(`sdk:${e}`,n))}assertAllowed(e){if(-1===he.indexOf(e))throw new Error(`Event "${e}" is not allowed for public consumers`);if(!de.test(e))throw new Error(`Event name "${e}" does not follow namespace:domain[:action] naming`)}}class _e extends o{constructor(e,t){super(),this._requestCounter=0,this._baseURL=e||"",this._defaultHeaders=t||{},a.info(`HTTP Service created with baseURL: ${this._baseURL||"none"}`)}setAuthToken(e){this._defaultHeaders.Authorization=`Bearer ${e}`}request(e){this.ensureNotDisposed();const t=e.requestId||`req_${Date.now()}_${++this._requestCounter}`,i=this._buildURL(e.url,e.params),s=this._mergeHeaders(e.headers),n={method:e.method||"GET",headers:s};void 0!==e.data&&"GET"!==(e.method||"GET")&&("string"==typeof e.data?n.body=e.data:(n.body=JSON.stringify(e.data),s["Content-Type"]||s["content-type"]||(s["Content-Type"]="application/json")));const r=e.timeout||3e4,o=new AbortController;return n.signal=o.signal,new Promise((s,c)=>{const h=setTimeout(()=>o.abort(),r);fetch(i,n).then(async n=>{clearTimeout(h);const r={};let o;n.headers.forEach((e,t)=>{r[t]=e});const c=n.headers.get("content-type");o=c&&c.includes("application/json")?await n.json():await n.text();const d={requestId:t,status:n.status,headers:r,data:o,config:e};a.debug(`HTTP request succeeded: ${e.method} ${i} [${t}]`),s(d)}).catch(s=>{clearTimeout(h);const n=s&&"AbortError"===s.name,r={requestId:t,status:s&&s.status||void 0,message:n?"Request aborted (timeout)":s&&s.message||"HTTP request failed",error:s,config:e};a.error(`HTTP request failed: ${e.method} ${i} [${t}]`,s),c(r)})})}get(e,t,i){return this.request({...i,url:e,method:"GET",params:t})}post(e,t,i){return this.request({...i,url:e,method:"POST",data:t})}put(e,t,i){return this.request({...i,url:e,method:"PUT",data:t})}delete(e,t){return this.request({...t,url:e,method:"DELETE"})}patch(e,t,i){return this.request({...i,url:e,method:"PATCH",data:t})}_buildURL(e,t){if(e.startsWith("http://")||e.startsWith("https://"))return this._appendParams(e,t);let i=this._baseURL;return!i||i.endsWith("/")||e.startsWith("/")?i&&i.endsWith("/")&&e.startsWith("/")&&(i=i.slice(0,-1)):i+="/",i+=e,this._appendParams(i,t)}_appendParams(e,t){if(!t||0===Object.keys(t).length)return e;const i=new URLSearchParams;for(const[e,s]of Object.entries(t))i.append(e,String(s));const s=e.includes("?")?"&":"?";return`${e}${s}${i.toString()}`}_mergeHeaders(e){const t={...this._defaultHeaders};return e&&Object.assign(t,e),t}onDispose(){a.info("HTTP Service disposed")}}function ue(e,t="https"){if(e.includes("://"))return e;return`${t.replace(/:$/,"")}://${e}`}class pe extends v{constructor(e,t){super(),this._httpService=new _e(e||"https://api.newportai.com/s2/aigc/api/vih_dispatcher",t)}getAuthToken(){if(this.ensureNotDisposed(),this._context.authToken)return this._httpService?.setAuthToken(this._context.authToken),Promise.resolve();throw this._context.emitError("Auth token not found",i.SDK_AUTH_TOKEN_FAILED)}async fetchConnectionConfig(){this.ensureNotDisposed();const e=await this._httpService.request({url:"/v1/session/start",method:"POST",data:{avatarId:"auth"===this._context.options.connectConfig.type?this._context.options.connectConfig.config.avatarId:"",voice:"auth"===this._context.options.connectConfig.type&&this._context.options.connectConfig.config.avatarVoice||""},headers:this._context.options.sandbox?{"X-Env-Sandbox":"true"}:void 0}).catch(e=>{throw this._context.emitError(e,i.SDK_GET_LIVEKIT_CONFIG_FAILED)});if(0!==e.data.code||!e.data.data)throw this._context.emitError(new r(i.SDK_GET_LIVEKIT_CONFIG_FAILED,e.data.msg||"LiveKit config response invalid"),i.SDK_GET_LIVEKIT_CONFIG_FAILED);return{roomId:"",roomToken:e.data.data.userToken,livekitUrl:ue(e.data.data.sfuUrl,"wss")}}onDispose(){this._httpService.dispose()}}class me extends v{constructor(e,t){super(),this._connectStartAt=null,this._hasReportedFirstFrame=!1,this._videoElement=null,this._videoFirstFrameHandler=null,this._pendingTextResponse=new Map,this._pendingTextAudioQueue=[],this._pendingTextAudioStartAt=new Map,this._pendingNoSpeechStartAt=null,this._eventUnsubscribers=[],this._reporter=e??null,this._now=t??(()=>Date.now())}setReporter(e){this._reporter=e??null}startConnectMeasurement(){this._connectStartAt=this._now(),this._hasReportedFirstFrame=!1}bindVideoElement(e){this._unbindVideoElement(),this._videoElement=e,this._videoFirstFrameHandler=this._handleVideoFirstFrame.bind(this),this._videoElement.addEventListener("loadeddata",this._videoFirstFrameHandler,{once:!1})}setContext(e){super.setContext(e),this._bindEventBus()}_bindEventBus(){this._clearEventListeners(),this._subscribeConversationMetrics(),this._subscribeAudioMetrics()}_subscribeConversationMetrics(){this._eventUnsubscribers.push(this._context.eventBus.on("inner:conversation:question:sent",({questionId:e})=>{const t=this._now();this._pendingTextResponse.set(e,t),this._pendingTextAudioQueue.push(e),this._pendingTextAudioStartAt.set(e,t)})),this._eventUnsubscribers.push(this._context.eventBus.on("inner:conversation:answer:chunk",({questionId:e})=>{this._tryCompleteTextResponse(e)})),this._eventUnsubscribers.push(this._context.eventBus.on("inner:conversation:answer:completed",({questionId:e})=>{this._tryCompleteTextResponse(e)})),this._eventUnsubscribers.push(this._context.eventBus.on("inner:conversation:server:message",({questionId:e})=>{this._tryCompleteTextResponse(e)}))}_subscribeAudioMetrics(){this._eventUnsubscribers.push(this._context.eventBus.on("inner:audio:speaking:changed",({isSpeaking:e})=>{e&&(this._tryCompleteTextToAudio(),this._tryCompleteNoSpeechToAudio())})),this._eventUnsubscribers.push(this._context.eventBus.on("inner:audio:no_speech:reported",({timestamp:e})=>{null===this._pendingNoSpeechStartAt&&(this._pendingNoSpeechStartAt=e)}))}_handleVideoFirstFrame(){this._hasReportedFirstFrame||null===this._connectStartAt||(this._hasReportedFirstFrame=!0,this._report({metric:"connect_to_first_frame_ms",durationMs:this._now()-this._connectStartAt,startedAt:this._connectStartAt,endedAt:this._now()}))}_tryCompleteTextResponse(e){const t=this._pendingTextResponse.get(e);if(void 0===t)return;this._pendingTextResponse.delete(e);const i=this._now();this._report({metric:"text_send_to_text_response_ms",durationMs:i-t,startedAt:t,endedAt:i,questionId:e})}_tryCompleteTextToAudio(){let e;for(;this._pendingTextAudioQueue.length>0;){const t=this._pendingTextAudioQueue.shift();if(t&&this._pendingTextAudioStartAt.has(t)){e=t;break}}if(!e)return;const t=this._pendingTextAudioStartAt.get(e);if(void 0===t)return;this._pendingTextAudioStartAt.delete(e);const i=this._now();this._report({metric:"text_send_to_audio_response_ms",durationMs:i-t,startedAt:t,endedAt:i,questionId:e})}_tryCompleteNoSpeechToAudio(){if(null===this._pendingNoSpeechStartAt)return;const e=this._pendingNoSpeechStartAt;this._pendingNoSpeechStartAt=null;const t=this._now();this._report({metric:"no_speech_report_to_audio_response_ms",durationMs:t-e,startedAt:e,endedAt:t})}_report(e){const t=this._reporter??this._defaultReporter;try{t(e)}catch(e){a.error("Performance metric reporter failed",e)}}_defaultReporter(e){a.info("[performance-metric]",e)}_unbindVideoElement(){this._videoElement&&this._videoFirstFrameHandler&&this._videoElement.removeEventListener("loadeddata",this._videoFirstFrameHandler),this._videoElement=null,this._videoFirstFrameHandler=null}_clearEventListeners(){this._eventUnsubscribers.forEach(e=>{try{e()}catch(e){a.error("Performance monitor unsubscribe failed",e)}}),this._eventUnsubscribers=[]}onDispose(){this._unbindVideoElement(),this._clearEventListeners(),this._pendingTextResponse.clear(),this._pendingTextAudioQueue.length=0,this._pendingTextAudioStartAt.clear(),this._pendingNoSpeechStartAt=null,this._reporter=null}}class ve extends v{constructor(e,t=6e4){super(),this._cachedConfig=null,this._cachedAt=null,this._inflightPromise=null,this._nextDirectConfig=null,this._httpController=e,this._ttlMs=t}async preConnect(){this.ensureNotDisposed();const e=this.getValidConfig();return e||(this._inflightPromise||(this._inflightPromise=this._fetchConfig().finally(()=>{this._inflightPromise=null})),this._inflightPromise)}getValidConfig(){return this.ensureNotDisposed(),this._cachedConfig&&null!==this._cachedAt?Date.now()-this._cachedAt>=this._ttlMs?null:this._cachedConfig:null}async refreshConfig(){return this.ensureNotDisposed(),this._cachedConfig=null,this._cachedAt=null,this._inflightPromise||(this._inflightPromise=this._fetchConfig().finally(()=>{this._inflightPromise=null})),this._inflightPromise}replaceDirectConfig(e){this.ensureNotDisposed();const t=this._validateDirectConfig(e);this._nextDirectConfig=t,this._cachedConfig=null,this._cachedAt=null}async _fetchConfig(){const e=this._context.options.connectConfig;if("direct"===e.type){const t=this._nextDirectConfig??this._validateDirectConfig(e.config),i={livekitUrl:t.sfuUrl,token:t.userToken};return this._cache(i),this._nextDirectConfig=null,i}return this._fetchAuthConfigWithRetry(e.config.authToken||"")}_fromAuthPayload(e){if(!e.livekitUrl||!e.roomToken)throw this._context.emitError("Invalid connection config payload",i.SDK_GET_LIVEKIT_CONFIG_FAILED);return{livekitUrl:e.livekitUrl,token:e.roomToken,roomId:e.roomId,videoOptions:{renderMode:e.greenScreen?.enabled?"processed":"raw",greenScreen:{enabled:Boolean(e.greenScreen?.enabled),...e.greenScreen}}}}_cache(e){this._cachedConfig=e,this._cachedAt=Date.now()}async _fetchAuthConfigWithRetry(e){let t=null;for(let i=1;i<=ve.AUTH_RETRY_MAX_ATTEMPTS;i++)try{const t=this._context.authToken||e;this._context.setAuthToken(t),await this._httpController.getAuthToken();const i=await this._httpController.fetchConnectionConfig(),s=this._fromAuthPayload(i);return this._cache(s),s}catch(e){if(t=e,i>=ve.AUTH_RETRY_MAX_ATTEMPTS)break;await this._delay(ve.AUTH_RETRY_BASE_DELAY_MS*i)}throw this._context.emitError(t||"Failed to fetch auth connection config",i.SDK_GET_LIVEKIT_CONFIG_FAILED)}_delay(e){return new Promise(t=>setTimeout(t,e))}_validateDirectConfig(e){const t=(e.sfuUrl||"").trim(),s=(e.userToken||"").trim();if(!t||!s)throw this._context.emitError("Invalid direct connection config",i.SDK_PRECONNECT_FAILED);return{sfuUrl:t,userToken:s}}onDispose(){this._cachedConfig=null,this._cachedAt=null,this._inflightPromise=null,this._nextDirectConfig=null}}ve.AUTH_RETRY_MAX_ATTEMPTS=2,ve.AUTH_RETRY_BASE_DELAY_MS=300;class ge extends o{constructor(e){super(),this._videoController=null,this._audioController=null,this._conversationController=null,this._cameraController=null,this._liveKitService=null,this._connectionCoordinator=null,this._httpController=null,this._configManager=null,this._performanceMonitor=null,this._pendingDirectConfig=null,this._isReconnectInProgress=!1,this._reconnectPromise=null,this._liveKitProtocolDispatcher=null,this._context=new m(e),a.info("SDK Client created")}get events(){return this.ensureNotDisposed(),this._publicEventAPI||(this._publicEmitter=new le(this._context.eventBus),this._publicEventAPI=this._publicEmitter.publicAPI()),this._publicEventAPI}sendTextQuestion(e){if(this.ensureNotDisposed(),this._ensureConnected(),this._conversationController)return this._conversationController.sendQuestion(e);throw new r(i.CONVERSATION_CONTROLLER_NOT_AVAILABLE,"Conversation controller is not available")}async interrupt(){if(this.ensureNotDisposed(),this._ensureConnected(),this._conversationController)return this._conversationController.interrupt();throw new r(i.CONVERSATION_CONTROLLER_NOT_AVAILABLE,"Conversation controller is not available")}setPerformanceMetricReporter(e){if(this.ensureNotDisposed(),!this._performanceMonitor)return this._performanceMonitor=new me(e),void this._performanceMonitor.setContext(this._context);this._performanceMonitor.setReporter(e)}setRenderFitMode(e){this.ensureNotDisposed(),this._ensureConnected(),this._videoController&&this._videoController.setRenderFitMode(e)}async startAudioCapture(){this.ensureNotDisposed(),this._ensureConnected(),await this._startAudioCaptureRtc()}async stopAudioCapture(){this.ensureNotDisposed(),this._ensureConnected(),await this._stopAudioCaptureRtc()}setVolume(e){this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().setVolume(e)}getVolume(){return this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().getVolume()||1}mute(){this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().mute()}unmute(){this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().unmute()}get isMuted(){return this.ensureNotDisposed(),this._ensureConnected(),this._requireAudioController().isMuted()}get isAudioCapturing(){return this.ensureNotDisposed(),this._ensureConnected(),this._liveKitService?.isMicrophoneActive()??!1}setAuthToken(e){this.ensureNotDisposed(),this._context.setAuthToken(e),this._httpController&&this._httpController.getAuthToken()}updateConnectionConfig(e){if(this.ensureNotDisposed(),"direct"!==this._context.options.connectConfig.type)throw this._context.emitError(new r(i.SDK_INVALID_STATE_TRANSITION,"updateConnectionConfig is only available in direct mode"),i.SDK_INVALID_STATE_TRANSITION);this._pendingDirectConfig=this._validateDirectConnectionConfig(e)}async startCamera(){this.ensureNotDisposed(),this._ensureConnected(),await this._requireLiveKitService().startCamera()}stopCamera(){this.ensureNotDisposed(),this._ensureConnected(),this._liveKitService?.stopCamera()}getCameraStream(){return this.ensureNotDisposed(),this._ensureConnected(),this._cameraController?.getStream()??null}getCameraTrack(){return this.ensureNotDisposed(),this._ensureConnected(),this._cameraController?.getTrack()??null}attachCameraTo(e){this.ensureNotDisposed(),this._ensureConnected(),this._requireLiveKitService().attachCameraTo(e)}async preConnect(){this.ensureNotDisposed();try{this._ensureConfigManagerReady();const e=await this._configManager.preConnect();return this._applyConnectionConfig(e),!0}catch(e){throw this._context.emitError(e,i.SDK_PRECONNECT_FAILED)}}async connect(){if(this.ensureNotDisposed(),this._ensurePerformanceMonitorReady(),this._performanceMonitor?.startConnectMeasurement(),this._connectionCoordinator&&this._context.sessionState.isConnected)a.warn("SDK already initialized");else{try{this._ensureConfigManagerReady();const e=this._configManager.getValidConfig();if(e)this._applyConnectionConfig(e);else{if(!await this.preConnect())throw new r(i.SDK_CONNECT_FAILED,"PreConnect failed without explicit error")}}catch(e){throw this._context.emitError(e,i.SDK_CONNECT_FAILED)}try{await this._disposeConnectionRuntimeBeforeConnect(),a.info("Initializing SDK..."),this._connectionCoordinator=new T,this._connectionCoordinator.setContext(this._context),this._context.bindConnectionState(()=>this._connectionCoordinator.getState()),this._connectionCoordinator.start(),this._connectionCoordinator.startConnecting(),this._bootstrapDomainControllers(),this._bootstrapLiveKitService(),this._wireLiveKitEventAdapterToControllers(),this._setupRtcProtocolDispatcher(),await this._establishMediaAndSessionTransports(),a.info("SDK initialized and connected")}catch(e){throw this._connectionCoordinator&&this._connectionCoordinator.transitionToIdle(),await this._cleanup(),this._context.emitError(e,i.SDK_INITIALIZATION_FAILED)}}}async disconnect(){if(this.ensureNotDisposed(),this._connectionCoordinator&&"idle"!==this._connectionCoordinator.getState()&&"disposed"!==this._connectionCoordinator.getState()){a.info("Disconnecting SDK..."),this._connectionCoordinator.startDisconnecting();try{this._audioController&&this._audioController.stopWsCapture(),this._liveKitService&&(await this._liveKitService.sendSystemEvent("session.stop"),await this._liveKitService.disconnect()),this._cameraController&&this._cameraController.stopCamera(),this._connectionCoordinator.completeDisconnecting(),a.info("SDK disconnected")}catch(e){throw a.error("Error during disconnect:",e),this._context.emitError(e,i.SDK_DISCONNECT_FAILED)}}}async reconnect(){if(this.ensureNotDisposed(),this._reconnectPromise)return this._reconnectPromise;const e=this._connectionCoordinator;if(!e?.canStartReconnectingManual()){const t=e?e.getSnapshot():this.connectionSnapshot;return a.warn("SDK reconnect not allowed in current state, returning current snapshot"),t}const t=e.captureSnapshotAndStartReconnectingManual();return this._reconnectPromise=(async()=>{this._isReconnectInProgress=!0;try{return await this.disconnect(),this._stageDirectConfigForNextReconnect(),await this._refreshConnectionConfigForReconnect(),await this.connect(),t}catch(e){throw a.error("Error during reconnect:",e),this._context.emitError(e,i.SDK_RECONNECT_FAILED)}finally{this._isReconnectInProgress=!1,this._reconnectPromise=null}})(),this._reconnectPromise}get connectionSnapshot(){return this.ensureNotDisposed(),this._connectionCoordinator?this._connectionCoordinator.getSnapshot():E(g("idle"))}async _cleanup(){if(this._conversationController?.setRtcTextSender(null),this._liveKitService?.setProtocolMessageDispatcher(null),this._liveKitProtocolDispatcher&&(this._liveKitProtocolDispatcher.dispose(),this._liveKitProtocolDispatcher=null),this._audioController&&this._audioController.stopWsCapture(),this._liveKitService)try{await this._liveKitService.disconnect()}catch(e){a.error("Error disconnecting LiveKit:",e)}this._cameraController&&this._cameraController.stopCamera()}async _disposeConnectionRuntimeBeforeConnect(){await this._cleanup(),this._conversationController?.setRtcTextSender(null),this._liveKitService?.setProtocolMessageDispatcher(null),this._liveKitProtocolDispatcher&&(this._liveKitProtocolDispatcher.dispose(),this._liveKitProtocolDispatcher=null),this._videoController?.dispose(),this._videoController=null,this._audioController?.dispose(),this._audioController=null,this._cameraController?.dispose(),this._cameraController=null,this._conversationController?.dispose(),this._conversationController=null,this._liveKitService?.dispose(),this._liveKitService=null,this._connectionCoordinator?.dispose(),this._connectionCoordinator=null}_bootstrapDomainControllers(){this._videoController=new L(this._context.options.video),this._videoController.setContext(this._context),this._performanceMonitor?.bindVideoElement(this._videoController.getSource().getInternalElement()),this._audioController=new U(this._context.options.audio),this._audioController.setContext(this._context),this._cameraController=new Q,this._cameraController.setContext(this._context),this._conversationController=new ie,this._conversationController.setContext(this._context)}_bootstrapLiveKitService(){this._liveKitService=new ae,this._liveKitService.setContext(this._context)}_wireLiveKitEventAdapterToControllers(){if(this._liveKitService&&this._videoController&&this._audioController){const e=this._liveKitService.getEventAdapter();e&&("function"==typeof e.setVideoController&&e.setVideoController(this._videoController),"function"==typeof e.setAudioController&&e.setAudioController(this._audioController))}}_setupRtcProtocolDispatcher(){this._liveKitProtocolDispatcher&&(this._liveKitProtocolDispatcher.dispose(),this._liveKitProtocolDispatcher=null),this._liveKitProtocolDispatcher=new ce,this._liveKitProtocolDispatcher.setContext(this._context),this._liveKitProtocolDispatcher.setConversationManager(this._conversationController.manager),this._liveKitService.setProtocolMessageDispatcher(e=>{this._liveKitProtocolDispatcher.dispatch(e)}),this._conversationController.setRtcTextSender(this._liveKitService)}async _establishMediaAndSessionTransports(){await this._liveKitService.connect(this._context.livekitUrl,this._context.token,"auth"===this._context.options.connectConfig.type?this._context.options.connectConfig.config.avatarId:"")}async _refreshConnectionConfigForReconnect(){this._ensureConfigManagerReady();const e=await this._configManager.refreshConfig();this._applyConnectionConfig(e)}_ensureConfigManagerReady(){a.info("Creating HTTP controller..."),this._httpController=this._httpController??new pe(this._context.options.http?.baseURL,this._context.options.http?.headers),this._httpController.setContext(this._context),this._configManager=this._configManager??new ve(this._httpController),this._configManager.setContext(this._context)}_applyConnectionConfig(e){this._context.setLivekitConfig(e.livekitUrl,e.token,e.roomId||""),e.videoOptions&&this._context.setVideoOptions(e.videoOptions),"auth"===this._context.options.connectConfig.type&&this._context.eventBus.emit("inner:sdk:connected",{source:"http"})}_stageDirectConfigForNextReconnect(){"direct"===this._context.options.connectConfig.type&&this._pendingDirectConfig&&(this._ensureConfigManagerReady(),this._configManager.replaceDirectConfig(this._pendingDirectConfig),this._pendingDirectConfig=null)}_validateDirectConnectionConfig(e){const t=(e?.sfuUrl||"").trim(),s=(e?.userToken||"").trim();if(!t||!s)throw this._context.emitError(new r(i.SDK_PRECONNECT_FAILED,"Invalid direct connection config"),i.SDK_PRECONNECT_FAILED);return{sfuUrl:t,userToken:s}}_ensurePerformanceMonitorReady(){const e=this._context.options.performanceMonitor;if(!(!1!==e?.enabled))return this._performanceMonitor?.dispose(),void(this._performanceMonitor=null);this._performanceMonitor?this._performanceMonitor.setReporter(e?.reporter):(this._performanceMonitor=new me(e?.reporter),this._performanceMonitor.setContext(this._context))}get isConnected(){return this.ensureNotDisposed(),this._context.sessionState.isConnected}_ensureConnected(){if(!this._context.sessionState.isConnected)throw new r(i.SDK_NOT_CONNECTED,"SDK is not connected. Call connect() first.")}async _startAudioCaptureRtc(){await this._requireLiveKitService().startMicrophone()}async _stopAudioCaptureRtc(){await this._requireLiveKitService().stopMicrophone()}_requireAudioController(){if(!this._audioController)throw new r(i.AUDIO_CONTROLLER_NOT_AVAILABLE,"Audio controller is not available");return this._audioController}_requireLiveKitService(){if(!this._liveKitService)throw new r(i.LIVEKIT_CONNECT_FAILED,"LiveKit service is not available");return this._liveKitService}onDispose(){this.disconnect().catch(e=>{a.error("Error during disconnect in dispose:",e)}),this._videoController&&(this._videoController.dispose(),this._videoController=null),this._audioController&&(this._audioController.dispose(),this._audioController=null),this._cameraController&&(this._cameraController.dispose(),this._cameraController=null),this._conversationController?.setRtcTextSender(null),this._liveKitService?.setProtocolMessageDispatcher(null),this._liveKitProtocolDispatcher&&(this._liveKitProtocolDispatcher.dispose(),this._liveKitProtocolDispatcher=null),this._conversationController&&(this._conversationController.dispose(),this._conversationController=null),this._liveKitService&&(this._liveKitService.dispose(),this._liveKitService=null),this._httpController&&(this._httpController.dispose(),this._httpController=null),this._configManager&&(this._configManager.dispose(),this._configManager=null),this._performanceMonitor&&(this._performanceMonitor.dispose(),this._performanceMonitor=null),this._connectionCoordinator&&(this._connectionCoordinator.transitionToDisposed(),this._connectionCoordinator.dispose(),this._connectionCoordinator=null),this._context.dispose(),a.info("SDK Client disposed")}}class Ee extends o{constructor(e,t){super(),this._videoElement=null,this._videoUrl=null,this._isPlaying=!1,this._frameCallbackId=null,this._videoUrl=e,t?this._videoElement=t:(this._videoElement=document.createElement("video"),this._videoElement.style.opacity="0",this._videoElement.muted=!0,this._videoElement.playsInline=!0,this._videoElement.loop=!0,document.querySelector("#video-container")?.appendChild(this._videoElement)),a.info("Local Video Debug Source created")}get videoElement(){return this._videoElement}async load(){if(!this._videoElement)throw new Error("Video element or URL not set");return new Promise((e,t)=>{const i=this._videoElement,s=()=>{i.removeEventListener("loadedmetadata",s),i.removeEventListener("error",n),a.info(`Video loaded: ${i.videoWidth}x${i.videoHeight}`),e()},n=e=>{i.removeEventListener("loadedmetadata",s),i.removeEventListener("error",n),t(new Error(`Failed to load video: ${e}`))};i.addEventListener("loadedmetadata",s),i.addEventListener("error",n),i.src=this._videoUrl||"",i.load()})}async play(){if(!this._videoElement)throw new Error("Video element not set");if(!this._isPlaying)try{await this._videoElement.play(),this._videoElement.style.opacity="0",this._videoElement.setAttribute("loop","true"),this._isPlaying=!0,a.info("Video playback started")}catch(e){throw a.error("Failed to play video:",e),e}}pause(){this._videoElement&&this._isPlaying&&(this._videoElement.pause(),this._isPlaying=!1,a.info("Video playback paused"))}stop(){this._videoElement&&(this._videoElement.pause(),this._videoElement.currentTime=0,this._isPlaying=!1,a.info("Video playback stopped"))}get isPlaying(){return this._isPlaying&&null!==this._videoElement&&!this._videoElement.paused}get videoWidth(){return this._videoElement?.videoWidth||0}get videoHeight(){return this._videoElement?.videoHeight||0}async captureFrame(){if(!this._videoElement||this._videoElement.readyState<2)return null;try{if("VideoFrame"in window&&"function"==typeof window.VideoFrame)try{return new VideoFrame(this._videoElement,{timestamp:1e6*this._videoElement.currentTime})}catch(e){a.error("",e)}const e=await createImageBitmap(this._videoElement),t=new VideoFrame(e,{timestamp:1e6*this._videoElement.currentTime});return e.close(),t}catch(e){return a.error("Failed to capture video frame:",e),null}}onFrame(e){if(!this._videoElement)return;this.offFrame();const t=this._videoElement;if("requestVideoFrameCallback"in t){const i=(s,n)=>{this._isPlaying&&this._videoElement&&this.captureFrame().then(s=>{s&&(e(s),s.close()),this._isPlaying&&this._videoElement&&(this._frameCallbackId=t.requestVideoFrameCallback(i))}).catch(e=>{a.error("Error in frame callback:",e)})};this._frameCallbackId=t.requestVideoFrameCallback(i)}else{const t=()=>{this._isPlaying&&this._videoElement&&this.captureFrame().then(i=>{i&&(e(i),i.close()),this._isPlaying&&this._videoElement&&(this._frameCallbackId=requestAnimationFrame(t))}).catch(e=>{a.error("Error in frame callback:",e)})};this._frameCallbackId=requestAnimationFrame(t)}}offFrame(){null!==this._frameCallbackId&&(this._videoElement&&"cancelVideoFrameCallback"in this._videoElement?this._videoElement.cancelVideoFrameCallback(this._frameCallbackId):cancelAnimationFrame(this._frameCallbackId),this._frameCallbackId=null)}onDispose(){this.stop(),this.offFrame(),this._videoElement&&this._videoElement.parentElement===document.body&&document.body.removeChild(this._videoElement),this._videoElement=null,this._videoUrl=null,a.info("Local Video Debug Source disposed")}}class fe extends o{constructor(e,t,i){super(),this._outputCanvas=null,this._outputRenderer=null,this._source=new S;const s={...e,renderMode:"processed"};this._pipeline=new w(this._source,s),this._outputRenderer=new R(i,t),this._pipeline.setRenderer(this._outputRenderer),this._outputCanvas=this._outputRenderer.getCanvas(),a.info("Video Pipeline Runner created")}get outputCanvas(){return this._outputCanvas}get processor(){return this._pipeline.strategy.getProcessors()[0]||null}setProcessor(e){this._pipeline.setProcessor(e),a.info("Processor set on pipeline")}async processFrame(e){if(this.ensureNotDisposed(),!this._outputRenderer)return a.error("Output renderer not available"),void e.close();try{const t=this._pipeline.strategy.getProcessors()[0]||null;let i=null;if(t){try{i=t.process(e)}catch(t){a.error("Error processing frame:",t),i=e}if(null===i&&"getImageData"in t){const i=t.getImageData();if(i&&this._outputCanvas&&this._outputRenderer.getContext()){const e=this._outputRenderer.getContext();e&&(this._outputCanvas.width===i.width&&this._outputCanvas.height===i.height||(this._outputCanvas.width=i.width,this._outputCanvas.height=i.height),e.putImageData(i,0,0))}return void e.close()}i&&i!==e?(this._outputRenderer.render(i),e.close()):i===e?this._outputRenderer.render(e):e.close()}else this._outputRenderer.render(e)}catch(t){a.error("Error in processFrame:",t),e.close()}}setOutputSize(e,t){this._outputCanvas&&(this._outputCanvas.width=e,this._outputCanvas.height=t,a.info(`Output canvas size set to ${e}x${t}`))}onDispose(){this._pipeline.dispose(),this._outputRenderer&&(this._outputRenderer.dispose(),this._outputRenderer=null),this._outputCanvas&&this._outputCanvas.parentElement===document.body&&document.body.removeChild(this._outputCanvas),this._outputCanvas=null,a.info("Video Pipeline Runner disposed")}}e.DEFAULT_AUDIO_BUFFER_SIZE=4096,e.DEFAULT_AUDIO_CHANNELS=1,e.DEFAULT_AUDIO_SAMPLE_RATE=l,e.DEFAULT_RECONNECT_ATTEMPTS=3,e.DEFAULT_RECONNECT_DELAY=10,e.DEFAULT_WS_TIMEOUT=1e4,e.Disposable=o,e.EventBus=c,e.Logger=a,e.SDKClient=ge,e.SDKError=r,e.SessionState=h,e.StandaloneVideoDebugger=class extends o{constructor(e,t,i,s){if(super(),this._isRunning=!1,this._videoSource=new Ee(e,t),this._options={renderMode:"processed",containerElement:t,...s},this._pipelineRunner=new fe(this._options,t,i),this._options.greenScreen?.enabled){const e=new x(this._options.greenScreen);this._pipelineRunner.setProcessor(e),a.info("Green screen processor enabled in debugger")}a.info("Standalone Video Debugger created")}async switchSource(e,t){this.ensureNotDisposed();const i=this._videoSource,s=this._isRunning,n=new Ee(e,t);try{await n.load(),s&&await n.play(),n.onFrame(e=>{this._pipelineRunner.processFrame(e).catch(e=>{a.error("Error processing frame:",e)})}),this._videoSource=n;try{i.offFrame(),i.stop(),i.dispose()}catch(e){a.warn("Error disposing old video source during switch:",e)}const e=this._videoSource.videoWidth,t=this._videoSource.videoHeight;e>0&&t>0&&this._pipelineRunner.setOutputSize(e,t)}catch(e){a.error("Failed to switch video source:",e);try{n.dispose()}catch(e){a.warn("Error disposing new video source after failed switch:",e)}throw e}}get outputCanvas(){return this._pipelineRunner.outputCanvas}get videoSource(){return this._videoSource}get processor(){return this._pipelineRunner.processor}setProcessor(e){this._pipelineRunner.setProcessor(e)}updateGreenScreenOptions(e){const t=this._pipelineRunner.processor;if(t&&"updateOptions"in t&&"function"==typeof t.updateOptions)t.updateOptions(e),a.info("Green screen options updated");else{const t=this._options.greenScreen||{enabled:!1},i={...t,...e,enabled:void 0!==e.enabled?e.enabled:t.enabled},s=new x(i);this._pipelineRunner.setProcessor(s),this._options.greenScreen=i,a.info("Green screen processor recreated with new options")}}async initialize(){this.ensureNotDisposed();try{await this._videoSource.load();const e=this._videoSource.videoWidth,t=this._videoSource.videoHeight;e>0&&t>0&&this._pipelineRunner.setOutputSize(e,t),a.info("Video debugger initialized")}catch(e){throw a.error("Failed to initialize video debugger:",e),e}}async start(){if(this.ensureNotDisposed(),this._isRunning)a.warn("Debugger is already running");else try{0===this._videoSource.videoWidth&&await this.initialize(),await this._videoSource.play(),this._videoSource.onFrame(e=>{this._pipelineRunner.processFrame(e).catch(e=>{a.error("Error processing frame:",e)})}),this._isRunning=!0,a.info("Video debugger started")}catch(e){throw a.error("Failed to start video debugger:",e),e}}stop(){this._isRunning&&(this._videoSource.stop(),this._videoSource.offFrame(),this._isRunning=!1,a.info("Video debugger stopped"))}pause(){this._isRunning&&(this._videoSource.pause(),a.info("Video debugger paused"))}async resume(){this._isRunning&&(await this._videoSource.play(),a.info("Video debugger resumed"))}get isRunning(){return this._isRunning}onDispose(){this.stop(),this._videoSource.dispose(),this._pipelineRunner.dispose(),a.info("Standalone Video Debugger disposed")}},e.createClient=function(e){const t=e.connectConfig;if(!("direct"!==t.type||t.config.sfuUrl&&t.config.userToken))throw new r(i.INVALID_CONNECT_CONFIG,"Invalid direct connect config");if("auth"===t.type&&!t.config.avatarId)throw new r(i.NO_AVATARID,"avatarId is required");return new ge(e)}});
|
package/package.json
CHANGED