@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.
- package/LICENSE.md +24 -0
- package/dist/cjs/components/fw-sc-advanced.js +555 -71
- package/dist/cjs/components/fw-sc-advanced.js.map +1 -1
- package/dist/cjs/components/fw-streamcrafter.js +176 -1
- package/dist/cjs/components/fw-streamcrafter.js.map +1 -1
- package/dist/cjs/controllers/ingest-controller-host.js +34 -1
- package/dist/cjs/controllers/ingest-controller-host.js.map +1 -1
- package/dist/esm/components/fw-sc-advanced.js +556 -72
- package/dist/esm/components/fw-sc-advanced.js.map +1 -1
- package/dist/esm/components/fw-streamcrafter.js +177 -2
- package/dist/esm/components/fw-streamcrafter.js.map +1 -1
- package/dist/esm/controllers/ingest-controller-host.js +34 -1
- package/dist/esm/controllers/ingest-controller-host.js.map +1 -1
- package/dist/fw-streamcrafter.iife.js +646 -204
- package/dist/fw-streamcrafter.iife.js.map +1 -1
- package/dist/types/components/fw-sc-advanced.d.ts +12 -2
- package/dist/types/components/fw-streamcrafter.d.ts +12 -0
- package/dist/types/controllers/ingest-controller-host.d.ts +5 -0
- package/package.json +13 -13
- package/src/components/fw-sc-advanced.ts +569 -93
- package/src/components/fw-streamcrafter.ts +178 -1
- package/src/controllers/ingest-controller-host.ts +36 -1
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
var FwStreamCrafter=function(e){"use strict";var t="undefined"!=typeof document?document.currentScript:null;function
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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)=>
|
|
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)=>
|
|
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)=>
|
|
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=
|
|
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=${
|
|
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=${
|
|
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:
|
|
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?
|
|
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?
|
|
2320
|
-
${this.enableCompositor?
|
|
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?
|
|
2366
|
+
${e.sources.length>0?B`
|
|
2326
2367
|
<div
|
|
2327
|
-
class=${
|
|
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)=>
|
|
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)=>
|
|
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?
|
|
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?
|
|
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:
|
|
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=${
|
|
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
|
-
${(
|
|
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?
|
|
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
|
-
`:
|
|
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?
|
|
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,
|
|
2464
|
-
<div
|
|
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?
|
|
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
|
-
${
|
|
2572
|
+
${i&&!this.enableCompositor?B`
|
|
2477
2573
|
<button
|
|
2478
2574
|
type="button"
|
|
2479
|
-
class=${
|
|
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
|
-
${
|
|
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=${
|
|
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)=>
|
|
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)=>
|
|
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
|
|
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
|
-
${
|
|
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?
|
|
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=[
|
|
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
|
-
`],
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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:()=>
|
|
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}],
|
|
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:()=>
|
|
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:()=>
|
|
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
|
|
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=>
|
|
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
|
-
${
|
|
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}))}};
|
|
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
|
-
`],
|
|
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?
|
|
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=>
|
|
2845
|
+
${this.scenes.map(e=>B`
|
|
2750
2846
|
<div
|
|
2751
|
-
class=${
|
|
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?
|
|
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}))}};
|
|
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
|
-
`],
|
|
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?
|
|
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=${
|
|
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=${
|
|
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?((
|
|
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?
|
|
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===
|
|
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=${
|
|
2934
|
+
?disabled=${i===e.length-1}
|
|
2865
2935
|
title="Move down"
|
|
2866
2936
|
>
|
|
2867
2937
|
↓
|
|
2868
2938
|
</button>
|
|
2869
2939
|
<button
|
|
2870
|
-
class=${
|
|
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
|
|
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
|
-
`],
|
|
2893
|
-
${this._isDragging?
|
|
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
|
-
`}};
|
|
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
|
-
`],
|
|
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
|
-
<
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
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(
|
|
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
|
-
|
|
3123
|
+
|
|
3124
|
+
<!-- Audio Mixing Status -->
|
|
3006
3125
|
<div class="section">
|
|
3007
|
-
<div
|
|
3008
|
-
|
|
3009
|
-
|
|
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
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
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?
|
|
3023
|
-
<div
|
|
3024
|
-
<div class="
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
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
|
|
3262
|
+
`}_renderInfo(){const e=this.ic.s;return B`
|
|
3031
3263
|
<div class="section">
|
|
3032
|
-
<div class="
|
|
3033
|
-
|
|
3034
|
-
|
|
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="
|
|
3038
|
-
|
|
3039
|
-
|
|
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
|
-
`}
|
|
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
|
|
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:
|
|
3403
|
+
width: 280px;
|
|
3050
3404
|
height: 100%;
|
|
3051
|
-
border-left: 1px solid rgba(
|
|
3405
|
+
border-left: 1px solid rgba(65, 72, 104, 0.5);
|
|
3052
3406
|
background: #1a1b26;
|
|
3053
|
-
|
|
3054
|
-
|
|
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
|
-
|
|
3061
|
-
|
|
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:
|
|
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:
|
|
3428
|
+
background: transparent;
|
|
3072
3429
|
color: #565f89;
|
|
3073
|
-
font-size: 0.6875rem;
|
|
3074
|
-
font-weight: 600;
|
|
3075
3430
|
cursor: pointer;
|
|
3076
|
-
|
|
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:
|
|
3439
|
+
background: transparent;
|
|
3085
3440
|
border: none;
|
|
3086
3441
|
color: #565f89;
|
|
3087
3442
|
cursor: pointer;
|
|
3088
|
-
padding:
|
|
3443
|
+
padding: 8px;
|
|
3444
|
+
transition: color 0.15s;
|
|
3089
3445
|
}
|
|
3090
3446
|
.close:hover {
|
|
3091
3447
|
color: #c0caf5;
|
|
3092
3448
|
}
|
|
3093
3449
|
.body {
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
.section {
|
|
3097
|
-
margin-bottom: 0.75rem;
|
|
3450
|
+
flex: 1;
|
|
3451
|
+
overflow-y: auto;
|
|
3098
3452
|
}
|
|
3099
|
-
.
|
|
3100
|
-
font-size:
|
|
3101
|
-
|
|
3453
|
+
.section-header {
|
|
3454
|
+
font-size: 10px;
|
|
3455
|
+
color: #565f89;
|
|
3102
3456
|
text-transform: uppercase;
|
|
3103
3457
|
letter-spacing: 0.05em;
|
|
3104
|
-
|
|
3105
|
-
margin-bottom:
|
|
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:
|
|
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
|
-
|
|
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
|