@livepeer-frameworks/streamcrafter-wc 0.1.0 → 0.1.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.
@@ -1,37 +1,37 @@
1
- var FwStreamCrafter=function(e){"use strict";var t="undefined"!=typeof document?document.currentScript:null;function r(e,t,r,i){var s,o=arguments.length,n=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(s=e[a])&&(n=(o<3?s(n):o>3?s(t,r,n):s(t,r))||n);return o>3&&n&&Object.defineProperty(t,r,n),n}"function"==typeof SuppressedError&&SuppressedError;
1
+ var FwStreamCrafter=function(e){"use strict";var t="undefined"!=typeof document?document.currentScript:null;function i(e,t,i,r){var s,o=arguments.length,n=o<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var a=e.length-1;a>=0;a--)(s=e[a])&&(n=(o<3?s(n):o>3?s(t,i,n):s(t,i))||n);return o>3&&n&&Object.defineProperty(t,i,n),n}"function"==typeof SuppressedError&&SuppressedError;
2
2
  /**
3
3
  * @license
4
4
  * Copyright 2019 Google LLC
5
5
  * SPDX-License-Identifier: BSD-3-Clause
6
6
  */
7
- const i=globalThis,s=i.ShadowRoot&&(void 0===i.ShadyCSS||i.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,o=Symbol(),n=new WeakMap;let a=class{constructor(e,t,r){if(this._$cssResult$=!0,r!==o)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(s&&void 0===e){const r=void 0!==t&&1===t.length;r&&(e=n.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),r&&n.set(t,e))}return e}toString(){return this.cssText}};const c=(e,...t)=>{const r=1===e.length?e[0]:t.reduce((t,r,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(r)+e[i+1],e[0]);return new a(r,e,o)},l=s?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const r of e.cssRules)t+=r.cssText;return(e=>new a("string"==typeof e?e:e+"",void 0,o))(t)})(e):e,{is:d,defineProperty:h,getOwnPropertyDescriptor:u,getOwnPropertyNames:p,getOwnPropertySymbols:g,getPrototypeOf:f}=Object,m=globalThis,w=m.trustedTypes,v=w?w.emptyScript:"",y=m.reactiveElementPolyfillSupport,b=(e,t)=>e,x={toAttribute(e,t){switch(t){case Boolean:e=e?v:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let r=e;switch(t){case Boolean:r=null!==e;break;case Number:r=null===e?null:Number(e);break;case Object:case Array:try{r=JSON.parse(e)}catch(e){r=null}}return r}},S=(e,t)=>!d(e,t),k={attribute:!0,type:String,converter:x,reflect:!1,useDefault:!1,hasChanged:S};
7
+ const r=globalThis,s=r.ShadowRoot&&(void 0===r.ShadyCSS||r.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,o=Symbol(),n=new WeakMap;let a=class{constructor(e,t,i){if(this._$cssResult$=!0,i!==o)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(s&&void 0===e){const i=void 0!==t&&1===t.length;i&&(e=n.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),i&&n.set(t,e))}return e}toString(){return this.cssText}};const c=(e,...t)=>{const i=1===e.length?e[0]:t.reduce((t,i,r)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+e[r+1],e[0]);return new a(i,e,o)},l=s?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return(e=>new a("string"==typeof e?e:e+"",void 0,o))(t)})(e):e,{is:d,defineProperty:h,getOwnPropertyDescriptor:u,getOwnPropertyNames:p,getOwnPropertySymbols:g,getPrototypeOf:f}=Object,m=globalThis,v=m.trustedTypes,w=v?v.emptyScript:"",b=m.reactiveElementPolyfillSupport,y=(e,t)=>e,x={toAttribute(e,t){switch(t){case Boolean:e=e?w:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},S=(e,t)=>!d(e,t),k={attribute:!0,type:String,converter:x,reflect:!1,useDefault:!1,hasChanged:S};
8
8
  /**
9
9
  * @license
10
10
  * Copyright 2017 Google LLC
11
11
  * SPDX-License-Identifier: BSD-3-Clause
12
- */Symbol.metadata??=Symbol("metadata"),m.litPropertyMetadata??=new WeakMap;let C=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=k){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const r=Symbol(),i=this.getPropertyDescriptor(e,r,t);void 0!==i&&h(this.prototype,e,i)}}static getPropertyDescriptor(e,t,r){const{get:i,set:s}=u(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:i,set(t){const o=i?.call(this);s?.call(this,t),this.requestUpdate(e,o,r)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??k}static _$Ei(){if(this.hasOwnProperty(b("elementProperties")))return;const e=f(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(b("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(b("properties"))){const e=this.properties,t=[...p(e),...g(e)];for(const r of t)this.createProperty(r,e[r])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,r]of t)this.elementProperties.set(e,r)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const r=this._$Eu(e,t);void 0!==r&&this._$Eh.set(r,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const r=new Set(e.flat(1/0).reverse());for(const e of r)t.unshift(l(e))}else void 0!==e&&t.push(l(e));return t}static _$Eu(e,t){const r=t.attribute;return!1===r?void 0:"string"==typeof r?r:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const r of t.keys())this.hasOwnProperty(r)&&(e.set(r,this[r]),delete this[r]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(s)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const r of t){const t=document.createElement("style"),s=i.litNonce;void 0!==s&&t.setAttribute("nonce",s),t.textContent=r.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,r){this._$AK(e,r)}_$ET(e,t){const r=this.constructor.elementProperties.get(e),i=this.constructor._$Eu(e,r);if(void 0!==i&&!0===r.reflect){const s=(void 0!==r.converter?.toAttribute?r.converter:x).toAttribute(t,r.type);this._$Em=e,null==s?this.removeAttribute(i):this.setAttribute(i,s),this._$Em=null}}_$AK(e,t){const r=this.constructor,i=r._$Eh.get(e);if(void 0!==i&&this._$Em!==i){const e=r.getPropertyOptions(i),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:x;this._$Em=i;const o=s.fromAttribute(t,e.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(e,t,r,i=!1,s){if(void 0!==e){const o=this.constructor;if(!1===i&&(s=this[e]),r??=o.getPropertyOptions(e),!((r.hasChanged??S)(s,t)||r.useDefault&&r.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,r))))return;this.C(e,t,r)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:r,reflect:i,wrapped:s},o){r&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||r||(t=void 0),this._$AL.set(e,t)),!0===i&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,r]of e){const{wrapped:e}=r,i=this[t];!0!==e||this._$AL.has(t)||void 0===i||this.C(t,void 0,r,i)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};C.elementStyles=[],C.shadowRootOptions={mode:"open"},C[b("elementProperties")]=new Map,C[b("finalized")]=new Map,y?.({ReactiveElement:C}),(m.reactiveElementVersions??=[]).push("2.1.2");
12
+ */Symbol.metadata??=Symbol("metadata"),m.litPropertyMetadata??=new WeakMap;let C=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=k){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),r=this.getPropertyDescriptor(e,i,t);void 0!==r&&h(this.prototype,e,r)}}static getPropertyDescriptor(e,t,i){const{get:r,set:s}=u(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:r,set(t){const o=r?.call(this);s?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??k}static _$Ei(){if(this.hasOwnProperty(y("elementProperties")))return;const e=f(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(y("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(y("properties"))){const e=this.properties,t=[...p(e),...g(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(l(e))}else void 0!==e&&t.push(l(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(s)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const i of t){const t=document.createElement("style"),s=r.litNonce;void 0!==s&&t.setAttribute("nonce",s),t.textContent=i.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),r=this.constructor._$Eu(e,i);if(void 0!==r&&!0===i.reflect){const s=(void 0!==i.converter?.toAttribute?i.converter:x).toAttribute(t,i.type);this._$Em=e,null==s?this.removeAttribute(r):this.setAttribute(r,s),this._$Em=null}}_$AK(e,t){const i=this.constructor,r=i._$Eh.get(e);if(void 0!==r&&this._$Em!==r){const e=i.getPropertyOptions(r),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:x;this._$Em=r;const o=s.fromAttribute(t,e.type);this[r]=o??this._$Ej?.get(r)??o,this._$Em=null}}requestUpdate(e,t,i,r=!1,s){if(void 0!==e){const o=this.constructor;if(!1===r&&(s=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??S)(s,t)||i.useDefault&&i.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:r,wrapped:s},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===r&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,r=this[t];!0!==e||this._$AL.has(t)||void 0===r||this.C(t,void 0,i,r)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};C.elementStyles=[],C.shadowRootOptions={mode:"open"},C[y("elementProperties")]=new Map,C[y("finalized")]=new Map,b?.({ReactiveElement:C}),(m.reactiveElementVersions??=[]).push("2.1.2");
13
13
  /**
14
14
  * @license
15
15
  * Copyright 2017 Google LLC
16
16
  * SPDX-License-Identifier: BSD-3-Clause
17
17
  */
18
- const $=globalThis,M=e=>e,T=$.trustedTypes,A=T?T.createPolicy("lit-html",{createHTML:e=>e}):void 0,_="$lit$",E=`lit$${Math.random().toFixed(9).slice(2)}$`,I="?"+E,P=`<${I}>`,R=document,W=()=>R.createComment(""),z=e=>null===e||"object"!=typeof e&&"function"!=typeof e,U=Array.isArray,L="[ \t\n\f\r]",D=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,V=/-->/g,O=/>/g,j=RegExp(`>|${L}(?:([^\\s"'>=/]+)(${L}*=${L}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),N=/'/g,F=/"/g,H=/^(?:script|style|textarea|title)$/i,q=(e=>(t,...r)=>({_$litType$:e,strings:t,values:r}))(1),B=Symbol.for("lit-noChange"),G=Symbol.for("lit-nothing"),Q=new WeakMap,X=R.createTreeWalker(R,129);function K(e,t){if(!U(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==A?A.createHTML(t):t}const J=(e,t)=>{const r=e.length-1,i=[];let s,o=2===t?"<svg>":3===t?"<math>":"",n=D;for(let t=0;t<r;t++){const r=e[t];let a,c,l=-1,d=0;for(;d<r.length&&(n.lastIndex=d,c=n.exec(r),null!==c);)d=n.lastIndex,n===D?"!--"===c[1]?n=V:void 0!==c[1]?n=O:void 0!==c[2]?(H.test(c[2])&&(s=RegExp("</"+c[2],"g")),n=j):void 0!==c[3]&&(n=j):n===j?">"===c[0]?(n=s??D,l=-1):void 0===c[1]?l=-2:(l=n.lastIndex-c[2].length,a=c[1],n=void 0===c[3]?j:'"'===c[3]?F:N):n===F||n===N?n=j:n===V||n===O?n=D:(n=j,s=void 0);const h=n===j&&e[t+1].startsWith("/>")?" ":"";o+=n===D?r+P:l>=0?(i.push(a),r.slice(0,l)+_+r.slice(l)+E+h):r+E+(-2===l?t:h)}return[K(e,o+(e[r]||"<?>")+(2===t?"</svg>":3===t?"</math>":"")),i]};class Z{constructor({strings:e,_$litType$:t},r){let i;this.parts=[];let s=0,o=0;const n=e.length-1,a=this.parts,[c,l]=J(e,t);if(this.el=Z.createElement(c,r),X.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=X.nextNode())&&a.length<n;){if(1===i.nodeType){if(i.hasAttributes())for(const e of i.getAttributeNames())if(e.endsWith(_)){const t=l[o++],r=i.getAttribute(e).split(E),n=/([.?@])?(.*)/.exec(t);a.push({type:1,index:s,name:n[2],strings:r,ctor:"."===n[1]?ie:"?"===n[1]?se:"@"===n[1]?oe:re}),i.removeAttribute(e)}else e.startsWith(E)&&(a.push({type:6,index:s}),i.removeAttribute(e));if(H.test(i.tagName)){const e=i.textContent.split(E),t=e.length-1;if(t>0){i.textContent=T?T.emptyScript:"";for(let r=0;r<t;r++)i.append(e[r],W()),X.nextNode(),a.push({type:2,index:++s});i.append(e[t],W())}}}else if(8===i.nodeType)if(i.data===I)a.push({type:2,index:s});else{let e=-1;for(;-1!==(e=i.data.indexOf(E,e+1));)a.push({type:7,index:s}),e+=E.length-1}s++}}static createElement(e,t){const r=R.createElement("template");return r.innerHTML=e,r}}function Y(e,t,r=e,i){if(t===B)return t;let s=void 0!==i?r._$Co?.[i]:r._$Cl;const o=z(t)?void 0:t._$litDirective$;return s?.constructor!==o&&(s?._$AO?.(!1),void 0===o?s=void 0:(s=new o(e),s._$AT(e,r,i)),void 0!==i?(r._$Co??=[])[i]=s:r._$Cl=s),void 0!==s&&(t=Y(e,s._$AS(e,t.values),s,i)),t}class ee{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){const{el:{content:t},parts:r}=this._$AD,i=(e?.creationScope??R).importNode(t,!0);X.currentNode=i;let s=X.nextNode(),o=0,n=0,a=r[0];for(;void 0!==a;){if(o===a.index){let t;2===a.type?t=new te(s,s.nextSibling,this,e):1===a.type?t=new a.ctor(s,a.name,a.strings,this,e):6===a.type&&(t=new ne(s,this,e)),this._$AV.push(t),a=r[++n]}o!==a?.index&&(s=X.nextNode(),o++)}return X.currentNode=R,i}p(e){let t=0;for(const r of this._$AV)void 0!==r&&(void 0!==r.strings?(r._$AI(e,r,t),t+=r.strings.length-2):r._$AI(e[t])),t++}}class te{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,r,i){this.type=2,this._$AH=G,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=r,this.options=i,this._$Cv=i?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode;const t=this._$AM;return void 0!==t&&11===e?.nodeType&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=Y(this,e,t),z(e)?e===G||null==e||""===e?(this._$AH!==G&&this._$AR(),this._$AH=G):e!==this._$AH&&e!==B&&this._(e):void 0!==e._$litType$?this.$(e):void 0!==e.nodeType?this.T(e):(e=>U(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==G&&z(this._$AH)?this._$AA.nextSibling.data=e:this.T(R.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:r}=e,i="number"==typeof r?this._$AC(e):(void 0===r.el&&(r.el=Z.createElement(K(r.h,r.h[0]),this.options)),r);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new ee(i,this),r=e.u(this.options);e.p(t),this.T(r),this._$AH=e}}_$AC(e){let t=Q.get(e.strings);return void 0===t&&Q.set(e.strings,t=new Z(e)),t}k(e){U(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let r,i=0;for(const s of e)i===t.length?t.push(r=new te(this.O(W()),this.O(W()),this,this.options)):r=t[i],r._$AI(s),i++;i<t.length&&(this._$AR(r&&r._$AB.nextSibling,i),t.length=i)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){const t=M(e).nextSibling;M(e).remove(),e=t}}setConnected(e){void 0===this._$AM&&(this._$Cv=e,this._$AP?.(e))}}class re{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,r,i,s){this.type=1,this._$AH=G,this._$AN=void 0,this.element=e,this.name=t,this._$AM=i,this.options=s,r.length>2||""!==r[0]||""!==r[1]?(this._$AH=Array(r.length-1).fill(new String),this.strings=r):this._$AH=G}_$AI(e,t=this,r,i){const s=this.strings;let o=!1;if(void 0===s)e=Y(this,e,t,0),o=!z(e)||e!==this._$AH&&e!==B,o&&(this._$AH=e);else{const i=e;let n,a;for(e=s[0],n=0;n<s.length-1;n++)a=Y(this,i[r+n],t,n),a===B&&(a=this._$AH[n]),o||=!z(a)||a!==this._$AH[n],a===G?e=G:e!==G&&(e+=(a??"")+s[n+1]),this._$AH[n]=a}o&&!i&&this.j(e)}j(e){e===G?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}}class ie extends re{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===G?void 0:e}}class se extends re{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==G)}}class oe extends re{constructor(e,t,r,i,s){super(e,t,r,i,s),this.type=5}_$AI(e,t=this){if((e=Y(this,e,t,0)??G)===B)return;const r=this._$AH,i=e===G&&r!==G||e.capture!==r.capture||e.once!==r.once||e.passive!==r.passive,s=e!==G&&(r===G||i);i&&this.element.removeEventListener(this.name,this,r),s&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){"function"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}}class ne{constructor(e,t,r){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=r}get _$AU(){return this._$AM._$AU}_$AI(e){Y(this,e)}}const ae=$.litHtmlPolyfillSupport;ae?.(Z,te),($.litHtmlVersions??=[]).push("3.3.2");const ce=globalThis;
18
+ const $=globalThis,M=e=>e,_=$.trustedTypes,A=_?_.createPolicy("lit-html",{createHTML:e=>e}):void 0,T="$lit$",E=`lit$${Math.random().toFixed(9).slice(2)}$`,P="?"+E,R=`<${P}>`,I=document,W=()=>I.createComment(""),z=e=>null===e||"object"!=typeof e&&"function"!=typeof e,L=Array.isArray,U="[ \t\n\f\r]",D=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,V=/-->/g,O=/>/g,N=RegExp(`>|${U}(?:([^\\s"'>=/]+)(${U}*=${U}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),j=/'/g,F=/"/g,H=/^(?:script|style|textarea|title)$/i,B=(e=>(t,...i)=>({_$litType$:e,strings:t,values:i}))(1),q=Symbol.for("lit-noChange"),G=Symbol.for("lit-nothing"),Q=new WeakMap,X=I.createTreeWalker(I,129);function K(e,t){if(!L(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==A?A.createHTML(t):t}const J=(e,t)=>{const i=e.length-1,r=[];let s,o=2===t?"<svg>":3===t?"<math>":"",n=D;for(let t=0;t<i;t++){const i=e[t];let a,c,l=-1,d=0;for(;d<i.length&&(n.lastIndex=d,c=n.exec(i),null!==c);)d=n.lastIndex,n===D?"!--"===c[1]?n=V:void 0!==c[1]?n=O:void 0!==c[2]?(H.test(c[2])&&(s=RegExp("</"+c[2],"g")),n=N):void 0!==c[3]&&(n=N):n===N?">"===c[0]?(n=s??D,l=-1):void 0===c[1]?l=-2:(l=n.lastIndex-c[2].length,a=c[1],n=void 0===c[3]?N:'"'===c[3]?F:j):n===F||n===j?n=N:n===V||n===O?n=D:(n=N,s=void 0);const h=n===N&&e[t+1].startsWith("/>")?" ":"";o+=n===D?i+R:l>=0?(r.push(a),i.slice(0,l)+T+i.slice(l)+E+h):i+E+(-2===l?t:h)}return[K(e,o+(e[i]||"<?>")+(2===t?"</svg>":3===t?"</math>":"")),r]};class Y{constructor({strings:e,_$litType$:t},i){let r;this.parts=[];let s=0,o=0;const n=e.length-1,a=this.parts,[c,l]=J(e,t);if(this.el=Y.createElement(c,i),X.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(r=X.nextNode())&&a.length<n;){if(1===r.nodeType){if(r.hasAttributes())for(const e of r.getAttributeNames())if(e.endsWith(T)){const t=l[o++],i=r.getAttribute(e).split(E),n=/([.?@])?(.*)/.exec(t);a.push({type:1,index:s,name:n[2],strings:i,ctor:"."===n[1]?re:"?"===n[1]?se:"@"===n[1]?oe:ie}),r.removeAttribute(e)}else e.startsWith(E)&&(a.push({type:6,index:s}),r.removeAttribute(e));if(H.test(r.tagName)){const e=r.textContent.split(E),t=e.length-1;if(t>0){r.textContent=_?_.emptyScript:"";for(let i=0;i<t;i++)r.append(e[i],W()),X.nextNode(),a.push({type:2,index:++s});r.append(e[t],W())}}}else if(8===r.nodeType)if(r.data===P)a.push({type:2,index:s});else{let e=-1;for(;-1!==(e=r.data.indexOf(E,e+1));)a.push({type:7,index:s}),e+=E.length-1}s++}}static createElement(e,t){const i=I.createElement("template");return i.innerHTML=e,i}}function Z(e,t,i=e,r){if(t===q)return t;let s=void 0!==r?i._$Co?.[r]:i._$Cl;const o=z(t)?void 0:t._$litDirective$;return s?.constructor!==o&&(s?._$AO?.(!1),void 0===o?s=void 0:(s=new o(e),s._$AT(e,i,r)),void 0!==r?(i._$Co??=[])[r]=s:i._$Cl=s),void 0!==s&&(t=Z(e,s._$AS(e,t.values),s,r)),t}class ee{constructor(e,t){this._$AV=[],this._$AN=void 0,this._$AD=e,this._$AM=t}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(e){const{el:{content:t},parts:i}=this._$AD,r=(e?.creationScope??I).importNode(t,!0);X.currentNode=r;let s=X.nextNode(),o=0,n=0,a=i[0];for(;void 0!==a;){if(o===a.index){let t;2===a.type?t=new te(s,s.nextSibling,this,e):1===a.type?t=new a.ctor(s,a.name,a.strings,this,e):6===a.type&&(t=new ne(s,this,e)),this._$AV.push(t),a=i[++n]}o!==a?.index&&(s=X.nextNode(),o++)}return X.currentNode=I,r}p(e){let t=0;for(const i of this._$AV)void 0!==i&&(void 0!==i.strings?(i._$AI(e,i,t),t+=i.strings.length-2):i._$AI(e[t])),t++}}class te{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(e,t,i,r){this.type=2,this._$AH=G,this._$AN=void 0,this._$AA=e,this._$AB=t,this._$AM=i,this.options=r,this._$Cv=r?.isConnected??!0}get parentNode(){let e=this._$AA.parentNode;const t=this._$AM;return void 0!==t&&11===e?.nodeType&&(e=t.parentNode),e}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(e,t=this){e=Z(this,e,t),z(e)?e===G||null==e||""===e?(this._$AH!==G&&this._$AR(),this._$AH=G):e!==this._$AH&&e!==q&&this._(e):void 0!==e._$litType$?this.$(e):void 0!==e.nodeType?this.T(e):(e=>L(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==G&&z(this._$AH)?this._$AA.nextSibling.data=e:this.T(I.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:i}=e,r="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=Y.createElement(K(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===r)this._$AH.p(t);else{const e=new ee(r,this),i=e.u(this.options);e.p(t),this.T(i),this._$AH=e}}_$AC(e){let t=Q.get(e.strings);return void 0===t&&Q.set(e.strings,t=new Y(e)),t}k(e){L(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,r=0;for(const s of e)r===t.length?t.push(i=new te(this.O(W()),this.O(W()),this,this.options)):i=t[r],i._$AI(s),r++;r<t.length&&(this._$AR(i&&i._$AB.nextSibling,r),t.length=r)}_$AR(e=this._$AA.nextSibling,t){for(this._$AP?.(!1,!0,t);e!==this._$AB;){const t=M(e).nextSibling;M(e).remove(),e=t}}setConnected(e){void 0===this._$AM&&(this._$Cv=e,this._$AP?.(e))}}class ie{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(e,t,i,r,s){this.type=1,this._$AH=G,this._$AN=void 0,this.element=e,this.name=t,this._$AM=r,this.options=s,i.length>2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=G}_$AI(e,t=this,i,r){const s=this.strings;let o=!1;if(void 0===s)e=Z(this,e,t,0),o=!z(e)||e!==this._$AH&&e!==q,o&&(this._$AH=e);else{const r=e;let n,a;for(e=s[0],n=0;n<s.length-1;n++)a=Z(this,r[i+n],t,n),a===q&&(a=this._$AH[n]),o||=!z(a)||a!==this._$AH[n],a===G?e=G:e!==G&&(e+=(a??"")+s[n+1]),this._$AH[n]=a}o&&!r&&this.j(e)}j(e){e===G?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,e??"")}}class re extends ie{constructor(){super(...arguments),this.type=3}j(e){this.element[this.name]=e===G?void 0:e}}class se extends ie{constructor(){super(...arguments),this.type=4}j(e){this.element.toggleAttribute(this.name,!!e&&e!==G)}}class oe extends ie{constructor(e,t,i,r,s){super(e,t,i,r,s),this.type=5}_$AI(e,t=this){if((e=Z(this,e,t,0)??G)===q)return;const i=this._$AH,r=e===G&&i!==G||e.capture!==i.capture||e.once!==i.once||e.passive!==i.passive,s=e!==G&&(i===G||r);r&&this.element.removeEventListener(this.name,this,i),s&&this.element.addEventListener(this.name,this,e),this._$AH=e}handleEvent(e){"function"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,e):this._$AH.handleEvent(e)}}class ne{constructor(e,t,i){this.element=e,this.type=6,this._$AN=void 0,this._$AM=t,this.options=i}get _$AU(){return this._$AM._$AU}_$AI(e){Z(this,e)}}const ae=$.litHtmlPolyfillSupport;ae?.(Y,te),($.litHtmlVersions??=[]).push("3.3.2");const ce=globalThis;
19
19
  /**
20
20
  * @license
21
21
  * Copyright 2017 Google LLC
22
22
  * SPDX-License-Identifier: BSD-3-Clause
23
- */let le=class extends C{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=((e,t,r)=>{const i=r?.renderBefore??t;let s=i._$litPart$;if(void 0===s){const e=r?.renderBefore??null;i._$litPart$=s=new te(t.insertBefore(W(),e),e,void 0,r??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return B}};le._$litElement$=!0,le.finalized=!0,ce.litElementHydrateSupport?.({LitElement:le});const de=ce.litElementPolyfillSupport;de?.({LitElement:le}),(ce.litElementVersions??=[]).push("4.2.2");
23
+ */let le=class extends C{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=((e,t,i)=>{const r=i?.renderBefore??t;let s=r._$litPart$;if(void 0===s){const e=i?.renderBefore??null;r._$litPart$=s=new te(t.insertBefore(W(),e),e,void 0,i??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return q}};le._$litElement$=!0,le.finalized=!0,ce.litElementHydrateSupport?.({LitElement:le});const de=ce.litElementPolyfillSupport;de?.({LitElement:le}),(ce.litElementVersions??=[]).push("4.2.2");
24
24
  /**
25
25
  * @license
26
26
  * Copyright 2017 Google LLC
27
27
  * SPDX-License-Identifier: BSD-3-Clause
28
28
  */
29
- const he=e=>(t,r)=>{void 0!==r?r.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)},ue={attribute:!0,type:String,converter:x,reflect:!1,hasChanged:S},pe=(e=ue,t,r)=>{const{kind:i,metadata:s}=r;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===i&&((e=Object.create(e)).wrapped=!0),o.set(r.name,e),"accessor"===i){const{name:i}=r;return{set(r){const s=t.get.call(this);t.set.call(this,r),this.requestUpdate(i,s,e,!0,r)},init(t){return void 0!==t&&this.C(i,void 0,e,t),t}}}if("setter"===i){const{name:i}=r;return function(r){const s=this[i];t.call(this,r),this.requestUpdate(i,s,e,!0,r)}}throw Error("Unsupported decorator location: "+i)};
29
+ const he=e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)},ue={attribute:!0,type:String,converter:x,reflect:!1,hasChanged:S},pe=(e=ue,t,i)=>{const{kind:r,metadata:s}=i;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===r&&((e=Object.create(e)).wrapped=!0),o.set(i.name,e),"accessor"===r){const{name:r}=i;return{set(i){const s=t.get.call(this);t.set.call(this,i),this.requestUpdate(r,s,e,!0,i)},init(t){return void 0!==t&&this.C(r,void 0,e,t),t}}}if("setter"===r){const{name:r}=i;return function(i){const s=this[r];t.call(this,i),this.requestUpdate(r,s,e,!0,i)}}throw Error("Unsupported decorator location: "+r)};
30
30
  /**
31
31
  * @license
32
32
  * Copyright 2017 Google LLC
33
33
  * SPDX-License-Identifier: BSD-3-Clause
34
- */function ge(e){return(t,r)=>"object"==typeof r?pe(e,t,r):((e,t,r)=>{const i=t.hasOwnProperty(r);return t.constructor.createProperty(r,e),i?Object.getOwnPropertyDescriptor(t,r):void 0})(e,t,r)}
34
+ */function ge(e){return(t,i)=>"object"==typeof i?pe(e,t,i):((e,t,i)=>{const r=t.hasOwnProperty(i);return t.constructor.createProperty(i,e),r?Object.getOwnPropertyDescriptor(t,i):void 0})(e,t,i)}
35
35
  /**
36
36
  * @license
37
37
  * Copyright 2017 Google LLC
@@ -47,17 +47,17 @@ const he=e=>(t,r)=>{void 0!==r?r.addInitializer(()=>{customElements.define(e,t)}
47
47
  * Copyright 2017 Google LLC
48
48
  * SPDX-License-Identifier: BSD-3-Clause
49
49
  */
50
- function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Reflect.decorate&&"object"!=typeof t&&Object.defineProperty(e,t,r),r))(t,r,{get(){return(t=>t.renderRoot?.querySelector(e)??null)(this)}})}
50
+ function me(e,t){return(t,i,r)=>((e,t,i)=>(i.configurable=!0,i.enumerable=!0,Reflect.decorate&&"object"!=typeof t&&Object.defineProperty(e,t,i),i))(t,i,{get(){return(t=>t.renderRoot?.querySelector(e)??null)(this)}})}
51
51
  /**
52
52
  * @license
53
53
  * Copyright 2017 Google LLC
54
54
  * SPDX-License-Identifier: BSD-3-Clause
55
- */const we=1;class ve{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,r){this._$Ct=e,this._$AM=t,this._$Ci=r}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}}
55
+ */const ve=1;class we{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}}
56
56
  /**
57
57
  * @license
58
58
  * Copyright 2018 Google LLC
59
59
  * SPDX-License-Identifier: BSD-3-Clause
60
- */const ye=(e=>(...t)=>({_$litDirective$:e,values:t}))(class extends ve{constructor(e){if(super(e),e.type!==we||"class"!==e.name||e.strings?.length>2)throw Error("`classMap()` can only be used in the `class` attribute and must be the only part in the attribute.")}render(e){return" "+Object.keys(e).filter(t=>e[t]).join(" ")+" "}update(e,[t]){if(void 0===this.st){this.st=new Set,void 0!==e.strings&&(this.nt=new Set(e.strings.join(" ").split(/\s/).filter(e=>""!==e)));for(const e in t)t[e]&&!this.nt?.has(e)&&this.st.add(e);return this.render(t)}const r=e.element.classList;for(const e of this.st)e in t||(r.remove(e),this.st.delete(e));for(const e in t){const i=!!t[e];i===this.st.has(e)||this.nt?.has(e)||(i?(r.add(e),this.st.add(e)):(r.remove(e),this.st.delete(e)))}return B}}),be=c`
60
+ */const be=(e=>(...t)=>({_$litDirective$:e,values:t}))(class extends we{constructor(e){if(super(e),e.type!==ve||"class"!==e.name||e.strings?.length>2)throw Error("`classMap()` can only be used in the `class` attribute and must be the only part in the attribute.")}render(e){return" "+Object.keys(e).filter(t=>e[t]).join(" ")+" "}update(e,[t]){if(void 0===this.st){this.st=new Set,void 0!==e.strings&&(this.nt=new Set(e.strings.join(" ").split(/\s/).filter(e=>""!==e)));for(const e in t)t[e]&&!this.nt?.has(e)&&this.st.add(e);return this.render(t)}const i=e.element.classList;for(const e of this.st)e in t||(i.remove(e),this.st.delete(e));for(const e in t){const r=!!t[e];r===this.st.has(e)||this.nt?.has(e)||(r?(i.add(e),this.st.add(e)):(i.remove(e),this.st.delete(e)))}return q}}),ye=c`
61
61
  /**
62
62
  * StreamCrafter CSS
63
63
  * Wrapped in @layer fw-streamcrafter for cascade isolation.
@@ -2236,7 +2236,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2236
2236
  .bg-none {
2237
2237
  background: none;
2238
2238
  }
2239
- `,Se=(e=18)=>q` <svg
2239
+ `,Se=(e=18)=>B` <svg
2240
2240
  width="${e}"
2241
2241
  height="${e}"
2242
2242
  viewBox="0 0 24 24"
@@ -2248,7 +2248,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2248
2248
  >
2249
2249
  <path d="M23 7l-7 5 7 5V7z" />
2250
2250
  <rect x="1" y="5" width="15" height="14" rx="2" ry="2" />
2251
- </svg>`,ke=(e=18)=>q` <svg
2251
+ </svg>`,ke=(e=18)=>B` <svg
2252
2252
  width="${e}"
2253
2253
  height="${e}"
2254
2254
  viewBox="0 0 24 24"
@@ -2261,7 +2261,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2261
2261
  <rect x="2" y="3" width="20" height="14" rx="2" ry="2" />
2262
2262
  <line x1="8" y1="21" x2="16" y2="21" />
2263
2263
  <line x1="12" y1="17" x2="12" y2="21" />
2264
- </svg>`,Ce=(e=14)=>q` <svg
2264
+ </svg>`,Ce=(e=14)=>B` <svg
2265
2265
  width="${e}"
2266
2266
  height="${e}"
2267
2267
  viewBox="0 0 24 24"
@@ -2273,7 +2273,47 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2273
2273
  >
2274
2274
  <line x1="18" y1="6" x2="6" y2="18" />
2275
2275
  <line x1="6" y1="6" x2="18" y2="18" />
2276
- </svg>`,$e=(e=14)=>q` <svg
2276
+ </svg>`,$e=(e=16)=>B` <svg
2277
+ width="${e}"
2278
+ height="${e}"
2279
+ viewBox="0 0 24 24"
2280
+ fill="none"
2281
+ stroke="currentColor"
2282
+ stroke-width="2"
2283
+ stroke-linecap="round"
2284
+ stroke-linejoin="round"
2285
+ >
2286
+ <circle cx="12" cy="12" r="3" />
2287
+ <path
2288
+ d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"
2289
+ />
2290
+ </svg>`,Me=(e=14)=>B` <svg
2291
+ width="${e}"
2292
+ height="${e}"
2293
+ viewBox="0 0 24 24"
2294
+ fill="none"
2295
+ stroke="currentColor"
2296
+ stroke-width="2"
2297
+ stroke-linecap="round"
2298
+ stroke-linejoin="round"
2299
+ >
2300
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
2301
+ <circle cx="12" cy="12" r="3" />
2302
+ </svg>`,_e=(e=14)=>B` <svg
2303
+ width="${e}"
2304
+ height="${e}"
2305
+ viewBox="0 0 24 24"
2306
+ fill="none"
2307
+ stroke="currentColor"
2308
+ stroke-width="2"
2309
+ stroke-linecap="round"
2310
+ stroke-linejoin="round"
2311
+ >
2312
+ <path
2313
+ d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"
2314
+ />
2315
+ <line x1="1" y1="1" x2="23" y2="23" />
2316
+ </svg>`,Ae=(e=14)=>B` <svg
2277
2317
  width="${e}"
2278
2318
  height="${e}"
2279
2319
  viewBox="0 0 24 24"
@@ -2285,16 +2325,17 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2285
2325
  >
2286
2326
  <polygon points="23 7 16 12 23 17 23 7" />
2287
2327
  <rect x="1" y="5" width="15" height="14" rx="2" ry="2" />
2288
- </svg>`,Me={enabled:!1,width:1920,height:1080,frameRate:30,renderer:"auto",defaultTransition:{type:"fade",durationMs:500,easing:"ease-in-out"}},Te={x:0,y:0,width:1,height:1,opacity:1,rotation:0,borderRadius:0,crop:{top:0,right:0,bottom:0,left:0}};class Ae{constructor(){this.listeners=new Map}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}once(e,t){const r=i=>{this.off(e,r),t(i)};return this.on(e,r)}off(e,t){const r=this.listeners.get(e);r&&(r.delete(t),0===r.size&&this.listeners.delete(e))}emit(e,t){const r=this.listeners.get(e);r&&r.forEach(r=>{try{r(t)}catch(t){console.error(`Error in event handler for "${String(e)}":`,t)}})}removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}listenerCount(e){return this.listeners.get(e)?.size??0}}function _e(e="professional"){const t={professional:{width:{ideal:1920},height:{ideal:1080},frameRate:{ideal:30}},broadcast:{width:{ideal:1920},height:{ideal:1080},frameRate:{ideal:30}},conference:{width:{ideal:1280},height:{ideal:720},frameRate:{ideal:24}},auto:{width:{ideal:1920},height:{ideal:1080},frameRate:{ideal:30}}};return t[e]||t.professional}function Ee(e,t){const r=function(e="professional"){const t={professional:{echoCancellation:!1,noiseSuppression:!1,autoGainControl:!1,sampleRate:48e3,channelCount:2,latency:.01},broadcast:{echoCancellation:!1,noiseSuppression:!0,autoGainControl:!1,sampleRate:48e3,channelCount:2,latency:.02},conference:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,sampleRate:44100,channelCount:1,latency:.05},auto:{echoCancellation:!1,noiseSuppression:!1,autoGainControl:!1,sampleRate:48e3,channelCount:2}};return t[e]||t.professional}(e),i=_e(e);return{audio:{echoCancellation:r.echoCancellation,noiseSuppression:r.noiseSuppression,autoGainControl:r.autoGainControl,sampleRate:r.sampleRate,channelCount:r.channelCount,...t?.audioDeviceId&&{deviceId:{exact:t.audioDeviceId}}},video:{width:i.width,height:i.height,frameRate:i.frameRate,...t?.videoDeviceId&&{deviceId:{exact:t.videoDeviceId}},...t?.facingMode&&{facingMode:t.facingMode}}}}class Ie extends Ae{constructor(){super(),this.devices=[],this.currentStream=null,this.permissionStatus={video:!1,audio:!1},this.setupDeviceChangeListener()}setupDeviceChangeListener(){"undefined"!=typeof navigator&&navigator.mediaDevices&&navigator.mediaDevices.addEventListener("devicechange",async()=>{await this.enumerateDevices(),this.emit("devicesChanged",{devices:this.devices})})}async enumerateDevices(){if(!navigator.mediaDevices?.enumerateDevices)throw new Error("enumerateDevices not supported");const e=await navigator.mediaDevices.enumerateDevices();return this.devices=e.filter(e=>"audioinput"===e.kind||"videoinput"===e.kind||"audiooutput"===e.kind).map(e=>({deviceId:e.deviceId,kind:e.kind,label:e.label||`${e.kind} (${e.deviceId.slice(0,8)}...)`,groupId:e.groupId})),this.devices}async getVideoInputs(){return await this.enumerateDevices(),this.devices.filter(e=>"videoinput"===e.kind)}async getAudioInputs(){return await this.enumerateDevices(),this.devices.filter(e=>"audioinput"===e.kind)}async getAudioOutputs(){return await this.enumerateDevices(),this.devices.filter(e=>"audiooutput"===e.kind)}async requestPermissions(e={video:!0,audio:!0}){try{return(await navigator.mediaDevices.getUserMedia({video:e.video,audio:e.audio})).getTracks().forEach(e=>e.stop()),e.video&&(this.permissionStatus.video=!0),e.audio&&(this.permissionStatus.audio=!0),await this.enumerateDevices(),this.emit("permissionChanged",{granted:!0,denied:!1}),this.permissionStatus}catch(e){const t=e instanceof Error?e:new Error(String(e));throw"NotAllowedError"!==t.name&&"PermissionDeniedError"!==t.name||this.emit("permissionChanged",{granted:!1,denied:!0}),this.emit("error",{message:`Permission request failed: ${t.message}`,error:t}),e}}hasPermission(e){return this.permissionStatus[e]}async getUserMedia(e={}){const t=e.profile||"professional";let r;r=e.customConstraints?e.customConstraints:Ee(t,{videoDeviceId:e.videoDeviceId,audioDeviceId:e.audioDeviceId,facingMode:e.facingMode});try{const e=await navigator.mediaDevices.getUserMedia(r);return this.currentStream=e,e.getVideoTracks().length>0&&(this.permissionStatus.video=!0),e.getAudioTracks().length>0&&(this.permissionStatus.audio=!0),e}catch(e){const t=e instanceof Error?e:new Error(String(e));if("OverconstrainedError"===t.name){const e={video:!!r.video,audio:!!r.audio},t=await navigator.mediaDevices.getUserMedia(e);return this.currentStream=t,t}throw this.emit("error",{message:`getUserMedia failed: ${t.message}`,error:t}),e}}getStream(){return this.currentStream}stopAllTracks(){this.currentStream&&(this.currentStream.getTracks().forEach(e=>{e.stop()}),this.currentStream=null)}async replaceVideoTrack(e,t="professional"){if(!this.currentStream)throw new Error("No active stream to replace track in");const r=this.currentStream.getVideoTracks()[0];r&&(r.stop(),this.currentStream.removeTrack(r));const i=Ee(t,{videoDeviceId:e}),s=(await navigator.mediaDevices.getUserMedia({video:i.video,audio:!1})).getVideoTracks()[0];return s&&this.currentStream.addTrack(s),s||null}async replaceAudioTrack(e,t="professional"){if(!this.currentStream)throw new Error("No active stream to replace track in");const r=this.currentStream.getAudioTracks()[0];r&&(r.stop(),this.currentStream.removeTrack(r));const i=Ee(t,{audioDeviceId:e}),s=(await navigator.mediaDevices.getUserMedia({video:!1,audio:i.audio})).getAudioTracks()[0];return s&&this.currentStream.addTrack(s),s||null}getAllDevices(){return[...this.devices]}destroy(){this.stopAllTracks(),this.removeAllListeners()}}class Pe extends Ae{constructor(){super(...arguments),this.captures=new Map,this.captureCounter=0}async start(e={}){try{let t;if(!1===e.video)t=!1;else if("object"==typeof e.video){t={frameRate:{ideal:30,max:60},width:{ideal:1920},height:{ideal:1080},...e.video,...void 0!==e.cursor?{cursor:e.cursor}:{}}}else t={frameRate:{ideal:30,max:60},width:{ideal:1920},height:{ideal:1080},...void 0!==e.cursor?{cursor:e.cursor}:{}};const r={video:t,audio:e.audio??!1};e.preferCurrentTab&&"preferCurrentTab"in r&&(r.preferCurrentTab=!0),e.surfaceSwitching&&(r.surfaceSwitching="include"),void 0!==e.selfBrowserSurface&&(r.selfBrowserSurface=e.selfBrowserSurface),e.monitorTypeSurfaces&&(r.monitorTypeSurfaces=e.monitorTypeSurfaces),e.systemAudio&&r.audio&&"object"==typeof r.audio&&(r.audio.systemAudio=e.systemAudio);const i=await navigator.mediaDevices.getDisplayMedia(r),s=`screen-${++this.captureCounter}-${Date.now()}`,o=i.getVideoTracks()[0],n=o?.label||`Screen ${this.captureCounter}`;return this.captures.set(s,{stream:i,label:n}),i.getTracks().forEach(e=>{e.addEventListener("ended",()=>{this.handleTrackEnded(s,i)})}),this.emit("started",{stream:i,captureId:s}),i}catch(e){const t=e instanceof Error?e:new Error(String(e));if("AbortError"===t.name||"NotAllowedError"===t.name)return this.emit("ended",{captureId:"",stream:null,reason:"cancelled"}),null;throw this.emit("error",{message:`Screen capture failed: ${t.message}`,error:t}),e}}handleTrackEnded(e,t){const r=t.getTracks().filter(e=>"live"===e.readyState);0===r.length&&(this.captures.delete(e),this.emit("ended",{captureId:e,stream:t,reason:"user_stopped"}))}stopByStream(e){for(const[t,r]of this.captures)if(r.stream===e)return r.stream.getTracks().forEach(e=>e.stop()),this.captures.delete(t),void this.emit("ended",{captureId:t,stream:e,reason:"stopped"})}stop(){for(const[e,t]of this.captures)t.stream.getTracks().forEach(e=>e.stop()),this.emit("ended",{captureId:e,stream:t.stream,reason:"stopped"});this.captures.clear()}getCaptures(){return Array.from(this.captures.entries()).map(([e,t])=>({captureId:e,stream:t.stream,label:t.label}))}isActive(){return this.captures.size>0}getCaptureCount(){return this.captures.size}getStream(){const e=this.captures.values().next().value;return e?.stream??null}getVideoTrack(){const e=this.getStream();return e?.getVideoTracks()[0]??null}getAudioTrack(){const e=this.getStream();return e?.getAudioTracks()[0]??null}hasAudio(){for(const[,e]of this.captures)if(e.stream.getAudioTracks().length>0)return!0;return!1}destroy(){this.stop(),this.removeAllListeners()}}class Re extends Ae{constructor(e){super(),this.peerConnection=null,this.videoTrackGenerator=null,this.audioTrackGenerator=null,this.state="disconnected",this.videoWriter=null,this.audioWriter=null,this.videoWriteQueue=[],this.audioWriteQueue=[],this.isProcessingVideoQueue=!1,this.isProcessingAudioQueue=!1,this.videoTransformWorker=null,this.audioTransformWorker=null,this.encoderListenerCleanup=null,this.negotiatedVideoCodec=null,this.negotiatedAudioCodec=null,this.resourceUrl=null,this.config=e}log(e,t){this.config.debug&&console.log(`[WHIP] ${e}`,t??"")}logError(e,t){console.error(`[WHIP ERROR] ${e}`,t??""),this.emit("error",{message:e,error:t})}setState(e){const t=this.state;this.state=e,this.emit("stateChange",{state:e,previousState:t})}preferCodecs(e){const t=e.getTransceivers();for(const e of t){if(!e.setCodecPreferences)continue;const t=e.sender.track?.kind;if("video"===t){const t=RTCRtpSender.getCapabilities("video");if(!t?.codecs)continue;const r=t.codecs.filter(e=>"video/VP9"===e.mimeType||"video/H264"===e.mimeType).sort((e,t)=>"video/VP9"===e.mimeType&&"video/VP9"!==t.mimeType?-1:"video/VP9"!==e.mimeType&&"video/VP9"===t.mimeType?1:0);if(r.length>0)try{e.setCodecPreferences(r),this.log("Set video codec preferences",r.map(e=>e.mimeType))}catch(e){this.log("Failed to set video codec preferences",e)}}if("audio"===t){const t=RTCRtpSender.getCapabilities("audio");if(!t?.codecs)continue;const r=t.codecs.filter(e=>"audio/opus"===e.mimeType);if(r.length>0)try{e.setCodecPreferences(r),this.log("Set audio codec preferences",r.map(e=>e.mimeType))}catch(e){this.log("Failed to set audio codec preferences",e)}}}}verifyCodecAlignment(){if(!this.peerConnection)return;const e=this.peerConnection.getSenders();for(const t of e){const e=t.getParameters(),r=e.codecs?.[0];"video"===t.track?.kind&&r?.mimeType&&(this.negotiatedVideoCodec=r.mimeType,this.log("Negotiated video codec",r.mimeType)),"audio"===t.track?.kind&&r?.mimeType&&(this.negotiatedAudioCodec=r.mimeType,this.log("Negotiated audio codec",r.mimeType))}}canUseEncodedInsertion(){if(!this.peerConnection||"connected"!==this.state)return this.log("canUseEncodedInsertion: no connection",{hasPC:!!this.peerConnection,state:this.state}),!1;if("undefined"==typeof RTCRtpScriptTransform)return this.log("canUseEncodedInsertion: RTCRtpScriptTransform not supported"),!1;const e=this.peerConnection.getSenders().some(e=>"transform"in e);if(!e)return this.log("Sender transform not supported"),!1;if(this.negotiatedVideoCodec){if(!("video/VP9"===this.negotiatedVideoCodec||"video/H264"===this.negotiatedVideoCodec))return this.log("Video codec not compatible with WebCodecs",this.negotiatedVideoCodec),!1}if(this.negotiatedAudioCodec){if(!("audio/opus"===this.negotiatedAudioCodec))return this.log("Audio codec not compatible with WebCodecs",this.negotiatedAudioCodec),!1}return!0}getNegotiatedVideoCodec(){return this.negotiatedVideoCodec}getNegotiatedAudioCodec(){return this.negotiatedAudioCodec}get isConnected(){return"connected"===this.state}async connect(e){try{if(this.log("Starting WHIP connection"),this.setState("connecting"),!this.config.whipUrl)throw new Error("WHIP URL is required");const t={iceServers:this.config.iceServers||[]};this.log("Creating RTCPeerConnection",t);const r=new RTCPeerConnection(t);r.onconnectionstatechange=()=>{const e=r.connectionState;switch(this.log(`Connection state changed: ${e}`),e){case"connected":this.log("WHIP streaming connected successfully"),this.setState("connected");break;case"disconnected":this.setState("disconnected");break;case"failed":this.setState("failed");break;case"closed":this.setState("closed")}},r.oniceconnectionstatechange=()=>{this.log(`ICE connection state: ${r.iceConnectionState}`)},r.onicegatheringstatechange=()=>{this.log(`ICE gathering state: ${r.iceGatheringState}`)},r.onicecandidate=e=>{this.emit("iceCandidate",{candidate:e.candidate}),e.candidate?this.log("ICE candidate generated",e.candidate.candidate):this.log("ICE candidate gathering complete")},this.log("Adding tracks to peer connection"),e.getTracks().forEach((t,i)=>{this.log(`Adding ${t.kind} track ${i}`,{id:t.id,kind:t.kind,enabled:t.enabled,readyState:t.readyState}),r.addTrack(t,e)}),this.peerConnection=r,this.preferCodecs(r),this.log("Creating offer");const i=await r.createOffer({offerToReceiveAudio:!1,offerToReceiveVideo:!1});this.log("Setting local description"),await r.setLocalDescription(i),this.log("Local SDP offer created",{type:i.type,sdpLength:i.sdp?.length}),this.log(`Sending offer to WHIP endpoint: ${this.config.whipUrl}`);const s=await fetch(this.config.whipUrl,{method:"POST",headers:{"Content-Type":"application/sdp",Accept:"application/sdp"},body:i.sdp});if(this.log(`WHIP response status: ${s.status} ${s.statusText}`),!s.ok){const e=await s.text().catch(()=>"Unknown error");throw new Error(`WHIP request failed: ${s.status} ${s.statusText} - ${e}`)}this.resourceUrl=s.headers.get("Location"),this.resourceUrl&&this.log("WHIP resource URL:",this.resourceUrl);const o=await s.text();this.log("Received SDP answer",{length:o.length}),await r.setRemoteDescription({type:"answer",sdp:o}),this.log("Remote description set successfully"),this.verifyCodecAlignment(),this.log("WHIP connection established, waiting for ICE connection...")}catch(e){throw this.logError("Failed to connect",e instanceof Error?e:new Error(String(e))),this.setState("failed"),this.cleanup(),e}}async connectWithGenerators(){try{if(this.log("Starting WHIP connection with track generators"),this.setState("connecting"),!this.config.whipUrl)throw new Error("WHIP URL is required");this.log("Creating MediaStreamTrackGenerators");const e=new MediaStreamTrackGenerator({kind:"video"}),t=new MediaStreamTrackGenerator({kind:"audio"});this.videoTrackGenerator=e,this.audioTrackGenerator=t,this.log("Track generators created successfully");const r={iceServers:this.config.iceServers||[]};this.log("Creating RTCPeerConnection",r);const i=new RTCPeerConnection(r);i.onconnectionstatechange=()=>{const e=i.connectionState;switch(this.log(`Connection state changed: ${e}`),e){case"connected":this.log("WHIP streaming connected successfully"),this.setState("connected");break;case"disconnected":this.setState("disconnected");break;case"failed":this.setState("failed");break;case"closed":this.setState("closed")}},i.oniceconnectionstatechange=()=>{this.log(`ICE connection state: ${i.iceConnectionState}`)},i.onicegatheringstatechange=()=>{this.log(`ICE gathering state: ${i.iceGatheringState}`)},i.onicecandidate=e=>{this.emit("iceCandidate",{candidate:e.candidate}),e.candidate?this.log("ICE candidate generated",e.candidate.candidate):this.log("ICE candidate gathering complete")};const s=new MediaStream([e,t]);this.log("Adding tracks to peer connection"),s.getTracks().forEach((e,t)=>{this.log(`Adding ${e.kind} track ${t}`,{id:e.id,kind:e.kind,enabled:e.enabled,readyState:e.readyState}),i.addTrack(e,s)}),this.peerConnection=i,this.preferCodecs(i),this.log("Creating offer");const o=await i.createOffer({offerToReceiveAudio:!1,offerToReceiveVideo:!1});this.log("Setting local description"),await i.setLocalDescription(o),this.log(`Sending offer to WHIP endpoint: ${this.config.whipUrl}`);const n=await fetch(this.config.whipUrl,{method:"POST",headers:{"Content-Type":"application/sdp",Accept:"application/sdp"},body:o.sdp});if(this.log(`WHIP response status: ${n.status} ${n.statusText}`),!n.ok){const e=await n.text().catch(()=>"Unknown error");throw new Error(`WHIP request failed: ${n.status} ${n.statusText} - ${e}`)}this.resourceUrl=n.headers.get("Location"),this.resourceUrl&&this.log("WHIP resource URL:",this.resourceUrl);const a=await n.text();return this.log("Received SDP answer",{length:a.length}),await i.setRemoteDescription({type:"answer",sdp:a}),this.log("Remote description set successfully"),this.verifyCodecAlignment(),this.log("WHIP connection established with generators"),{videoGenerator:e,audioGenerator:t}}catch(e){throw this.logError("Failed to connect with generators",e instanceof Error?e:new Error(String(e))),this.setState("failed"),this.cleanup(),e}}async processVideoQueue(){if(!this.isProcessingVideoQueue&&0!==this.videoWriteQueue.length){this.isProcessingVideoQueue=!0;try{for(;this.videoWriteQueue.length>0;){const e=this.videoWriteQueue.shift();if(!e)continue;const{frame:t,resolve:r,reject:i}=e;if(this.videoTrackGenerator)try{this.videoWriter||(this.videoWriter=this.videoTrackGenerator.writable.getWriter()),await this.videoWriter.write(t),r(!0)}catch(e){if(this.videoWriter){try{this.videoWriter.releaseLock()}catch{}this.videoWriter=null}i(e instanceof Error?e:new Error(String(e)))}else i(new Error("Video track generator not available"))}}finally{this.isProcessingVideoQueue=!1}}}async processAudioQueue(){if(!this.isProcessingAudioQueue&&0!==this.audioWriteQueue.length){this.isProcessingAudioQueue=!0;try{for(;this.audioWriteQueue.length>0;){const e=this.audioWriteQueue.shift();if(!e)continue;const{audioData:t,resolve:r,reject:i}=e;if(this.audioTrackGenerator)try{this.audioWriter||(this.audioWriter=this.audioTrackGenerator.writable.getWriter()),await this.audioWriter.write(t),r(!0)}catch(e){if(this.audioWriter){try{this.audioWriter.releaseLock()}catch{}this.audioWriter=null}i(e instanceof Error?e:new Error(String(e)))}else i(new Error("Audio track generator not available"))}}finally{this.isProcessingAudioQueue=!1}}}async sendVideoFrame(e){if(!this.videoTrackGenerator){if(e)try{e.close()}catch{}return!1}return new Promise((t,r)=>{this.videoWriteQueue.push({frame:e,resolve:t,reject:r}),this.processVideoQueue()})}async sendAudioData(e){if(!this.audioTrackGenerator){if(e)try{e.close()}catch{}return!1}return new Promise((t,r)=>{this.audioWriteQueue.push({audioData:e,resolve:t,reject:r}),this.processAudioQueue()})}async replaceTrack(e,t){if(!this.peerConnection)throw new Error("No peer connection");const r=this.peerConnection.getSenders().find(t=>t.track?.kind===e.kind);if(!r)throw new Error(`No sender found for ${e.kind} track`);await r.replaceTrack(t),this.log(`Replaced ${e.kind} track`)}async addTrack(e,t){if(!this.peerConnection)throw new Error("No peer connection");this.peerConnection.addTrack(e,t||new MediaStream([e])),this.log(`Added ${e.kind} track`)}async getStats(){if(!this.peerConnection)return null;try{return await this.peerConnection.getStats()}catch(e){return this.logError("Failed to get connection stats",e instanceof Error?e:new Error(String(e))),null}}getState(){return this.state}getPeerConnection(){return this.peerConnection}attachEncoderTransform(e,r){if(!this.peerConnection)throw new Error("No peer connection - call connect() first");if("undefined"==typeof RTCRtpScriptTransform)return void this.log("RTCRtpScriptTransform not supported, skipping encoder transform");this.log("Attaching encoder transform");const i=()=>{if(r)return new Worker(r,{type:"module"});try{const e=new URL("../workers/rtcTransform.worker.js",t&&"SCRIPT"===t.tagName.toUpperCase()&&t.src||new URL("fw-streamcrafter.iife.js",document.baseURI).href);return new Worker(e,{type:"module"})}catch(e){this.log("Packaged worker URL failed, trying fallback paths",e)}const e=["/workers/rtcTransform.worker.js","./workers/rtcTransform.worker.js","/node_modules/@livepeer-frameworks/streamcrafter-core/dist/workers/rtcTransform.worker.js"];for(const t of e)try{return new Worker(t,{type:"module"})}catch{try{return new Worker(t)}catch{}}return null},s=this.peerConnection.getSenders(),o=s.find(e=>"video"===e.track?.kind),n=s.find(e=>"audio"===e.track?.kind);o&&"transform"in o&&(this.log("Creating video transform worker"),this.videoTransformWorker=i(),this.videoTransformWorker?(this.videoTransformWorker.postMessage({type:"configure",config:{debug:this.config.debug,maxQueueSize:30}}),o.transform=new RTCRtpScriptTransform(this.videoTransformWorker,{kind:"video"}),this.log("Video transform attached")):this.logError("Failed to create video transform worker")),n&&"transform"in n&&(this.log("Creating audio transform worker"),this.audioTransformWorker=i(),this.audioTransformWorker?(this.audioTransformWorker.postMessage({type:"configure",config:{debug:this.config.debug,maxQueueSize:50}}),n.transform=new RTCRtpScriptTransform(this.audioTransformWorker,{kind:"audio"}),this.log("Audio transform attached")):this.logError("Failed to create audio transform worker"));const a=e=>{this.videoTransformWorker&&this.videoTransformWorker.postMessage({type:"videoChunk",data:e},[e.data])},c=e=>{this.audioTransformWorker&&this.audioTransformWorker.postMessage({type:"audioChunk",data:e},[e.data])};e.on("videoChunk",a),e.on("audioChunk",c),this.encoderListenerCleanup=()=>{e.off("videoChunk",a),e.off("audioChunk",c)},this.log("Encoder transform attached successfully")}hasEncoderTransform(){return null!==this.videoTransformWorker||null!==this.audioTransformWorker}detachEncoderTransform(){this.encoderListenerCleanup&&(this.encoderListenerCleanup(),this.encoderListenerCleanup=null),this.videoTransformWorker&&(this.videoTransformWorker.postMessage({type:"stop"}),this.videoTransformWorker.terminate(),this.videoTransformWorker=null),this.audioTransformWorker&&(this.audioTransformWorker.postMessage({type:"stop"}),this.audioTransformWorker.terminate(),this.audioTransformWorker=null),this.log("Encoder transform detached")}cleanupWriters(){if(this.videoWriter){try{this.videoWriter.releaseLock()}catch{}this.videoWriter=null}if(this.audioWriter){try{this.audioWriter.releaseLock()}catch{}this.audioWriter=null}this.videoWriteQueue=[],this.audioWriteQueue=[],this.isProcessingVideoQueue=!1,this.isProcessingAudioQueue=!1}cleanup(){this.cleanupWriters(),this.detachEncoderTransform(),this.videoTrackGenerator&&(this.videoTrackGenerator.stop(),this.videoTrackGenerator=null),this.audioTrackGenerator&&(this.audioTrackGenerator.stop(),this.audioTrackGenerator=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.resourceUrl=null}async disconnect(){if(this.log("Disconnecting WHIP"),this.resourceUrl){try{this.log("Sending DELETE to WHIP resource:",this.resourceUrl),await fetch(this.resourceUrl,{method:"DELETE"})}catch(e){this.log("Failed to delete WHIP resource (non-fatal)",e)}this.resourceUrl=null}this.cleanup(),this.setState("disconnected")}destroy(){this.cleanup(),this.removeAllListeners()}}class We extends Ae{constructor(e={}){super(),this.audioContext=null,this.destination=null,this.masterGain=null,this.compressor=null,this.limiter=null,this.analyzer=null,this.sources=new Map,this.outputStream=null,this.levelMonitoringActive=!1,this.peakLevel=0,this.peakDecayRate=.95,this.config={sampleRate:e.sampleRate??48e3,channelCount:e.channelCount??2}}async initialize(){if(!this.audioContext)try{this.audioContext=new AudioContext({sampleRate:this.config.sampleRate}),this.destination=this.audioContext.createMediaStreamDestination(),this.destination.channelCount=this.config.channelCount,this.masterGain=this.audioContext.createGain(),this.compressor=this.audioContext.createDynamicsCompressor(),this.compressor.threshold.value=-24,this.compressor.knee.value=30,this.compressor.ratio.value=4,this.compressor.attack.value=.003,this.compressor.release.value=.25,this.limiter=this.audioContext.createDynamicsCompressor(),this.limiter.threshold.value=-1,this.limiter.knee.value=0,this.limiter.ratio.value=20,this.limiter.attack.value=.001,this.limiter.release.value=.1,this.analyzer=this.audioContext.createAnalyser(),this.analyzer.fftSize=256,this.analyzer.smoothingTimeConstant=.3,this.masterGain.connect(this.compressor),this.compressor.connect(this.analyzer),this.analyzer.connect(this.limiter),this.limiter.connect(this.destination),this.outputStream=this.destination.stream,console.log("[AudioMixer] Initialized with compressor/limiter chain",{sampleRate:this.audioContext.sampleRate,channelCount:this.config.channelCount})}catch(e){const t=e instanceof Error?e:new Error(String(e));throw console.error("[AudioMixer] Failed to initialize:",t),this.emit("error",{message:t.message,error:t}),t}}addSource(e,t,r={}){if(!this.audioContext||!this.masterGain)throw new Error("AudioMixer not initialized. Call initialize() first.");if("audio"!==t.kind)throw new Error("Track must be an audio track");this.sources.has(e)&&this.removeSource(e);try{const i=new MediaStream([t]),s=this.audioContext.createMediaStreamSource(i),o=this.audioContext.createGain();o.gain.value=r.muted?0:r.volume??1;const n=this.audioContext.createStereoPanner();n.pan.value=r.pan??0,s.connect(o),o.connect(n),n.connect(this.masterGain);const a={id:e,sourceNode:s,gainNode:o,panNode:n,track:t,options:{volume:r.volume??1,muted:r.muted??!1,pan:r.pan??0}};this.sources.set(e,a),console.log("[AudioMixer] Added source:",e),this.emit("sourceAdded",{sourceId:e})}catch(e){const t=e instanceof Error?e:new Error(String(e));throw console.error("[AudioMixer] Failed to add source:",t),this.emit("error",{message:`Failed to add source: ${t.message}`,error:t}),t}}removeSource(e){const t=this.sources.get(e);if(t)try{t.sourceNode.disconnect(),t.gainNode.disconnect(),t.panNode.disconnect(),this.sources.delete(e),console.log("[AudioMixer] Removed source:",e),this.emit("sourceRemoved",{sourceId:e})}catch(e){console.error("[AudioMixer] Error removing source:",e)}}updateSource(e,t){const r=this.sources.get(e);r?(void 0!==t.volume&&(r.options.volume=t.volume,r.options.muted||r.gainNode.gain.setTargetAtTime(t.volume,this.audioContext?.currentTime??0,.01)),void 0!==t.muted&&(r.options.muted=t.muted,r.gainNode.gain.setTargetAtTime(t.muted?0:r.options.volume,this.audioContext?.currentTime??0,.01)),void 0!==t.pan&&(r.options.pan=t.pan,r.panNode.pan.setTargetAtTime(t.pan,this.audioContext?.currentTime??0,.01))):console.warn("[AudioMixer] Source not found:",e)}setVolume(e,t){this.updateSource(e,{volume:Math.max(0,Math.min(2,t))})}mute(e){this.updateSource(e,{muted:!0})}unmute(e){this.updateSource(e,{muted:!1})}toggleMute(e){const t=this.sources.get(e);if(!t)return!1;const r=!t.options.muted;return this.updateSource(e,{muted:r}),r}setPan(e,t){this.updateSource(e,{pan:Math.max(-1,Math.min(1,t))})}setMasterVolume(e){this.masterGain&&this.masterGain.gain.setTargetAtTime(Math.max(0,Math.min(2,e)),this.audioContext?.currentTime??0,.01)}getMasterVolume(){return this.masterGain?.gain.value??1}getOutputStream(){return this.outputStream}getOutputTrack(){return this.outputStream?.getAudioTracks()[0]??null}getSourceIds(){return Array.from(this.sources.keys())}getSourceOptions(e){const t=this.sources.get(e);return t?{...t.options}:null}hasSource(e){return this.sources.has(e)}getSourceCount(){return this.sources.size}async resume(){this.audioContext&&"suspended"===this.audioContext.state&&await this.audioContext.resume()}async suspend(){this.audioContext&&"running"===this.audioContext.state&&await this.audioContext.suspend()}getState(){return this.audioContext?.state??null}getLevel(){if(!this.analyzer)return 0;const e=new Uint8Array(this.analyzer.frequencyBinCount);this.analyzer.getByteTimeDomainData(e);let t=0;for(let r=0;r<e.length;r++){const i=Math.abs(e[r]-128)/128;i>t&&(t=i)}if(t<1e-4)return 0;const r=(20*Math.log10(t)- -60)/60;return Math.max(0,Math.min(1,r))}getLevels(){const e=this.getLevel();return e>this.peakLevel?this.peakLevel=e:this.peakLevel*=this.peakDecayRate,{level:e,peakLevel:this.peakLevel}}startLevelMonitoring(){if(this.levelMonitoringActive)return;this.levelMonitoringActive=!0;const e=()=>{if(!this.levelMonitoringActive||"running"!==this.audioContext?.state)return;const{level:t,peakLevel:r}=this.getLevels();this.emit("levelUpdate",{level:t,peakLevel:r}),requestAnimationFrame(e)};requestAnimationFrame(e),console.log("[AudioMixer] Level monitoring started")}stopLevelMonitoring(){this.levelMonitoringActive=!1,this.peakLevel=0,console.log("[AudioMixer] Level monitoring stopped")}isMonitoringLevels(){return this.levelMonitoringActive}destroy(){this.stopLevelMonitoring();for(const e of this.sources.keys())this.removeSource(e);this.compressor&&(this.compressor.disconnect(),this.compressor=null),this.limiter&&(this.limiter.disconnect(),this.limiter=null),this.analyzer&&(this.analyzer.disconnect(),this.analyzer=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.destination=null,this.masterGain=null,this.outputStream=null,this.removeAllListeners()}}const ze={enabled:!0,maxAttempts:5,baseDelay:1e3,maxDelay:3e4,backoffMultiplier:2};class Ue extends Ae{constructor(e={}){super(),this.reconnectTimeout=null,this.countdownInterval=null,this.reconnectCallback=null,this.config={...ze,...e},this.state={isReconnecting:!1,attemptNumber:0,nextAttemptIn:null,lastError:null}}calculateDelay(e){const t=this.config.baseDelay*Math.pow(this.config.backoffMultiplier,e-1),r=.1*t*(2*Math.random()-1);return Math.min(t+r,this.config.maxDelay)}start(e){this.config.enabled?this.state.isReconnecting?console.log("[ReconnectionManager] Already reconnecting"):(this.reconnectCallback=e,this.state={isReconnecting:!0,attemptNumber:0,nextAttemptIn:null,lastError:null},this.scheduleNextAttempt()):console.log("[ReconnectionManager] Reconnection disabled")}scheduleNextAttempt(){if(!this.state.isReconnecting)return;if(this.state.attemptNumber++,this.state.attemptNumber>this.config.maxAttempts)return void this.handleExhausted();const e=this.calculateDelay(this.state.attemptNumber);this.state.nextAttemptIn=e,console.log(`[ReconnectionManager] Scheduling attempt ${this.state.attemptNumber}/${this.config.maxAttempts} in ${e}ms`),this.emit("attemptStart",{attempt:this.state.attemptNumber,delay:e}),this.startCountdown(e),this.reconnectTimeout=setTimeout(()=>{this.executeAttempt()},e)}startCountdown(e){this.stopCountdown();const t=Date.now();this.countdownInterval=setInterval(()=>{const r=Date.now()-t;this.state.nextAttemptIn=Math.max(0,e-r)},100)}stopCountdown(){this.countdownInterval&&(clearInterval(this.countdownInterval),this.countdownInterval=null)}async executeAttempt(){if(this.stopCountdown(),this.state.nextAttemptIn=null,this.reconnectCallback){console.log(`[ReconnectionManager] Executing attempt ${this.state.attemptNumber}`);try{await this.reconnectCallback(),this.handleSuccess()}catch(e){const t=e instanceof Error?e.message:String(e);this.handleFailure(t)}}else console.error("[ReconnectionManager] No reconnect callback set")}handleSuccess(){console.log("[ReconnectionManager] Reconnection successful"),this.state={isReconnecting:!1,attemptNumber:0,nextAttemptIn:null,lastError:null},this.cleanup(),this.emit("attemptSuccess",void 0)}handleFailure(e){console.log(`[ReconnectionManager] Attempt ${this.state.attemptNumber} failed:`,e),this.state.lastError=e,this.emit("attemptFailed",{attempt:this.state.attemptNumber,error:e}),this.scheduleNextAttempt()}handleExhausted(){console.log("[ReconnectionManager] All reconnection attempts exhausted"),this.emit("exhausted",{totalAttempts:this.config.maxAttempts}),this.stop()}stop(){console.log("[ReconnectionManager] Stopping reconnection"),this.cleanup(),this.state={isReconnecting:!1,attemptNumber:0,nextAttemptIn:null,lastError:this.state.lastError}}cleanup(){this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.stopCountdown(),this.reconnectCallback=null}reset(){this.stop(),this.state.lastError=null}getState(){return{...this.state}}isReconnecting(){return this.state.isReconnecting}getAttemptNumber(){return this.state.attemptNumber}getMaxAttempts(){return this.config.maxAttempts}updateConfig(e){this.config={...this.config,...e}}destroy(){this.cleanup(),this.removeAllListeners()}}const Le=[{mode:"solo",label:"Solo",icon:"⬜",minSources:1,maxSources:1},{mode:"pip-br",label:"PiP ↘",icon:"◳",minSources:2,maxSources:2},{mode:"pip-bl",label:"PiP ↙",icon:"◲",minSources:2,maxSources:2},{mode:"pip-tr",label:"PiP ↗",icon:"◱",minSources:2,maxSources:2},{mode:"pip-tl",label:"PiP ↖",icon:"◰",minSources:2,maxSources:2},{mode:"split-h",label:"Split ⬌",icon:"▥",minSources:2,maxSources:2},{mode:"split-v",label:"Split ⬍",icon:"▤",minSources:2,maxSources:2},{mode:"focus-l",label:"Focus ◀",icon:"◧",minSources:2,maxSources:2},{mode:"focus-r",label:"Focus ▶",icon:"◨",minSources:2,maxSources:2},{mode:"pip-dual-br",label:"Main+2 PiP",icon:"⊞",minSources:3,maxSources:3},{mode:"pip-dual-bl",label:"Main+2 PiP ↙",icon:"⊟",minSources:3,maxSources:3},{mode:"split-pip-l",label:"Split+PiP",icon:"⊠",minSources:3,maxSources:3},{mode:"split-pip-r",label:"Split+PiP ▶",icon:"⊡",minSources:3,maxSources:3},{mode:"featured",label:"Featured",icon:"⬒",minSources:3,maxSources:99},{mode:"featured-r",label:"Featured ▶",icon:"⬓",minSources:3,maxSources:99},{mode:"grid",label:"Grid",icon:"▦",minSources:2,maxSources:99},{mode:"stack",label:"Stack",icon:"☰",minSources:2,maxSources:99}];let De="letterbox";function Ve(e,t,r,i=De){return{id:`layer-${t}-${e}`,sourceId:e,visible:!0,locked:!1,zIndex:t,transform:{...Te,...r},scalingMode:i}}const Oe=.25,je=.02,Ne=.005;function Fe(e){return[Ve(e[0],0,{x:0,y:0,width:1,height:1})]}function He(e,t,r=.25){if(e.length<2)return Fe(e);const i={tl:{x:je,y:je},tr:{x:1-r-je,y:je},bl:{x:je,y:1-r-je},br:{x:1-r-je,y:1-r-je}}[t];return[Ve(e[0],0,{x:0,y:0,width:1,height:1}),Ve(e[1],1,{x:i.x,y:i.y,width:r,height:r,borderRadius:8})]}function qe(e,t,r=.5){if(e.length<2)return Fe(e);const i=.0025;return"h"===t?[Ve(e[0],0,{x:0,y:0,width:r-i,height:1}),Ve(e[1],0,{x:r+i,y:0,width:1-r-i,height:1})]:[Ve(e[0],0,{x:0,y:0,width:1,height:r-i}),Ve(e[1],0,{x:0,y:r+i,width:1,height:1-r-i})]}function Be(e,t){if(e.length<3)return He(e,"br"===t?"br":"bl");const r=Oe,i=[Ve(e[0],0,{x:0,y:0,width:1,height:1})];return"br"===t?i.push(Ve(e[1],1,{x:.73,y:.47,width:r,height:r,borderRadius:8}),Ve(e[2],2,{x:.73,y:.73,width:r,height:r,borderRadius:8})):i.push(Ve(e[1],1,{x:je,y:.47,width:r,height:r,borderRadius:8}),Ve(e[2],2,{x:je,y:.73,width:r,height:r,borderRadius:8})),i}function Ge(e,t){if(e.length<3)return qe(e,"h");const r=Oe,i=[Ve(e[0],0,{x:0,y:0,width:.4975,height:1}),Ve(e[1],0,{x:.5025,y:0,width:.4975,height:1})];return"l"===t?i.push(Ve(e[2],1,{x:.2275,y:.73,width:r,height:r,borderRadius:8})):i.push(Ve(e[2],1,{x:.73,y:.73,width:r,height:r,borderRadius:8})),i}function Qe(e,t){const r=e.length;if(r<=2)return qe(e,"bottom"===t?"v":"h",.75);const i=Ne,s=.795,o=[];if("bottom"===t){o.push(Ve(e[0],0,{x:0,y:0,width:1,height:s}));const t=r-1,n=(1-i*(t-1))/t;for(let t=1;t<r;t++)o.push(Ve(e[t],0,{x:(t-1)*(n+i),y:.8,width:n,height:.2}))}else{o.push(Ve(e[0],0,{x:0,y:0,width:s,height:1}));const t=r-1,n=(1-i*(t-1))/t;for(let t=1;t<r;t++)o.push(Ve(e[t],0,{x:.8,y:(t-1)*(n+i),width:.2,height:n}))}return o}function Xe(e,t){if(0===t.length)return[];De=e.scalingMode??"letterbox";const r=e.pipScale??Oe,i=e.splitRatio??.5,s=Math.min(Math.max(i,.0025),.9975);switch(e.mode){case"solo":case"fullscreen":default:return Fe(t);case"pip-br":case"pip":return He(t,"br",r);case"pip-bl":return He(t,"bl",r);case"pip-tr":return He(t,"tr",r);case"pip-tl":return He(t,"tl",r);case"split-h":case"side-by-side":return qe(t,"h",s);case"split-v":return qe(t,"v",s);case"focus-l":return qe(t,"h",.7);case"focus-r":return qe(t,"h",.3);case"pip-dual-br":return Be(t,"br");case"pip-dual-bl":return Be(t,"bl");case"split-pip-l":return Ge(t,"l");case"split-pip-r":return Ge(t,"r");case"featured":return Qe(t,"bottom");case"featured-r":return Qe(t,"right");case"grid":return function(e){const t=e.length;if(0===t)return[];if(1===t)return Fe(e);if(2===t)return qe(e,"h");const r=Ne,i=Math.ceil(Math.sqrt(t)),s=Math.ceil(t/i),o=(1-r*(i-1))/i,n=(1-r*(s-1))/s,a=[];for(let c=0;c<t;c++){const l=c%i,d=Math.floor(c/i),h=d===s-1,u=h?(t-1)%i+1:i;let p=0;h&&u<i&&(p=(1-(u*o+(u-1)*r))/2);const g=p+l*(o+r),f=d*(n+r);a.push(Ve(e[c],c,{x:g,y:f,width:o,height:n}))}return a}(t);case"stack":return function(e){const t=e.length;if(0===t)return[];if(1===t)return Fe(e);const r=Ne,i=(1-r*(t-1))/t;return e.map((e,t)=>Ve(e,0,{x:0,y:t*(i+r),width:1,height:i}))}(t)}}const Ke={durationMs:300,easing:"ease-out"};class Je extends Ae{constructor(e){super(),this.scenes=new Map,this.activeSceneId=null,this.defaultLayoutTransition=Ke,this.isAnimating=!1,this.worker=null,this.workerReady=!1,this.pendingMessages=[],this.frameProcessors=new Map,this.frameReaders=new Map,this.outputCanvas=null,this.outputStream=null,this.lastStats={fps:0,frameTimeMs:0},this.config={...Me,...e},this.defaultTransition=this.config.defaultTransition||{type:"fade",durationMs:500,easing:"ease-in-out"},this.currentLayout={mode:"solo",scalingMode:"letterbox"}}async initializeWorker(){let e=null;const r=[new URL("../workers/compositor.worker.js",t&&"SCRIPT"===t.tagName.toUpperCase()&&t.src||new URL("fw-streamcrafter.iife.js",document.baseURI).href).href,"/node_modules/@livepeer-frameworks/streamcrafter-core/dist/workers/compositor.worker.js","/workers/compositor.worker.js","./workers/compositor.worker.js"];console.log("[SceneManager] Trying fallback worker paths:",r);for(const t of r){if(this.worker)break;try{console.log(`[SceneManager] Trying worker path: ${t}`);const e=(()=>{try{return new Worker(t,{type:"module"})}catch{return new Worker(t)}})();if(await new Promise(t=>{const r=setTimeout(()=>{e.terminate(),t(!1)},2e3);e.onerror=()=>{clearTimeout(r),e.terminate(),t(!1)},e.onmessage=()=>{clearTimeout(r),t(!0)},setTimeout(()=>{clearTimeout(r),t(!0)},500)})){e.terminate();try{this.worker=new Worker(t,{type:"module"})}catch{this.worker=new Worker(t)}console.log(`[SceneManager] Worker loaded from: ${t}`);break}console.warn(`[SceneManager] Worker failed to load from: ${t}`)}catch(r){e=r instanceof Error?r:new Error(String(r)),console.warn(`[SceneManager] Failed to load worker from ${t}:`,e.message),this.worker=null}}if(!this.worker)throw new Error(`Failed to initialize compositor worker. Make sure the worker is bundled correctly. Last error: ${e?.message??"unknown"}`)}async initialize(){if(console.log("[SceneManager] initialize() called"),this.worker)throw new Error("SceneManager already initialized");console.log("[SceneManager] Creating output canvas",{width:this.config.width,height:this.config.height}),this.outputCanvas=document.createElement("canvas"),this.outputCanvas.width=this.config.width,this.outputCanvas.height=this.config.height;const e=this.outputCanvas.transferControlToOffscreen();console.log("[SceneManager] Created OffscreenCanvas"),console.log("[SceneManager] Initializing worker..."),await this.initializeWorker(),console.log("[SceneManager] Worker initialized, waiting for ready...");const t=new Promise((e,t)=>{const r=setTimeout(()=>{console.error("[SceneManager] Worker initialization timeout"),t(new Error("Compositor worker initialization timeout"))},1e4);this.worker.onmessage=t=>{console.log("[SceneManager] Worker message:",t.data.type),"ready"===t.data.type&&(clearTimeout(r),e()),this.handleWorkerMessage(t.data)},this.worker.onerror=e=>{console.error("[SceneManager] Worker error:",e.message),clearTimeout(r),t(new Error(e.message))}});console.log("[SceneManager] Sending init message to worker"),this.worker.postMessage({type:"init",config:this.config,canvas:e},[e]),await t,console.log("[SceneManager] Worker is ready"),console.log("[SceneManager] Creating default scene");const r=this.createScene("Default");console.log("[SceneManager] Setting active scene:",r.id),this.setActiveScene(r.id),console.log("[SceneManager] Initialize complete")}handleWorkerMessage(e){switch(e.type){case"ready":this.workerReady=!0;for(const e of this.pendingMessages)this.worker?.postMessage(e);this.pendingMessages=[];break;case"stats":this.lastStats=e.stats,this.emit("statsUpdate",{stats:e.stats});break;case"transitionComplete":this.emit("transitionCompleted",{sceneId:e.sceneId});break;case"layoutAnimationComplete":{this.isAnimating=!1;const e=this.getActiveScene();if(e){const t=e.layers.filter(e=>e.visible).map(e=>e.sourceId);e.layers=Xe(this.currentLayout,t)}this.emit("layoutAnimationCompleted",{layout:this.currentLayout});break}case"rendererChanged":this.config.renderer=e.renderer,this.emit("rendererChanged",{renderer:e.renderer});break;case"error":this.emit("error",{message:e.message})}}sendToWorker(e,t){this.workerReady&&this.worker?this.worker.postMessage(e,t||[]):this.pendingMessages.push(e)}createScene(e,t="#000000"){const r=`scene-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,i={id:r,name:e,layers:[],backgroundColor:t};return this.scenes.set(r,i),this.emit("sceneCreated",{scene:i}),i}deleteScene(e){if(!this.scenes.has(e))throw new Error(`Scene not found: ${e}`);if(this.activeSceneId===e)throw new Error("Cannot delete the active scene");this.scenes.delete(e),this.emit("sceneDeleted",{sceneId:e})}getScene(e){return this.scenes.get(e)}getAllScenes(){return Array.from(this.scenes.values())}getActiveScene(){return this.activeSceneId?this.scenes.get(this.activeSceneId):void 0}setActiveScene(e){const t=this.scenes.get(e);if(!t)throw new Error(`Scene not found: ${e}`);const r=this.activeSceneId;this.activeSceneId=e,this.sendToWorker({type:"updateScene",scene:t}),this.emit("sceneActivated",{scene:t,previousSceneId:r})}async transitionTo(e,t){const r=this.scenes.get(e);if(!r)throw new Error(`Scene not found: ${e}`);const i=t||this.defaultTransition;this.sendToWorker({type:"updateScene",scene:r}),this.sendToWorker({type:"startTransition",transition:i,toSceneId:e});const s=this.activeSceneId;this.emit("transitionStarted",{fromSceneId:s||"",toSceneId:e,transition:i}),this.activeSceneId=e}addLayer(e,t,r){const i=this.scenes.get(e);if(!i)throw new Error(`Scene not found: ${e}`);const s=`layer-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,o=i.layers.reduce((e,t)=>Math.max(e,t.zIndex),-1),n={id:s,sourceId:t,visible:!0,locked:!1,zIndex:o+1,transform:{...Te,...r},scalingMode:this.currentLayout.scalingMode??"letterbox"};return i.layers.push(n),this.updateSceneInWorker(i),this.emit("layerAdded",{sceneId:e,layer:n}),n}removeLayer(e,t){const r=this.scenes.get(e);if(!r)throw new Error(`Scene not found: ${e}`);const i=r.layers.findIndex(e=>e.id===t);if(-1===i)throw new Error(`Layer not found: ${t}`);r.layers.splice(i,1),this.updateSceneInWorker(r),this.emit("layerRemoved",{sceneId:e,layerId:t})}updateLayerTransform(e,t,r){const i=this.scenes.get(e);if(!i)throw new Error(`Scene not found: ${e}`);const s=i.layers.find(e=>e.id===t);if(!s)throw new Error(`Layer not found: ${t}`);s.transform={...s.transform,...r},this.updateSceneInWorker(i),this.emit("layerUpdated",{sceneId:e,layer:s})}setLayerVisibility(e,t,r){const i=this.scenes.get(e);if(!i)throw new Error(`Scene not found: ${e}`);const s=i.layers.find(e=>e.id===t);if(!s)throw new Error(`Layer not found: ${t}`);s.visible=r,this.updateSceneInWorker(i),this.emit("layerUpdated",{sceneId:e,layer:s})}reorderLayers(e,t){const r=this.scenes.get(e);if(!r)throw new Error(`Scene not found: ${e}`);t.forEach((e,t)=>{const i=r.layers.find(t=>t.id===e);i&&(i.zIndex=t)}),this.updateSceneInWorker(r)}cycleSourceOrder(e="forward"){const t=this.getActiveScene();if(!t||t.layers.length<2)return void console.warn("[SceneManager] cycleSourceOrder: Need at least 2 layers");console.log("[SceneManager] cycleSourceOrder BEFORE:",{direction:e,layers:t.layers.map(e=>({id:e.id,sourceId:e.sourceId,zIndex:e.zIndex}))});const r=[...t.layers].sort((e,t)=>e.zIndex-t.zIndex),i=r.map(e=>e.id);if(console.log("[SceneManager] sorted layerIds before rotate:",[...i]),"forward"===e){const e=i.shift();e&&i.push(e)}else{const e=i.pop();e&&i.unshift(e)}console.log("[SceneManager] layerIds after rotate:",[...i]),this.reorderLayers(t.id,i),console.log("[SceneManager] after reorderLayers:",{layers:t.layers.map(e=>({id:e.id,sourceId:e.sourceId,zIndex:e.zIndex}))}),this.currentLayout&&this.applyLayout(this.currentLayout,!0,{durationMs:200,easing:"ease-out"}),console.log("[SceneManager] cycleSourceOrder AFTER applyLayout:",{layers:t.layers.map(e=>({id:e.id,sourceId:e.sourceId,zIndex:e.zIndex}))}),this.emit("layerUpdated",{sceneId:t.id,layer:t.layers[0]})}updateSceneInWorker(e){this.activeSceneId===e.id&&this.sendToWorker({type:"updateScene",scene:e})}applyLayout(e,t=!0,r){const i=this.getActiveScene();if(!i)return void console.warn("[SceneManager] applyLayout: No active scene");this.currentLayout=e;const s=[...i.layers].filter(e=>e.visible).sort((e,t)=>e.zIndex-t.zIndex).map(e=>e.sourceId);console.log("[SceneManager] applyLayout",{mode:e.mode,sourceIds:s,currentLayerCount:i.layers.length,animate:t});const o=Xe(e,s),n={...i,layers:o};if(i.layers=o,t&&o.length>0){const t={...this.defaultLayoutTransition,...r};this.isAnimating=!0,this.emit("layoutAnimationStarted",{layout:e}),this.sendToWorker({type:"animateLayout",targetScene:n,transition:t})}else this.updateSceneInWorker(i);this.sendToWorker({type:"updateLayout",layout:e})}setDefaultLayoutTransition(e){this.defaultLayoutTransition={...this.defaultLayoutTransition,...e}}isLayoutAnimating(){return this.isAnimating}getCurrentLayout(){return this.currentLayout}bindSource(e,t){const r=t.getVideoTracks()[0];if(!r)throw new Error("No video track in stream");const i=globalThis.MediaStreamTrackProcessor;if(!i)return void console.warn("[SceneManager] MediaStreamTrackProcessor not available, compositor will not work");const s=new i({track:r});this.frameProcessors.set(e,s);const o=s.readable.getReader();this.frameReaders.set(e,o);const n=async()=>{try{const{done:t,value:r}=await o.read();if(t||!r)return;const i=r;this.sendToWorker({type:"sourceFrame",sourceId:e,frame:i},[i]),n()}catch(e){"AbortError"!==e?.name&&console.error("[SceneManager] Frame read error:",e)}};n()}unbindSource(e){const t=this.frameReaders.get(e);t&&(t.cancel().catch(()=>{}),this.frameReaders.delete(e));this.frameProcessors.get(e)&&this.frameProcessors.delete(e)}async bindImageSource(e,t){const r=await fetch(t),i=await r.blob(),s=await createImageBitmap(i);this.sendToWorker({type:"sourceImage",sourceId:e,bitmap:s},[s])}applyFilter(e,t){this.sendToWorker({type:"applyFilter",layerId:e,filter:t})}getOutputTrack(){return this.outputCanvas?(this.outputStream||(this.outputStream=this.outputCanvas.captureStream(this.config.frameRate)),this.outputStream.getVideoTracks()[0]||null):null}getOutputStream(){return this.outputCanvas?(this.outputStream||(this.outputStream=this.outputCanvas.captureStream(this.config.frameRate)),this.outputStream):null}getRendererType(){return this.config.renderer}setRenderer(e){this.config.renderer=e,this.sendToWorker({type:"setRenderer",renderer:e})}getStats(){return this.lastStats}getConfig(){return{...this.config}}updateOutputConfig(e){const t=e.width??this.config.width,r=e.height??this.config.height,i=e.frameRate??this.config.frameRate;return(t!==this.config.width||r!==this.config.height||i!==this.config.frameRate)&&(this.config.width=t,this.config.height=r,this.config.frameRate=i,this.sendToWorker({type:"resize",width:t,height:r,frameRate:i}),!0)}isInitialized(){return this.workerReady}destroy(){for(const[e]of this.frameProcessors)this.unbindSource(e);this.frameProcessors.clear(),this.frameReaders.clear(),this.worker&&(this.sendToWorker({type:"destroy"}),this.worker.terminate(),this.worker=null),this.scenes.clear(),this.activeSceneId=null,this.outputStream=null,this.outputCanvas=null,this.workerReady=!1,this.removeAllListeners()}}const Ze={professional:{codec:"avc1.4d0032",width:1920,height:1080,bitrate:8e6,framerate:30},broadcast:{codec:"avc1.4d0028",width:1920,height:1080,bitrate:45e5,framerate:30},conference:{codec:"avc1.4d001f",width:1280,height:720,bitrate:25e5,framerate:30},low:{codec:"avc1.42001e",width:640,height:480,bitrate:1e6,framerate:24}},Ye={codec:"opus",sampleRate:48e3,numberOfChannels:2,bitrate:128e3};class et extends Ae{constructor(e={}){super(),this.worker=null,this.videoProcessor=null,this.audioProcessor=null,this.videoReader=null,this.audioReader=null,this.isRunning=!1,this.isInitialized=!1,this.stats=null,this.config=null,this.pendingRequests=new Map,this.requestCounter=0,this.providedWorker=null,this.options={workerUrl:e.workerUrl??"",debug:e.debug??!1,timeout:e.timeout??1e4},this.providedWorker=e.worker??null}log(e,t){this.options.debug&&console.log(`[EncoderManager] ${e}`,t??"")}generateRequestId(){return`req_${++this.requestCounter}_${Date.now()}`}sendRequest(e){return new Promise((t,r)=>{if(!this.worker)return void r(new Error("Worker not created"));const i=e.requestId;if(!i)return this.worker.postMessage(e),void t(void 0);const s=setTimeout(()=>{this.pendingRequests.delete(i),r(new Error(`Request ${i} timed out`))},this.options.timeout);this.pendingRequests.set(i,{resolve:t,reject:r,timer:s}),this.worker.postMessage(e)})}handleResponse(e,t,r){const i=this.pendingRequests.get(e);i&&(clearTimeout(i.timer),this.pendingRequests.delete(e),t?i.resolve():i.reject(new Error(r??"Unknown error")))}tryCreateWorker(e,t=!0){return new Promise(r=>{try{const i=new Worker(e,t?{type:"module"}:void 0);let s=!1;const o=()=>{i.removeEventListener("message",n),i.removeEventListener("error",a)},n=e=>{s||(s=!0,o(),r(i))},a=t=>{s||(s=!0,o(),this.log("Worker failed to load from: "+e.toString(),t.message),i.terminate(),r(null))};i.addEventListener("message",n),i.addEventListener("error",a),setTimeout(()=>{s||(s=!0,o(),r(i))},2e3)}catch(t){this.log("Failed to create worker: "+e.toString(),t),r(null)}})}async createWorkerAsync(){if(this.providedWorker)return this.log("Using provided worker instance"),this.providedWorker;if(this.options.workerUrl){this.log("Creating worker from URL:",this.options.workerUrl);const e=await this.tryCreateWorker(this.options.workerUrl);if(e)return e}const e=[];try{const r=new URL("../workers/encoder.worker.js",t&&"SCRIPT"===t.tagName.toUpperCase()&&t.src||new URL("fw-streamcrafter.iife.js",document.baseURI).href);e.push({url:r,description:"import.meta.url relative"})}catch{}e.push({url:"/workers/encoder.worker.js",description:"Vite dev server"},{url:"/node_modules/@livepeer-frameworks/streamcrafter-core/dist/workers/encoder.worker.js",description:"node_modules"},{url:"./workers/encoder.worker.js",description:"relative path"});for(const{url:t,description:r}of e){this.log(`Trying worker path: ${t.toString()} (${r})`);const e=await this.tryCreateWorker(t);if(e)return this.log("Worker loaded from:",t.toString()),e}throw new Error("Failed to create encoder worker. Provide a worker URL via options.workerUrl or ensure workers are served correctly.")}createWorker(){if(this.providedWorker)return this.providedWorker;if(this.options.workerUrl)return new Worker(this.options.workerUrl,{type:"module"});try{const e=new URL("../workers/encoder.worker.js",t&&"SCRIPT"===t.tagName.toUpperCase()&&t.src||new URL("fw-streamcrafter.iife.js",document.baseURI).href);return new Worker(e,{type:"module"})}catch{}return new Worker("/workers/encoder.worker.js",{type:"module"})}handleWorkerMessage(e){switch(e.type){case"ready":this.log("Worker ready"),e.requestId&&this.handleResponse(e.requestId,!0),this.emit("ready",void 0);break;case"started":this.log("Encoding started"),e.requestId&&this.handleResponse(e.requestId,!0),this.emit("started",void 0);break;case"stopped":this.log("Encoding stopped"),e.requestId&&this.handleResponse(e.requestId,!0),this.emit("stopped",void 0);break;case"flushed":this.log("Encoder flushed"),e.requestId&&this.handleResponse(e.requestId,!0);break;case"stats":this.stats=e.data,this.emit("stats",this.stats);break;case"error":{const t=e.data;console.error("[EncoderManager] Worker error:",t),e.requestId&&this.handleResponse(e.requestId,!1,t.message),this.emit("error",t);break}case"encodedVideoChunk":this.emit("videoChunk",e.data);break;case"encodedAudioChunk":this.emit("audioChunk",e.data);break;default:this.log("Unknown message from worker",e)}}async initialize(e,t){if(this.log("Initializing encoder",t),this.config=t,"undefined"==typeof VideoEncoder||"undefined"==typeof AudioEncoder)throw new Error("WebCodecs not supported in this browser");if("undefined"==typeof MediaStreamTrackProcessor)throw new Error("MediaStreamTrackProcessor not supported in this browser");const r=e.getVideoTracks()[0],i=e.getAudioTracks()[0];r&&(this.videoProcessor=new MediaStreamTrackProcessor({track:r})),i&&(this.audioProcessor=new MediaStreamTrackProcessor({track:i})),this.worker=await this.createWorkerAsync(),this.worker.onmessage=e=>{this.handleWorkerMessage(e.data)},this.worker.onerror=e=>{console.error("[EncoderManager] Worker error:",e),this.emit("error",{message:e.message,fatal:!0})};const s=this.generateRequestId();this.log("Sending initialize to worker",{requestId:s}),await this.sendRequest({type:"initialize",requestId:s,data:{config:t}}),this.isInitialized=!0,this.log("Worker initialized and ready")}async start(){if(!this.isInitialized)throw new Error("EncoderManager not initialized");if(this.isRunning)return;this.log("Starting encoder");const e=this.generateRequestId();await this.sendRequest({type:"start",requestId:e}),this.isRunning=!0,this.videoProcessor&&this.startVideoProcessing(),this.audioProcessor&&this.startAudioProcessing(),this.log("Encoder started, frame processing active")}async startVideoProcessing(){if(this.videoProcessor&&this.worker)try{this.videoReader=this.videoProcessor.readable.getReader();const e=this.videoReader;for(;this.isRunning;){const{value:t,done:r}=await e.read();if(r||!t)break;try{this.worker.postMessage({type:"videoFrame",data:t},[t])}catch(e){console.error("[EncoderManager] Error sending video frame:",e);try{t.close()}catch{}}}}catch(e){this.isRunning&&console.error("[EncoderManager] Video processing error:",e)}}async startAudioProcessing(){if(this.audioProcessor&&this.worker)try{this.audioReader=this.audioProcessor.readable.getReader();const e=this.audioReader;for(;this.isRunning;){const{value:t,done:r}=await e.read();if(r||!t)break;try{this.worker.postMessage({type:"audioData",data:t},[t])}catch(e){console.error("[EncoderManager] Error sending audio data:",e);try{t.close()}catch{}}}}catch(e){this.isRunning&&console.error("[EncoderManager] Audio processing error:",e)}}async stop(){if(this.isRunning){if(this.isRunning=!1,this.log("Stopping encoder"),this.videoReader){try{await this.videoReader.cancel(),this.videoReader.releaseLock()}catch{}this.videoReader=null}if(this.audioReader){try{await this.audioReader.cancel(),this.audioReader.releaseLock()}catch{}this.audioReader=null}if(this.worker&&this.isInitialized){const e=this.generateRequestId();try{await this.sendRequest({type:"stop",requestId:e})}catch(e){this.log("Stop request failed (may be expected)",e)}}this.emit("stopped",void 0)}}async updateConfig(e){if(!this.worker||!this.isInitialized)throw new Error("EncoderManager not initialized");const t=this.generateRequestId();await this.sendRequest({type:"updateConfig",requestId:t,data:e}),this.config&&(e.video&&(this.config.video={...this.config.video,...e.video}),e.audio&&(this.config.audio={...this.config.audio,...e.audio}))}async updateInputStream(e){if(!this.isInitialized||!this.worker)throw new Error("EncoderManager not initialized");const t=this.isRunning;if(this.log("Updating input stream (hot-swap)",{wasRunning:t}),this.videoReader){try{await this.videoReader.cancel(),this.videoReader.releaseLock()}catch{}this.videoReader=null}if(this.audioReader){try{await this.audioReader.cancel(),this.audioReader.releaseLock()}catch{}this.audioReader=null}const r=e.getVideoTracks()[0],i=e.getAudioTracks()[0];this.videoProcessor=r?new MediaStreamTrackProcessor({track:r}):null,this.audioProcessor=i?new MediaStreamTrackProcessor({track:i}):null,t&&(this.videoProcessor&&this.startVideoProcessing(),this.audioProcessor&&this.startAudioProcessing(),this.log("Input stream updated, processing restarted"))}async flush(){if(!this.worker||!this.isInitialized)return;const e=this.generateRequestId();await this.sendRequest({type:"flush",requestId:e})}getStats(){return this.stats}getConfig(){return this.config}getIsInitialized(){return this.isInitialized}getIsRunning(){return this.isRunning}destroy(){this.stop(),this.isInitialized=!1,this.videoProcessor=null,this.audioProcessor=null;for(const[,e]of this.pendingRequests)clearTimeout(e.timer),e.reject(new Error("EncoderManager destroyed"));this.pendingRequests.clear(),this.worker&&(this.worker.terminate(),this.worker=null),this.removeAllListeners()}}function tt(){const e={videoEncoder:"undefined"!=typeof VideoEncoder,audioEncoder:"undefined"!=typeof AudioEncoder,mediaStreamTrackProcessor:"undefined"!=typeof MediaStreamTrackProcessor,mediaStreamTrackGenerator:"undefined"!=typeof MediaStreamTrackGenerator};return{webcodecs:e,webrtc:{peerConnection:"undefined"!=typeof RTCPeerConnection,replaceTrack:"undefined"!=typeof RTCRtpSender&&"replaceTrack"in RTCRtpSender.prototype,insertableStreams:"undefined"!=typeof RTCRtpSender&&"createEncodedStreams"in RTCRtpSender.prototype,scriptTransform:"undefined"!=typeof RTCRtpScriptTransform},mediaDevices:{getUserMedia:"undefined"!=typeof navigator&&void 0!==navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.getUserMedia,getDisplayMedia:"undefined"!=typeof navigator&&void 0!==navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.getDisplayMedia,enumerateDevices:"undefined"!=typeof navigator&&void 0!==navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.enumerateDevices},recommended:e.videoEncoder&&e.audioEncoder&&e.mediaStreamTrackProcessor&&e.mediaStreamTrackGenerator?"webcodecs":"mediastream"}}function rt(){return"undefined"!=typeof RTCRtpScriptTransform}function it(){return"undefined"!=typeof VideoEncoder&&"undefined"!=typeof AudioEncoder&&"undefined"!=typeof MediaStreamTrackProcessor&&"undefined"!=typeof MediaStreamTrackGenerator&&rt()}let st=0;class ot extends Ae{constructor(e){super(),this.whipClient=null,this.whipEndpoints=[],this.currentEndpointIndex=0,this.isStoppingIntentionally=!1,this.state="idle",this.stateContext={},this.sources=new Map,this.outputStream=null,this.statsInterval=null,this.lastStats=null,this.statsInFlight=!1,this.sceneManager=null,this.compositorBaseConfig=null,this.encoderManager=null,this.encoderOverrides={},this.config=e,this.currentProfile=e.profile||"broadcast",this.whipEndpoints=this.buildWhipEndpoints(e),this.deviceManager=new Ie,this.screenCapture=new Pe,this.audioMixer=new We,this.reconnectionManager=new Ue(e.reconnection);const t=tt();this.useWebCodecs=e.useWebCodecs??"webcodecs"===t.recommended,this.setupEventForwarding(),this.log("IngestControllerV2 initialized",{useWebCodecs:this.useWebCodecs,profile:this.currentProfile,audioMixing:e.audioMixing??!1})}buildWhipEndpoints(e){if(e.whipUrls&&e.whipUrls.length>0){return[e.whipUrl,...e.whipUrls].filter((e,t,r)=>r.indexOf(e)===t)}return[e.whipUrl]}getCurrentWhipUrl(){return this.whipEndpoints[this.currentEndpointIndex]??this.config.whipUrl}getNextWhipUrl(){return this.whipEndpoints.length>1&&(this.currentEndpointIndex=(this.currentEndpointIndex+1)%this.whipEndpoints.length),this.getCurrentWhipUrl()}log(e,t){this.config.debug&&console.log(`[IngestControllerV2] ${e}`,t??"")}setupEventForwarding(){this.deviceManager.on("devicesChanged",e=>{this.emit("deviceChange",e)}),this.deviceManager.on("error",e=>{this.emit("error",{error:e.message,recoverable:!0})}),this.screenCapture.on("ended",e=>{if(this.log("Screen capture ended",e),e.stream)for(const[t,r]of this.sources)if("screen"===r.type&&r.stream===e.stream){this.removeSource(t);break}}),this.screenCapture.on("error",e=>{this.emit("error",{error:e.message,recoverable:!0})}),this.reconnectionManager.on("attemptStart",e=>{this.emit("reconnectionAttempt",{attempt:e.attempt,maxAttempts:this.reconnectionManager.getMaxAttempts()})}),this.reconnectionManager.on("attemptSuccess",()=>{this.emit("reconnectionSuccess",void 0),this.setState("streaming")}),this.reconnectionManager.on("attemptFailed",e=>{this.log("Reconnection attempt failed",e)}),this.reconnectionManager.on("exhausted",()=>{this.emit("reconnectionFailed",{error:"All reconnection attempts exhausted"}),this.setState("error",{error:"Connection lost - reconnection failed"})})}setState(e,t){this.state=e,t&&(this.stateContext={...this.stateContext,...t}),this.stateContext.sources=Array.from(this.sources.values()),this.stateContext.activeProfile=this.currentProfile,this.stateContext.reconnection=this.reconnectionManager.getState(),this.emit("stateChange",{state:this.state,context:this.stateContext})}async ensureAudioMixer(){this.config.audioMixing&&null===this.audioMixer.getState()&&await this.audioMixer.initialize()}addMediaSource(e,t,r){const i=function(e){return`${e}-${++st}-${Date.now()}`}(e),s=t.getVideoTracks().length>0,o=Array.from(this.sources.values()).filter(e=>e.stream.getVideoTracks().length>0),n=s&&0===o.length,a={id:i,type:e,stream:t,label:r,active:!0,muted:!1,volume:1,primaryVideo:n};if(this.sources.set(i,a),this.log(`Added source: ${i} (${e})`,{label:r,tracks:t.getTracks().length,primaryVideo:n}),this.config.audioMixing){const e=t.getAudioTracks()[0];e&&this.audioMixer.addSource(i,e,{volume:1})}if(this.sceneManager&&this.sceneManager.isInitialized()){this.log("Binding source to compositor",{sourceId:i}),this.sceneManager.bindSource(i,t);const e=this.sceneManager.getActiveScene();this.log("Adding layer to scene",{sourceId:i,activeSceneId:e?.id,sceneLayers:e?.layers.length}),e&&(this.sceneManager.addLayer(e.id,i),this.log("Layer added",{sourceId:i,layerCount:e.layers.length}))}else this.log("Compositor not ready when adding source",{sourceId:i,hasSceneManager:!!this.sceneManager,isInitialized:this.sceneManager?.isInitialized()??!1});return this.emit("sourceAdded",{source:a}),this.updateOutputStreamFromSources(),a}removeSource(e){const t=this.sources.get(e);if(!t)return;const r=t.primaryVideo;if(t.stream.getTracks().forEach(e=>e.stop()),this.config.audioMixing&&this.audioMixer.removeSource(e),this.sceneManager){this.sceneManager.unbindSource(e);const t=this.sceneManager.getActiveScene();if(t){const r=t.layers.find(t=>t.sourceId===e);r&&this.sceneManager.removeLayer(t.id,r.id)}}if(this.sources.delete(e),this.log(`Removed source: ${e}`),r){const e=Array.from(this.sources.values()).filter(e=>e.stream.getVideoTracks().length>0);e.length>0&&(e[0].primaryVideo=!0,this.sources.set(e[0].id,e[0]),this.log(`Reassigned primary video to: ${e[0].id}`))}this.emit("sourceRemoved",{sourceId:e}),this.updateOutputStreamFromSources()}setPrimaryVideoSource(e){const t=this.sources.get(e);if(t)if(0!==t.stream.getVideoTracks().length){for(const[e,t]of this.sources)t.primaryVideo&&(t.primaryVideo=!1,this.sources.set(e,t));t.primaryVideo=!0,this.sources.set(e,t),this.log(`Set primary video source: ${e}`),this.emit("sourceUpdated",{source:t,changes:{primaryVideo:!0}}),this.updateOutputStreamFromSources()}else this.log(`Cannot set source ${e} as primary - no video track`)}getPrimaryVideoSource(){for(const e of this.sources.values())if(e.primaryVideo)return e;return null}updateOutputStreamFromSources(){const e=Array.from(this.sources.values()).filter(e=>e.active);if(0===e.length)return void(this.outputStream=null);const t=[];if(this.sceneManager&&this.sceneManager.isInitialized()){const e=this.sceneManager.getOutputTrack();e&&t.push(e)}else{const r=e.filter(e=>e.stream.getVideoTracks().length>0),i=r.find(e=>e.primaryVideo)||r[0];if(i){const e=i.stream.getVideoTracks()[0];e&&t.push(e)}}if(this.config.audioMixing&&"running"===this.audioMixer.getState()){const e=this.audioMixer.getOutputTrack();e&&t.push(e)}else for(const r of e){const e=r.stream.getAudioTracks()[0];if(e&&!r.muted){t.push(e);break}}this.outputStream=t.length>0?new MediaStream(t):null,this.whipClient&&"streaming"===this.state&&this.updateWhipTracks(),this.encoderManager&&this.outputStream&&this.encoderManager.updateInputStream(this.outputStream).catch(e=>{this.log("Failed to update encoder input stream",e)}),this.log("Output stream updated",{videoTracks:this.outputStream?.getVideoTracks().length??0,audioTracks:this.outputStream?.getAudioTracks().length??0,usingCompositor:!!this.sceneManager})}async updateWhipTracks(){if(this.whipClient&&this.outputStream)try{const e=this.whipClient.getPeerConnection();if(!e)return;const t=e.getSenders(),r=this.outputStream.getVideoTracks()[0],i=t.find(e=>"video"===e.track?.kind);i&&await i.replaceTrack(r??null);const s=this.outputStream.getAudioTracks()[0],o=t.find(e=>"audio"===e.track?.kind);o&&await o.replaceTrack(s??null)}catch(e){this.log("Error updating WHIP tracks",e)}}async startCamera(e={}){this.log("Starting camera capture",e),this.setState("requesting_permissions");try{await this.ensureAudioMixer();const t=e.profile||this.currentProfile,r={...e,profile:t};if(this.encoderOverrides?.video){const e=this.encoderOverrides.video,i=_e(t);r.customConstraints={video:{...i,...e.width&&{width:{ideal:e.width}},...e.height&&{height:{ideal:e.height}},...e.framerate&&{frameRate:{ideal:e.framerate}}},audio:!0},this.log("Using encoder overrides for capture constraints:",r.customConstraints)}const i=await this.deviceManager.getUserMedia(r),s=await this.getCameraLabel(i),o=this.addMediaSource("camera",i,s);return this.setState("capturing",{hasVideo:i.getVideoTracks().length>0,hasAudio:i.getAudioTracks().length>0}),o}catch(e){throw this.setState("error",{error:e instanceof Error?e.message:String(e)}),e}}async getCameraLabel(e){const t=e.getVideoTracks()[0];return t&&t.label||"Camera"}async startScreenShare(e={}){this.log("Starting screen share",e),this.setState("requesting_permissions");try{await this.ensureAudioMixer();const t={...e};if(this.encoderOverrides?.video){const e=this.encoderOverrides.video;t.video={...e.width&&{width:{ideal:e.width}},...e.height&&{height:{ideal:e.height}},...e.framerate&&{frameRate:{ideal:e.framerate}}},this.log("Using encoder overrides for screen capture constraints:",t.video)}const r=await this.screenCapture.start(t);if(r){const e=r.getVideoTracks()[0],t=e?.label||`Screen ${this.screenCapture.getCaptureCount()}`,i=this.addMediaSource("screen",r,t);return this.setState("capturing",{hasVideo:!0,isScreenShare:!0}),i}return this.sources.size>0?this.setState("capturing"):this.setState("idle"),null}catch(e){throw this.setState("error",{error:e instanceof Error?e.message:String(e)}),e}}addCustomSource(e,t){return this.addMediaSource("custom",e,t)}setSourceVolume(e,t){const r=this.sources.get(e);r&&(r.volume=Math.max(0,Math.min(2,t)),this.sources.set(e,r),this.config.audioMixing&&this.audioMixer.setVolume(e,r.volume),this.emit("sourceUpdated",{source:r,changes:{volume:r.volume}}))}setSourceMuted(e,t){const r=this.sources.get(e);r&&(r.muted=t,this.sources.set(e,r),this.config.audioMixing?t?this.audioMixer.mute(e):this.audioMixer.unmute(e):r.stream.getAudioTracks().forEach(e=>{e.enabled=!t}),this.emit("sourceUpdated",{source:r,changes:{muted:t}}),this.updateOutputStreamFromSources())}setSourceActive(e,t){const r=this.sources.get(e);r&&(r.active=t,this.sources.set(e,r),this.emit("sourceUpdated",{source:r,changes:{active:t}}),this.updateOutputStreamFromSources())}setMasterVolume(e){this.config.audioMixing&&this.audioMixer.setMasterVolume(e)}getMasterVolume(){return this.config.audioMixing?this.audioMixer.getMasterVolume():1}async stopCapture(){this.log("Stopping all capture");for(const e of Array.from(this.sources.keys()))this.removeSource(e);this.deviceManager.stopAllTracks(),this.screenCapture.stop(),this.outputStream=null,"streaming"!==this.state&&this.setState("idle",{hasVideo:!1,hasAudio:!1,isScreenShare:!1})}async setQualityProfile(e){if(e===this.currentProfile)return;const t=this.currentProfile;this.currentProfile=e,this.log(`Changing quality profile: ${t} -> ${e}`);for(const[t,r]of this.sources)if("camera"===r.type){const t=r.stream.getVideoTracks()[0];if(t)try{const r=_e(e);await t.applyConstraints(r)}catch(e){this.log("Failed to apply new constraints",e)}}this.emit("qualityChanged",{profile:e,previousProfile:t}),this.setState(this.state,{activeProfile:e})}setupWhipClientHandlers(){this.whipClient&&(this.whipClient.on("stateChange",e=>{if(this.log("WHIP state changed",e),this.stateContext={...this.stateContext,connectionState:e.state},"connected"===e.state){if(this.setState("streaming"),this.startStatsPolling(),this.reconnectionManager.reset(),this.useWebCodecs&&this.encoderManager&&this.whipClient){this.log("Attempting to attach WebCodecs encoder transform");const e=this.whipClient.canUseEncodedInsertion();if(this.log("canUseEncodedInsertion result:",e),e)try{this.whipClient.attachEncoderTransform(this.encoderManager),this.encoderManager.start(),this.log("WebCodecs encoder transform attached",{videoCodec:this.whipClient.getNegotiatedVideoCodec(),audioCodec:this.whipClient.getNegotiatedAudioCodec()}),this.emit("webCodecsActive",{active:!0})}catch(e){this.log("Failed to attach encoder transform, continuing with browser encoding",e),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null)}else this.log("Codec alignment check failed, using browser encoding",{videoCodec:this.whipClient.getNegotiatedVideoCodec(),audioCodec:this.whipClient.getNegotiatedAudioCodec()}),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null)}}else if("failed"===e.state||"disconnected"===e.state){if(this.isStoppingIntentionally)return;"streaming"===this.state&&!1!==this.config.reconnection?.enabled?this.handleConnectionLost():(this.setState("error",{error:"failed"===e.state?"Connection failed":"Connection lost"}),this.stopStatsPolling())}}),this.whipClient.on("error",e=>{this.isStoppingIntentionally||this.emit("error",{error:e.message,recoverable:!1})}))}async startStreaming(){if(!this.outputStream)throw new Error("No media source available. Add a camera or screen share first.");this.log("Starting streaming"),this.currentEndpointIndex=0,this.setState("connecting");try{if(this.whipClient=new Re({whipUrl:this.getCurrentWhipUrl(),iceServers:this.config.iceServers,debug:this.config.debug}),this.setupWhipClientHandlers(),this.config.audioMixing&&await this.audioMixer.resume(),this.useWebCodecs&&rt()){this.log("Initializing WebCodecs encoder (Path C: RTCRtpScriptTransform)");try{this.encoderManager=new et({debug:this.config.debug}),this.encoderManager.on("error",e=>{this.emit("error",{error:e.message,recoverable:!e.fatal}),e.fatal&&"streaming"===this.state&&(this.log("Fatal encoder error, reconnecting without WebCodecs"),this.handleEncoderFailure())}),this.encoderManager.on("stats",e=>{this.log("Encoder stats",e)});const e=function(e="broadcast",t){const r=Ze[e],i=Ye,s=t?.video?.width??r.width,o=t?.video?.height??r.height,n=t?.video?.framerate??r.framerate,a=function(e,t,r){const i=e*t;return i>=8294400?r>30?"avc1.640034":"avc1.640033":i>=3686400?r>30?"avc1.640033":"avc1.640032":i>=2073600?r>30?"avc1.640032":"avc1.64002a":i>=921600?r>30?"avc1.64002a":"avc1.640028":"avc1.64001f"}(s,o,n);return{video:{...r,codec:a,width:s,height:o,framerate:n,...void 0!==t?.video?.bitrate&&{bitrate:t.video.bitrate}},audio:{...i,...void 0!==t?.audio?.bitrate&&{bitrate:t.audio.bitrate},...void 0!==t?.audio?.sampleRate&&{sampleRate:t.audio.sampleRate},...void 0!==t?.audio?.numberOfChannels&&{numberOfChannels:t.audio.numberOfChannels}}}}("auto"===this.currentProfile?"broadcast":this.currentProfile,this.encoderOverrides);this.log("Encoder config with overrides:",e),await this.encoderManager.initialize(this.outputStream,e),this.log("WebCodecs encoder initialized")}catch(e){this.log("WebCodecs encoder initialization failed, falling back to browser encoding",e),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null)}}else this.useWebCodecs&&this.log("WebCodecs requested but RTCRtpScriptTransform not supported, using browser encoding");await this.whipClient.connect(this.outputStream)}catch(e){throw this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null),this.setState("error",{error:e instanceof Error?e.message:String(e)}),e}}async handleEncoderFailure(){if(this.log("Handling encoder failure - reconnecting without WebCodecs"),this.setState("reconnecting"),this.stopStatsPolling(),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null),this.useWebCodecs=!1,this.whipClient)try{await this.whipClient.disconnect()}finally{this.whipClient.destroy(),this.whipClient=null}if(this.outputStream)try{this.whipClient=new Re({whipUrl:this.getNextWhipUrl(),iceServers:this.config.iceServers,debug:this.config.debug}),this.setupWhipClientHandlers(),await this.whipClient.connect(this.outputStream)}catch(e){this.setState("error",{error:`Reconnection failed: ${e instanceof Error?e.message:String(e)}`})}else this.setState("error",{error:"No output stream available for reconnection"})}handleConnectionLost(){this.log("Connection lost, starting reconnection"),this.setState("reconnecting"),this.stopStatsPolling(),this.reconnectionManager.start(async()=>{if(this.whipClient)try{await this.whipClient.disconnect()}finally{this.whipClient.destroy(),this.whipClient=null}if(!this.outputStream)throw new Error("No output stream available");this.whipClient=new Re({whipUrl:this.getNextWhipUrl(),iceServers:this.config.iceServers,debug:this.config.debug}),this.setupWhipClientHandlers(),await new Promise((e,t)=>{const r=setTimeout(()=>{t(new Error("Connection timeout"))},3e4),i=s=>{"connected"===s.state?(clearTimeout(r),this.whipClient?.off("stateChange",i),e()):"failed"===s.state&&(clearTimeout(r),this.whipClient?.off("stateChange",i),t(new Error("Connection failed")))};this.whipClient.on("stateChange",i),this.whipClient.connect(this.outputStream).catch(t)})})}async stopStreaming(){this.log("Stopping streaming"),this.isStoppingIntentionally=!0;try{this.stopStatsPolling(),this.reconnectionManager.stop(),this.encoderManager&&(await this.encoderManager.stop(),this.encoderManager.destroy(),this.encoderManager=null),this.whipClient&&(await this.whipClient.disconnect(),this.whipClient.destroy(),this.whipClient=null),this.sources.size>0?this.setState("capturing"):this.setState("idle"),this.stateContext={...this.stateContext,connectionState:"disconnected"}}finally{this.isStoppingIntentionally=!1}}async switchVideoDevice(e){const t=await this.deviceManager.replaceVideoTrack(e,this.currentProfile);if(t&&this.whipClient){const e=this.whipClient.getPeerConnection();if(e){const r=e.getSenders().find(e=>"video"===e.track?.kind);r&&await r.replaceTrack(t)}}}async switchAudioDevice(e){const t=await this.deviceManager.replaceAudioTrack(e,this.currentProfile);if(t&&this.whipClient){const e=this.whipClient.getPeerConnection();if(e){const r=e.getSenders().find(e=>"audio"===e.track?.kind);r&&await r.replaceTrack(t)}}}startStatsPolling(){this.statsInterval||(this.statsInterval=setInterval(async()=>{if(!this.statsInFlight){this.statsInFlight=!0;try{const e=await this.getStats();e&&(this.lastStats=e,this.emit("statsUpdate",e))}finally{this.statsInFlight=!1}}},1e3))}stopStatsPolling(){this.statsInterval&&(clearInterval(this.statsInterval),this.statsInterval=null)}async getStats(){if(!this.whipClient)return null;const e=await this.whipClient.getStats();if(!e)return null;const t={video:{bytesSent:0,packetsSent:0,packetsLost:0,framesEncoded:0,framesPerSecond:0,bitrate:0},audio:{bytesSent:0,packetsSent:0,packetsLost:0,bitrate:0},connection:{rtt:0,state:this.whipClient.getPeerConnection()?.connectionState??"new",iceState:this.whipClient.getPeerConnection()?.iceConnectionState??"new"},timestamp:Date.now()},r=this.lastStats;return e.forEach(e=>{if("outbound-rtp"===e.type){const i=e;if("video"===i.kind){if(t.video.bytesSent=i.bytesSent??0,t.video.packetsSent=i.packetsSent??0,t.video.framesEncoded=i.framesEncoded??0,t.video.framesPerSecond=i.framesPerSecond??0,r){const e=(t.timestamp-r.timestamp)/1e3,i=t.video.bytesSent-r.video.bytesSent;t.video.bitrate=Math.round(8*i/e)}}else if("audio"===i.kind&&(t.audio.bytesSent=i.bytesSent??0,t.audio.packetsSent=i.packetsSent??0,r)){const e=(t.timestamp-r.timestamp)/1e3,i=t.audio.bytesSent-r.audio.bytesSent;t.audio.bitrate=Math.round(8*i/e)}}else"candidate-pair"===e.type&&"succeeded"===e.state&&(t.connection.rtt=e.currentRoundTripTime??0)}),t}async enableCompositor(e){if(this.log("enableCompositor called",{alreadyEnabled:!!this.sceneManager}),this.sceneManager)return void this.log("Compositor already enabled");const t={...Me,...this.config.compositor,...e};this.log("Creating SceneManager with config",t),this.sceneManager=new Je(t),this.compositorBaseConfig=t;try{this.log("Initializing SceneManager..."),await this.sceneManager.initialize(),this.log("SceneManager initialized successfully")}catch(e){this.sceneManager=null;const t=e instanceof Error?e.message:String(e);throw this.log("Compositor initialization failed:",t),new Error(`Compositor initialization failed: ${t}`)}if(!this.sceneManager)throw this.log("ERROR: SceneManager was unexpectedly null after initialization"),new Error("SceneManager was unexpectedly null after initialization");this.log("SceneManager is valid, getting active scene...");const r=this.sceneManager.getActiveScene();this.log("Compositor active scene:",r?.id??"none");for(const[e,t]of this.sources){if(!this.sceneManager)break;this.sceneManager.bindSource(e,t.stream),r&&this.sceneManager.addLayer(r.id,e)}this.sceneManager&&this.sceneManager.on("error",e=>{this.emit("error",{error:e.message,recoverable:!0})}),this.log("Compositor enabled",t),this.updateOutputStreamFromSources()}disableCompositor(){this.sceneManager&&(this.sceneManager.destroy(),this.sceneManager=null,this.log("Compositor disabled"),this.updateOutputStreamFromSources())}getSceneManager(){return this.sceneManager}isCompositorEnabled(){return null!==this.sceneManager&&this.sceneManager.isInitialized()}getState(){return this.state}getStateContext(){return{...this.stateContext}}getMediaStream(){return this.outputStream}getSources(){return Array.from(this.sources.values())}getSource(e){return this.sources.get(e)}getQualityProfile(){return this.currentProfile}getDeviceManager(){return this.deviceManager}getScreenCapture(){return this.screenCapture}getAudioMixer(){return this.audioMixer}getReconnectionManager(){return this.reconnectionManager}async getDevices(){return this.deviceManager.enumerateDevices()}isStreaming(){return"streaming"===this.state}isCapturing(){return"capturing"===this.state||"streaming"===this.state}isReconnecting(){return"reconnecting"===this.state}setUseWebCodecs(e){"streaming"!==this.state?(this.useWebCodecs=e,this.log("useWebCodecs set to",e)):this.log("Cannot change useWebCodecs while streaming")}setEncoderOverrides(e){if("streaming"!==this.state){if(this.encoderOverrides=e,this.log("Encoder overrides set:",e),this.sceneManager){const t=this.compositorBaseConfig??this.sceneManager.getConfig(),r=e.video?.width??t.width,i=e.video?.height??t.height,s=e.video?.framerate??t.frameRate;this.sceneManager.updateOutputConfig({width:r,height:i,frameRate:s})&&this.updateOutputStreamFromSources()}}else this.log("Cannot change encoder overrides while streaming")}getEncoderOverrides(){return this.encoderOverrides}getUseWebCodecs(){return this.useWebCodecs}getEncoderManager(){return this.encoderManager}isWebCodecsActive(){return null!==this.encoderManager&&!0===this.whipClient?.hasEncoderTransform()}destroy(){this.log("Destroying IngestControllerV2"),this.stopStatsPolling(),this.reconnectionManager.destroy(),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null),this.whipClient&&(this.whipClient.destroy(),this.whipClient=null),this.sceneManager&&(this.sceneManager.destroy(),this.sceneManager=null);for(const e of Array.from(this.sources.keys()))this.removeSource(e);this.deviceManager.destroy(),this.screenCapture.destroy(),this.audioMixer.destroy(),this.removeAllListeners(),this.setState("destroyed")}}class nt{constructor(e,t="broadcast"){this.controller=null,this.unsubs=[],this.encoderStatsCleanup=null,this.host=e,e.addController(this);const r=tt();this.s={state:"idle",stateContext:{},isStreaming:!1,isCapturing:!1,isReconnecting:!1,error:null,mediaStream:null,sources:[],qualityProfile:t,reconnectionState:null,stats:null,useWebCodecs:"webcodecs"===r.recommended,isWebCodecsActive:!1,isWebCodecsAvailable:it(),encoderStats:null}}initialize(e){this.teardown();const t=new ot({...e,useWebCodecs:this.s.useWebCodecs});this.controller=t,this.subscribeToEvents(t)}hostConnected(){}hostDisconnected(){this.teardown()}teardown(){this.unsubs.forEach(e=>e()),this.unsubs=[],this.encoderStatsCleanup&&(this.encoderStatsCleanup(),this.encoderStatsCleanup=null),this.controller?.destroy(),this.controller=null}update(e){Object.assign(this.s,e),this.host.requestUpdate()}subscribeToEvents(e){const t=this.unsubs;t.push(e.on("stateChange",t=>{const r=t.state,i=t.context??{};this.update({state:r,stateContext:i,isStreaming:"streaming"===r,isCapturing:"capturing"===r||"streaming"===r,isReconnecting:"reconnecting"===r,mediaStream:e.getMediaStream(),sources:e.getSources(),reconnectionState:i.reconnection??this.s.reconnectionState}),this.dispatchEvent("fw-sc-state-change",{state:r,context:i})})),t.push(e.on("statsUpdate",e=>{this.update({stats:e})})),t.push(e.on("error",e=>{this.update({error:e.error}),this.dispatchEvent("fw-sc-error",{error:e.error})})),t.push(e.on("sourceAdded",()=>{this.update({sources:e.getSources(),mediaStream:e.getMediaStream()})})),t.push(e.on("sourceRemoved",()=>{this.update({sources:e.getSources(),mediaStream:e.getMediaStream()})})),t.push(e.on("sourceUpdated",()=>{this.update({sources:e.getSources(),mediaStream:e.getMediaStream()})})),t.push(e.on("qualityChanged",e=>{this.update({qualityProfile:e.profile})})),t.push(e.on("reconnectionAttempt",()=>{this.update({reconnectionState:e.getReconnectionManager().getState()})})),t.push(e.on("webCodecsActive",e=>{this.update({isWebCodecsActive:e.active}),e.active&&this.setupEncoderStatsListener()})),t.push(e.on("stateChange",t=>{"streaming"===t.state?setTimeout(()=>{this.update({isWebCodecsActive:e.isWebCodecsActive()}),e.isWebCodecsActive()&&!this.encoderStatsCleanup&&this.setupEncoderStatsListener()},200):"idle"!==t.state&&"capturing"!==t.state||(this.update({isWebCodecsActive:!1,encoderStats:null}),this.encoderStatsCleanup&&(this.encoderStatsCleanup(),this.encoderStatsCleanup=null))}))}setupEncoderStatsListener(){if(!this.controller)return;const e=this.controller.getEncoderManager();e&&(this.encoderStatsCleanup=e.on("stats",e=>{this.update({encoderStats:e})}))}dispatchEvent(e,t){this.host.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))}async startCamera(e){if(!this.controller)throw new Error("Controller not initialized");return this.update({error:null}),this.controller.startCamera(e)}async startScreenShare(e){if(!this.controller)throw new Error("Controller not initialized");return this.update({error:null}),this.controller.startScreenShare(e)}addCustomSource(e,t){if(!this.controller)throw new Error("Controller not initialized");return this.controller.addCustomSource(e,t)}removeSource(e){this.controller?.removeSource(e)}async stopCapture(){await(this.controller?.stopCapture())}setSourceVolume(e,t){this.controller?.setSourceVolume(e,t)}setSourceMuted(e,t){this.controller?.setSourceMuted(e,t)}setSourceActive(e,t){this.controller?.setSourceActive(e,t)}setPrimaryVideoSource(e){this.controller?.setPrimaryVideoSource(e)}setMasterVolume(e){this.controller?.setMasterVolume(e)}getMasterVolume(){return this.controller?.getMasterVolume()??1}async setQualityProfile(e){await(this.controller?.setQualityProfile(e))}async startStreaming(){if(!this.controller)throw new Error("Controller not initialized");this.update({error:null}),await this.controller.startStreaming()}async stopStreaming(){await(this.controller?.stopStreaming())}async getDevices(){return this.controller?.getDevices()??[]}async switchVideoDevice(e){await(this.controller?.switchVideoDevice(e))}async switchAudioDevice(e){await(this.controller?.switchAudioDevice(e))}async getStats(){return this.controller?.getStats()??null}setUseWebCodecs(e){this.update({useWebCodecs:e}),this.controller?.setUseWebCodecs(e)}setEncoderOverrides(e){this.controller?.setEncoderOverrides(e)}getController(){return this.controller}}const at=[{id:"professional",label:"Professional",description:"1080p @ 8 Mbps"},{id:"broadcast",label:"Broadcast",description:"1080p @ 4.5 Mbps"},{id:"conference",label:"Conference",description:"720p @ 2.5 Mbps"}];e.FwStreamCrafter=class extends le{constructor(){super(),this.whipUrl="",this.gatewayUrl="",this.streamKey="",this.initialProfile="broadcast",this.autoStartCamera=!1,this.devMode=!1,this.debug=!1,this.enableCompositor=!1,this._showSettings=!1,this._showSources=!0,this._isAdvancedPanelOpen=!1,this.pc=new nt(this,this.initialProfile)}connectedCallback(){super.connectedCallback(),this._initController()}willUpdate(e){(e.has("whipUrl")||e.has("initialProfile")||e.has("debug"))&&this._initController()}updated(e){e.has("_showSources")||e.has("_showSettings"),this._syncVideoPreview()}_initController(){this.whipUrl&&(this.pc.initialize({whipUrl:this.whipUrl,profile:this.initialProfile,debug:this.debug,reconnection:{enabled:!0,maxAttempts:5},audioMixing:!0}),this.autoStartCamera&&"idle"===this.pc.s.state&&this.pc.startCamera().catch(console.error))}_syncVideoPreview(){const e=this._videoEl,t=this.pc.s.mediaStream;e&&t&&e.srcObject!==t?(e.srcObject=t,e.play().catch(()=>{})):e&&!t&&(e.srcObject=null)}async startCamera(e){return this.pc.startCamera(e)}async startScreenShare(e){return this.pc.startScreenShare(e)}async startStreaming(){return this.pc.startStreaming()}async stopStreaming(){return this.pc.stopStreaming()}async stopCapture(){return this.pc.stopCapture()}removeSource(e){this.pc.removeSource(e)}setSourceVolume(e,t){this.pc.setSourceVolume(e,t)}setSourceMuted(e,t){this.pc.setSourceMuted(e,t)}setPrimaryVideoSource(e){this.pc.setPrimaryVideoSource(e)}setMasterVolume(e){this.pc.setMasterVolume(e)}async setQualityProfile(e){return this.pc.setQualityProfile(e)}destroy(){this.pc.getController()?.destroy()}render(){const e=this.pc.s,t=function(e,t){if(t?.isReconnecting)return`Reconnecting (${t.attemptNumber}/5)...`;switch(e){case"idle":return"Idle";case"requesting_permissions":return"Permissions...";case"capturing":return"Ready";case"connecting":return"Connecting...";case"streaming":return"Live";case"reconnecting":return"Reconnecting...";case"error":return"Error";case"destroyed":return"Destroyed";default:return e}}(e.state,e.reconnectionState),r=(i=e.state,s=e.isReconnecting,"streaming"===i?"fw-sc-badge fw-sc-badge--live":s?"fw-sc-badge fw-sc-badge--connecting":"error"===i?"fw-sc-badge fw-sc-badge--error":"capturing"===i?"fw-sc-badge fw-sc-badge--ready":"fw-sc-badge fw-sc-badge--idle");var i,s;const o="destroyed"!==e.state&&"error"!==e.state,n=e.isCapturing&&!e.isStreaming&&!!this.whipUrl,a=e.sources.some(e=>"camera"===e.type);return q`
2328
+ </svg>`,Te={enabled:!1,width:1920,height:1080,frameRate:30,renderer:"auto",defaultTransition:{type:"fade",durationMs:500,easing:"ease-in-out"}},Ee={x:0,y:0,width:1,height:1,opacity:1,rotation:0,borderRadius:0,crop:{top:0,right:0,bottom:0,left:0}};class Pe{constructor(){this.listeners=new Map}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}once(e,t){const i=r=>{this.off(e,i),t(r)};return this.on(e,i)}off(e,t){const i=this.listeners.get(e);i&&(i.delete(t),0===i.size&&this.listeners.delete(e))}emit(e,t){const i=this.listeners.get(e);i&&i.forEach(i=>{try{i(t)}catch(t){console.error(`Error in event handler for "${String(e)}":`,t)}})}removeAllListeners(e){e?this.listeners.delete(e):this.listeners.clear()}listenerCount(e){return this.listeners.get(e)?.size??0}}function Re(e="professional"){const t={professional:{width:{ideal:1920},height:{ideal:1080},frameRate:{ideal:30}},broadcast:{width:{ideal:1920},height:{ideal:1080},frameRate:{ideal:30}},conference:{width:{ideal:1280},height:{ideal:720},frameRate:{ideal:24}},auto:{width:{ideal:1920},height:{ideal:1080},frameRate:{ideal:30}}};return t[e]||t.professional}function Ie(e,t){const i=function(e="professional"){const t={professional:{echoCancellation:!1,noiseSuppression:!1,autoGainControl:!1,sampleRate:48e3,channelCount:2,latency:.01},broadcast:{echoCancellation:!1,noiseSuppression:!0,autoGainControl:!1,sampleRate:48e3,channelCount:2,latency:.02},conference:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,sampleRate:44100,channelCount:1,latency:.05},auto:{echoCancellation:!1,noiseSuppression:!1,autoGainControl:!1,sampleRate:48e3,channelCount:2}};return t[e]||t.professional}(e),r=Re(e);return{audio:{echoCancellation:i.echoCancellation,noiseSuppression:i.noiseSuppression,autoGainControl:i.autoGainControl,sampleRate:i.sampleRate,channelCount:i.channelCount,...t?.audioDeviceId&&{deviceId:{exact:t.audioDeviceId}}},video:{width:r.width,height:r.height,frameRate:r.frameRate,...t?.videoDeviceId&&{deviceId:{exact:t.videoDeviceId}},...t?.facingMode&&{facingMode:t.facingMode}}}}class We extends Pe{constructor(){super(),this.devices=[],this.currentStream=null,this.permissionStatus={video:!1,audio:!1},this.setupDeviceChangeListener()}setupDeviceChangeListener(){"undefined"!=typeof navigator&&navigator.mediaDevices&&navigator.mediaDevices.addEventListener("devicechange",async()=>{await this.enumerateDevices(),this.emit("devicesChanged",{devices:this.devices})})}async enumerateDevices(){if(!navigator.mediaDevices?.enumerateDevices)throw new Error("enumerateDevices not supported");const e=await navigator.mediaDevices.enumerateDevices();return this.devices=e.filter(e=>"audioinput"===e.kind||"videoinput"===e.kind||"audiooutput"===e.kind).map(e=>({deviceId:e.deviceId,kind:e.kind,label:e.label||`${e.kind} (${e.deviceId.slice(0,8)}...)`,groupId:e.groupId})),this.devices}async getVideoInputs(){return await this.enumerateDevices(),this.devices.filter(e=>"videoinput"===e.kind)}async getAudioInputs(){return await this.enumerateDevices(),this.devices.filter(e=>"audioinput"===e.kind)}async getAudioOutputs(){return await this.enumerateDevices(),this.devices.filter(e=>"audiooutput"===e.kind)}async requestPermissions(e={video:!0,audio:!0}){try{return(await navigator.mediaDevices.getUserMedia({video:e.video,audio:e.audio})).getTracks().forEach(e=>e.stop()),e.video&&(this.permissionStatus.video=!0),e.audio&&(this.permissionStatus.audio=!0),await this.enumerateDevices(),this.emit("permissionChanged",{granted:!0,denied:!1}),this.permissionStatus}catch(e){const t=e instanceof Error?e:new Error(String(e));throw"NotAllowedError"!==t.name&&"PermissionDeniedError"!==t.name||this.emit("permissionChanged",{granted:!1,denied:!0}),this.emit("error",{message:`Permission request failed: ${t.message}`,error:t}),e}}hasPermission(e){return this.permissionStatus[e]}async getUserMedia(e={}){const t=e.profile||"professional";let i;i=e.customConstraints?e.customConstraints:Ie(t,{videoDeviceId:e.videoDeviceId,audioDeviceId:e.audioDeviceId,facingMode:e.facingMode});try{const e=await navigator.mediaDevices.getUserMedia(i);return this.currentStream=e,e.getVideoTracks().length>0&&(this.permissionStatus.video=!0),e.getAudioTracks().length>0&&(this.permissionStatus.audio=!0),e}catch(e){const t=e instanceof Error?e:new Error(String(e));if("OverconstrainedError"===t.name){const e={video:!!i.video,audio:!!i.audio},t=await navigator.mediaDevices.getUserMedia(e);return this.currentStream=t,t}throw this.emit("error",{message:`getUserMedia failed: ${t.message}`,error:t}),e}}getStream(){return this.currentStream}stopAllTracks(){this.currentStream&&(this.currentStream.getTracks().forEach(e=>{e.stop()}),this.currentStream=null)}async replaceVideoTrack(e,t="professional"){if(!this.currentStream)throw new Error("No active stream to replace track in");const i=this.currentStream.getVideoTracks()[0];i&&(i.stop(),this.currentStream.removeTrack(i));const r=Ie(t,{videoDeviceId:e}),s=(await navigator.mediaDevices.getUserMedia({video:r.video,audio:!1})).getVideoTracks()[0];return s&&this.currentStream.addTrack(s),s||null}async replaceAudioTrack(e,t="professional"){if(!this.currentStream)throw new Error("No active stream to replace track in");const i=this.currentStream.getAudioTracks()[0];i&&(i.stop(),this.currentStream.removeTrack(i));const r=Ie(t,{audioDeviceId:e}),s=(await navigator.mediaDevices.getUserMedia({video:!1,audio:r.audio})).getAudioTracks()[0];return s&&this.currentStream.addTrack(s),s||null}getAllDevices(){return[...this.devices]}destroy(){this.stopAllTracks(),this.removeAllListeners()}}class ze extends Pe{constructor(){super(...arguments),this.captures=new Map,this.captureCounter=0}async start(e={}){try{let t;if(!1===e.video)t=!1;else if("object"==typeof e.video){t={frameRate:{ideal:30,max:60},width:{ideal:1920},height:{ideal:1080},...e.video,...void 0!==e.cursor?{cursor:e.cursor}:{}}}else t={frameRate:{ideal:30,max:60},width:{ideal:1920},height:{ideal:1080},...void 0!==e.cursor?{cursor:e.cursor}:{}};const i={video:t,audio:e.audio??!1};e.preferCurrentTab&&"preferCurrentTab"in i&&(i.preferCurrentTab=!0),e.surfaceSwitching&&(i.surfaceSwitching="include"),void 0!==e.selfBrowserSurface&&(i.selfBrowserSurface=e.selfBrowserSurface),e.monitorTypeSurfaces&&(i.monitorTypeSurfaces=e.monitorTypeSurfaces),e.systemAudio&&i.audio&&"object"==typeof i.audio&&(i.audio.systemAudio=e.systemAudio);const r=await navigator.mediaDevices.getDisplayMedia(i),s=`screen-${++this.captureCounter}-${Date.now()}`,o=r.getVideoTracks()[0],n=o?.label||`Screen ${this.captureCounter}`;return this.captures.set(s,{stream:r,label:n}),r.getTracks().forEach(e=>{e.addEventListener("ended",()=>{this.handleTrackEnded(s,r)})}),this.emit("started",{stream:r,captureId:s}),r}catch(e){const t=e instanceof Error?e:new Error(String(e));if("AbortError"===t.name||"NotAllowedError"===t.name)return this.emit("ended",{captureId:"",stream:null,reason:"cancelled"}),null;throw this.emit("error",{message:`Screen capture failed: ${t.message}`,error:t}),e}}handleTrackEnded(e,t){const i=t.getTracks().filter(e=>"live"===e.readyState);0===i.length&&(this.captures.delete(e),this.emit("ended",{captureId:e,stream:t,reason:"user_stopped"}))}stopByStream(e){for(const[t,i]of this.captures)if(i.stream===e)return i.stream.getTracks().forEach(e=>e.stop()),this.captures.delete(t),void this.emit("ended",{captureId:t,stream:e,reason:"stopped"})}stop(){for(const[e,t]of this.captures)t.stream.getTracks().forEach(e=>e.stop()),this.emit("ended",{captureId:e,stream:t.stream,reason:"stopped"});this.captures.clear()}getCaptures(){return Array.from(this.captures.entries()).map(([e,t])=>({captureId:e,stream:t.stream,label:t.label}))}isActive(){return this.captures.size>0}getCaptureCount(){return this.captures.size}getStream(){const e=this.captures.values().next().value;return e?.stream??null}getVideoTrack(){const e=this.getStream();return e?.getVideoTracks()[0]??null}getAudioTrack(){const e=this.getStream();return e?.getAudioTracks()[0]??null}hasAudio(){for(const[,e]of this.captures)if(e.stream.getAudioTracks().length>0)return!0;return!1}destroy(){this.stop(),this.removeAllListeners()}}class Le extends Pe{constructor(e){super(),this.peerConnection=null,this.videoTrackGenerator=null,this.audioTrackGenerator=null,this.state="disconnected",this.videoWriter=null,this.audioWriter=null,this.videoWriteQueue=[],this.audioWriteQueue=[],this.isProcessingVideoQueue=!1,this.isProcessingAudioQueue=!1,this.videoTransformWorker=null,this.audioTransformWorker=null,this.encoderListenerCleanup=null,this.negotiatedVideoCodec=null,this.negotiatedAudioCodec=null,this.resourceUrl=null,this.config=e}log(e,t){this.config.debug&&console.log(`[WHIP] ${e}`,t??"")}logError(e,t){console.error(`[WHIP ERROR] ${e}`,t??""),this.emit("error",{message:e,error:t})}setState(e){const t=this.state;this.state=e,this.emit("stateChange",{state:e,previousState:t})}preferCodecs(e){const t=e.getTransceivers();for(const e of t){if(!e.setCodecPreferences)continue;const t=e.sender.track?.kind;if("video"===t){const t=RTCRtpSender.getCapabilities("video");if(!t?.codecs)continue;const i=t.codecs.filter(e=>"video/VP9"===e.mimeType||"video/H264"===e.mimeType).sort((e,t)=>"video/VP9"===e.mimeType&&"video/VP9"!==t.mimeType?-1:"video/VP9"!==e.mimeType&&"video/VP9"===t.mimeType?1:0);if(i.length>0)try{e.setCodecPreferences(i),this.log("Set video codec preferences",i.map(e=>e.mimeType))}catch(e){this.log("Failed to set video codec preferences",e)}}if("audio"===t){const t=RTCRtpSender.getCapabilities("audio");if(!t?.codecs)continue;const i=t.codecs.filter(e=>"audio/opus"===e.mimeType);if(i.length>0)try{e.setCodecPreferences(i),this.log("Set audio codec preferences",i.map(e=>e.mimeType))}catch(e){this.log("Failed to set audio codec preferences",e)}}}}verifyCodecAlignment(){if(!this.peerConnection)return;const e=this.peerConnection.getSenders();for(const t of e){const e=t.getParameters(),i=e.codecs?.[0];"video"===t.track?.kind&&i?.mimeType&&(this.negotiatedVideoCodec=i.mimeType,this.log("Negotiated video codec",i.mimeType)),"audio"===t.track?.kind&&i?.mimeType&&(this.negotiatedAudioCodec=i.mimeType,this.log("Negotiated audio codec",i.mimeType))}}canUseEncodedInsertion(){if(!this.peerConnection||"connected"!==this.state)return this.log("canUseEncodedInsertion: no connection",{hasPC:!!this.peerConnection,state:this.state}),!1;if("undefined"==typeof RTCRtpScriptTransform)return this.log("canUseEncodedInsertion: RTCRtpScriptTransform not supported"),!1;const e=this.peerConnection.getSenders().some(e=>"transform"in e);if(!e)return this.log("Sender transform not supported"),!1;if(this.negotiatedVideoCodec){if(!("video/VP9"===this.negotiatedVideoCodec||"video/H264"===this.negotiatedVideoCodec))return this.log("Video codec not compatible with WebCodecs",this.negotiatedVideoCodec),!1}if(this.negotiatedAudioCodec){if(!("audio/opus"===this.negotiatedAudioCodec))return this.log("Audio codec not compatible with WebCodecs",this.negotiatedAudioCodec),!1}return!0}getNegotiatedVideoCodec(){return this.negotiatedVideoCodec}getNegotiatedAudioCodec(){return this.negotiatedAudioCodec}get isConnected(){return"connected"===this.state}async connect(e){try{if(this.log("Starting WHIP connection"),this.setState("connecting"),!this.config.whipUrl)throw new Error("WHIP URL is required");const t={iceServers:this.config.iceServers||[]};this.log("Creating RTCPeerConnection",t);const i=new RTCPeerConnection(t);i.onconnectionstatechange=()=>{const e=i.connectionState;switch(this.log(`Connection state changed: ${e}`),e){case"connected":this.log("WHIP streaming connected successfully"),this.setState("connected");break;case"disconnected":this.setState("disconnected");break;case"failed":this.setState("failed");break;case"closed":this.setState("closed")}},i.oniceconnectionstatechange=()=>{this.log(`ICE connection state: ${i.iceConnectionState}`)},i.onicegatheringstatechange=()=>{this.log(`ICE gathering state: ${i.iceGatheringState}`)},i.onicecandidate=e=>{this.emit("iceCandidate",{candidate:e.candidate}),e.candidate?this.log("ICE candidate generated",e.candidate.candidate):this.log("ICE candidate gathering complete")},this.log("Adding tracks to peer connection"),e.getTracks().forEach((t,r)=>{this.log(`Adding ${t.kind} track ${r}`,{id:t.id,kind:t.kind,enabled:t.enabled,readyState:t.readyState}),i.addTrack(t,e)}),this.peerConnection=i,this.preferCodecs(i),this.log("Creating offer");const r=await i.createOffer({offerToReceiveAudio:!1,offerToReceiveVideo:!1});this.log("Setting local description"),await i.setLocalDescription(r),this.log("Local SDP offer created",{type:r.type,sdpLength:r.sdp?.length}),this.log(`Sending offer to WHIP endpoint: ${this.config.whipUrl}`);const s=await fetch(this.config.whipUrl,{method:"POST",headers:{"Content-Type":"application/sdp",Accept:"application/sdp"},body:r.sdp});if(this.log(`WHIP response status: ${s.status} ${s.statusText}`),!s.ok){const e=await s.text().catch(()=>"Unknown error");throw new Error(`WHIP request failed: ${s.status} ${s.statusText} - ${e}`)}this.resourceUrl=s.headers.get("Location"),this.resourceUrl&&this.log("WHIP resource URL:",this.resourceUrl);const o=await s.text();this.log("Received SDP answer",{length:o.length}),await i.setRemoteDescription({type:"answer",sdp:o}),this.log("Remote description set successfully"),this.verifyCodecAlignment(),this.log("WHIP connection established, waiting for ICE connection...")}catch(e){throw this.logError("Failed to connect",e instanceof Error?e:new Error(String(e))),this.setState("failed"),this.cleanup(),e}}async connectWithGenerators(){try{if(this.log("Starting WHIP connection with track generators"),this.setState("connecting"),!this.config.whipUrl)throw new Error("WHIP URL is required");this.log("Creating MediaStreamTrackGenerators");const e=new MediaStreamTrackGenerator({kind:"video"}),t=new MediaStreamTrackGenerator({kind:"audio"});this.videoTrackGenerator=e,this.audioTrackGenerator=t,this.log("Track generators created successfully");const i={iceServers:this.config.iceServers||[]};this.log("Creating RTCPeerConnection",i);const r=new RTCPeerConnection(i);r.onconnectionstatechange=()=>{const e=r.connectionState;switch(this.log(`Connection state changed: ${e}`),e){case"connected":this.log("WHIP streaming connected successfully"),this.setState("connected");break;case"disconnected":this.setState("disconnected");break;case"failed":this.setState("failed");break;case"closed":this.setState("closed")}},r.oniceconnectionstatechange=()=>{this.log(`ICE connection state: ${r.iceConnectionState}`)},r.onicegatheringstatechange=()=>{this.log(`ICE gathering state: ${r.iceGatheringState}`)},r.onicecandidate=e=>{this.emit("iceCandidate",{candidate:e.candidate}),e.candidate?this.log("ICE candidate generated",e.candidate.candidate):this.log("ICE candidate gathering complete")};const s=new MediaStream([e,t]);this.log("Adding tracks to peer connection"),s.getTracks().forEach((e,t)=>{this.log(`Adding ${e.kind} track ${t}`,{id:e.id,kind:e.kind,enabled:e.enabled,readyState:e.readyState}),r.addTrack(e,s)}),this.peerConnection=r,this.preferCodecs(r),this.log("Creating offer");const o=await r.createOffer({offerToReceiveAudio:!1,offerToReceiveVideo:!1});this.log("Setting local description"),await r.setLocalDescription(o),this.log(`Sending offer to WHIP endpoint: ${this.config.whipUrl}`);const n=await fetch(this.config.whipUrl,{method:"POST",headers:{"Content-Type":"application/sdp",Accept:"application/sdp"},body:o.sdp});if(this.log(`WHIP response status: ${n.status} ${n.statusText}`),!n.ok){const e=await n.text().catch(()=>"Unknown error");throw new Error(`WHIP request failed: ${n.status} ${n.statusText} - ${e}`)}this.resourceUrl=n.headers.get("Location"),this.resourceUrl&&this.log("WHIP resource URL:",this.resourceUrl);const a=await n.text();return this.log("Received SDP answer",{length:a.length}),await r.setRemoteDescription({type:"answer",sdp:a}),this.log("Remote description set successfully"),this.verifyCodecAlignment(),this.log("WHIP connection established with generators"),{videoGenerator:e,audioGenerator:t}}catch(e){throw this.logError("Failed to connect with generators",e instanceof Error?e:new Error(String(e))),this.setState("failed"),this.cleanup(),e}}async processVideoQueue(){if(!this.isProcessingVideoQueue&&0!==this.videoWriteQueue.length){this.isProcessingVideoQueue=!0;try{for(;this.videoWriteQueue.length>0;){const e=this.videoWriteQueue.shift();if(!e)continue;const{frame:t,resolve:i,reject:r}=e;if(this.videoTrackGenerator)try{this.videoWriter||(this.videoWriter=this.videoTrackGenerator.writable.getWriter()),await this.videoWriter.write(t),i(!0)}catch(e){if(this.videoWriter){try{this.videoWriter.releaseLock()}catch{}this.videoWriter=null}r(e instanceof Error?e:new Error(String(e)))}else r(new Error("Video track generator not available"))}}finally{this.isProcessingVideoQueue=!1}}}async processAudioQueue(){if(!this.isProcessingAudioQueue&&0!==this.audioWriteQueue.length){this.isProcessingAudioQueue=!0;try{for(;this.audioWriteQueue.length>0;){const e=this.audioWriteQueue.shift();if(!e)continue;const{audioData:t,resolve:i,reject:r}=e;if(this.audioTrackGenerator)try{this.audioWriter||(this.audioWriter=this.audioTrackGenerator.writable.getWriter()),await this.audioWriter.write(t),i(!0)}catch(e){if(this.audioWriter){try{this.audioWriter.releaseLock()}catch{}this.audioWriter=null}r(e instanceof Error?e:new Error(String(e)))}else r(new Error("Audio track generator not available"))}}finally{this.isProcessingAudioQueue=!1}}}async sendVideoFrame(e){if(!this.videoTrackGenerator){if(e)try{e.close()}catch{}return!1}return new Promise((t,i)=>{this.videoWriteQueue.push({frame:e,resolve:t,reject:i}),this.processVideoQueue()})}async sendAudioData(e){if(!this.audioTrackGenerator){if(e)try{e.close()}catch{}return!1}return new Promise((t,i)=>{this.audioWriteQueue.push({audioData:e,resolve:t,reject:i}),this.processAudioQueue()})}async replaceTrack(e,t){if(!this.peerConnection)throw new Error("No peer connection");const i=this.peerConnection.getSenders().find(t=>t.track?.kind===e.kind);if(!i)throw new Error(`No sender found for ${e.kind} track`);await i.replaceTrack(t),this.log(`Replaced ${e.kind} track`)}async addTrack(e,t){if(!this.peerConnection)throw new Error("No peer connection");this.peerConnection.addTrack(e,t||new MediaStream([e])),this.log(`Added ${e.kind} track`)}async getStats(){if(!this.peerConnection)return null;try{return await this.peerConnection.getStats()}catch(e){return this.logError("Failed to get connection stats",e instanceof Error?e:new Error(String(e))),null}}getState(){return this.state}getPeerConnection(){return this.peerConnection}attachEncoderTransform(e,i){if(!this.peerConnection)throw new Error("No peer connection - call connect() first");if("undefined"==typeof RTCRtpScriptTransform)return void this.log("RTCRtpScriptTransform not supported, skipping encoder transform");this.log("Attaching encoder transform");const r=()=>{if(i)return new Worker(i,{type:"module"});try{const e=new URL("../workers/rtcTransform.worker.js",t&&"SCRIPT"===t.tagName.toUpperCase()&&t.src||new URL("fw-streamcrafter.iife.js",document.baseURI).href);return new Worker(e,{type:"module"})}catch(e){this.log("Packaged worker URL failed, trying fallback paths",e)}const e=["/workers/rtcTransform.worker.js","./workers/rtcTransform.worker.js","/node_modules/@livepeer-frameworks/streamcrafter-core/dist/workers/rtcTransform.worker.js"];for(const t of e)try{return new Worker(t,{type:"module"})}catch{try{return new Worker(t)}catch{}}return null},s=this.peerConnection.getSenders(),o=s.find(e=>"video"===e.track?.kind),n=s.find(e=>"audio"===e.track?.kind);o&&"transform"in o&&(this.log("Creating video transform worker"),this.videoTransformWorker=r(),this.videoTransformWorker?(this.videoTransformWorker.postMessage({type:"configure",config:{debug:this.config.debug,maxQueueSize:30}}),o.transform=new RTCRtpScriptTransform(this.videoTransformWorker,{kind:"video"}),this.log("Video transform attached")):this.logError("Failed to create video transform worker")),n&&"transform"in n&&(this.log("Creating audio transform worker"),this.audioTransformWorker=r(),this.audioTransformWorker?(this.audioTransformWorker.postMessage({type:"configure",config:{debug:this.config.debug,maxQueueSize:50}}),n.transform=new RTCRtpScriptTransform(this.audioTransformWorker,{kind:"audio"}),this.log("Audio transform attached")):this.logError("Failed to create audio transform worker"));const a=e=>{this.videoTransformWorker&&this.videoTransformWorker.postMessage({type:"videoChunk",data:e},[e.data])},c=e=>{this.audioTransformWorker&&this.audioTransformWorker.postMessage({type:"audioChunk",data:e},[e.data])};e.on("videoChunk",a),e.on("audioChunk",c),this.encoderListenerCleanup=()=>{e.off("videoChunk",a),e.off("audioChunk",c)},this.log("Encoder transform attached successfully")}hasEncoderTransform(){return null!==this.videoTransformWorker||null!==this.audioTransformWorker}detachEncoderTransform(){this.encoderListenerCleanup&&(this.encoderListenerCleanup(),this.encoderListenerCleanup=null),this.videoTransformWorker&&(this.videoTransformWorker.postMessage({type:"stop"}),this.videoTransformWorker.terminate(),this.videoTransformWorker=null),this.audioTransformWorker&&(this.audioTransformWorker.postMessage({type:"stop"}),this.audioTransformWorker.terminate(),this.audioTransformWorker=null),this.log("Encoder transform detached")}cleanupWriters(){if(this.videoWriter){try{this.videoWriter.releaseLock()}catch{}this.videoWriter=null}if(this.audioWriter){try{this.audioWriter.releaseLock()}catch{}this.audioWriter=null}this.videoWriteQueue=[],this.audioWriteQueue=[],this.isProcessingVideoQueue=!1,this.isProcessingAudioQueue=!1}cleanup(){this.cleanupWriters(),this.detachEncoderTransform(),this.videoTrackGenerator&&(this.videoTrackGenerator.stop(),this.videoTrackGenerator=null),this.audioTrackGenerator&&(this.audioTrackGenerator.stop(),this.audioTrackGenerator=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.resourceUrl=null}async disconnect(){if(this.log("Disconnecting WHIP"),this.resourceUrl){try{this.log("Sending DELETE to WHIP resource:",this.resourceUrl),await fetch(this.resourceUrl,{method:"DELETE"})}catch(e){this.log("Failed to delete WHIP resource (non-fatal)",e)}this.resourceUrl=null}this.cleanup(),this.setState("disconnected")}destroy(){this.cleanup(),this.removeAllListeners()}}class Ue extends Pe{constructor(e={}){super(),this.audioContext=null,this.destination=null,this.masterGain=null,this.compressor=null,this.limiter=null,this.analyzer=null,this.sources=new Map,this.outputStream=null,this.levelMonitoringActive=!1,this.peakLevel=0,this.peakDecayRate=.95,this.config={sampleRate:e.sampleRate??48e3,channelCount:e.channelCount??2}}async initialize(){if(!this.audioContext)try{this.audioContext=new AudioContext({sampleRate:this.config.sampleRate}),this.destination=this.audioContext.createMediaStreamDestination(),this.destination.channelCount=this.config.channelCount,this.masterGain=this.audioContext.createGain(),this.compressor=this.audioContext.createDynamicsCompressor(),this.compressor.threshold.value=-24,this.compressor.knee.value=30,this.compressor.ratio.value=4,this.compressor.attack.value=.003,this.compressor.release.value=.25,this.limiter=this.audioContext.createDynamicsCompressor(),this.limiter.threshold.value=-1,this.limiter.knee.value=0,this.limiter.ratio.value=20,this.limiter.attack.value=.001,this.limiter.release.value=.1,this.analyzer=this.audioContext.createAnalyser(),this.analyzer.fftSize=256,this.analyzer.smoothingTimeConstant=.3,this.masterGain.connect(this.compressor),this.compressor.connect(this.analyzer),this.analyzer.connect(this.limiter),this.limiter.connect(this.destination),this.outputStream=this.destination.stream,console.log("[AudioMixer] Initialized with compressor/limiter chain",{sampleRate:this.audioContext.sampleRate,channelCount:this.config.channelCount})}catch(e){const t=e instanceof Error?e:new Error(String(e));throw console.error("[AudioMixer] Failed to initialize:",t),this.emit("error",{message:t.message,error:t}),t}}addSource(e,t,i={}){if(!this.audioContext||!this.masterGain)throw new Error("AudioMixer not initialized. Call initialize() first.");if("audio"!==t.kind)throw new Error("Track must be an audio track");this.sources.has(e)&&this.removeSource(e);try{const r=new MediaStream([t]),s=this.audioContext.createMediaStreamSource(r),o=this.audioContext.createGain();o.gain.value=i.muted?0:i.volume??1;const n=this.audioContext.createStereoPanner();n.pan.value=i.pan??0,s.connect(o),o.connect(n),n.connect(this.masterGain);const a={id:e,sourceNode:s,gainNode:o,panNode:n,track:t,options:{volume:i.volume??1,muted:i.muted??!1,pan:i.pan??0}};this.sources.set(e,a),console.log("[AudioMixer] Added source:",e),this.emit("sourceAdded",{sourceId:e})}catch(e){const t=e instanceof Error?e:new Error(String(e));throw console.error("[AudioMixer] Failed to add source:",t),this.emit("error",{message:`Failed to add source: ${t.message}`,error:t}),t}}removeSource(e){const t=this.sources.get(e);if(t)try{t.sourceNode.disconnect(),t.gainNode.disconnect(),t.panNode.disconnect(),this.sources.delete(e),console.log("[AudioMixer] Removed source:",e),this.emit("sourceRemoved",{sourceId:e})}catch(e){console.error("[AudioMixer] Error removing source:",e)}}updateSource(e,t){const i=this.sources.get(e);i?(void 0!==t.volume&&(i.options.volume=t.volume,i.options.muted||i.gainNode.gain.setTargetAtTime(t.volume,this.audioContext?.currentTime??0,.01)),void 0!==t.muted&&(i.options.muted=t.muted,i.gainNode.gain.setTargetAtTime(t.muted?0:i.options.volume,this.audioContext?.currentTime??0,.01)),void 0!==t.pan&&(i.options.pan=t.pan,i.panNode.pan.setTargetAtTime(t.pan,this.audioContext?.currentTime??0,.01))):console.warn("[AudioMixer] Source not found:",e)}setVolume(e,t){this.updateSource(e,{volume:Math.max(0,Math.min(2,t))})}mute(e){this.updateSource(e,{muted:!0})}unmute(e){this.updateSource(e,{muted:!1})}toggleMute(e){const t=this.sources.get(e);if(!t)return!1;const i=!t.options.muted;return this.updateSource(e,{muted:i}),i}setPan(e,t){this.updateSource(e,{pan:Math.max(-1,Math.min(1,t))})}setMasterVolume(e){this.masterGain&&this.masterGain.gain.setTargetAtTime(Math.max(0,Math.min(2,e)),this.audioContext?.currentTime??0,.01)}getMasterVolume(){return this.masterGain?.gain.value??1}getOutputStream(){return this.outputStream}getOutputTrack(){return this.outputStream?.getAudioTracks()[0]??null}getSourceIds(){return Array.from(this.sources.keys())}getSourceOptions(e){const t=this.sources.get(e);return t?{...t.options}:null}hasSource(e){return this.sources.has(e)}getSourceCount(){return this.sources.size}async resume(){this.audioContext&&"suspended"===this.audioContext.state&&await this.audioContext.resume()}async suspend(){this.audioContext&&"running"===this.audioContext.state&&await this.audioContext.suspend()}getState(){return this.audioContext?.state??null}getLevel(){if(!this.analyzer)return 0;const e=new Uint8Array(this.analyzer.frequencyBinCount);this.analyzer.getByteTimeDomainData(e);let t=0;for(let i=0;i<e.length;i++){const r=Math.abs(e[i]-128)/128;r>t&&(t=r)}if(t<1e-4)return 0;const i=(20*Math.log10(t)- -60)/60;return Math.max(0,Math.min(1,i))}getLevels(){const e=this.getLevel();return e>this.peakLevel?this.peakLevel=e:this.peakLevel*=this.peakDecayRate,{level:e,peakLevel:this.peakLevel}}startLevelMonitoring(){if(this.levelMonitoringActive)return;this.levelMonitoringActive=!0;const e=()=>{if(!this.levelMonitoringActive||"running"!==this.audioContext?.state)return;const{level:t,peakLevel:i}=this.getLevels();this.emit("levelUpdate",{level:t,peakLevel:i}),requestAnimationFrame(e)};requestAnimationFrame(e),console.log("[AudioMixer] Level monitoring started")}stopLevelMonitoring(){this.levelMonitoringActive=!1,this.peakLevel=0,console.log("[AudioMixer] Level monitoring stopped")}isMonitoringLevels(){return this.levelMonitoringActive}destroy(){this.stopLevelMonitoring();for(const e of this.sources.keys())this.removeSource(e);this.compressor&&(this.compressor.disconnect(),this.compressor=null),this.limiter&&(this.limiter.disconnect(),this.limiter=null),this.analyzer&&(this.analyzer.disconnect(),this.analyzer=null),this.audioContext&&(this.audioContext.close().catch(()=>{}),this.audioContext=null),this.destination=null,this.masterGain=null,this.outputStream=null,this.removeAllListeners()}}const De={enabled:!0,maxAttempts:5,baseDelay:1e3,maxDelay:3e4,backoffMultiplier:2};class Ve extends Pe{constructor(e={}){super(),this.reconnectTimeout=null,this.countdownInterval=null,this.reconnectCallback=null,this.config={...De,...e},this.state={isReconnecting:!1,attemptNumber:0,nextAttemptIn:null,lastError:null}}calculateDelay(e){const t=this.config.baseDelay*Math.pow(this.config.backoffMultiplier,e-1),i=.1*t*(2*Math.random()-1);return Math.min(t+i,this.config.maxDelay)}start(e){this.config.enabled?this.state.isReconnecting?console.log("[ReconnectionManager] Already reconnecting"):(this.reconnectCallback=e,this.state={isReconnecting:!0,attemptNumber:0,nextAttemptIn:null,lastError:null},this.scheduleNextAttempt()):console.log("[ReconnectionManager] Reconnection disabled")}scheduleNextAttempt(){if(!this.state.isReconnecting)return;if(this.state.attemptNumber++,this.state.attemptNumber>this.config.maxAttempts)return void this.handleExhausted();const e=this.calculateDelay(this.state.attemptNumber);this.state.nextAttemptIn=e,console.log(`[ReconnectionManager] Scheduling attempt ${this.state.attemptNumber}/${this.config.maxAttempts} in ${e}ms`),this.emit("attemptStart",{attempt:this.state.attemptNumber,delay:e}),this.startCountdown(e),this.reconnectTimeout=setTimeout(()=>{this.executeAttempt()},e)}startCountdown(e){this.stopCountdown();const t=Date.now();this.countdownInterval=setInterval(()=>{const i=Date.now()-t;this.state.nextAttemptIn=Math.max(0,e-i)},100)}stopCountdown(){this.countdownInterval&&(clearInterval(this.countdownInterval),this.countdownInterval=null)}async executeAttempt(){if(this.stopCountdown(),this.state.nextAttemptIn=null,this.reconnectCallback){console.log(`[ReconnectionManager] Executing attempt ${this.state.attemptNumber}`);try{await this.reconnectCallback(),this.handleSuccess()}catch(e){const t=e instanceof Error?e.message:String(e);this.handleFailure(t)}}else console.error("[ReconnectionManager] No reconnect callback set")}handleSuccess(){console.log("[ReconnectionManager] Reconnection successful"),this.state={isReconnecting:!1,attemptNumber:0,nextAttemptIn:null,lastError:null},this.cleanup(),this.emit("attemptSuccess",void 0)}handleFailure(e){console.log(`[ReconnectionManager] Attempt ${this.state.attemptNumber} failed:`,e),this.state.lastError=e,this.emit("attemptFailed",{attempt:this.state.attemptNumber,error:e}),this.scheduleNextAttempt()}handleExhausted(){console.log("[ReconnectionManager] All reconnection attempts exhausted"),this.emit("exhausted",{totalAttempts:this.config.maxAttempts}),this.stop()}stop(){console.log("[ReconnectionManager] Stopping reconnection"),this.cleanup(),this.state={isReconnecting:!1,attemptNumber:0,nextAttemptIn:null,lastError:this.state.lastError}}cleanup(){this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.stopCountdown(),this.reconnectCallback=null}reset(){this.stop(),this.state.lastError=null}getState(){return{...this.state}}isReconnecting(){return this.state.isReconnecting}getAttemptNumber(){return this.state.attemptNumber}getMaxAttempts(){return this.config.maxAttempts}updateConfig(e){this.config={...this.config,...e}}destroy(){this.cleanup(),this.removeAllListeners()}}const Oe=[{mode:"solo",label:"Solo",icon:"⬜",minSources:1,maxSources:1},{mode:"pip-br",label:"PiP ↘",icon:"◳",minSources:2,maxSources:2},{mode:"pip-bl",label:"PiP ↙",icon:"◲",minSources:2,maxSources:2},{mode:"pip-tr",label:"PiP ↗",icon:"◱",minSources:2,maxSources:2},{mode:"pip-tl",label:"PiP ↖",icon:"◰",minSources:2,maxSources:2},{mode:"split-h",label:"Split ⬌",icon:"▥",minSources:2,maxSources:2},{mode:"split-v",label:"Split ⬍",icon:"▤",minSources:2,maxSources:2},{mode:"focus-l",label:"Focus ◀",icon:"◧",minSources:2,maxSources:2},{mode:"focus-r",label:"Focus ▶",icon:"◨",minSources:2,maxSources:2},{mode:"pip-dual-br",label:"Main+2 PiP",icon:"⊞",minSources:3,maxSources:3},{mode:"pip-dual-bl",label:"Main+2 PiP ↙",icon:"⊟",minSources:3,maxSources:3},{mode:"split-pip-l",label:"Split+PiP",icon:"⊠",minSources:3,maxSources:3},{mode:"split-pip-r",label:"Split+PiP ▶",icon:"⊡",minSources:3,maxSources:3},{mode:"featured",label:"Featured",icon:"⬒",minSources:3,maxSources:99},{mode:"featured-r",label:"Featured ▶",icon:"⬓",minSources:3,maxSources:99},{mode:"grid",label:"Grid",icon:"▦",minSources:2,maxSources:99},{mode:"stack",label:"Stack",icon:"☰",minSources:2,maxSources:99}];let Ne="letterbox";function je(e,t,i,r=Ne){return{id:`layer-${t}-${e}`,sourceId:e,visible:!0,locked:!1,zIndex:t,transform:{...Ee,...i},scalingMode:r}}const Fe=.25,He=.02,Be=.005;function qe(e){return[je(e[0],0,{x:0,y:0,width:1,height:1})]}function Ge(e,t,i=.25){if(e.length<2)return qe(e);const r={tl:{x:He,y:He},tr:{x:1-i-He,y:He},bl:{x:He,y:1-i-He},br:{x:1-i-He,y:1-i-He}}[t];return[je(e[0],0,{x:0,y:0,width:1,height:1}),je(e[1],1,{x:r.x,y:r.y,width:i,height:i,borderRadius:8})]}function Qe(e,t,i=.5){if(e.length<2)return qe(e);const r=.0025;return"h"===t?[je(e[0],0,{x:0,y:0,width:i-r,height:1}),je(e[1],0,{x:i+r,y:0,width:1-i-r,height:1})]:[je(e[0],0,{x:0,y:0,width:1,height:i-r}),je(e[1],0,{x:0,y:i+r,width:1,height:1-i-r})]}function Xe(e,t){if(e.length<3)return Ge(e,"br"===t?"br":"bl");const i=Fe,r=[je(e[0],0,{x:0,y:0,width:1,height:1})];return"br"===t?r.push(je(e[1],1,{x:.73,y:.47,width:i,height:i,borderRadius:8}),je(e[2],2,{x:.73,y:.73,width:i,height:i,borderRadius:8})):r.push(je(e[1],1,{x:He,y:.47,width:i,height:i,borderRadius:8}),je(e[2],2,{x:He,y:.73,width:i,height:i,borderRadius:8})),r}function Ke(e,t){if(e.length<3)return Qe(e,"h");const i=Fe,r=[je(e[0],0,{x:0,y:0,width:.4975,height:1}),je(e[1],0,{x:.5025,y:0,width:.4975,height:1})];return"l"===t?r.push(je(e[2],1,{x:.2275,y:.73,width:i,height:i,borderRadius:8})):r.push(je(e[2],1,{x:.73,y:.73,width:i,height:i,borderRadius:8})),r}function Je(e,t){const i=e.length;if(i<=2)return Qe(e,"bottom"===t?"v":"h",.75);const r=Be,s=.795,o=[];if("bottom"===t){o.push(je(e[0],0,{x:0,y:0,width:1,height:s}));const t=i-1,n=(1-r*(t-1))/t;for(let t=1;t<i;t++)o.push(je(e[t],0,{x:(t-1)*(n+r),y:.8,width:n,height:.2}))}else{o.push(je(e[0],0,{x:0,y:0,width:s,height:1}));const t=i-1,n=(1-r*(t-1))/t;for(let t=1;t<i;t++)o.push(je(e[t],0,{x:.8,y:(t-1)*(n+r),width:.2,height:n}))}return o}function Ye(e,t){if(0===t.length)return[];Ne=e.scalingMode??"letterbox";const i=e.pipScale??Fe,r=e.splitRatio??.5,s=Math.min(Math.max(r,.0025),.9975);switch(e.mode){case"solo":case"fullscreen":default:return qe(t);case"pip-br":case"pip":return Ge(t,"br",i);case"pip-bl":return Ge(t,"bl",i);case"pip-tr":return Ge(t,"tr",i);case"pip-tl":return Ge(t,"tl",i);case"split-h":case"side-by-side":return Qe(t,"h",s);case"split-v":return Qe(t,"v",s);case"focus-l":return Qe(t,"h",.7);case"focus-r":return Qe(t,"h",.3);case"pip-dual-br":return Xe(t,"br");case"pip-dual-bl":return Xe(t,"bl");case"split-pip-l":return Ke(t,"l");case"split-pip-r":return Ke(t,"r");case"featured":return Je(t,"bottom");case"featured-r":return Je(t,"right");case"grid":return function(e){const t=e.length;if(0===t)return[];if(1===t)return qe(e);if(2===t)return Qe(e,"h");const i=Be,r=Math.ceil(Math.sqrt(t)),s=Math.ceil(t/r),o=(1-i*(r-1))/r,n=(1-i*(s-1))/s,a=[];for(let c=0;c<t;c++){const l=c%r,d=Math.floor(c/r),h=d===s-1,u=h?(t-1)%r+1:r;let p=0;h&&u<r&&(p=(1-(u*o+(u-1)*i))/2);const g=p+l*(o+i),f=d*(n+i);a.push(je(e[c],c,{x:g,y:f,width:o,height:n}))}return a}(t);case"stack":return function(e){const t=e.length;if(0===t)return[];if(1===t)return qe(e);const i=Be,r=(1-i*(t-1))/t;return e.map((e,t)=>je(e,0,{x:0,y:t*(r+i),width:1,height:r}))}(t)}}const Ze={durationMs:300,easing:"ease-out"};class et extends Pe{constructor(e){super(),this.scenes=new Map,this.activeSceneId=null,this.defaultLayoutTransition=Ze,this.isAnimating=!1,this.worker=null,this.workerReady=!1,this.pendingMessages=[],this.frameProcessors=new Map,this.frameReaders=new Map,this.outputCanvas=null,this.outputStream=null,this.lastStats={fps:0,frameTimeMs:0},this.config={...Te,...e},this.defaultTransition=this.config.defaultTransition||{type:"fade",durationMs:500,easing:"ease-in-out"},this.currentLayout={mode:"solo",scalingMode:"letterbox"}}async initializeWorker(){let e=null;const i=[new URL("../workers/compositor.worker.js",t&&"SCRIPT"===t.tagName.toUpperCase()&&t.src||new URL("fw-streamcrafter.iife.js",document.baseURI).href).href,"/node_modules/@livepeer-frameworks/streamcrafter-core/dist/workers/compositor.worker.js","/workers/compositor.worker.js","./workers/compositor.worker.js"];console.log("[SceneManager] Trying fallback worker paths:",i);for(const t of i){if(this.worker)break;try{console.log(`[SceneManager] Trying worker path: ${t}`);const e=(()=>{try{return new Worker(t,{type:"module"})}catch{return new Worker(t)}})();if(await new Promise(t=>{const i=setTimeout(()=>{e.terminate(),t(!1)},2e3);e.onerror=()=>{clearTimeout(i),e.terminate(),t(!1)},e.onmessage=()=>{clearTimeout(i),t(!0)},setTimeout(()=>{clearTimeout(i),t(!0)},500)})){e.terminate();try{this.worker=new Worker(t,{type:"module"})}catch{this.worker=new Worker(t)}console.log(`[SceneManager] Worker loaded from: ${t}`);break}console.warn(`[SceneManager] Worker failed to load from: ${t}`)}catch(i){e=i instanceof Error?i:new Error(String(i)),console.warn(`[SceneManager] Failed to load worker from ${t}:`,e.message),this.worker=null}}if(!this.worker)throw new Error(`Failed to initialize compositor worker. Make sure the worker is bundled correctly. Last error: ${e?.message??"unknown"}`)}async initialize(){if(console.log("[SceneManager] initialize() called"),this.worker)throw new Error("SceneManager already initialized");console.log("[SceneManager] Creating output canvas",{width:this.config.width,height:this.config.height}),this.outputCanvas=document.createElement("canvas"),this.outputCanvas.width=this.config.width,this.outputCanvas.height=this.config.height;const e=this.outputCanvas.transferControlToOffscreen();console.log("[SceneManager] Created OffscreenCanvas"),console.log("[SceneManager] Initializing worker..."),await this.initializeWorker(),console.log("[SceneManager] Worker initialized, waiting for ready...");const t=new Promise((e,t)=>{const i=setTimeout(()=>{console.error("[SceneManager] Worker initialization timeout"),t(new Error("Compositor worker initialization timeout"))},1e4);this.worker.onmessage=t=>{console.log("[SceneManager] Worker message:",t.data.type),"ready"===t.data.type&&(clearTimeout(i),e()),this.handleWorkerMessage(t.data)},this.worker.onerror=e=>{console.error("[SceneManager] Worker error:",e.message),clearTimeout(i),t(new Error(e.message))}});console.log("[SceneManager] Sending init message to worker"),this.worker.postMessage({type:"init",config:this.config,canvas:e},[e]),await t,console.log("[SceneManager] Worker is ready"),console.log("[SceneManager] Creating default scene");const i=this.createScene("Default");console.log("[SceneManager] Setting active scene:",i.id),this.setActiveScene(i.id),console.log("[SceneManager] Initialize complete")}handleWorkerMessage(e){switch(e.type){case"ready":this.workerReady=!0;for(const e of this.pendingMessages)this.worker?.postMessage(e);this.pendingMessages=[];break;case"stats":this.lastStats=e.stats,this.emit("statsUpdate",{stats:e.stats});break;case"transitionComplete":this.emit("transitionCompleted",{sceneId:e.sceneId});break;case"layoutAnimationComplete":{this.isAnimating=!1;const e=this.getActiveScene();if(e){const t=e.layers.filter(e=>e.visible).map(e=>e.sourceId);e.layers=Ye(this.currentLayout,t)}this.emit("layoutAnimationCompleted",{layout:this.currentLayout});break}case"rendererChanged":this.config.renderer=e.renderer,this.emit("rendererChanged",{renderer:e.renderer});break;case"error":this.emit("error",{message:e.message})}}sendToWorker(e,t){this.workerReady&&this.worker?this.worker.postMessage(e,t||[]):this.pendingMessages.push(e)}createScene(e,t="#000000"){const i=`scene-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,r={id:i,name:e,layers:[],backgroundColor:t};return this.scenes.set(i,r),this.emit("sceneCreated",{scene:r}),r}deleteScene(e){if(!this.scenes.has(e))throw new Error(`Scene not found: ${e}`);if(this.activeSceneId===e)throw new Error("Cannot delete the active scene");this.scenes.delete(e),this.emit("sceneDeleted",{sceneId:e})}getScene(e){return this.scenes.get(e)}getAllScenes(){return Array.from(this.scenes.values())}getActiveScene(){return this.activeSceneId?this.scenes.get(this.activeSceneId):void 0}setActiveScene(e){const t=this.scenes.get(e);if(!t)throw new Error(`Scene not found: ${e}`);const i=this.activeSceneId;this.activeSceneId=e,this.sendToWorker({type:"updateScene",scene:t}),this.emit("sceneActivated",{scene:t,previousSceneId:i})}async transitionTo(e,t){const i=this.scenes.get(e);if(!i)throw new Error(`Scene not found: ${e}`);const r=t||this.defaultTransition;this.sendToWorker({type:"updateScene",scene:i}),this.sendToWorker({type:"startTransition",transition:r,toSceneId:e});const s=this.activeSceneId;this.emit("transitionStarted",{fromSceneId:s||"",toSceneId:e,transition:r}),this.activeSceneId=e}addLayer(e,t,i){const r=this.scenes.get(e);if(!r)throw new Error(`Scene not found: ${e}`);const s=`layer-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,o=r.layers.reduce((e,t)=>Math.max(e,t.zIndex),-1),n={id:s,sourceId:t,visible:!0,locked:!1,zIndex:o+1,transform:{...Ee,...i},scalingMode:this.currentLayout.scalingMode??"letterbox"};return r.layers.push(n),this.updateSceneInWorker(r),this.emit("layerAdded",{sceneId:e,layer:n}),n}removeLayer(e,t){const i=this.scenes.get(e);if(!i)throw new Error(`Scene not found: ${e}`);const r=i.layers.findIndex(e=>e.id===t);if(-1===r)throw new Error(`Layer not found: ${t}`);i.layers.splice(r,1),this.updateSceneInWorker(i),this.emit("layerRemoved",{sceneId:e,layerId:t})}updateLayerTransform(e,t,i){const r=this.scenes.get(e);if(!r)throw new Error(`Scene not found: ${e}`);const s=r.layers.find(e=>e.id===t);if(!s)throw new Error(`Layer not found: ${t}`);s.transform={...s.transform,...i},this.updateSceneInWorker(r),this.emit("layerUpdated",{sceneId:e,layer:s})}setLayerVisibility(e,t,i){const r=this.scenes.get(e);if(!r)throw new Error(`Scene not found: ${e}`);const s=r.layers.find(e=>e.id===t);if(!s)throw new Error(`Layer not found: ${t}`);s.visible=i,this.updateSceneInWorker(r),this.emit("layerUpdated",{sceneId:e,layer:s})}reorderLayers(e,t){const i=this.scenes.get(e);if(!i)throw new Error(`Scene not found: ${e}`);t.forEach((e,t)=>{const r=i.layers.find(t=>t.id===e);r&&(r.zIndex=t)}),this.updateSceneInWorker(i)}cycleSourceOrder(e="forward"){const t=this.getActiveScene();if(!t||t.layers.length<2)return void console.warn("[SceneManager] cycleSourceOrder: Need at least 2 layers");console.log("[SceneManager] cycleSourceOrder BEFORE:",{direction:e,layers:t.layers.map(e=>({id:e.id,sourceId:e.sourceId,zIndex:e.zIndex}))});const i=[...t.layers].sort((e,t)=>e.zIndex-t.zIndex),r=i.map(e=>e.id);if(console.log("[SceneManager] sorted layerIds before rotate:",[...r]),"forward"===e){const e=r.shift();e&&r.push(e)}else{const e=r.pop();e&&r.unshift(e)}console.log("[SceneManager] layerIds after rotate:",[...r]),this.reorderLayers(t.id,r),console.log("[SceneManager] after reorderLayers:",{layers:t.layers.map(e=>({id:e.id,sourceId:e.sourceId,zIndex:e.zIndex}))}),this.currentLayout&&this.applyLayout(this.currentLayout,!0,{durationMs:200,easing:"ease-out"}),console.log("[SceneManager] cycleSourceOrder AFTER applyLayout:",{layers:t.layers.map(e=>({id:e.id,sourceId:e.sourceId,zIndex:e.zIndex}))}),this.emit("layerUpdated",{sceneId:t.id,layer:t.layers[0]})}updateSceneInWorker(e){this.activeSceneId===e.id&&this.sendToWorker({type:"updateScene",scene:e})}applyLayout(e,t=!0,i){const r=this.getActiveScene();if(!r)return void console.warn("[SceneManager] applyLayout: No active scene");this.currentLayout=e;const s=[...r.layers].filter(e=>e.visible).sort((e,t)=>e.zIndex-t.zIndex).map(e=>e.sourceId);console.log("[SceneManager] applyLayout",{mode:e.mode,sourceIds:s,currentLayerCount:r.layers.length,animate:t});const o=Ye(e,s),n={...r,layers:o};if(r.layers=o,t&&o.length>0){const t={...this.defaultLayoutTransition,...i};this.isAnimating=!0,this.emit("layoutAnimationStarted",{layout:e}),this.sendToWorker({type:"animateLayout",targetScene:n,transition:t})}else this.updateSceneInWorker(r);this.sendToWorker({type:"updateLayout",layout:e})}setDefaultLayoutTransition(e){this.defaultLayoutTransition={...this.defaultLayoutTransition,...e}}isLayoutAnimating(){return this.isAnimating}getCurrentLayout(){return this.currentLayout}bindSource(e,t){const i=t.getVideoTracks()[0];if(!i)throw new Error("No video track in stream");const r=globalThis.MediaStreamTrackProcessor;if(!r)return void console.warn("[SceneManager] MediaStreamTrackProcessor not available, compositor will not work");const s=new r({track:i});this.frameProcessors.set(e,s);const o=s.readable.getReader();this.frameReaders.set(e,o);const n=async()=>{try{const{done:t,value:i}=await o.read();if(t||!i)return;const r=i;this.sendToWorker({type:"sourceFrame",sourceId:e,frame:r},[r]),n()}catch(e){"AbortError"!==e?.name&&console.error("[SceneManager] Frame read error:",e)}};n()}unbindSource(e){const t=this.frameReaders.get(e);t&&(t.cancel().catch(()=>{}),this.frameReaders.delete(e));this.frameProcessors.get(e)&&this.frameProcessors.delete(e)}async bindImageSource(e,t){const i=await fetch(t),r=await i.blob(),s=await createImageBitmap(r);this.sendToWorker({type:"sourceImage",sourceId:e,bitmap:s},[s])}applyFilter(e,t){this.sendToWorker({type:"applyFilter",layerId:e,filter:t})}getOutputTrack(){return this.outputCanvas?(this.outputStream||(this.outputStream=this.outputCanvas.captureStream(this.config.frameRate)),this.outputStream.getVideoTracks()[0]||null):null}getOutputStream(){return this.outputCanvas?(this.outputStream||(this.outputStream=this.outputCanvas.captureStream(this.config.frameRate)),this.outputStream):null}getRendererType(){return this.config.renderer}setRenderer(e){this.config.renderer=e,this.sendToWorker({type:"setRenderer",renderer:e})}getStats(){return this.lastStats}getConfig(){return{...this.config}}updateOutputConfig(e){const t=e.width??this.config.width,i=e.height??this.config.height,r=e.frameRate??this.config.frameRate;return(t!==this.config.width||i!==this.config.height||r!==this.config.frameRate)&&(this.config.width=t,this.config.height=i,this.config.frameRate=r,this.sendToWorker({type:"resize",width:t,height:i,frameRate:r}),!0)}isInitialized(){return this.workerReady}destroy(){for(const[e]of this.frameProcessors)this.unbindSource(e);this.frameProcessors.clear(),this.frameReaders.clear(),this.worker&&(this.sendToWorker({type:"destroy"}),this.worker.terminate(),this.worker=null),this.scenes.clear(),this.activeSceneId=null,this.outputStream=null,this.outputCanvas=null,this.workerReady=!1,this.removeAllListeners()}}const tt={professional:{codec:"avc1.4d0032",width:1920,height:1080,bitrate:8e6,framerate:30},broadcast:{codec:"avc1.4d0028",width:1920,height:1080,bitrate:45e5,framerate:30},conference:{codec:"avc1.4d001f",width:1280,height:720,bitrate:25e5,framerate:30},low:{codec:"avc1.42001e",width:640,height:480,bitrate:1e6,framerate:24}},it={codec:"opus",sampleRate:48e3,numberOfChannels:2,bitrate:128e3};class rt extends Pe{constructor(e={}){super(),this.worker=null,this.videoProcessor=null,this.audioProcessor=null,this.videoReader=null,this.audioReader=null,this.isRunning=!1,this.isInitialized=!1,this.stats=null,this.config=null,this.pendingRequests=new Map,this.requestCounter=0,this.providedWorker=null,this.options={workerUrl:e.workerUrl??"",debug:e.debug??!1,timeout:e.timeout??1e4},this.providedWorker=e.worker??null}log(e,t){this.options.debug&&console.log(`[EncoderManager] ${e}`,t??"")}generateRequestId(){return`req_${++this.requestCounter}_${Date.now()}`}sendRequest(e){return new Promise((t,i)=>{if(!this.worker)return void i(new Error("Worker not created"));const r=e.requestId;if(!r)return this.worker.postMessage(e),void t(void 0);const s=setTimeout(()=>{this.pendingRequests.delete(r),i(new Error(`Request ${r} timed out`))},this.options.timeout);this.pendingRequests.set(r,{resolve:t,reject:i,timer:s}),this.worker.postMessage(e)})}handleResponse(e,t,i){const r=this.pendingRequests.get(e);r&&(clearTimeout(r.timer),this.pendingRequests.delete(e),t?r.resolve():r.reject(new Error(i??"Unknown error")))}tryCreateWorker(e,t=!0){return new Promise(i=>{try{const r=new Worker(e,t?{type:"module"}:void 0);let s=!1;const o=()=>{r.removeEventListener("message",n),r.removeEventListener("error",a)},n=e=>{s||(s=!0,o(),i(r))},a=t=>{s||(s=!0,o(),this.log("Worker failed to load from: "+e.toString(),t.message),r.terminate(),i(null))};r.addEventListener("message",n),r.addEventListener("error",a),setTimeout(()=>{s||(s=!0,o(),i(r))},2e3)}catch(t){this.log("Failed to create worker: "+e.toString(),t),i(null)}})}async createWorkerAsync(){if(this.providedWorker)return this.log("Using provided worker instance"),this.providedWorker;if(this.options.workerUrl){this.log("Creating worker from URL:",this.options.workerUrl);const e=await this.tryCreateWorker(this.options.workerUrl);if(e)return e}const e=[];try{const i=new URL("../workers/encoder.worker.js",t&&"SCRIPT"===t.tagName.toUpperCase()&&t.src||new URL("fw-streamcrafter.iife.js",document.baseURI).href);e.push({url:i,description:"import.meta.url relative"})}catch{}e.push({url:"/workers/encoder.worker.js",description:"Vite dev server"},{url:"/node_modules/@livepeer-frameworks/streamcrafter-core/dist/workers/encoder.worker.js",description:"node_modules"},{url:"./workers/encoder.worker.js",description:"relative path"});for(const{url:t,description:i}of e){this.log(`Trying worker path: ${t.toString()} (${i})`);const e=await this.tryCreateWorker(t);if(e)return this.log("Worker loaded from:",t.toString()),e}throw new Error("Failed to create encoder worker. Provide a worker URL via options.workerUrl or ensure workers are served correctly.")}createWorker(){if(this.providedWorker)return this.providedWorker;if(this.options.workerUrl)return new Worker(this.options.workerUrl,{type:"module"});try{const e=new URL("../workers/encoder.worker.js",t&&"SCRIPT"===t.tagName.toUpperCase()&&t.src||new URL("fw-streamcrafter.iife.js",document.baseURI).href);return new Worker(e,{type:"module"})}catch{}return new Worker("/workers/encoder.worker.js",{type:"module"})}handleWorkerMessage(e){switch(e.type){case"ready":this.log("Worker ready"),e.requestId&&this.handleResponse(e.requestId,!0),this.emit("ready",void 0);break;case"started":this.log("Encoding started"),e.requestId&&this.handleResponse(e.requestId,!0),this.emit("started",void 0);break;case"stopped":this.log("Encoding stopped"),e.requestId&&this.handleResponse(e.requestId,!0),this.emit("stopped",void 0);break;case"flushed":this.log("Encoder flushed"),e.requestId&&this.handleResponse(e.requestId,!0);break;case"stats":this.stats=e.data,this.emit("stats",this.stats);break;case"error":{const t=e.data;console.error("[EncoderManager] Worker error:",t),e.requestId&&this.handleResponse(e.requestId,!1,t.message),this.emit("error",t);break}case"encodedVideoChunk":this.emit("videoChunk",e.data);break;case"encodedAudioChunk":this.emit("audioChunk",e.data);break;default:this.log("Unknown message from worker",e)}}async initialize(e,t){if(this.log("Initializing encoder",t),this.config=t,"undefined"==typeof VideoEncoder||"undefined"==typeof AudioEncoder)throw new Error("WebCodecs not supported in this browser");if("undefined"==typeof MediaStreamTrackProcessor)throw new Error("MediaStreamTrackProcessor not supported in this browser");const i=e.getVideoTracks()[0],r=e.getAudioTracks()[0];i&&(this.videoProcessor=new MediaStreamTrackProcessor({track:i})),r&&(this.audioProcessor=new MediaStreamTrackProcessor({track:r})),this.worker=await this.createWorkerAsync(),this.worker.onmessage=e=>{this.handleWorkerMessage(e.data)},this.worker.onerror=e=>{console.error("[EncoderManager] Worker error:",e),this.emit("error",{message:e.message,fatal:!0})};const s=this.generateRequestId();this.log("Sending initialize to worker",{requestId:s}),await this.sendRequest({type:"initialize",requestId:s,data:{config:t}}),this.isInitialized=!0,this.log("Worker initialized and ready")}async start(){if(!this.isInitialized)throw new Error("EncoderManager not initialized");if(this.isRunning)return;this.log("Starting encoder");const e=this.generateRequestId();await this.sendRequest({type:"start",requestId:e}),this.isRunning=!0,this.videoProcessor&&this.startVideoProcessing(),this.audioProcessor&&this.startAudioProcessing(),this.log("Encoder started, frame processing active")}async startVideoProcessing(){if(this.videoProcessor&&this.worker)try{this.videoReader=this.videoProcessor.readable.getReader();const e=this.videoReader;for(;this.isRunning;){const{value:t,done:i}=await e.read();if(i||!t)break;try{this.worker.postMessage({type:"videoFrame",data:t},[t])}catch(e){console.error("[EncoderManager] Error sending video frame:",e);try{t.close()}catch{}}}}catch(e){this.isRunning&&console.error("[EncoderManager] Video processing error:",e)}}async startAudioProcessing(){if(this.audioProcessor&&this.worker)try{this.audioReader=this.audioProcessor.readable.getReader();const e=this.audioReader;for(;this.isRunning;){const{value:t,done:i}=await e.read();if(i||!t)break;try{this.worker.postMessage({type:"audioData",data:t},[t])}catch(e){console.error("[EncoderManager] Error sending audio data:",e);try{t.close()}catch{}}}}catch(e){this.isRunning&&console.error("[EncoderManager] Audio processing error:",e)}}async stop(){if(this.isRunning){if(this.isRunning=!1,this.log("Stopping encoder"),this.videoReader){try{await this.videoReader.cancel(),this.videoReader.releaseLock()}catch{}this.videoReader=null}if(this.audioReader){try{await this.audioReader.cancel(),this.audioReader.releaseLock()}catch{}this.audioReader=null}if(this.worker&&this.isInitialized){const e=this.generateRequestId();try{await this.sendRequest({type:"stop",requestId:e})}catch(e){this.log("Stop request failed (may be expected)",e)}}this.emit("stopped",void 0)}}async updateConfig(e){if(!this.worker||!this.isInitialized)throw new Error("EncoderManager not initialized");const t=this.generateRequestId();await this.sendRequest({type:"updateConfig",requestId:t,data:e}),this.config&&(e.video&&(this.config.video={...this.config.video,...e.video}),e.audio&&(this.config.audio={...this.config.audio,...e.audio}))}async updateInputStream(e){if(!this.isInitialized||!this.worker)throw new Error("EncoderManager not initialized");const t=this.isRunning;if(this.log("Updating input stream (hot-swap)",{wasRunning:t}),this.videoReader){try{await this.videoReader.cancel(),this.videoReader.releaseLock()}catch{}this.videoReader=null}if(this.audioReader){try{await this.audioReader.cancel(),this.audioReader.releaseLock()}catch{}this.audioReader=null}const i=e.getVideoTracks()[0],r=e.getAudioTracks()[0];this.videoProcessor=i?new MediaStreamTrackProcessor({track:i}):null,this.audioProcessor=r?new MediaStreamTrackProcessor({track:r}):null,t&&(this.videoProcessor&&this.startVideoProcessing(),this.audioProcessor&&this.startAudioProcessing(),this.log("Input stream updated, processing restarted"))}async flush(){if(!this.worker||!this.isInitialized)return;const e=this.generateRequestId();await this.sendRequest({type:"flush",requestId:e})}getStats(){return this.stats}getConfig(){return this.config}getIsInitialized(){return this.isInitialized}getIsRunning(){return this.isRunning}destroy(){this.stop(),this.isInitialized=!1,this.videoProcessor=null,this.audioProcessor=null;for(const[,e]of this.pendingRequests)clearTimeout(e.timer),e.reject(new Error("EncoderManager destroyed"));this.pendingRequests.clear(),this.worker&&(this.worker.terminate(),this.worker=null),this.removeAllListeners()}}function st(){const e={videoEncoder:"undefined"!=typeof VideoEncoder,audioEncoder:"undefined"!=typeof AudioEncoder,mediaStreamTrackProcessor:"undefined"!=typeof MediaStreamTrackProcessor,mediaStreamTrackGenerator:"undefined"!=typeof MediaStreamTrackGenerator};return{webcodecs:e,webrtc:{peerConnection:"undefined"!=typeof RTCPeerConnection,replaceTrack:"undefined"!=typeof RTCRtpSender&&"replaceTrack"in RTCRtpSender.prototype,insertableStreams:"undefined"!=typeof RTCRtpSender&&"createEncodedStreams"in RTCRtpSender.prototype,scriptTransform:"undefined"!=typeof RTCRtpScriptTransform},mediaDevices:{getUserMedia:"undefined"!=typeof navigator&&void 0!==navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.getUserMedia,getDisplayMedia:"undefined"!=typeof navigator&&void 0!==navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.getDisplayMedia,enumerateDevices:"undefined"!=typeof navigator&&void 0!==navigator.mediaDevices&&"function"==typeof navigator.mediaDevices.enumerateDevices},recommended:e.videoEncoder&&e.audioEncoder&&e.mediaStreamTrackProcessor&&e.mediaStreamTrackGenerator?"webcodecs":"mediastream"}}function ot(){return"undefined"!=typeof RTCRtpScriptTransform}function nt(){return"undefined"!=typeof VideoEncoder&&"undefined"!=typeof AudioEncoder&&"undefined"!=typeof MediaStreamTrackProcessor&&"undefined"!=typeof MediaStreamTrackGenerator&&ot()}let at=0;class ct extends Pe{constructor(e){super(),this.whipClient=null,this.whipEndpoints=[],this.currentEndpointIndex=0,this.isStoppingIntentionally=!1,this.state="idle",this.stateContext={},this.sources=new Map,this.outputStream=null,this.statsInterval=null,this.lastStats=null,this.statsInFlight=!1,this.sceneManager=null,this.compositorBaseConfig=null,this.encoderManager=null,this.encoderOverrides={},this.config=e,this.currentProfile=e.profile||"broadcast",this.whipEndpoints=this.buildWhipEndpoints(e),this.deviceManager=new We,this.screenCapture=new ze,this.audioMixer=new Ue,this.reconnectionManager=new Ve(e.reconnection);const t=st();this.useWebCodecs=e.useWebCodecs??"webcodecs"===t.recommended,this.setupEventForwarding(),this.log("IngestControllerV2 initialized",{useWebCodecs:this.useWebCodecs,profile:this.currentProfile,audioMixing:e.audioMixing??!1})}buildWhipEndpoints(e){if(e.whipUrls&&e.whipUrls.length>0){return[e.whipUrl,...e.whipUrls].filter((e,t,i)=>i.indexOf(e)===t)}return[e.whipUrl]}getCurrentWhipUrl(){return this.whipEndpoints[this.currentEndpointIndex]??this.config.whipUrl}getNextWhipUrl(){return this.whipEndpoints.length>1&&(this.currentEndpointIndex=(this.currentEndpointIndex+1)%this.whipEndpoints.length),this.getCurrentWhipUrl()}log(e,t){this.config.debug&&console.log(`[IngestControllerV2] ${e}`,t??"")}setupEventForwarding(){this.deviceManager.on("devicesChanged",e=>{this.emit("deviceChange",e)}),this.deviceManager.on("error",e=>{this.emit("error",{error:e.message,recoverable:!0})}),this.screenCapture.on("ended",e=>{if(this.log("Screen capture ended",e),e.stream)for(const[t,i]of this.sources)if("screen"===i.type&&i.stream===e.stream){this.removeSource(t);break}}),this.screenCapture.on("error",e=>{this.emit("error",{error:e.message,recoverable:!0})}),this.reconnectionManager.on("attemptStart",e=>{this.emit("reconnectionAttempt",{attempt:e.attempt,maxAttempts:this.reconnectionManager.getMaxAttempts()})}),this.reconnectionManager.on("attemptSuccess",()=>{this.emit("reconnectionSuccess",void 0),this.setState("streaming")}),this.reconnectionManager.on("attemptFailed",e=>{this.log("Reconnection attempt failed",e)}),this.reconnectionManager.on("exhausted",()=>{this.emit("reconnectionFailed",{error:"All reconnection attempts exhausted"}),this.setState("error",{error:"Connection lost - reconnection failed"})})}setState(e,t){this.state=e,t&&(this.stateContext={...this.stateContext,...t}),this.stateContext.sources=Array.from(this.sources.values()),this.stateContext.activeProfile=this.currentProfile,this.stateContext.reconnection=this.reconnectionManager.getState(),this.emit("stateChange",{state:this.state,context:this.stateContext})}async ensureAudioMixer(){this.config.audioMixing&&null===this.audioMixer.getState()&&await this.audioMixer.initialize()}addMediaSource(e,t,i){const r=function(e){return`${e}-${++at}-${Date.now()}`}(e),s=t.getVideoTracks().length>0,o=Array.from(this.sources.values()).filter(e=>e.stream.getVideoTracks().length>0),n=s&&0===o.length,a={id:r,type:e,stream:t,label:i,active:!0,muted:!1,volume:1,primaryVideo:n};if(this.sources.set(r,a),this.log(`Added source: ${r} (${e})`,{label:i,tracks:t.getTracks().length,primaryVideo:n}),this.config.audioMixing){const e=t.getAudioTracks()[0];e&&this.audioMixer.addSource(r,e,{volume:1})}if(this.sceneManager&&this.sceneManager.isInitialized()){this.log("Binding source to compositor",{sourceId:r}),this.sceneManager.bindSource(r,t);const e=this.sceneManager.getActiveScene();this.log("Adding layer to scene",{sourceId:r,activeSceneId:e?.id,sceneLayers:e?.layers.length}),e&&(this.sceneManager.addLayer(e.id,r),this.log("Layer added",{sourceId:r,layerCount:e.layers.length}))}else this.log("Compositor not ready when adding source",{sourceId:r,hasSceneManager:!!this.sceneManager,isInitialized:this.sceneManager?.isInitialized()??!1});return this.emit("sourceAdded",{source:a}),this.updateOutputStreamFromSources(),a}removeSource(e){const t=this.sources.get(e);if(!t)return;const i=t.primaryVideo;if(t.stream.getTracks().forEach(e=>e.stop()),this.config.audioMixing&&this.audioMixer.removeSource(e),this.sceneManager){this.sceneManager.unbindSource(e);const t=this.sceneManager.getActiveScene();if(t){const i=t.layers.find(t=>t.sourceId===e);i&&this.sceneManager.removeLayer(t.id,i.id)}}if(this.sources.delete(e),this.log(`Removed source: ${e}`),i){const e=Array.from(this.sources.values()).filter(e=>e.stream.getVideoTracks().length>0);e.length>0&&(e[0].primaryVideo=!0,this.sources.set(e[0].id,e[0]),this.log(`Reassigned primary video to: ${e[0].id}`))}this.emit("sourceRemoved",{sourceId:e}),this.updateOutputStreamFromSources()}setPrimaryVideoSource(e){const t=this.sources.get(e);if(t)if(0!==t.stream.getVideoTracks().length){for(const[e,t]of this.sources)t.primaryVideo&&(t.primaryVideo=!1,this.sources.set(e,t));t.primaryVideo=!0,this.sources.set(e,t),this.log(`Set primary video source: ${e}`),this.emit("sourceUpdated",{source:t,changes:{primaryVideo:!0}}),this.updateOutputStreamFromSources()}else this.log(`Cannot set source ${e} as primary - no video track`)}getPrimaryVideoSource(){for(const e of this.sources.values())if(e.primaryVideo)return e;return null}updateOutputStreamFromSources(){const e=Array.from(this.sources.values()).filter(e=>e.active);if(0===e.length)return void(this.outputStream=null);const t=[];if(this.sceneManager&&this.sceneManager.isInitialized()){const e=this.sceneManager.getOutputTrack();e&&t.push(e)}else{const i=e.filter(e=>e.stream.getVideoTracks().length>0),r=i.find(e=>e.primaryVideo)||i[0];if(r){const e=r.stream.getVideoTracks()[0];e&&t.push(e)}}if(this.config.audioMixing&&"running"===this.audioMixer.getState()){const e=this.audioMixer.getOutputTrack();e&&t.push(e)}else for(const i of e){const e=i.stream.getAudioTracks()[0];if(e&&!i.muted){t.push(e);break}}this.outputStream=t.length>0?new MediaStream(t):null,this.whipClient&&"streaming"===this.state&&this.updateWhipTracks(),this.encoderManager&&this.outputStream&&this.encoderManager.updateInputStream(this.outputStream).catch(e=>{this.log("Failed to update encoder input stream",e)}),this.log("Output stream updated",{videoTracks:this.outputStream?.getVideoTracks().length??0,audioTracks:this.outputStream?.getAudioTracks().length??0,usingCompositor:!!this.sceneManager})}async updateWhipTracks(){if(this.whipClient&&this.outputStream)try{const e=this.whipClient.getPeerConnection();if(!e)return;const t=e.getSenders(),i=this.outputStream.getVideoTracks()[0],r=t.find(e=>"video"===e.track?.kind);r&&await r.replaceTrack(i??null);const s=this.outputStream.getAudioTracks()[0],o=t.find(e=>"audio"===e.track?.kind);o&&await o.replaceTrack(s??null)}catch(e){this.log("Error updating WHIP tracks",e)}}async startCamera(e={}){this.log("Starting camera capture",e),this.setState("requesting_permissions");try{await this.ensureAudioMixer();const t=e.profile||this.currentProfile,i={...e,profile:t};if(this.encoderOverrides?.video){const e=this.encoderOverrides.video,r=Re(t);i.customConstraints={video:{...r,...e.width&&{width:{ideal:e.width}},...e.height&&{height:{ideal:e.height}},...e.framerate&&{frameRate:{ideal:e.framerate}}},audio:!0},this.log("Using encoder overrides for capture constraints:",i.customConstraints)}const r=await this.deviceManager.getUserMedia(i),s=await this.getCameraLabel(r),o=this.addMediaSource("camera",r,s);return this.setState("capturing",{hasVideo:r.getVideoTracks().length>0,hasAudio:r.getAudioTracks().length>0}),o}catch(e){throw this.setState("error",{error:e instanceof Error?e.message:String(e)}),e}}async getCameraLabel(e){const t=e.getVideoTracks()[0];return t&&t.label||"Camera"}async startScreenShare(e={}){this.log("Starting screen share",e),this.setState("requesting_permissions");try{await this.ensureAudioMixer();const t={...e};if(this.encoderOverrides?.video){const e=this.encoderOverrides.video;t.video={...e.width&&{width:{ideal:e.width}},...e.height&&{height:{ideal:e.height}},...e.framerate&&{frameRate:{ideal:e.framerate}}},this.log("Using encoder overrides for screen capture constraints:",t.video)}const i=await this.screenCapture.start(t);if(i){const e=i.getVideoTracks()[0],t=e?.label||`Screen ${this.screenCapture.getCaptureCount()}`,r=this.addMediaSource("screen",i,t);return this.setState("capturing",{hasVideo:!0,isScreenShare:!0}),r}return this.sources.size>0?this.setState("capturing"):this.setState("idle"),null}catch(e){throw this.setState("error",{error:e instanceof Error?e.message:String(e)}),e}}addCustomSource(e,t){return this.addMediaSource("custom",e,t)}setSourceVolume(e,t){const i=this.sources.get(e);i&&(i.volume=Math.max(0,Math.min(2,t)),this.sources.set(e,i),this.config.audioMixing&&this.audioMixer.setVolume(e,i.volume),this.emit("sourceUpdated",{source:i,changes:{volume:i.volume}}))}setSourceMuted(e,t){const i=this.sources.get(e);i&&(i.muted=t,this.sources.set(e,i),this.config.audioMixing?t?this.audioMixer.mute(e):this.audioMixer.unmute(e):i.stream.getAudioTracks().forEach(e=>{e.enabled=!t}),this.emit("sourceUpdated",{source:i,changes:{muted:t}}),this.updateOutputStreamFromSources())}setSourceActive(e,t){const i=this.sources.get(e);i&&(i.active=t,this.sources.set(e,i),this.emit("sourceUpdated",{source:i,changes:{active:t}}),this.updateOutputStreamFromSources())}setMasterVolume(e){this.config.audioMixing&&this.audioMixer.setMasterVolume(e)}getMasterVolume(){return this.config.audioMixing?this.audioMixer.getMasterVolume():1}async stopCapture(){this.log("Stopping all capture");for(const e of Array.from(this.sources.keys()))this.removeSource(e);this.deviceManager.stopAllTracks(),this.screenCapture.stop(),this.outputStream=null,"streaming"!==this.state&&this.setState("idle",{hasVideo:!1,hasAudio:!1,isScreenShare:!1})}async setQualityProfile(e){if(e===this.currentProfile)return;const t=this.currentProfile;this.currentProfile=e,this.log(`Changing quality profile: ${t} -> ${e}`);for(const[t,i]of this.sources)if("camera"===i.type){const t=i.stream.getVideoTracks()[0];if(t)try{const i=Re(e);await t.applyConstraints(i)}catch(e){this.log("Failed to apply new constraints",e)}}this.emit("qualityChanged",{profile:e,previousProfile:t}),this.setState(this.state,{activeProfile:e})}setupWhipClientHandlers(){this.whipClient&&(this.whipClient.on("stateChange",e=>{if(this.log("WHIP state changed",e),this.stateContext={...this.stateContext,connectionState:e.state},"connected"===e.state){if(this.setState("streaming"),this.startStatsPolling(),this.reconnectionManager.reset(),this.useWebCodecs&&this.encoderManager&&this.whipClient){this.log("Attempting to attach WebCodecs encoder transform");const e=this.whipClient.canUseEncodedInsertion();if(this.log("canUseEncodedInsertion result:",e),e)try{this.whipClient.attachEncoderTransform(this.encoderManager),this.encoderManager.start(),this.log("WebCodecs encoder transform attached",{videoCodec:this.whipClient.getNegotiatedVideoCodec(),audioCodec:this.whipClient.getNegotiatedAudioCodec()}),this.emit("webCodecsActive",{active:!0})}catch(e){this.log("Failed to attach encoder transform, continuing with browser encoding",e),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null)}else this.log("Codec alignment check failed, using browser encoding",{videoCodec:this.whipClient.getNegotiatedVideoCodec(),audioCodec:this.whipClient.getNegotiatedAudioCodec()}),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null)}}else if("failed"===e.state||"disconnected"===e.state){if(this.isStoppingIntentionally)return;"streaming"===this.state&&!1!==this.config.reconnection?.enabled?this.handleConnectionLost():(this.setState("error",{error:"failed"===e.state?"Connection failed":"Connection lost"}),this.stopStatsPolling())}}),this.whipClient.on("error",e=>{this.isStoppingIntentionally||this.emit("error",{error:e.message,recoverable:!1})}))}async startStreaming(){if(!this.outputStream)throw new Error("No media source available. Add a camera or screen share first.");this.log("Starting streaming"),this.currentEndpointIndex=0,this.setState("connecting");try{if(this.whipClient=new Le({whipUrl:this.getCurrentWhipUrl(),iceServers:this.config.iceServers,debug:this.config.debug}),this.setupWhipClientHandlers(),this.config.audioMixing&&await this.audioMixer.resume(),this.useWebCodecs&&ot()){this.log("Initializing WebCodecs encoder (Path C: RTCRtpScriptTransform)");try{this.encoderManager=new rt({debug:this.config.debug}),this.encoderManager.on("error",e=>{this.emit("error",{error:e.message,recoverable:!e.fatal}),e.fatal&&"streaming"===this.state&&(this.log("Fatal encoder error, reconnecting without WebCodecs"),this.handleEncoderFailure())}),this.encoderManager.on("stats",e=>{this.log("Encoder stats",e)});const e=function(e="broadcast",t){const i=tt[e],r=it,s=t?.video?.width??i.width,o=t?.video?.height??i.height,n=t?.video?.framerate??i.framerate,a=function(e,t,i){const r=e*t;return r>=8294400?i>30?"avc1.640034":"avc1.640033":r>=3686400?i>30?"avc1.640033":"avc1.640032":r>=2073600?i>30?"avc1.640032":"avc1.64002a":r>=921600?i>30?"avc1.64002a":"avc1.640028":"avc1.64001f"}(s,o,n);return{video:{...i,codec:a,width:s,height:o,framerate:n,...void 0!==t?.video?.bitrate&&{bitrate:t.video.bitrate}},audio:{...r,...void 0!==t?.audio?.bitrate&&{bitrate:t.audio.bitrate},...void 0!==t?.audio?.sampleRate&&{sampleRate:t.audio.sampleRate},...void 0!==t?.audio?.numberOfChannels&&{numberOfChannels:t.audio.numberOfChannels}}}}("auto"===this.currentProfile?"broadcast":this.currentProfile,this.encoderOverrides);this.log("Encoder config with overrides:",e),await this.encoderManager.initialize(this.outputStream,e),this.log("WebCodecs encoder initialized")}catch(e){this.log("WebCodecs encoder initialization failed, falling back to browser encoding",e),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null)}}else this.useWebCodecs&&this.log("WebCodecs requested but RTCRtpScriptTransform not supported, using browser encoding");await this.whipClient.connect(this.outputStream)}catch(e){throw this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null),this.setState("error",{error:e instanceof Error?e.message:String(e)}),e}}async handleEncoderFailure(){if(this.log("Handling encoder failure - reconnecting without WebCodecs"),this.setState("reconnecting"),this.stopStatsPolling(),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null),this.useWebCodecs=!1,this.whipClient)try{await this.whipClient.disconnect()}finally{this.whipClient.destroy(),this.whipClient=null}if(this.outputStream)try{this.whipClient=new Le({whipUrl:this.getNextWhipUrl(),iceServers:this.config.iceServers,debug:this.config.debug}),this.setupWhipClientHandlers(),await this.whipClient.connect(this.outputStream)}catch(e){this.setState("error",{error:`Reconnection failed: ${e instanceof Error?e.message:String(e)}`})}else this.setState("error",{error:"No output stream available for reconnection"})}handleConnectionLost(){this.log("Connection lost, starting reconnection"),this.setState("reconnecting"),this.stopStatsPolling(),this.reconnectionManager.start(async()=>{if(this.whipClient)try{await this.whipClient.disconnect()}finally{this.whipClient.destroy(),this.whipClient=null}if(!this.outputStream)throw new Error("No output stream available");this.whipClient=new Le({whipUrl:this.getNextWhipUrl(),iceServers:this.config.iceServers,debug:this.config.debug}),this.setupWhipClientHandlers(),await new Promise((e,t)=>{const i=setTimeout(()=>{t(new Error("Connection timeout"))},3e4),r=s=>{"connected"===s.state?(clearTimeout(i),this.whipClient?.off("stateChange",r),e()):"failed"===s.state&&(clearTimeout(i),this.whipClient?.off("stateChange",r),t(new Error("Connection failed")))};this.whipClient.on("stateChange",r),this.whipClient.connect(this.outputStream).catch(t)})})}async stopStreaming(){this.log("Stopping streaming"),this.isStoppingIntentionally=!0;try{this.stopStatsPolling(),this.reconnectionManager.stop(),this.encoderManager&&(await this.encoderManager.stop(),this.encoderManager.destroy(),this.encoderManager=null),this.whipClient&&(await this.whipClient.disconnect(),this.whipClient.destroy(),this.whipClient=null),this.sources.size>0?this.setState("capturing"):this.setState("idle"),this.stateContext={...this.stateContext,connectionState:"disconnected"}}finally{this.isStoppingIntentionally=!1}}async switchVideoDevice(e){const t=await this.deviceManager.replaceVideoTrack(e,this.currentProfile);if(t&&this.whipClient){const e=this.whipClient.getPeerConnection();if(e){const i=e.getSenders().find(e=>"video"===e.track?.kind);i&&await i.replaceTrack(t)}}}async switchAudioDevice(e){const t=await this.deviceManager.replaceAudioTrack(e,this.currentProfile);if(t&&this.whipClient){const e=this.whipClient.getPeerConnection();if(e){const i=e.getSenders().find(e=>"audio"===e.track?.kind);i&&await i.replaceTrack(t)}}}startStatsPolling(){this.statsInterval||(this.statsInterval=setInterval(async()=>{if(!this.statsInFlight){this.statsInFlight=!0;try{const e=await this.getStats();e&&(this.lastStats=e,this.emit("statsUpdate",e))}finally{this.statsInFlight=!1}}},1e3))}stopStatsPolling(){this.statsInterval&&(clearInterval(this.statsInterval),this.statsInterval=null)}async getStats(){if(!this.whipClient)return null;const e=await this.whipClient.getStats();if(!e)return null;const t={video:{bytesSent:0,packetsSent:0,packetsLost:0,framesEncoded:0,framesPerSecond:0,bitrate:0},audio:{bytesSent:0,packetsSent:0,packetsLost:0,bitrate:0},connection:{rtt:0,state:this.whipClient.getPeerConnection()?.connectionState??"new",iceState:this.whipClient.getPeerConnection()?.iceConnectionState??"new"},timestamp:Date.now()},i=this.lastStats;return e.forEach(e=>{if("outbound-rtp"===e.type){const r=e;if("video"===r.kind){if(t.video.bytesSent=r.bytesSent??0,t.video.packetsSent=r.packetsSent??0,t.video.framesEncoded=r.framesEncoded??0,t.video.framesPerSecond=r.framesPerSecond??0,i){const e=(t.timestamp-i.timestamp)/1e3,r=t.video.bytesSent-i.video.bytesSent;t.video.bitrate=Math.round(8*r/e)}}else if("audio"===r.kind&&(t.audio.bytesSent=r.bytesSent??0,t.audio.packetsSent=r.packetsSent??0,i)){const e=(t.timestamp-i.timestamp)/1e3,r=t.audio.bytesSent-i.audio.bytesSent;t.audio.bitrate=Math.round(8*r/e)}}else"candidate-pair"===e.type&&"succeeded"===e.state&&(t.connection.rtt=e.currentRoundTripTime??0)}),t}async enableCompositor(e){if(this.log("enableCompositor called",{alreadyEnabled:!!this.sceneManager}),this.sceneManager)return void this.log("Compositor already enabled");const t={...Te,...this.config.compositor,...e};this.log("Creating SceneManager with config",t),this.sceneManager=new et(t),this.compositorBaseConfig=t;try{this.log("Initializing SceneManager..."),await this.sceneManager.initialize(),this.log("SceneManager initialized successfully")}catch(e){this.sceneManager=null;const t=e instanceof Error?e.message:String(e);throw this.log("Compositor initialization failed:",t),new Error(`Compositor initialization failed: ${t}`)}if(!this.sceneManager)throw this.log("ERROR: SceneManager was unexpectedly null after initialization"),new Error("SceneManager was unexpectedly null after initialization");this.log("SceneManager is valid, getting active scene...");const i=this.sceneManager.getActiveScene();this.log("Compositor active scene:",i?.id??"none");for(const[e,t]of this.sources){if(!this.sceneManager)break;this.sceneManager.bindSource(e,t.stream),i&&this.sceneManager.addLayer(i.id,e)}this.sceneManager&&this.sceneManager.on("error",e=>{this.emit("error",{error:e.message,recoverable:!0})}),this.log("Compositor enabled",t),this.updateOutputStreamFromSources()}disableCompositor(){this.sceneManager&&(this.sceneManager.destroy(),this.sceneManager=null,this.log("Compositor disabled"),this.updateOutputStreamFromSources())}getSceneManager(){return this.sceneManager}isCompositorEnabled(){return null!==this.sceneManager&&this.sceneManager.isInitialized()}getState(){return this.state}getStateContext(){return{...this.stateContext}}getMediaStream(){return this.outputStream}getSources(){return Array.from(this.sources.values())}getSource(e){return this.sources.get(e)}getQualityProfile(){return this.currentProfile}getDeviceManager(){return this.deviceManager}getScreenCapture(){return this.screenCapture}getAudioMixer(){return this.audioMixer}getReconnectionManager(){return this.reconnectionManager}async getDevices(){return this.deviceManager.enumerateDevices()}isStreaming(){return"streaming"===this.state}isCapturing(){return"capturing"===this.state||"streaming"===this.state}isReconnecting(){return"reconnecting"===this.state}setUseWebCodecs(e){"streaming"!==this.state?(this.useWebCodecs=e,this.log("useWebCodecs set to",e)):this.log("Cannot change useWebCodecs while streaming")}setEncoderOverrides(e){if("streaming"!==this.state){if(this.encoderOverrides=e,this.log("Encoder overrides set:",e),this.sceneManager){const t=this.compositorBaseConfig??this.sceneManager.getConfig(),i=e.video?.width??t.width,r=e.video?.height??t.height,s=e.video?.framerate??t.frameRate;this.sceneManager.updateOutputConfig({width:i,height:r,frameRate:s})&&this.updateOutputStreamFromSources()}}else this.log("Cannot change encoder overrides while streaming")}getEncoderOverrides(){return this.encoderOverrides}getUseWebCodecs(){return this.useWebCodecs}getEncoderManager(){return this.encoderManager}isWebCodecsActive(){return null!==this.encoderManager&&!0===this.whipClient?.hasEncoderTransform()}destroy(){this.log("Destroying IngestControllerV2"),this.stopStatsPolling(),this.reconnectionManager.destroy(),this.encoderManager&&(this.encoderManager.destroy(),this.encoderManager=null),this.whipClient&&(this.whipClient.destroy(),this.whipClient=null),this.sceneManager&&(this.sceneManager.destroy(),this.sceneManager=null);for(const e of Array.from(this.sources.keys()))this.removeSource(e);this.deviceManager.destroy(),this.screenCapture.destroy(),this.audioMixer.destroy(),this.removeAllListeners(),this.setState("destroyed")}}class lt{constructor(e,t="broadcast"){this.controller=null,this.unsubs=[],this.encoderStatsCleanup=null,this.audioLevelCleanup=null,this.host=e,e.addController(this);const i=st();this.s={state:"idle",stateContext:{},isStreaming:!1,isCapturing:!1,isReconnecting:!1,error:null,mediaStream:null,sources:[],qualityProfile:t,reconnectionState:null,stats:null,useWebCodecs:"webcodecs"===i.recommended,isWebCodecsActive:!1,isWebCodecsAvailable:nt(),encoderStats:null,audioLevel:0,peakAudioLevel:0}}initialize(e){this.teardown();const t=new ct({...e,useWebCodecs:this.s.useWebCodecs});this.controller=t,this.subscribeToEvents(t)}hostConnected(){}hostDisconnected(){this.teardown()}teardown(){this.unsubs.forEach(e=>e()),this.unsubs=[],this.encoderStatsCleanup&&(this.encoderStatsCleanup(),this.encoderStatsCleanup=null),this.stopAudioLevelMonitoring(),this.controller?.destroy(),this.controller=null}update(e){Object.assign(this.s,e),this.host.requestUpdate()}subscribeToEvents(e){const t=this.unsubs;t.push(e.on("stateChange",t=>{const i=t.state,r=t.context??{},s="capturing"===i||"streaming"===i;this.update({state:i,stateContext:r,isStreaming:"streaming"===i,isCapturing:s,isReconnecting:"reconnecting"===i,mediaStream:e.getMediaStream(),sources:e.getSources(),reconnectionState:r.reconnection??this.s.reconnectionState}),s?this.startAudioLevelMonitoring():this.stopAudioLevelMonitoring(),this.dispatchEvent("fw-sc-state-change",{state:i,context:r})})),t.push(e.on("statsUpdate",e=>{this.update({stats:e})})),t.push(e.on("error",e=>{this.update({error:e.error}),this.dispatchEvent("fw-sc-error",{error:e.error})})),t.push(e.on("sourceAdded",()=>{this.update({sources:e.getSources(),mediaStream:e.getMediaStream()})})),t.push(e.on("sourceRemoved",()=>{this.update({sources:e.getSources(),mediaStream:e.getMediaStream()})})),t.push(e.on("sourceUpdated",()=>{this.update({sources:e.getSources(),mediaStream:e.getMediaStream()})})),t.push(e.on("qualityChanged",e=>{this.update({qualityProfile:e.profile})})),t.push(e.on("reconnectionAttempt",()=>{this.update({reconnectionState:e.getReconnectionManager().getState()})})),t.push(e.on("webCodecsActive",e=>{this.update({isWebCodecsActive:e.active}),e.active&&this.setupEncoderStatsListener()})),t.push(e.on("stateChange",t=>{"streaming"===t.state?setTimeout(()=>{this.update({isWebCodecsActive:e.isWebCodecsActive()}),e.isWebCodecsActive()&&!this.encoderStatsCleanup&&this.setupEncoderStatsListener()},200):"idle"!==t.state&&"capturing"!==t.state||(this.update({isWebCodecsActive:!1,encoderStats:null}),this.encoderStatsCleanup&&(this.encoderStatsCleanup(),this.encoderStatsCleanup=null))}))}setupEncoderStatsListener(){if(!this.controller)return;const e=this.controller.getEncoderManager();e&&(this.encoderStatsCleanup=e.on("stats",e=>{this.update({encoderStats:e})}))}startAudioLevelMonitoring(){if(this.audioLevelCleanup||!this.controller)return;const e=this.controller.getAudioMixer();if(!e)return;const t=e.on("levelUpdate",e=>{this.update({audioLevel:e.level,peakAudioLevel:e.peakLevel})});e.startLevelMonitoring(),this.audioLevelCleanup=()=>{t(),e.stopLevelMonitoring()}}stopAudioLevelMonitoring(){this.audioLevelCleanup&&(this.audioLevelCleanup(),this.audioLevelCleanup=null),this.update({audioLevel:0,peakAudioLevel:0})}dispatchEvent(e,t){this.host.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))}async startCamera(e){if(!this.controller)throw new Error("Controller not initialized");return this.update({error:null}),this.controller.startCamera(e)}async startScreenShare(e){if(!this.controller)throw new Error("Controller not initialized");return this.update({error:null}),this.controller.startScreenShare(e)}addCustomSource(e,t){if(!this.controller)throw new Error("Controller not initialized");return this.controller.addCustomSource(e,t)}removeSource(e){this.controller?.removeSource(e)}async stopCapture(){await(this.controller?.stopCapture())}setSourceVolume(e,t){this.controller?.setSourceVolume(e,t)}setSourceMuted(e,t){this.controller?.setSourceMuted(e,t)}setSourceActive(e,t){this.controller?.setSourceActive(e,t)}setPrimaryVideoSource(e){this.controller?.setPrimaryVideoSource(e)}setMasterVolume(e){this.controller?.setMasterVolume(e)}getMasterVolume(){return this.controller?.getMasterVolume()??1}async setQualityProfile(e){await(this.controller?.setQualityProfile(e))}async startStreaming(){if(!this.controller)throw new Error("Controller not initialized");this.update({error:null}),await this.controller.startStreaming()}async stopStreaming(){await(this.controller?.stopStreaming())}async getDevices(){return this.controller?.getDevices()??[]}async switchVideoDevice(e){await(this.controller?.switchVideoDevice(e))}async switchAudioDevice(e){await(this.controller?.switchAudioDevice(e))}async getStats(){return this.controller?.getStats()??null}setUseWebCodecs(e){this.update({useWebCodecs:e}),this.controller?.setUseWebCodecs(e)}setEncoderOverrides(e){this.controller?.setEncoderOverrides(e)}getController(){return this.controller}}const dt=[{id:"professional",label:"Professional",description:"1080p @ 8 Mbps"},{id:"broadcast",label:"Broadcast",description:"1080p @ 4.5 Mbps"},{id:"conference",label:"Conference",description:"720p @ 2.5 Mbps"}];e.FwStreamCrafter=class extends le{constructor(){super(),this.whipUrl="",this.gatewayUrl="",this.streamKey="",this.initialProfile="broadcast",this.autoStartCamera=!1,this.devMode=!1,this.debug=!1,this.enableCompositor=!1,this._showSettings=!1,this._showSources=!0,this._isAdvancedPanelOpen=!1,this._contextMenu=null,this._boundDismissContextMenu=this._dismissContextMenu.bind(this),this.pc=new lt(this,this.initialProfile)}connectedCallback(){super.connectedCallback(),this._initController()}willUpdate(e){(e.has("whipUrl")||e.has("initialProfile")||e.has("debug"))&&this._initController()}updated(e){e.has("_showSources")||e.has("_showSettings"),this._syncVideoPreview()}_initController(){this.whipUrl&&(this.pc.initialize({whipUrl:this.whipUrl,profile:this.initialProfile,debug:this.debug,reconnection:{enabled:!0,maxAttempts:5},audioMixing:!0}),this.autoStartCamera&&"idle"===this.pc.s.state&&this.pc.startCamera().catch(console.error))}_syncVideoPreview(){const e=this._videoEl,t=this.pc.s.mediaStream;e&&t&&e.srcObject!==t?(e.srcObject=t,e.play().catch(()=>{})):e&&!t&&(e.srcObject=null)}_handleContextMenu(e){e.preventDefault(),this._contextMenu={x:e.clientX,y:e.clientY},document.addEventListener("click",this._boundDismissContextMenu,{once:!0}),document.addEventListener("contextmenu",this._boundDismissContextMenu,{once:!0})}_dismissContextMenu(){this._contextMenu=null,document.removeEventListener("click",this._boundDismissContextMenu),document.removeEventListener("contextmenu",this._boundDismissContextMenu)}_copyWhipUrl(){this.whipUrl&&navigator.clipboard.writeText(this.whipUrl).catch(console.error),this._contextMenu=null}_copyStreamInfo(){const e=this.pc.s,t=dt.find(t=>t.id===e.qualityProfile),i=[`Status: ${e.state}`,`Quality: ${t?.label??e.qualityProfile} (${t?.description??""})`,`Sources: ${e.sources.length}`,this.whipUrl?`WHIP: ${this.whipUrl}`:null].filter(Boolean).join("\n");navigator.clipboard.writeText(i).catch(console.error),this._contextMenu=null}async startCamera(e){return this.pc.startCamera(e)}async startScreenShare(e){return this.pc.startScreenShare(e)}async startStreaming(){return this.pc.startStreaming()}async stopStreaming(){return this.pc.stopStreaming()}async stopCapture(){return this.pc.stopCapture()}removeSource(e){this.pc.removeSource(e)}setSourceVolume(e,t){this.pc.setSourceVolume(e,t)}setSourceMuted(e,t){this.pc.setSourceMuted(e,t)}setPrimaryVideoSource(e){this.pc.setPrimaryVideoSource(e)}setMasterVolume(e){this.pc.setMasterVolume(e)}async setQualityProfile(e){return this.pc.setQualityProfile(e)}destroy(){this.pc.getController()?.destroy()}render(){const e=this.pc.s,t=function(e,t){if(t?.isReconnecting)return`Reconnecting (${t.attemptNumber}/5)...`;switch(e){case"idle":return"Idle";case"requesting_permissions":return"Permissions...";case"capturing":return"Ready";case"connecting":return"Connecting...";case"streaming":return"Live";case"reconnecting":return"Reconnecting...";case"error":return"Error";case"destroyed":return"Destroyed";default:return e}}(e.state,e.reconnectionState),i=(r=e.state,s=e.isReconnecting,"streaming"===r?"fw-sc-badge fw-sc-badge--live":s?"fw-sc-badge fw-sc-badge--connecting":"error"===r?"fw-sc-badge fw-sc-badge--error":"capturing"===r?"fw-sc-badge fw-sc-badge--ready":"fw-sc-badge fw-sc-badge--idle");var r,s;const o="destroyed"!==e.state&&"error"!==e.state,n=e.isCapturing&&!e.isStreaming&&!!this.whipUrl,a=e.sources.some(e=>"camera"===e.type);return B`
2289
2329
  <div
2290
- class=${ye({root:!0,"fw-sc-root":!0,"fw-sc-root--devmode":this.devMode})}
2330
+ class=${be({root:!0,"fw-sc-root":!0,"fw-sc-root--devmode":this.devMode})}
2331
+ @contextmenu=${e=>this._handleContextMenu(e)}
2291
2332
  >
2292
2333
  <div class="main fw-sc-main">
2293
2334
  <!-- Header -->
2294
2335
  <div class="fw-sc-header">
2295
2336
  <span class="fw-sc-header-title">StreamCrafter</span>
2296
2337
  <div class="fw-sc-header-status">
2297
- <span class=${r}>${t}</span>
2338
+ <span class=${i}>${t}</span>
2298
2339
  </div>
2299
2340
  </div>
2300
2341
 
@@ -2304,34 +2345,34 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2304
2345
  <div class="fw-sc-preview">
2305
2346
  <video playsinline muted autoplay aria-label="Stream preview"></video>
2306
2347
 
2307
- ${e.mediaStream?G:q`
2348
+ ${e.mediaStream?G:B`
2308
2349
  <div class="fw-sc-preview-placeholder">
2309
2350
  ${Se(48)}
2310
2351
  <span>Add a camera or screen to preview</span>
2311
2352
  </div>
2312
2353
  `}
2313
- ${"connecting"===e.state||"reconnecting"===e.state?q`
2354
+ ${"connecting"===e.state||"reconnecting"===e.state?B`
2314
2355
  <div class="fw-sc-status-overlay">
2315
2356
  <div class="fw-sc-status-spinner"></div>
2316
2357
  <span class="fw-sc-status-text">${t}</span>
2317
2358
  </div>
2318
2359
  `:G}
2319
- ${e.isStreaming?q`<div class="fw-sc-live-badge">Live</div>`:G}
2320
- ${this.enableCompositor?q` <fw-sc-compositor .ic=${this.pc}></fw-sc-compositor> `:G}
2360
+ ${e.isStreaming?B`<div class="fw-sc-live-badge">Live</div>`:G}
2361
+ ${this.enableCompositor?B` <fw-sc-compositor .ic=${this.pc}></fw-sc-compositor> `:G}
2321
2362
  </div>
2322
2363
  </div>
2323
2364
 
2324
2365
  <!-- Sources Mixer -->
2325
- ${e.sources.length>0?q`
2366
+ ${e.sources.length>0?B`
2326
2367
  <div
2327
- class=${ye({"fw-sc-section":!0,"fw-sc-mixer":!0,"fw-sc-section--collapsed":!this._showSources})}
2368
+ class=${be({"fw-sc-section":!0,"fw-sc-mixer":!0,"fw-sc-section--collapsed":!this._showSources})}
2328
2369
  >
2329
2370
  <div
2330
2371
  class="fw-sc-section-header"
2331
2372
  @click=${()=>{this._showSources=!this._showSources}}
2332
2373
  >
2333
2374
  <span>Mixer (${e.sources.length})</span>
2334
- ${this._showSources?((e=14)=>q` <svg
2375
+ ${this._showSources?((e=14)=>B` <svg
2335
2376
  width="${e}"
2336
2377
  height="${e}"
2337
2378
  viewBox="0 0 24 24"
@@ -2343,7 +2384,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2343
2384
  >
2344
2385
  <polyline points="13 17 18 12 13 7" />
2345
2386
  <polyline points="6 17 11 12 6 7" />
2346
- </svg>`)(14):((e=14)=>q` <svg
2387
+ </svg>`)(14):((e=14)=>B` <svg
2347
2388
  width="${e}"
2348
2389
  height="${e}"
2349
2390
  viewBox="0 0 24 24"
@@ -2357,7 +2398,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2357
2398
  <polyline points="18 17 13 12 18 7" />
2358
2399
  </svg>`)(14)}
2359
2400
  </div>
2360
- ${this._showSources?q`
2401
+ ${this._showSources?B`
2361
2402
  <div class="fw-sc-section-body--flush">
2362
2403
  <div class="fw-sc-sources">
2363
2404
  ${e.sources.map(e=>this._renderSourceRow(e))}
@@ -2368,14 +2409,28 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2368
2409
  `:G}
2369
2410
  </div>
2370
2411
 
2412
+ <!-- VU Meter -->
2413
+ ${e.isCapturing?B`
2414
+ <div class="fw-sc-vu-meter">
2415
+ <div
2416
+ class="fw-sc-vu-meter-fill"
2417
+ style="width:${Math.min(100*e.audioLevel,100)}%"
2418
+ ></div>
2419
+ <div
2420
+ class="fw-sc-vu-meter-peak"
2421
+ style="left:${Math.min(100*e.peakAudioLevel,100)}%"
2422
+ ></div>
2423
+ </div>
2424
+ `:G}
2425
+
2371
2426
  <!-- Error -->
2372
- ${e.error?q`
2427
+ ${e.error?B`
2373
2428
  <div class="fw-sc-error">
2374
2429
  <div class="fw-sc-error-title">Error</div>
2375
2430
  <div class="fw-sc-error-message">${e.error}</div>
2376
2431
  </div>
2377
2432
  `:G}
2378
- ${this.whipUrl||e.error?G:q`
2433
+ ${this.whipUrl||e.error?G:B`
2379
2434
  <div class="fw-sc-error" style="border-left-color: hsl(40 80% 65%)">
2380
2435
  <div class="fw-sc-error-title" style="color: hsl(40 80% 65%)">Warning</div>
2381
2436
  <div class="fw-sc-error-message">Configure WHIP endpoint to stream</div>
@@ -2407,31 +2462,17 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2407
2462
  <div style="position:relative">
2408
2463
  <button
2409
2464
  type="button"
2410
- class=${ye({"fw-sc-action-secondary":!0,"fw-sc-action-secondary--active":this._showSettings})}
2465
+ class=${be({"fw-sc-action-secondary":!0,"fw-sc-action-secondary--active":this._showSettings})}
2411
2466
  @click=${()=>{this._showSettings=!this._showSettings}}
2412
2467
  title="Settings"
2413
2468
  >
2414
- ${((e=16)=>q` <svg
2415
- width="${e}"
2416
- height="${e}"
2417
- viewBox="0 0 24 24"
2418
- fill="none"
2419
- stroke="currentColor"
2420
- stroke-width="2"
2421
- stroke-linecap="round"
2422
- stroke-linejoin="round"
2423
- >
2424
- <circle cx="12" cy="12" r="3" />
2425
- <path
2426
- d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"
2427
- />
2428
- </svg>`)(16)}
2469
+ ${$e(16)}
2429
2470
  </button>
2430
2471
  ${this._showSettings?this._renderSettingsPopup():G}
2431
2472
  </div>
2432
2473
 
2433
2474
  <!-- Go Live / Stop -->
2434
- ${e.isStreaming?q`
2475
+ ${e.isStreaming?B`
2435
2476
  <button
2436
2477
  type="button"
2437
2478
  class="fw-sc-action-primary fw-sc-action-stop"
@@ -2439,7 +2480,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2439
2480
  >
2440
2481
  Stop Streaming
2441
2482
  </button>
2442
- `:q`
2483
+ `:B`
2443
2484
  <button
2444
2485
  type="button"
2445
2486
  class="fw-sc-action-primary"
@@ -2452,36 +2493,91 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2452
2493
  </div>
2453
2494
  </div>
2454
2495
 
2496
+ <!-- Context Menu -->
2497
+ ${this._contextMenu?B`
2498
+ <div
2499
+ class="fw-sc-context-menu"
2500
+ style="position:fixed;top:${this._contextMenu.y}px;left:${this._contextMenu.x}px;z-index:1000;background:#1a1b26;border:1px solid rgba(90,96,127,0.3);border-radius:6px;padding:4px;box-shadow:0 4px 12px rgba(0,0,0,0.5);min-width:160px"
2501
+ >
2502
+ ${this.whipUrl?B`
2503
+ <button
2504
+ type="button"
2505
+ class="fw-sc-context-menu-item"
2506
+ @click=${()=>this._copyWhipUrl()}
2507
+ >
2508
+ Copy WHIP URL
2509
+ </button>
2510
+ `:G}
2511
+ <button
2512
+ type="button"
2513
+ class="fw-sc-context-menu-item"
2514
+ @click=${()=>this._copyStreamInfo()}
2515
+ >
2516
+ Copy Stream Info
2517
+ </button>
2518
+ ${this.devMode?B`
2519
+ <div class="fw-sc-context-menu-separator"></div>
2520
+ <button
2521
+ type="button"
2522
+ class="fw-sc-context-menu-item"
2523
+ @click=${()=>{this._isAdvancedPanelOpen=!this._isAdvancedPanelOpen,this._contextMenu=null}}
2524
+ >
2525
+ ${$e(14)}
2526
+ <span
2527
+ >${this._isAdvancedPanelOpen?"Hide Advanced":"Advanced"}</span
2528
+ >
2529
+ </button>
2530
+ `:G}
2531
+ </div>
2532
+ `:G}
2533
+
2455
2534
  <!-- Advanced Panel -->
2456
- ${this.devMode&&this._isAdvancedPanelOpen?q`
2535
+ ${this.devMode&&this._isAdvancedPanelOpen?B`
2457
2536
  <fw-sc-advanced
2458
2537
  .ic=${this.pc}
2538
+ .compositorEnabled=${this.enableCompositor}
2539
+ .compositorRendererType=${this._getCompositorRendererType()}
2540
+ .compositorStats=${this._getCompositorStats()}
2541
+ .sceneCount=${this._getSceneCount()}
2542
+ .layerCount=${this._getLayerCount()}
2459
2543
  @fw-close=${()=>{this._isAdvancedPanelOpen=!1}}
2460
2544
  ></fw-sc-advanced>
2461
2545
  `:G}
2462
2546
  </div>
2463
- `}_renderSourceRow(e){const t=this.pc.s,r=e.stream.getVideoTracks().length>0;return q`
2464
- <div class=${ye({"fw-sc-source":!0})}>
2547
+ `}_getSourceLayerVisibility(e){const t=this.pc.getController();if(!t||!this.enableCompositor)return!0;const i=t.getSceneManager();if(!i)return!0;const r=i.getActiveScene();if(!r)return!0;const s=r.layers.find(t=>t.sourceId===e);return s?.visible??!0}_toggleSourceLayerVisibility(e){const t=this.pc.getController();if(!t)return;const i=t.getSceneManager();if(!i)return;const r=i.getActiveScene();if(!r)return;const s=r.layers.find(t=>t.sourceId===e);s&&(i.setLayerVisibility(r.id,s.id,!s.visible),this.requestUpdate())}_getCompositorRendererType(){return this.enableCompositor?this.pc.getController()?.getSceneManager()?.getRendererType()??null:null}_getCompositorStats(){return this.enableCompositor?this.pc.getController()?.getSceneManager()?.getStats()??null:null}_getSceneCount(){return this.enableCompositor?this.pc.getController()?.getSceneManager()?.getAllScenes()?.length??0:0}_getLayerCount(){if(!this.enableCompositor)return 0;const e=this.pc.getController()?.getSceneManager()?.getActiveScene();return e?.layers?.length??0}_renderSourceRow(e){const t=this.pc.s,i=e.stream.getVideoTracks().length>0,r=this._getSourceLayerVisibility(e.id);return B`
2548
+ <div
2549
+ class=${be({"fw-sc-source":!0,"fw-sc-source--hidden":!r})}
2550
+ >
2551
+ ${this.enableCompositor?B`
2552
+ <button
2553
+ type="button"
2554
+ class=${be({"fw-sc-icon-btn":!0,"fw-sc-icon-btn--muted":!r})}
2555
+ @click=${()=>this._toggleSourceLayerVisibility(e.id)}
2556
+ title=${r?"Hide from composition":"Show in composition"}
2557
+ >
2558
+ ${r?Me(14):_e(14)}
2559
+ </button>
2560
+ `:G}
2465
2561
  <div class="fw-sc-source-icon">
2466
2562
  ${"camera"===e.type?Se(16):ke(16)}
2467
2563
  </div>
2468
2564
  <div class="fw-sc-source-info">
2469
2565
  <div class="fw-sc-source-label">
2470
2566
  ${e.label}
2471
- ${e.primaryVideo&&!this.enableCompositor?q`<span class="fw-sc-primary-badge">PRIMARY</span>`:G}
2567
+ ${e.primaryVideo&&!this.enableCompositor?B`<span class="fw-sc-primary-badge">PRIMARY</span>`:G}
2472
2568
  </div>
2473
2569
  <div class="fw-sc-source-type">${e.type}</div>
2474
2570
  </div>
2475
2571
  <div class="fw-sc-source-controls">
2476
- ${r&&!this.enableCompositor?q`
2572
+ ${i&&!this.enableCompositor?B`
2477
2573
  <button
2478
2574
  type="button"
2479
- class=${ye({"fw-sc-icon-btn":!0,"fw-sc-icon-btn--primary":!!e.primaryVideo})}
2575
+ class=${be({"fw-sc-icon-btn":!0,"fw-sc-icon-btn--primary":!!e.primaryVideo})}
2480
2576
  @click=${()=>this.pc.setPrimaryVideoSource(e.id)}
2481
2577
  ?disabled=${e.primaryVideo}
2482
2578
  title=${e.primaryVideo?"Primary video source":"Set as primary video"}
2483
2579
  >
2484
- ${$e(14)}
2580
+ ${Ae(14)}
2485
2581
  </button>
2486
2582
  `:G}
2487
2583
  <span class="fw-sc-volume-label">${Math.round(100*e.volume)}%</span>
@@ -2492,11 +2588,11 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2492
2588
  ></fw-sc-volume>
2493
2589
  <button
2494
2590
  type="button"
2495
- class=${ye({"fw-sc-icon-btn":!0,"fw-sc-icon-btn--active":e.muted})}
2591
+ class=${be({"fw-sc-icon-btn":!0,"fw-sc-icon-btn--active":e.muted})}
2496
2592
  @click=${()=>this.pc.setSourceMuted(e.id,!e.muted)}
2497
2593
  title=${e.muted?"Unmute":"Mute"}
2498
2594
  >
2499
- ${e.muted?((e=16)=>q` <svg
2595
+ ${e.muted?((e=16)=>B` <svg
2500
2596
  width="${e}"
2501
2597
  height="${e}"
2502
2598
  viewBox="0 0 24 24"
@@ -2511,7 +2607,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2511
2607
  <path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23" />
2512
2608
  <line x1="12" y1="19" x2="12" y2="23" />
2513
2609
  <line x1="8" y1="23" x2="16" y2="23" />
2514
- </svg>`)(14):((e=16)=>q` <svg
2610
+ </svg>`)(14):((e=16)=>B` <svg
2515
2611
  width="${e}"
2516
2612
  height="${e}"
2517
2613
  viewBox="0 0 24 24"
@@ -2538,7 +2634,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2538
2634
  </button>
2539
2635
  </div>
2540
2636
  </div>
2541
- `}_renderSettingsPopup(){const e=this.pc.s;return q`
2637
+ `}_renderSettingsPopup(){const e=this.pc.s;return B`
2542
2638
  <div
2543
2639
  class="fw-sc-settings-popup"
2544
2640
  style="position:absolute;bottom:100%;left:0;margin-bottom:8px;width:192px;background:#1a1b26;border:1px solid rgba(90,96,127,0.3);box-shadow:0 4px 12px rgba(0,0,0,0.4);border-radius:4px;overflow:hidden;z-index:50"
@@ -2550,7 +2646,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2550
2646
  Quality
2551
2647
  </div>
2552
2648
  <div style="display:flex;flex-direction:column;gap:2px">
2553
- ${at.map(t=>q`
2649
+ ${dt.map(t=>B`
2554
2650
  <button
2555
2651
  type="button"
2556
2652
  @click=${()=>{e.isStreaming||(this.pc.setQualityProfile(t.id),this.devMode||(this._showSettings=!1))}}
@@ -2563,7 +2659,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2563
2659
  `)}
2564
2660
  </div>
2565
2661
  </div>
2566
- ${this.devMode?q`
2662
+ ${this.devMode?B`
2567
2663
  <div style="padding:8px">
2568
2664
  <div
2569
2665
  style="font-size:10px;color:#565f89;text-transform:uppercase;font-weight:600;margin-bottom:4px;padding-left:4px"
@@ -2587,7 +2683,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2587
2683
  </div>
2588
2684
  `:G}
2589
2685
  </div>
2590
- `}},e.FwStreamCrafter.styles=[be,xe,c`
2686
+ `}},e.FwStreamCrafter.styles=[ye,xe,c`
2591
2687
  :host {
2592
2688
  display: block;
2593
2689
  }
@@ -2601,70 +2697,70 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2601
2697
  flex: 1;
2602
2698
  min-width: 0;
2603
2699
  }
2604
- `],r([ge({type:String,attribute:"whip-url"})],e.FwStreamCrafter.prototype,"whipUrl",void 0),r([ge({type:String,attribute:"gateway-url"})],e.FwStreamCrafter.prototype,"gatewayUrl",void 0),r([ge({type:String,attribute:"stream-key"})],e.FwStreamCrafter.prototype,"streamKey",void 0),r([ge({type:String,attribute:"initial-profile"})],e.FwStreamCrafter.prototype,"initialProfile",void 0),r([ge({type:Boolean,attribute:"auto-start-camera"})],e.FwStreamCrafter.prototype,"autoStartCamera",void 0),r([ge({type:Boolean,attribute:"dev-mode"})],e.FwStreamCrafter.prototype,"devMode",void 0),r([ge({type:Boolean})],e.FwStreamCrafter.prototype,"debug",void 0),r([ge({type:Boolean,attribute:"enable-compositor"})],e.FwStreamCrafter.prototype,"enableCompositor",void 0),r([fe()],e.FwStreamCrafter.prototype,"_showSettings",void 0),r([fe()],e.FwStreamCrafter.prototype,"_showSources",void 0),r([fe()],e.FwStreamCrafter.prototype,"_isAdvancedPanelOpen",void 0),r([me(".fw-sc-preview video")],e.FwStreamCrafter.prototype,"_videoEl",void 0),e.FwStreamCrafter=r([he("fw-streamcrafter")],e.FwStreamCrafter);const ct=[{mode:"solo",label:"Solo",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2700
+ `],i([ge({type:String,attribute:"whip-url"})],e.FwStreamCrafter.prototype,"whipUrl",void 0),i([ge({type:String,attribute:"gateway-url"})],e.FwStreamCrafter.prototype,"gatewayUrl",void 0),i([ge({type:String,attribute:"stream-key"})],e.FwStreamCrafter.prototype,"streamKey",void 0),i([ge({type:String,attribute:"initial-profile"})],e.FwStreamCrafter.prototype,"initialProfile",void 0),i([ge({type:Boolean,attribute:"auto-start-camera"})],e.FwStreamCrafter.prototype,"autoStartCamera",void 0),i([ge({type:Boolean,attribute:"dev-mode"})],e.FwStreamCrafter.prototype,"devMode",void 0),i([ge({type:Boolean})],e.FwStreamCrafter.prototype,"debug",void 0),i([ge({type:Boolean,attribute:"enable-compositor"})],e.FwStreamCrafter.prototype,"enableCompositor",void 0),i([fe()],e.FwStreamCrafter.prototype,"_showSettings",void 0),i([fe()],e.FwStreamCrafter.prototype,"_showSources",void 0),i([fe()],e.FwStreamCrafter.prototype,"_isAdvancedPanelOpen",void 0),i([fe()],e.FwStreamCrafter.prototype,"_contextMenu",void 0),i([me(".fw-sc-preview video")],e.FwStreamCrafter.prototype,"_videoEl",void 0),e.FwStreamCrafter=i([he("fw-streamcrafter")],e.FwStreamCrafter);const ht=[{mode:"solo",label:"Solo",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2605
2701
  <rect x="1" y="1" width="10" height="10" rx="1" />
2606
- </svg>`,minSources:1},{mode:"pip-br",label:"PiP ↘",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2702
+ </svg>`,minSources:1},{mode:"pip-br",label:"PiP ↘",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2607
2703
  <rect x="1" y="1" width="10" height="10" rx="1" fill-opacity="0.3" />
2608
2704
  <rect x="6.5" y="6.5" width="4" height="3" rx="0.5" />
2609
- </svg>`,minSources:2},{mode:"pip-bl",label:"PiP ↙",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2705
+ </svg>`,minSources:2},{mode:"pip-bl",label:"PiP ↙",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2610
2706
  <rect x="1" y="1" width="10" height="10" rx="1" fill-opacity="0.3" />
2611
2707
  <rect x="1.5" y="6.5" width="4" height="3" rx="0.5" />
2612
- </svg>`,minSources:2},{mode:"pip-tr",label:"PiP ↗",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2708
+ </svg>`,minSources:2},{mode:"pip-tr",label:"PiP ↗",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2613
2709
  <rect x="1" y="1" width="10" height="10" rx="1" fill-opacity="0.3" />
2614
2710
  <rect x="6.5" y="2.5" width="4" height="3" rx="0.5" />
2615
- </svg>`,minSources:2},{mode:"pip-tl",label:"PiP ↖",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2711
+ </svg>`,minSources:2},{mode:"pip-tl",label:"PiP ↖",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2616
2712
  <rect x="1" y="1" width="10" height="10" rx="1" fill-opacity="0.3" />
2617
2713
  <rect x="1.5" y="2.5" width="4" height="3" rx="0.5" />
2618
- </svg>`,minSources:2},{mode:"split-h",label:"Split ⬌",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2714
+ </svg>`,minSources:2},{mode:"split-h",label:"Split ⬌",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2619
2715
  <rect x="1" y="1" width="4.5" height="10" rx="1" />
2620
2716
  <rect x="6.5" y="1" width="4.5" height="10" rx="1" />
2621
- </svg>`,minSources:2},{mode:"split-v",label:"Split ⬍",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2717
+ </svg>`,minSources:2},{mode:"split-v",label:"Split ⬍",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2622
2718
  <rect x="1" y="1" width="10" height="4.5" rx="1" />
2623
2719
  <rect x="1" y="6.5" width="10" height="4.5" rx="1" />
2624
- </svg>`,minSources:2},{mode:"focus-l",label:"Focus ◀",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2720
+ </svg>`,minSources:2},{mode:"focus-l",label:"Focus ◀",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2625
2721
  <rect x="1" y="1" width="7" height="10" rx="1" />
2626
2722
  <rect x="8.5" y="1" width="2.5" height="10" rx="1" fill-opacity="0.5" />
2627
- </svg>`,minSources:2},{mode:"focus-r",label:"Focus ▶",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2723
+ </svg>`,minSources:2},{mode:"focus-r",label:"Focus ▶",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2628
2724
  <rect x="1" y="1" width="2.5" height="10" rx="1" fill-opacity="0.5" />
2629
2725
  <rect x="4" y="1" width="7" height="10" rx="1" />
2630
- </svg>`,minSources:2},{mode:"pip-dual-br",label:"Main+2 PiP",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2726
+ </svg>`,minSources:2},{mode:"pip-dual-br",label:"Main+2 PiP",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2631
2727
  <rect x="1" y="1" width="10" height="10" rx="1" fill-opacity="0.3" />
2632
2728
  <rect x="7" y="4" width="3.5" height="2.5" rx="0.5" />
2633
2729
  <rect x="7" y="7" width="3.5" height="2.5" rx="0.5" />
2634
- </svg>`,minSources:3},{mode:"split-pip-r",label:"Split+PiP",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2730
+ </svg>`,minSources:3},{mode:"split-pip-r",label:"Split+PiP",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2635
2731
  <rect x="1" y="1" width="4.5" height="10" rx="1" />
2636
2732
  <rect x="6.5" y="1" width="4.5" height="10" rx="1" fill-opacity="0.5" />
2637
2733
  <rect x="7.5" y="7" width="2.5" height="2.5" rx="0.5" />
2638
- </svg>`,minSources:3},{mode:"featured",label:"Featured",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2734
+ </svg>`,minSources:3},{mode:"featured",label:"Featured",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2639
2735
  <rect x="1" y="1" width="10" height="7.5" rx="1" />
2640
2736
  <rect x="1" y="9" width="3" height="2" rx="0.5" fill-opacity="0.5" />
2641
2737
  <rect x="4.5" y="9" width="3" height="2" rx="0.5" fill-opacity="0.5" />
2642
2738
  <rect x="8" y="9" width="3" height="2" rx="0.5" fill-opacity="0.5" />
2643
- </svg>`,minSources:3},{mode:"featured-r",label:"Featured ▶",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2739
+ </svg>`,minSources:3},{mode:"featured-r",label:"Featured ▶",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2644
2740
  <rect x="1" y="1" width="8" height="10" rx="1" />
2645
2741
  <rect x="9.5" y="1" width="1.5" height="3" rx="0.5" fill-opacity="0.5" />
2646
2742
  <rect x="9.5" y="4.5" width="1.5" height="3" rx="0.5" fill-opacity="0.5" />
2647
2743
  <rect x="9.5" y="8" width="1.5" height="3" rx="0.5" fill-opacity="0.5" />
2648
- </svg>`,minSources:3},{mode:"grid",label:"Grid",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2744
+ </svg>`,minSources:3},{mode:"grid",label:"Grid",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2649
2745
  <rect x="1" y="1" width="4.5" height="4.5" rx="1" />
2650
2746
  <rect x="6.5" y="1" width="4.5" height="4.5" rx="1" />
2651
2747
  <rect x="1" y="6.5" width="4.5" height="4.5" rx="1" />
2652
2748
  <rect x="6.5" y="6.5" width="4.5" height="4.5" rx="1" />
2653
- </svg>`,minSources:2},{mode:"stack",label:"Stack",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2749
+ </svg>`,minSources:2},{mode:"stack",label:"Stack",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2654
2750
  <rect x="1" y="1" width="10" height="2.8" rx="0.5" />
2655
2751
  <rect x="1" y="4.6" width="10" height="2.8" rx="0.5" />
2656
2752
  <rect x="1" y="8.2" width="10" height="2.8" rx="0.5" />
2657
- </svg>`,minSources:2}],lt=[{mode:"letterbox",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2753
+ </svg>`,minSources:2}],ut=[{mode:"letterbox",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2658
2754
  <rect x="1" y="3" width="10" height="6" rx="1" />
2659
2755
  <rect x="0" y="1" width="12" height="1.5" fill-opacity="0.3" />
2660
2756
  <rect x="0" y="9.5" width="12" height="1.5" fill-opacity="0.3" />
2661
- </svg>`,label:"Letterbox (fit)"},{mode:"crop",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2757
+ </svg>`,label:"Letterbox (fit)"},{mode:"crop",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2662
2758
  <rect x="0" y="0" width="12" height="12" rx="1" />
2663
2759
  <path
2664
2760
  d="M2 0v2H0v1h3V0H2zM10 0v3h2V2h-2V0H9v3h3V2h-2V0h1zM0 9v1h2v2h1V9H0zM12 9H9v3h1v-2h2v-1z"
2665
2761
  fill-opacity="0.5"
2666
2762
  />
2667
- </svg>`,label:"Crop (fill)"},{mode:"stretch",icon:()=>q`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2763
+ </svg>`,label:"Crop (fill)"},{mode:"stretch",icon:()=>B`<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
2668
2764
  <rect x="1" y="1" width="10" height="10" rx="1" fill-opacity="0.3" />
2669
2765
  <path
2670
2766
  d="M3 5.5h6M3 5l-1.5 1L3 7M9 5l1.5 1L9 7M5.5 3v6M5 3L6 1.5 7 3M5 9l1 1.5 1-1.5"
@@ -2672,13 +2768,13 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2672
2768
  stroke-width="1"
2673
2769
  fill="none"
2674
2770
  />
2675
- </svg>`,label:"Stretch"}];let dt=class extends le{constructor(){super(...arguments),this._tooltipText="",this._tooltipTarget=null}render(){const e=this.ic.s.sources.length,t=ct.filter(t=>function(e,t){const r=Le.find(t=>t.mode===e);return!!r&&t>=r.minSources&&t<=r.maxSources}(t.mode,e));return q`
2771
+ </svg>`,label:"Stretch"}];let pt=class extends le{constructor(){super(...arguments),this._tooltipText="",this._tooltipTarget=null}render(){const e=this.ic.s.sources.length,t=ht.filter(t=>function(e,t){const i=Oe.find(t=>t.mode===e);return!!i&&t>=i.minSources&&t<=i.maxSources}(t.mode,e));return B`
2676
2772
  <div class="fw-sc-layout-overlay">
2677
2773
  <div class="fw-sc-layout-bar">
2678
2774
  <div class="fw-sc-layout-section">
2679
2775
  <span class="fw-sc-layout-label">Layout</span>
2680
2776
  <div class="fw-sc-layout-icons">
2681
- ${t.map(e=>q`
2777
+ ${t.map(e=>B`
2682
2778
  <button
2683
2779
  type="button"
2684
2780
  class="fw-sc-layout-icon"
@@ -2694,7 +2790,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2694
2790
  <div class="fw-sc-layout-section">
2695
2791
  <span class="fw-sc-layout-label">Display</span>
2696
2792
  <div class="fw-sc-scaling-icons">
2697
- ${lt.map(e=>q`
2793
+ ${ut.map(e=>B`
2698
2794
  <button
2699
2795
  type="button"
2700
2796
  class="fw-sc-layout-icon"
@@ -2708,15 +2804,15 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2708
2804
  </div>
2709
2805
  </div>
2710
2806
  </div>
2711
- `}_handleLayoutSelect(e){this.dispatchEvent(new CustomEvent("fw-sc-layout-select",{detail:{mode:e},bubbles:!0,composed:!0}))}};dt.styles=[be,xe,c`
2807
+ `}_handleLayoutSelect(e){this.dispatchEvent(new CustomEvent("fw-sc-layout-select",{detail:{mode:e},bubbles:!0,composed:!0}))}};pt.styles=[ye,xe,c`
2712
2808
  :host {
2713
2809
  display: contents;
2714
2810
  }
2715
- `],r([ge({attribute:!1})],dt.prototype,"ic",void 0),r([fe()],dt.prototype,"_tooltipText",void 0),r([fe()],dt.prototype,"_tooltipTarget",void 0),dt=r([he("fw-sc-compositor")],dt);let ht=class extends le{constructor(){super(...arguments),this.scenes=[],this.activeSceneId=null,this.showTransitionControls=!0,this._selectedTransition="fade",this._transitionDuration=500,this._isTransitioning=!1}render(){return q`
2811
+ `],i([ge({attribute:!1})],pt.prototype,"ic",void 0),i([fe()],pt.prototype,"_tooltipText",void 0),i([fe()],pt.prototype,"_tooltipTarget",void 0),pt=i([he("fw-sc-compositor")],pt);let gt=class extends le{constructor(){super(...arguments),this.scenes=[],this.activeSceneId=null,this.showTransitionControls=!0,this._selectedTransition="fade",this._transitionDuration=500,this._isTransitioning=!1}render(){return B`
2716
2812
  <div class="fw-sc-scene-switcher">
2717
2813
  <div class="fw-sc-scene-switcher-header">
2718
2814
  <span class="fw-sc-scene-switcher-title">Scenes</span>
2719
- ${this.showTransitionControls?q`
2815
+ ${this.showTransitionControls?B`
2720
2816
  <div class="fw-sc-transition-controls">
2721
2817
  <select
2722
2818
  class="fw-sc-transition-select"
@@ -2746,15 +2842,15 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2746
2842
  </div>
2747
2843
 
2748
2844
  <div class="fw-sc-scene-list">
2749
- ${this.scenes.map(e=>q`
2845
+ ${this.scenes.map(e=>B`
2750
2846
  <div
2751
- class=${ye({"fw-sc-scene-item":!0,"fw-sc-scene-item--active":e.id===this.activeSceneId,"fw-sc-scene-item--transitioning":this._isTransitioning})}
2847
+ class=${be({"fw-sc-scene-item":!0,"fw-sc-scene-item--active":e.id===this.activeSceneId,"fw-sc-scene-item--transitioning":this._isTransitioning})}
2752
2848
  @click=${()=>this._handleSceneClick(e.id)}
2753
2849
  style="background-color:${e.backgroundColor}"
2754
2850
  >
2755
2851
  <span class="fw-sc-scene-name">${e.name}</span>
2756
2852
  <span class="fw-sc-scene-layer-count">${e.layers.length} layers</span>
2757
- ${this.scenes.length>1&&e.id!==this.activeSceneId?q`
2853
+ ${this.scenes.length>1&&e.id!==this.activeSceneId?B`
2758
2854
  <button
2759
2855
  class="fw-sc-scene-delete"
2760
2856
  @click=${t=>{t.stopPropagation(),this._handleDelete(e.id)}}
@@ -2775,11 +2871,11 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2775
2871
  </button>
2776
2872
  </div>
2777
2873
  </div>
2778
- `}async _handleSceneClick(e){if(e!==this.activeSceneId&&!this._isTransitioning){this._isTransitioning=!0;try{this.dispatchEvent(new CustomEvent("fw-sc-scene-select",{detail:{sceneId:e,transition:{type:this._selectedTransition,durationMs:this._transitionDuration,easing:"ease-in-out"}},bubbles:!0,composed:!0}))}finally{this._isTransitioning=!1}}}_handleDelete(e){this.scenes.length<=1||this.dispatchEvent(new CustomEvent("fw-sc-scene-delete",{detail:{sceneId:e},bubbles:!0,composed:!0}))}};ht.styles=[be,xe,c`
2874
+ `}async _handleSceneClick(e){if(e!==this.activeSceneId&&!this._isTransitioning){this._isTransitioning=!0;try{this.dispatchEvent(new CustomEvent("fw-sc-scene-select",{detail:{sceneId:e,transition:{type:this._selectedTransition,durationMs:this._transitionDuration,easing:"ease-in-out"}},bubbles:!0,composed:!0}))}finally{this._isTransitioning=!1}}}_handleDelete(e){this.scenes.length<=1||this.dispatchEvent(new CustomEvent("fw-sc-scene-delete",{detail:{sceneId:e},bubbles:!0,composed:!0}))}};gt.styles=[ye,xe,c`
2779
2875
  :host {
2780
2876
  display: block;
2781
2877
  }
2782
- `],r([ge({attribute:!1})],ht.prototype,"scenes",void 0),r([ge({type:String,attribute:"active-scene-id"})],ht.prototype,"activeSceneId",void 0),r([ge({type:Boolean,attribute:"show-transition-controls"})],ht.prototype,"showTransitionControls",void 0),r([fe()],ht.prototype,"_selectedTransition",void 0),r([fe()],ht.prototype,"_transitionDuration",void 0),r([fe()],ht.prototype,"_isTransitioning",void 0),ht=r([he("fw-sc-scene-switcher")],ht);let ut=class extends le{constructor(){super(...arguments),this.layers=[],this.sources=[],this.selectedLayerId=null,this._draggedId=null,this._dragOverId=null,this._editingLayerId=null}get _sortedLayers(){return[...this.layers].sort((e,t)=>t.zIndex-e.zIndex)}_getSourceLabel(e){const t=this.sources.find(t=>t.id===e);return t?.label||e}_getSourceIcon(e){const t=this.sources.find(t=>t.id===e);switch(t?.type){case"camera":return Se(14);case"screen":return ke(14);default:return $e(14)}}render(){const e=this._sortedLayers;return q`
2878
+ `],i([ge({attribute:!1})],gt.prototype,"scenes",void 0),i([ge({type:String,attribute:"active-scene-id"})],gt.prototype,"activeSceneId",void 0),i([ge({type:Boolean,attribute:"show-transition-controls"})],gt.prototype,"showTransitionControls",void 0),i([fe()],gt.prototype,"_selectedTransition",void 0),i([fe()],gt.prototype,"_transitionDuration",void 0),i([fe()],gt.prototype,"_isTransitioning",void 0),gt=i([he("fw-sc-scene-switcher")],gt);let ft=class extends le{constructor(){super(...arguments),this.layers=[],this.sources=[],this.selectedLayerId=null,this._draggedId=null,this._dragOverId=null,this._editingLayerId=null}get _sortedLayers(){return[...this.layers].sort((e,t)=>t.zIndex-e.zIndex)}_getSourceLabel(e){const t=this.sources.find(t=>t.id===e);return t?.label||e}_getSourceIcon(e){const t=this.sources.find(t=>t.id===e);switch(t?.type){case"camera":return Se(14);case"screen":return ke(14);default:return Ae(14)}}render(){const e=this._sortedLayers;return B`
2783
2879
  <div class="fw-sc-layer-list">
2784
2880
  <div class="fw-sc-layer-list-header">
2785
2881
  <span class="fw-sc-layer-list-title">Layers</span>
@@ -2787,9 +2883,9 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2787
2883
  </div>
2788
2884
 
2789
2885
  <div class="fw-sc-layer-items">
2790
- ${0===e.length?q` <div class="fw-sc-layer-empty">No layers. Add a source to get started.</div> `:e.map((t,r)=>q`
2886
+ ${0===e.length?B` <div class="fw-sc-layer-empty">No layers. Add a source to get started.</div> `:e.map((t,i)=>B`
2791
2887
  <div
2792
- class=${ye({"fw-sc-layer-item":!0,"fw-sc-layer-item--selected":t.id===this.selectedLayerId,"fw-sc-layer-item--dragging":t.id===this._draggedId,"fw-sc-layer-item--drag-over":t.id===this._dragOverId,"fw-sc-layer-item--hidden":!t.visible})}
2888
+ class=${be({"fw-sc-layer-item":!0,"fw-sc-layer-item--selected":t.id===this.selectedLayerId,"fw-sc-layer-item--dragging":t.id===this._draggedId,"fw-sc-layer-item--drag-over":t.id===this._dragOverId,"fw-sc-layer-item--hidden":!t.visible})}
2793
2889
  draggable="true"
2794
2890
  @dragstart=${e=>this._handleDragStart(e,t.id)}
2795
2891
  @dragover=${e=>this._handleDragOver(e,t.id)}
@@ -2799,42 +2895,16 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2799
2895
  @click=${()=>this._dispatch("fw-sc-layer-select",{layerId:t.id===this.selectedLayerId?null:t.id})}
2800
2896
  >
2801
2897
  <button
2802
- class=${ye({"fw-sc-layer-visibility":!0,"fw-sc-layer-visibility--visible":t.visible})}
2898
+ class=${be({"fw-sc-layer-visibility":!0,"fw-sc-layer-visibility--visible":t.visible})}
2803
2899
  @click=${e=>{e.stopPropagation(),this._dispatch("fw-sc-visibility-toggle",{layerId:t.id,visible:!t.visible})}}
2804
2900
  title=${t.visible?"Hide layer":"Show layer"}
2805
2901
  >
2806
- ${t.visible?((e=14)=>q` <svg
2807
- width="${e}"
2808
- height="${e}"
2809
- viewBox="0 0 24 24"
2810
- fill="none"
2811
- stroke="currentColor"
2812
- stroke-width="2"
2813
- stroke-linecap="round"
2814
- stroke-linejoin="round"
2815
- >
2816
- <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
2817
- <circle cx="12" cy="12" r="3" />
2818
- </svg>`)(14):((e=14)=>q` <svg
2819
- width="${e}"
2820
- height="${e}"
2821
- viewBox="0 0 24 24"
2822
- fill="none"
2823
- stroke="currentColor"
2824
- stroke-width="2"
2825
- stroke-linecap="round"
2826
- stroke-linejoin="round"
2827
- >
2828
- <path
2829
- d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"
2830
- />
2831
- <line x1="1" y1="1" x2="23" y2="23" />
2832
- </svg>`)(14)}
2902
+ ${t.visible?Me(14):_e(14)}
2833
2903
  </button>
2834
2904
  <span class="fw-sc-layer-icon">${this._getSourceIcon(t.sourceId)}</span>
2835
2905
  <span class="fw-sc-layer-name">${this._getSourceLabel(t.sourceId)}</span>
2836
2906
 
2837
- ${this._editingLayerId===t.id?q`
2907
+ ${this._editingLayerId===t.id?B`
2838
2908
  <div class="fw-sc-layer-opacity">
2839
2909
  <input
2840
2910
  type="range"
@@ -2853,7 +2923,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2853
2923
  <button
2854
2924
  class="fw-sc-layer-btn"
2855
2925
  @click=${e=>{e.stopPropagation(),this._moveUp(t.id)}}
2856
- ?disabled=${0===r}
2926
+ ?disabled=${0===i}
2857
2927
  title="Move up"
2858
2928
  >
2859
2929
 
@@ -2861,13 +2931,13 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2861
2931
  <button
2862
2932
  class="fw-sc-layer-btn"
2863
2933
  @click=${e=>{e.stopPropagation(),this._moveDown(t.id)}}
2864
- ?disabled=${r===e.length-1}
2934
+ ?disabled=${i===e.length-1}
2865
2935
  title="Move down"
2866
2936
  >
2867
2937
 
2868
2938
  </button>
2869
2939
  <button
2870
- class=${ye({"fw-sc-layer-btn":!0,"fw-sc-layer-btn--active":this._editingLayerId===t.id})}
2940
+ class=${be({"fw-sc-layer-btn":!0,"fw-sc-layer-btn--active":this._editingLayerId===t.id})}
2871
2941
  @click=${e=>{e.stopPropagation(),this._editingLayerId=this._editingLayerId===t.id?null:t.id}}
2872
2942
  title="Edit opacity"
2873
2943
  >
@@ -2885,12 +2955,12 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2885
2955
  `)}
2886
2956
  </div>
2887
2957
  </div>
2888
- `}_dispatch(e,t){this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))}_handleDragStart(e,t){this._draggedId=t,e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",t)}_handleDragOver(e,t){e.preventDefault(),e.dataTransfer.dropEffect="move",this._dragOverId=t}_handleDrop(e,t){if(e.preventDefault(),this._dragOverId=null,!this._draggedId||this._draggedId===t)return void(this._draggedId=null);const r=this._sortedLayers.map(e=>e.id),i=r.indexOf(this._draggedId),s=r.indexOf(t);if(-1===i||-1===s)return void(this._draggedId=null);const o=[...r];o.splice(i,1),o.splice(s,0,this._draggedId),this._dispatch("fw-sc-reorder",{layerIds:o}),this._draggedId=null}_moveUp(e){const t=this._sortedLayers.map(e=>e.id),r=t.indexOf(e);r<=0||([t[r-1],t[r]]=[t[r],t[r-1]],this._dispatch("fw-sc-reorder",{layerIds:t}))}_moveDown(e){const t=this._sortedLayers.map(e=>e.id),r=t.indexOf(e);r>=t.length-1||([t[r],t[r+1]]=[t[r+1],t[r]],this._dispatch("fw-sc-reorder",{layerIds:t}))}};ut.styles=[be,xe,c`
2958
+ `}_dispatch(e,t){this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))}_handleDragStart(e,t){this._draggedId=t,e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",t)}_handleDragOver(e,t){e.preventDefault(),e.dataTransfer.dropEffect="move",this._dragOverId=t}_handleDrop(e,t){if(e.preventDefault(),this._dragOverId=null,!this._draggedId||this._draggedId===t)return void(this._draggedId=null);const i=this._sortedLayers.map(e=>e.id),r=i.indexOf(this._draggedId),s=i.indexOf(t);if(-1===r||-1===s)return void(this._draggedId=null);const o=[...i];o.splice(r,1),o.splice(s,0,this._draggedId),this._dispatch("fw-sc-reorder",{layerIds:o}),this._draggedId=null}_moveUp(e){const t=this._sortedLayers.map(e=>e.id),i=t.indexOf(e);i<=0||([t[i-1],t[i]]=[t[i],t[i-1]],this._dispatch("fw-sc-reorder",{layerIds:t}))}_moveDown(e){const t=this._sortedLayers.map(e=>e.id),i=t.indexOf(e);i>=t.length-1||([t[i],t[i+1]]=[t[i+1],t[i]],this._dispatch("fw-sc-reorder",{layerIds:t}))}};ft.styles=[ye,xe,c`
2889
2959
  :host {
2890
2960
  display: block;
2891
2961
  }
2892
- `],r([ge({attribute:!1})],ut.prototype,"layers",void 0),r([ge({attribute:!1})],ut.prototype,"sources",void 0),r([ge({type:String,attribute:"selected-layer-id"})],ut.prototype,"selectedLayerId",void 0),r([fe()],ut.prototype,"_draggedId",void 0),r([fe()],ut.prototype,"_dragOverId",void 0),r([fe()],ut.prototype,"_editingLayerId",void 0),ut=r([he("fw-sc-layer-list")],ut);let pt=class extends le{constructor(){super(...arguments),this.value=1,this.min=0,this.max=2,this.snapThreshold=.05,this.compact=!1,this._isDragging=!1,this._popupPosition=0}get _displayValue(){return Math.round(100*this.value)}get _isBoost(){return this.value>1}get _isDefault(){return 1===this.value}get _accentColor(){return this._isBoost?"#e0af68":this._isDefault?"#9ece6a":"#7aa2f7"}_handleChange(e){let t=parseInt(e.target.value,10)/100;Math.abs(t-1)<=this.snapThreshold&&(t=1),this.dispatchEvent(new CustomEvent("fw-sc-volume-change",{detail:{value:t},bubbles:!0,composed:!0})),this._updatePopupPosition(t)}_handleMouseDown(){this._isDragging=!0,this._updatePopupPosition(this.value)}_handleMouseUp(){this._isDragging=!1}_updatePopupPosition(e){if(this._slider){const t=this._slider.getBoundingClientRect(),r=(e-this.min)/(this.max-this.min);this._popupPosition=r*t.width}}render(){const e=1/this.max*100+"%",t=this._isDefault?"#9ece6a":"rgba(158, 206, 106, 0.3)";return q`
2893
- ${this._isDragging?q`
2962
+ `],i([ge({attribute:!1})],ft.prototype,"layers",void 0),i([ge({attribute:!1})],ft.prototype,"sources",void 0),i([ge({type:String,attribute:"selected-layer-id"})],ft.prototype,"selectedLayerId",void 0),i([fe()],ft.prototype,"_draggedId",void 0),i([fe()],ft.prototype,"_dragOverId",void 0),i([fe()],ft.prototype,"_editingLayerId",void 0),ft=i([he("fw-sc-layer-list")],ft);let mt=class extends le{constructor(){super(...arguments),this.value=1,this.min=0,this.max=2,this.snapThreshold=.05,this.compact=!1,this._isDragging=!1,this._popupPosition=0}get _displayValue(){return Math.round(100*this.value)}get _isBoost(){return this.value>1}get _isDefault(){return 1===this.value}get _accentColor(){return this._isBoost?"#e0af68":this._isDefault?"#9ece6a":"#7aa2f7"}_handleChange(e){let t=parseInt(e.target.value,10)/100;Math.abs(t-1)<=this.snapThreshold&&(t=1),this.dispatchEvent(new CustomEvent("fw-sc-volume-change",{detail:{value:t},bubbles:!0,composed:!0})),this._updatePopupPosition(t)}_handleMouseDown(){this._isDragging=!0,this._updatePopupPosition(this.value)}_handleMouseUp(){this._isDragging=!1}_updatePopupPosition(e){if(this._slider){const t=this._slider.getBoundingClientRect(),i=(e-this.min)/(this.max-this.min);this._popupPosition=i*t.width}}render(){const e=1/this.max*100+"%",t=this._isDefault?"#9ece6a":"rgba(158, 206, 106, 0.3)";return B`
2963
+ ${this._isDragging?B`
2894
2964
  <div
2895
2965
  class="popup"
2896
2966
  style="left:${this._popupPosition}px;background:${this._accentColor}"
@@ -2915,7 +2985,7 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2915
2985
  style="accent-color:${this._accentColor}"
2916
2986
  />
2917
2987
  </div>
2918
- `}};pt.styles=[be,c`
2988
+ `}};function vt(e){return e>=1e6?`${(e/1e6).toFixed(1)} Mbps`:`${(e/1e3).toFixed(0)} kbps`}mt.styles=[ye,c`
2919
2989
  :host {
2920
2990
  display: inline-flex;
2921
2991
  position: relative;
@@ -2973,141 +3043,437 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
2973
3043
  border-left: 6px solid transparent;
2974
3044
  border-right: 6px solid transparent;
2975
3045
  }
2976
- `],r([ge({type:Number})],pt.prototype,"value",void 0),r([ge({type:Number})],pt.prototype,"min",void 0),r([ge({type:Number})],pt.prototype,"max",void 0),r([ge({type:Number,attribute:"snap-threshold"})],pt.prototype,"snapThreshold",void 0),r([ge({type:Boolean})],pt.prototype,"compact",void 0),r([fe()],pt.prototype,"_isDragging",void 0),r([fe()],pt.prototype,"_popupPosition",void 0),r([me("input[type=range]")],pt.prototype,"_slider",void 0),pt=r([he("fw-sc-volume")],pt);let gt=class extends le{constructor(){super(...arguments),this._activeTab="stats"}render(){return q`
3046
+ `],i([ge({type:Number})],mt.prototype,"value",void 0),i([ge({type:Number})],mt.prototype,"min",void 0),i([ge({type:Number})],mt.prototype,"max",void 0),i([ge({type:Number,attribute:"snap-threshold"})],mt.prototype,"snapThreshold",void 0),i([ge({type:Boolean})],mt.prototype,"compact",void 0),i([fe()],mt.prototype,"_isDragging",void 0),i([fe()],mt.prototype,"_popupPosition",void 0),i([me("input[type=range]")],mt.prototype,"_slider",void 0),mt=i([he("fw-sc-volume")],mt);let wt=class extends le{constructor(){super(...arguments),this.compositorEnabled=!1,this.compositorRendererType=null,this.compositorStats=null,this.sceneCount=0,this.layerCount=0,this._activeTab="audio"}render(){return B`
2977
3047
  <div class="panel">
2978
3048
  <div class="header">
2979
- <div class="tabs">
2980
- <button
2981
- class=${ye({tab:!0,"tab--active":"stats"===this._activeTab})}
2982
- @click=${()=>{this._activeTab="stats"}}
2983
- >
2984
- Stats
2985
- </button>
2986
- <button
2987
- class=${ye({tab:!0,"tab--active":"info"===this._activeTab})}
2988
- @click=${()=>{this._activeTab="info"}}
2989
- >
2990
- Info
2991
- </button>
2992
- </div>
3049
+ <button
3050
+ class=${be({tab:!0,"tab--active":"audio"===this._activeTab})}
3051
+ @click=${()=>{this._activeTab="audio"}}
3052
+ >
3053
+ Audio
3054
+ </button>
3055
+ <button
3056
+ class=${be({tab:!0,"tab--active":"stats"===this._activeTab})}
3057
+ @click=${()=>{this._activeTab="stats"}}
3058
+ >
3059
+ Stats
3060
+ </button>
3061
+ <button
3062
+ class=${be({tab:!0,"tab--active":"info"===this._activeTab})}
3063
+ @click=${()=>{this._activeTab="info"}}
3064
+ >
3065
+ Info
3066
+ </button>
3067
+ ${this.compositorEnabled?B`
3068
+ <button
3069
+ class=${be({tab:!0,"tab--active":"compositor"===this._activeTab})}
3070
+ @click=${()=>{this._activeTab="compositor"}}
3071
+ >
3072
+ Comp
3073
+ </button>
3074
+ `:G}
3075
+ <div style="flex:1"></div>
2993
3076
  <button
2994
3077
  class="close"
2995
3078
  @click=${()=>this.dispatchEvent(new CustomEvent("fw-close",{bubbles:!0,composed:!0}))}
2996
- aria-label="Close panel"
3079
+ aria-label="Close advanced panel"
2997
3080
  >
2998
- ${Ce(14)}
3081
+ ${Ce(12)}
2999
3082
  </button>
3000
3083
  </div>
3001
3084
  <div class="body">
3002
- ${"stats"===this._activeTab?this._renderStats():this._renderInfo()}
3085
+ ${"audio"===this._activeTab?this._renderAudio():"stats"===this._activeTab?this._renderStats():"info"===this._activeTab?this._renderInfo():this._renderCompositor()}
3086
+ </div>
3087
+ </div>
3088
+ `}_renderAudio(){const e=this.ic.s,t=this.ic.getMasterVolume(),i=e.audioLevel,r=i>.9?"#f7768e":i>.7?"#e0af68":"#9ece6a";return B`
3089
+ <!-- Master Volume -->
3090
+ <div class="section">
3091
+ <div class="section-header">Master Volume</div>
3092
+ <div style="display:flex;align-items:center;gap:12px">
3093
+ <fw-sc-volume
3094
+ .value=${t}
3095
+ .min=${0}
3096
+ .max=${2}
3097
+ @fw-sc-volume-change=${e=>this.ic.setMasterVolume(e.detail.value)}
3098
+ ></fw-sc-volume>
3099
+ <span
3100
+ style="font-size:14px;min-width:48px;text-align:right;color:${t>1?"#e0af68":1===t?"#9ece6a":"#c0caf5"}"
3101
+ >
3102
+ ${Math.round(100*t)}%
3103
+ </span>
3104
+ </div>
3105
+ ${t>1?B`<div style="font-size:10px;color:#e0af68;margin-top:4px">
3106
+ +${(100*(t-1)).toFixed(0)}% boost
3107
+ </div>`:G}
3108
+ </div>
3109
+
3110
+ <!-- Audio Level -->
3111
+ <div class="section">
3112
+ <div class="section-header">Output Level</div>
3113
+ <div class="level-bar">
3114
+ <div
3115
+ class="level-fill"
3116
+ style="width:${100*i}%;background:${r}"
3117
+ ></div>
3118
+ </div>
3119
+ <div class="level-labels">
3120
+ <span>-60dB</span><span>0dB</span>
3003
3121
  </div>
3004
3122
  </div>
3005
- `}_renderStats(){const e=this.ic.s,t=e.stats;return q`
3123
+
3124
+ <!-- Audio Mixing Status -->
3006
3125
  <div class="section">
3007
- <div class="label">Connection</div>
3008
- ${this._row("State",e.state)}
3009
- ${this._row("WebCodecs",e.isWebCodecsActive?"Active":e.useWebCodecs?"Pending":"Off")}
3126
+ <div style="display:flex;justify-content:space-between;align-items:center">
3127
+ <span class="section-header" style="margin-bottom:0">Audio Mixing</span>
3128
+ <span
3129
+ class="badge"
3130
+ style="background:rgba(158,206,106,0.2);color:#9ece6a"
3131
+ >
3132
+ ON
3133
+ </span>
3134
+ </div>
3135
+ <div style="font-size:10px;color:#565f89;margin-top:4px">
3136
+ Compressor + Limiter active
3137
+ </div>
3010
3138
  </div>
3011
- ${t?q`
3012
- <div class="section">
3013
- <div class="label">WebRTC Stats</div>
3014
- ${this._row("Video bitrate",t.video.bitrate?`${Math.round(t.video.bitrate/1e3)} kbps`:"—")}
3015
- ${this._row("Audio bitrate",t.audio.bitrate?`${Math.round(t.audio.bitrate/1e3)} kbps`:"")}
3016
- ${this._row("RTT",t.connection.rtt?`${(1e3*t.connection.rtt).toFixed(0)} ms`:"")}
3017
- ${this._row("FPS",t.video.framesPerSecond?String(t.video.framesPerSecond):"—")}
3018
- ${this._row("Packets sent",String(t.video.packetsSent))}
3019
- ${this._row("Packets lost",String(t.video.packetsLost))}
3139
+
3140
+ <!-- Audio Processing -->
3141
+ <div style="border-bottom:1px solid rgba(65,72,104,0.3)">
3142
+ <div class="section-dark">
3143
+ <span class="section-header" style="margin-bottom:0">Processing</span>
3144
+ <span style="font-size:9px;color:#565f89">
3145
+ profile: ${e.qualityProfile}
3146
+ </span>
3147
+ </div>
3148
+ ${this._renderToggle("Echo Cancellation",!0)}
3149
+ ${this._renderToggle("Noise Suppression",!0)}
3150
+ ${this._renderToggle("Auto Gain Control",!0)}
3151
+ </div>
3152
+ `}_renderToggle(e,t){return B`
3153
+ <div class="processing-row">
3154
+ <span class="processing-label">${e}</span>
3155
+ <button
3156
+ type="button"
3157
+ role="switch"
3158
+ aria-checked=${t}
3159
+ class="toggle ${t?"toggle--on":"toggle--off"}"
3160
+ >
3161
+ <div class="toggle-knob"></div>
3162
+ </button>
3163
+ </div>
3164
+ `}_renderStats(){const e=this.ic.s,t=e.stats,i="streaming"===e.state?"#9ece6a":"connecting"===e.state?"#7aa2f7":"error"===e.state?"#f7768e":"#c0caf5";return B`
3165
+ <div class="section">
3166
+ <div class="section-header" style="margin-bottom:4px">Connection</div>
3167
+ <div style="font-size:14px;font-weight:600;color:${i}">
3168
+ ${e.state.charAt(0).toUpperCase()+e.state.slice(1)}
3169
+ </div>
3170
+ </div>
3171
+ ${t?B`
3172
+ <div class="row">
3173
+ <span class="row-label">Bitrate</span>
3174
+ <span class="row-value">
3175
+ ${vt(t.video.bitrate+t.audio.bitrate)}
3176
+ </span>
3177
+ </div>
3178
+ <div class="row">
3179
+ <span class="row-label">Video</span>
3180
+ <span class="row-value" style="color:#7aa2f7">
3181
+ ${vt(t.video.bitrate)}
3182
+ </span>
3183
+ </div>
3184
+ <div class="row">
3185
+ <span class="row-label">Audio</span>
3186
+ <span class="row-value" style="color:#7aa2f7">
3187
+ ${vt(t.audio.bitrate)}
3188
+ </span>
3189
+ </div>
3190
+ <div class="row">
3191
+ <span class="row-label">Frame Rate</span>
3192
+ <span class="row-value">
3193
+ ${t.video.framesPerSecond.toFixed(0)} fps
3194
+ </span>
3195
+ </div>
3196
+ <div class="row">
3197
+ <span class="row-label">Frames Encoded</span>
3198
+ <span class="row-value">${t.video.framesEncoded}</span>
3199
+ </div>
3200
+ ${t.video.packetsLost>0||t.audio.packetsLost>0?B`
3201
+ <div class="row">
3202
+ <span class="row-label">Packets Lost</span>
3203
+ <span class="row-value" style="color:#f7768e">
3204
+ ${t.video.packetsLost+t.audio.packetsLost}
3205
+ </span>
3206
+ </div>
3207
+ `:G}
3208
+ <div class="row">
3209
+ <span class="row-label">RTT</span>
3210
+ <span
3211
+ class="row-value"
3212
+ style="color:${t.connection.rtt>200?"#e0af68":"#c0caf5"}"
3213
+ >
3214
+ ${t.connection.rtt.toFixed(0)} ms
3215
+ </span>
3216
+ </div>
3217
+ <div class="row">
3218
+ <span class="row-label">ICE State</span>
3219
+ <span class="row-value" style="text-transform:capitalize">
3220
+ ${t.connection.iceState}
3221
+ </span>
3222
+ </div>
3223
+ `:B`
3224
+ <div style="color:#565f89;text-align:center;padding:24px">
3225
+ ${"streaming"===e.state?"Waiting for stats...":"Start streaming to see stats"}
3226
+ </div>
3227
+ `}
3228
+ ${e.error?B`
3229
+ <div
3230
+ style="padding:12px;border-top:1px solid rgba(247,118,142,0.3);background:rgba(247,118,142,0.1)"
3231
+ >
3232
+ <div class="section-header" style="color:#f7768e;margin-bottom:4px">
3233
+ Error
3234
+ </div>
3235
+ <div style="font-size:12px;color:#f7768e">${e.error}</div>
3020
3236
  </div>
3021
3237
  `:G}
3022
- ${e.encoderStats?q`
3023
- <div class="section">
3024
- <div class="label">Encoder</div>
3025
- ${this._row("Video frames",String(e.encoderStats.video.framesEncoded))}
3026
- ${this._row("Video pending",String(e.encoderStats.video.framesPending))}
3027
- ${this._row("Audio samples",String(e.encoderStats.audio.samplesEncoded))}
3238
+ ${e.encoderStats?B`
3239
+ <div style="border-top:1px solid rgba(65,72,104,0.3)">
3240
+ <div class="section-dark">
3241
+ <span class="section-header" style="margin-bottom:0">Encoder</span>
3242
+ </div>
3243
+ <div class="row">
3244
+ <span class="row-label">Video frames</span>
3245
+ <span class="row-value">${e.encoderStats.video.framesEncoded}</span>
3246
+ </div>
3247
+ <div class="row">
3248
+ <span class="row-label">Video pending</span>
3249
+ <span
3250
+ class="row-value"
3251
+ style="color:${e.encoderStats.video.framesPending>5?"#e0af68":"#c0caf5"}"
3252
+ >
3253
+ ${e.encoderStats.video.framesPending}
3254
+ </span>
3255
+ </div>
3256
+ <div class="row">
3257
+ <span class="row-label">Audio samples</span>
3258
+ <span class="row-value">${e.encoderStats.audio.samplesEncoded}</span>
3259
+ </div>
3028
3260
  </div>
3029
3261
  `:G}
3030
- `}_renderInfo(){const e=this.ic.s;return q`
3262
+ `}_renderInfo(){const e=this.ic.s;return B`
3031
3263
  <div class="section">
3032
- <div class="label">Configuration</div>
3033
- ${this._row("Profile",e.qualityProfile)} ${this._row("Sources",String(e.sources.length))}
3034
- ${this._row("WebCodecs Available",e.isWebCodecsAvailable?"Yes":"No")}
3264
+ <div class="section-header" style="margin-bottom:4px">Quality Profile</div>
3265
+ <div style="font-size:14px;color:#c0caf5;text-transform:capitalize">
3266
+ ${e.qualityProfile}
3267
+ </div>
3035
3268
  </div>
3269
+
3270
+ <div class="section">
3271
+ <div class="section-header" style="margin-bottom:4px">Configuration</div>
3272
+ ${this._simpleRow("WebCodecs",e.isWebCodecsAvailable?"Available":"Unavailable")}
3273
+ ${this._simpleRow("WebCodecs Active",e.isWebCodecsActive?"Yes":e.useWebCodecs?"Pending":"No")}
3274
+ ${this._simpleRow("Sources",String(e.sources.length))}
3275
+ </div>
3276
+
3277
+ ${e.sources.length>0?B`
3278
+ <div style="border-bottom:1px solid rgba(65,72,104,0.3)">
3279
+ <div class="section-dark">
3280
+ <span class="section-header" style="margin-bottom:0">
3281
+ Sources (${e.sources.length})
3282
+ </span>
3283
+ </div>
3284
+ ${e.sources.map((e,t)=>B`
3285
+ <div
3286
+ style="padding:8px 12px;${t>0?"border-top:1px solid rgba(65,72,104,0.2)":""}"
3287
+ >
3288
+ <div style="display:flex;align-items:center;gap:8px">
3289
+ <span
3290
+ class="source-type"
3291
+ style="background:${"camera"===e.type?"rgba(122,162,247,0.2)":"screen"===e.type?"rgba(158,206,106,0.2)":"rgba(224,175,104,0.2)"};color:${"camera"===e.type?"#7aa2f7":"screen"===e.type?"#9ece6a":"#e0af68"}"
3292
+ >
3293
+ ${e.type}
3294
+ </span>
3295
+ <span
3296
+ style="color:#c0caf5;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"
3297
+ >
3298
+ ${e.label}
3299
+ </span>
3300
+ </div>
3301
+ <div
3302
+ style="display:flex;gap:12px;margin-top:4px;font-size:10px;color:#565f89"
3303
+ >
3304
+ <span>Vol: ${Math.round(100*e.volume)}%</span>
3305
+ ${e.muted?B`<span style="color:#f7768e">Muted</span>`:G}
3306
+ </div>
3307
+ </div>
3308
+ `)}
3309
+ </div>
3310
+ `:G}
3311
+ `}_renderCompositor(){const e=this.ic.s,t=this.compositorRendererType,i=this.compositorStats;return B`
3036
3312
  <div class="section">
3037
- <div class="label">Sources</div>
3038
- ${e.sources.map(e=>q`
3039
- ${this._row(e.label,`${e.type} ${e.muted?"(muted)":""}`)}
3040
- `)}
3313
+ <div class="section-header">Renderer</div>
3314
+ <div style="font-size:14px;font-weight:600;color:${"webgpu"===t?"#bb9af7":"webgl"===t?"#7aa2f7":"#9ece6a"}">
3315
+ ${"webgpu"===t?"WebGPU":"webgl"===t?"WebGL":"canvas2d"===t?"Canvas2D":"Not initialized"}
3316
+ </div>
3317
+ </div>
3318
+
3319
+ ${i?B`
3320
+ <div style="border-bottom:1px solid rgba(65,72,104,0.3)">
3321
+ <div class="section-dark">
3322
+ <span class="section-header" style="margin-bottom:0">Performance</span>
3323
+ </div>
3324
+ <div class="row">
3325
+ <span class="row-label">Frame Rate</span>
3326
+ <span class="row-value">${i.fps} fps</span>
3327
+ </div>
3328
+ <div class="row">
3329
+ <span class="row-label">Frame Time</span>
3330
+ <span
3331
+ class="row-value"
3332
+ style="color:${i.frameTimeMs>16?"#e0af68":"#c0caf5"}"
3333
+ >
3334
+ ${i.frameTimeMs.toFixed(2)} ms
3335
+ </span>
3336
+ </div>
3337
+ ${void 0!==i.gpuMemoryMB?B`
3338
+ <div class="row">
3339
+ <span class="row-label">GPU Memory</span>
3340
+ <span class="row-value">
3341
+ ${i.gpuMemoryMB.toFixed(1)} MB
3342
+ </span>
3343
+ </div>
3344
+ `:G}
3345
+ </div>
3346
+ `:G}
3347
+
3348
+ <div style="border-bottom:1px solid rgba(65,72,104,0.3)">
3349
+ <div class="section-dark">
3350
+ <span class="section-header" style="margin-bottom:0">Composition</span>
3351
+ </div>
3352
+ <div class="row">
3353
+ <span class="row-label">Scenes</span>
3354
+ <span class="row-value">${this.sceneCount}</span>
3355
+ </div>
3356
+ <div class="row">
3357
+ <span class="row-label">Layers</span>
3358
+ <span class="row-value">${this.layerCount}</span>
3359
+ </div>
3360
+ </div>
3361
+
3362
+ <!-- Encoder -->
3363
+ <div style="border-bottom:1px solid rgba(65,72,104,0.3)">
3364
+ <div class="section-dark">
3365
+ <span class="section-header" style="margin-bottom:0">Encoder</span>
3366
+ </div>
3367
+ <div class="row">
3368
+ <span class="row-label">Type</span>
3369
+ <span
3370
+ class="badge"
3371
+ style="background:${e.useWebCodecs&&e.isWebCodecsAvailable?"rgba(187,154,247,0.2)":"rgba(122,162,247,0.2)"};color:${e.useWebCodecs&&e.isWebCodecsAvailable?"#bb9af7":"#7aa2f7"}"
3372
+ >
3373
+ ${e.useWebCodecs&&e.isWebCodecsAvailable?"WebCodecs":"Browser"}
3374
+ ${"streaming"===e.state?B`<span style="opacity:0.7;margin-left:4px">
3375
+ ${e.isWebCodecsActive?"(active)":"(pending)"}
3376
+ </span>`:G}
3377
+ </span>
3378
+ </div>
3379
+ <div class="processing-row">
3380
+ <span class="processing-label">Use WebCodecs</span>
3381
+ <button
3382
+ type="button"
3383
+ role="switch"
3384
+ aria-checked=${e.useWebCodecs}
3385
+ class="toggle ${e.useWebCodecs?"toggle--on":"toggle--off"}"
3386
+ ?disabled=${"streaming"===e.state||!e.isWebCodecsAvailable}
3387
+ @click=${()=>this.ic.setUseWebCodecs(!e.useWebCodecs)}
3388
+ >
3389
+ <div class="toggle-knob"></div>
3390
+ </button>
3391
+ </div>
3392
+ ${e.isWebCodecsAvailable?G:B`<div style="padding:8px 12px;font-size:10px;color:#f7768e">
3393
+ Not available - RTCRtpScriptTransform unsupported
3394
+ </div>`}
3041
3395
  </div>
3042
- `}_row(e,t){return q`<div class="row">
3396
+ `}_simpleRow(e,t){return B`<div class="row">
3043
3397
  <span class="row-label">${e}</span><span class="row-value">${t}</span>
3044
- </div>`}};function ft(e,t){customElements.get(e)||customElements.define(e,t)}return gt.styles=[be,xe,c`
3398
+ </div>`}};function bt(e,t){customElements.get(e)||customElements.define(e,t)}return wt.styles=[ye,xe,c`
3045
3399
  :host {
3046
3400
  display: block;
3047
3401
  }
3048
3402
  .panel {
3049
- width: 320px;
3403
+ width: 280px;
3050
3404
  height: 100%;
3051
- border-left: 1px solid rgba(90, 96, 127, 0.3);
3405
+ border-left: 1px solid rgba(65, 72, 104, 0.5);
3052
3406
  background: #1a1b26;
3053
- overflow: auto;
3054
- font-size: 0.75rem;
3407
+ display: flex;
3408
+ flex-direction: column;
3409
+ font-size: 12px;
3410
+ font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, monospace;
3055
3411
  color: #a9b1d6;
3412
+ flex-shrink: 0;
3413
+ z-index: 40;
3056
3414
  }
3057
3415
  .header {
3058
3416
  display: flex;
3059
3417
  align-items: center;
3060
- justify-content: space-between;
3061
- padding: 0.5rem 0.75rem;
3062
- border-bottom: 1px solid rgba(90, 96, 127, 0.3);
3063
- }
3064
- .tabs {
3065
- display: flex;
3066
- gap: 0.5rem;
3418
+ border-bottom: 1px solid rgba(65, 72, 104, 0.3);
3419
+ background: #16161e;
3067
3420
  }
3068
3421
  .tab {
3069
- padding: 0.25rem 0.5rem;
3422
+ padding: 8px 12px;
3423
+ font-size: 10px;
3424
+ text-transform: uppercase;
3425
+ letter-spacing: 0.05em;
3426
+ font-weight: 600;
3070
3427
  border: none;
3071
- background: none;
3428
+ background: transparent;
3072
3429
  color: #565f89;
3073
- font-size: 0.6875rem;
3074
- font-weight: 600;
3075
3430
  cursor: pointer;
3076
- border-radius: 0.25rem;
3431
+ transition: all 0.15s;
3077
3432
  }
3078
3433
  .tab--active {
3434
+ background: #1a1b26;
3079
3435
  color: #c0caf5;
3080
- background: rgba(90, 96, 127, 0.2);
3081
3436
  }
3082
3437
  .close {
3083
3438
  display: flex;
3084
- background: none;
3439
+ background: transparent;
3085
3440
  border: none;
3086
3441
  color: #565f89;
3087
3442
  cursor: pointer;
3088
- padding: 0;
3443
+ padding: 8px;
3444
+ transition: color 0.15s;
3089
3445
  }
3090
3446
  .close:hover {
3091
3447
  color: #c0caf5;
3092
3448
  }
3093
3449
  .body {
3094
- padding: 0.75rem;
3095
- }
3096
- .section {
3097
- margin-bottom: 0.75rem;
3450
+ flex: 1;
3451
+ overflow-y: auto;
3098
3452
  }
3099
- .label {
3100
- font-size: 0.625rem;
3101
- font-weight: 600;
3453
+ .section-header {
3454
+ font-size: 10px;
3455
+ color: #565f89;
3102
3456
  text-transform: uppercase;
3103
3457
  letter-spacing: 0.05em;
3104
- color: #565f89;
3105
- margin-bottom: 0.375rem;
3458
+ font-weight: 600;
3459
+ margin-bottom: 8px;
3460
+ }
3461
+ .section {
3462
+ padding: 12px;
3463
+ border-bottom: 1px solid rgba(65, 72, 104, 0.3);
3464
+ }
3465
+ .section-dark {
3466
+ padding: 8px 12px;
3467
+ background: #16161e;
3468
+ display: flex;
3469
+ justify-content: space-between;
3470
+ align-items: center;
3106
3471
  }
3107
3472
  .row {
3108
3473
  display: flex;
3109
3474
  justify-content: space-between;
3110
- padding: 0.125rem 0;
3475
+ padding: 8px 12px;
3476
+ border-top: 1px solid rgba(65, 72, 104, 0.2);
3111
3477
  }
3112
3478
  .row-label {
3113
3479
  color: #565f89;
@@ -3117,5 +3483,81 @@ function me(e,t){return(t,r,i)=>((e,t,r)=>(r.configurable=!0,r.enumerable=!0,Ref
3117
3483
  font-family: ui-monospace, monospace;
3118
3484
  font-variant-numeric: tabular-nums;
3119
3485
  }
3120
- `],r([ge({attribute:!1})],gt.prototype,"ic",void 0),r([fe()],gt.prototype,"_activeTab",void 0),gt=r([he("fw-sc-advanced")],gt),ft("fw-streamcrafter",e.FwStreamCrafter),ft("fw-sc-compositor",dt),ft("fw-sc-scene-switcher",ht),ft("fw-sc-layer-list",ut),ft("fw-sc-volume",pt),ft("fw-sc-advanced",gt),e.IngestControllerHost=nt,e}({});
3486
+ .level-bar {
3487
+ height: 8px;
3488
+ background: rgba(65, 72, 104, 0.3);
3489
+ border-radius: 4px;
3490
+ overflow: hidden;
3491
+ }
3492
+ .level-fill {
3493
+ height: 100%;
3494
+ transition: all 75ms;
3495
+ }
3496
+ .level-labels {
3497
+ display: flex;
3498
+ justify-content: space-between;
3499
+ font-size: 10px;
3500
+ color: #565f89;
3501
+ margin-top: 4px;
3502
+ }
3503
+ .badge {
3504
+ font-size: 12px;
3505
+ font-family: monospace;
3506
+ padding: 2px 6px;
3507
+ }
3508
+ .toggle {
3509
+ position: relative;
3510
+ display: inline-flex;
3511
+ height: 20px;
3512
+ width: 36px;
3513
+ flex-shrink: 0;
3514
+ cursor: pointer;
3515
+ border-radius: 10px;
3516
+ border: 2px solid transparent;
3517
+ transition: background 0.2s;
3518
+ padding: 0;
3519
+ }
3520
+ .toggle:disabled {
3521
+ opacity: 0.5;
3522
+ cursor: not-allowed;
3523
+ }
3524
+ .toggle-knob {
3525
+ position: absolute;
3526
+ top: 2px;
3527
+ width: 12px;
3528
+ height: 12px;
3529
+ border-radius: 50%;
3530
+ background: white;
3531
+ transition: left 0.2s;
3532
+ }
3533
+ .toggle--on {
3534
+ background: #7aa2f7;
3535
+ }
3536
+ .toggle--off {
3537
+ background: rgba(65, 72, 104, 0.5);
3538
+ }
3539
+ .toggle--on .toggle-knob {
3540
+ left: 18px;
3541
+ }
3542
+ .toggle--off .toggle-knob {
3543
+ left: 4px;
3544
+ }
3545
+ .processing-row {
3546
+ display: flex;
3547
+ justify-content: space-between;
3548
+ align-items: center;
3549
+ padding: 8px 12px;
3550
+ border-top: 1px solid rgba(65, 72, 104, 0.2);
3551
+ }
3552
+ .processing-label {
3553
+ font-size: 12px;
3554
+ color: #a9b1d6;
3555
+ }
3556
+ .source-type {
3557
+ font-size: 10px;
3558
+ font-family: monospace;
3559
+ padding: 2px 6px;
3560
+ text-transform: uppercase;
3561
+ }
3562
+ `],i([ge({attribute:!1})],wt.prototype,"ic",void 0),i([ge({type:Boolean,attribute:"compositor-enabled"})],wt.prototype,"compositorEnabled",void 0),i([ge({type:String,attribute:"compositor-renderer"})],wt.prototype,"compositorRendererType",void 0),i([ge({attribute:!1})],wt.prototype,"compositorStats",void 0),i([ge({type:Number,attribute:"scene-count"})],wt.prototype,"sceneCount",void 0),i([ge({type:Number,attribute:"layer-count"})],wt.prototype,"layerCount",void 0),i([fe()],wt.prototype,"_activeTab",void 0),wt=i([he("fw-sc-advanced")],wt),bt("fw-streamcrafter",e.FwStreamCrafter),bt("fw-sc-compositor",pt),bt("fw-sc-scene-switcher",gt),bt("fw-sc-layer-list",ft),bt("fw-sc-volume",mt),bt("fw-sc-advanced",wt),e.IngestControllerHost=lt,e}({});
3121
3563
  //# sourceMappingURL=fw-streamcrafter.iife.js.map