@vidtreo/recorder-wc 0.9.10 → 1.0.0-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/dist/vidtreo-recorder.js +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ npm install @vidtreo/recorder-wc
|
|
|
20
20
|
|
|
21
21
|
<vidtreo-recorder
|
|
22
22
|
api-key="your-api-key"
|
|
23
|
-
backend-url="https://
|
|
23
|
+
backend-url="https://core.vidtreo.com"
|
|
24
24
|
></vidtreo-recorder>
|
|
25
25
|
```
|
|
26
26
|
|
|
@@ -33,7 +33,7 @@ npm install @vidtreo/recorder-wc
|
|
|
33
33
|
|
|
34
34
|
<vidtreo-recorder
|
|
35
35
|
api-key="your-api-key"
|
|
36
|
-
<!-- backend-url is optional, defaults to https://
|
|
36
|
+
<!-- backend-url is optional, defaults to https://core.vidtreo.com -->
|
|
37
37
|
></vidtreo-recorder>
|
|
38
38
|
```
|
|
39
39
|
|
|
@@ -52,7 +52,7 @@ All attributes are optional except where noted. Attributes use kebab-case (e.g.,
|
|
|
52
52
|
| Attribute | Type | Required | Default | Description |
|
|
53
53
|
|-----------|------|----------|---------|-------------|
|
|
54
54
|
| `api-key` | `string` | No* | - | API key for authentication. Required if not set via JavaScript. |
|
|
55
|
-
| `backend-url` | `string` | No | `https://
|
|
55
|
+
| `backend-url` | `string` | No | `https://core.vidtreo.com` | Backend API URL. Automatically adds `https://` prefix if missing. |
|
|
56
56
|
| `countdown-duration` | `number` | No | - | Countdown duration in milliseconds before recording starts (e.g., `3000` for 3 seconds) |
|
|
57
57
|
| `max-recording-time` | `number` | No | - | Maximum recording time in milliseconds (e.g., `300000` for 5 minutes) |
|
|
58
58
|
| `user-metadata` | `string` (JSON) | No | - | Custom metadata to attach to recordings. Must be valid JSON string. |
|
|
@@ -84,7 +84,7 @@ All attributes are optional except where noted. Attributes use kebab-case (e.g.,
|
|
|
84
84
|
|
|
85
85
|
<vidtreo-recorder
|
|
86
86
|
api-key="your-api-key"
|
|
87
|
-
backend-url="https://
|
|
87
|
+
backend-url="https://core.vidtreo.com"
|
|
88
88
|
></vidtreo-recorder>
|
|
89
89
|
```
|
|
90
90
|
|
|
@@ -93,7 +93,7 @@ All attributes are optional except where noted. Attributes use kebab-case (e.g.,
|
|
|
93
93
|
```html
|
|
94
94
|
<vidtreo-recorder
|
|
95
95
|
api-key="your-api-key"
|
|
96
|
-
backend-url="https://
|
|
96
|
+
backend-url="https://core.vidtreo.com"
|
|
97
97
|
countdown-duration="3000"
|
|
98
98
|
max-recording-time="300000"
|
|
99
99
|
></vidtreo-recorder>
|
|
@@ -104,7 +104,7 @@ All attributes are optional except where noted. Attributes use kebab-case (e.g.,
|
|
|
104
104
|
```html
|
|
105
105
|
<vidtreo-recorder
|
|
106
106
|
api-key="your-api-key"
|
|
107
|
-
backend-url="https://
|
|
107
|
+
backend-url="https://core.vidtreo.com"
|
|
108
108
|
user-metadata='{"userId": "12345", "sessionId": "abc123"}'
|
|
109
109
|
></vidtreo-recorder>
|
|
110
110
|
```
|
|
@@ -114,7 +114,7 @@ All attributes are optional except where noted. Attributes use kebab-case (e.g.,
|
|
|
114
114
|
```html
|
|
115
115
|
<vidtreo-recorder
|
|
116
116
|
api-key="your-api-key"
|
|
117
|
-
backend-url="https://
|
|
117
|
+
backend-url="https://core.vidtreo.com"
|
|
118
118
|
enable-source-switching="false"
|
|
119
119
|
enable-mute="false"
|
|
120
120
|
enable-pause="false"
|
|
@@ -127,7 +127,7 @@ All attributes are optional except where noted. Attributes use kebab-case (e.g.,
|
|
|
127
127
|
```html
|
|
128
128
|
<vidtreo-recorder
|
|
129
129
|
api-key="your-api-key"
|
|
130
|
-
backend-url="https://
|
|
130
|
+
backend-url="https://core.vidtreo.com"
|
|
131
131
|
enable-source-switching="false"
|
|
132
132
|
enable-mute="false"
|
|
133
133
|
enable-pause="false"
|
|
@@ -181,7 +181,7 @@ const recorder = document.querySelector('vidtreo-recorder');
|
|
|
181
181
|
<vidtreo-recorder
|
|
182
182
|
id="my-recorder"
|
|
183
183
|
api-key="your-api-key"
|
|
184
|
-
backend-url="https://
|
|
184
|
+
backend-url="https://core.vidtreo.com"
|
|
185
185
|
></vidtreo-recorder>
|
|
186
186
|
|
|
187
187
|
<button onclick="startRecording()">Start Recording</button>
|
|
@@ -217,7 +217,7 @@ const recorder = document.querySelector('vidtreo-recorder');
|
|
|
217
217
|
<vidtreo-recorder
|
|
218
218
|
id="my-recorder"
|
|
219
219
|
api-key="your-api-key"
|
|
220
|
-
backend-url="https://
|
|
220
|
+
backend-url="https://core.vidtreo.com"
|
|
221
221
|
></vidtreo-recorder>
|
|
222
222
|
|
|
223
223
|
<script type="module">
|
|
@@ -248,7 +248,7 @@ const recorder = document.querySelector('vidtreo-recorder');
|
|
|
248
248
|
<vidtreo-recorder
|
|
249
249
|
id="my-recorder"
|
|
250
250
|
api-key="your-api-key"
|
|
251
|
-
backend-url="https://
|
|
251
|
+
backend-url="https://core.vidtreo.com"
|
|
252
252
|
></vidtreo-recorder>
|
|
253
253
|
|
|
254
254
|
<script type="module">
|
|
@@ -295,7 +295,7 @@ The web component uses Shadow DOM, so styles are encapsulated. However, you can
|
|
|
295
295
|
|
|
296
296
|
<vidtreo-recorder
|
|
297
297
|
api-key="your-api-key"
|
|
298
|
-
backend-url="https://
|
|
298
|
+
backend-url="https://core.vidtreo.com"
|
|
299
299
|
></vidtreo-recorder>
|
|
300
300
|
```
|
|
301
301
|
|
|
@@ -306,7 +306,7 @@ The web component uses Shadow DOM, so styles are encapsulated. However, you can
|
|
|
306
306
|
<vidtreo-recorder
|
|
307
307
|
id="recorder"
|
|
308
308
|
api-key="your-api-key"
|
|
309
|
-
backend-url="https://
|
|
309
|
+
backend-url="https://core.vidtreo.com"
|
|
310
310
|
></vidtreo-recorder>
|
|
311
311
|
|
|
312
312
|
<button type="submit">Submit Recording</button>
|
|
@@ -346,7 +346,7 @@ For Vite projects, you can use environment variables:
|
|
|
346
346
|
```bash
|
|
347
347
|
# .env
|
|
348
348
|
VITE_VIDTREO_API_KEY=your-api-key
|
|
349
|
-
VITE_VIDTREO_BACKEND_URL=https://
|
|
349
|
+
VITE_VIDTREO_BACKEND_URL=https://core.vidtreo.com
|
|
350
350
|
```
|
|
351
351
|
|
|
352
352
|
```html
|
package/dist/vidtreo-recorder.js
CHANGED
|
@@ -104,7 +104,7 @@ function o(e){if(!e)throw Error(`Assertion failed.`)}var s,c,l,u,d,f,p,m,h,g,_,v
|
|
|
104
104
|
Tracks were discarded because your environment is not able to encode any of the following codecs: ${t.map(e=>`'${e}'`).join(`, `)}.`),t.includes(`mp3`)&&e.push(`
|
|
105
105
|
The @mediabunny/mp3-encoder extension package provides support for encoding MP3.`)}else e.push(`
|
|
106
106
|
Check the discardedTracks field for more info.`)}return e}async execute(){if(!this.isValid)throw Error(`Cannot execute this conversion because its output configuration is invalid. Make sure to always check the isValid field before executing a conversion.
|
|
107
|
-
`+this._getInvalidityExplanation().join(``));if(this._executed)throw Error(`Conversion cannot be executed twice.`);if(this._executed=!0,this.onProgress){this._computeProgress=!0,this._totalDuration=Math.min(await this.input.computeDuration()-this._startTimestamp,this._endTimestamp-this._startTimestamp);for(let e of this.utilizedTracks)this._maxTimestamps.set(e.id,0);this.onProgress?.(0)}await this.output.start(),this._start();try{await Promise.all(this._trackPromises)}catch(e){throw this._canceled||this.cancel(),e}this._canceled&&await new Promise(()=>{}),await this.output.finalize(),this._computeProgress&&this.onProgress?.(1)}async cancel(){if(!(this.output.state===`finalizing`||this.output.state===`finalized`)){if(this._canceled){console.warn(`Conversion already canceled.`);return}this._canceled=!0,await this.output.cancel()}}async _processVideoTrack(e,t){let n=e.codec;if(!n){this.discardedTracks.push({track:e,reason:`unknown_source_codec`});return}let r,i=s(e.rotation+(t.rotate??0)),a=this.output.format.supportsVideoRotationMetadata&&(t.allowRotationMetadata??!0),[c,l]=i%180==0?[e.codedWidth,e.codedHeight]:[e.codedHeight,e.codedWidth],u=t.crop;u&&rr(u,c,l);let[d,f]=u?[u.width,u.height]:[c,l],p=d,m=f,h=p/m,g=e=>Math.ceil(e/2)*2;t.width!==void 0&&t.height===void 0?(p=g(t.width),m=g(Math.round(p/h))):t.width===void 0&&t.height!==void 0?(m=g(t.height),p=g(Math.round(m*h))):t.width!==void 0&&t.height!==void 0&&(p=g(t.width),m=g(t.height));let _=await e.getFirstTimestamp(),v=!!t.forceTranscode||this._startTimestamp>0||_<0||!!t.frameRate||t.keyFrameInterval!==void 0||t.process!==void 0,y=p!==d||m!==f||i!==0&&(!a||t.process!==void 0)||!!u,ee=t.alpha??`discard`,te=this.output.format.getSupportedVideoCodecs();if(!v&&!t.bitrate&&!y&&te.includes(n)&&(!t.codec||t.codec===n)){let t=new ku(n);r=t,this._trackPromises.push((async()=>{await this._started;let n=new yr(e),r={decoderConfig:await e.getDecoderConfig()??void 0},i=Number.isFinite(this._endTimestamp)?await n.getPacket(this._endTimestamp,{metadataOnly:!0})??void 0:void 0;for await(let a of n.packets(void 0,i,{verifyKeyPackets:!0})){if(this._canceled)return;ee===`discard`&&(delete a.sideData.alpha,delete a.sideData.alphaByteLength),this._reportProgress(e.id,a.timestamp),await t.add(a,r),this._synchronizer.shouldWait(e.id,a.timestamp)&&await this._synchronizer.wait(a.timestamp)}t.close(),this._synchronizer.closeTrack(e.id)})())}else{if(!await e.canDecode()){this.discardedTracks.push({track:e,reason:`undecodable_source_codec`});return}t.codec&&(te=te.filter(e=>e===t.codec));let n=t.bitrate??pu,a=await Cu(te,{width:t.process&&t.processedWidth?t.processedWidth:p,height:t.process&&t.processedHeight?t.processedHeight:m,bitrate:n});if(!a){this.discardedTracks.push({track:e,reason:`no_encodable_target_codec`});return}let s={codec:a,bitrate:n,keyFrameInterval:t.keyFrameInterval,sizeChangeBehavior:t.fit??`passThrough`,alpha:ee,hardwareAcceleration:t.hardwareAcceleration},c=new Mu(s);if(r=c,!y){let t=new $u({format:new ql,target:new yl}),n=new Mu(s);t.addVideoTrack(n),await t.start();let r=await new Tr(e).getSample(_);if(r)try{await n.add(r),r.close(),await t.finalize()}catch(e){console.info(`Error when probing encoder support. Falling back to rerender path.`,e),y=!0,t.cancel()}else await t.cancel()}y?this._trackPromises.push((async()=>{await this._started;let n=new Er(e,{width:p,height:m,fit:t.fit??`fill`,rotation:i,crop:t.crop,poolSize:1,alpha:ee===`keep`}).canvases(this._startTimestamp,this._endTimestamp),r=t.frameRate,a=null,s=null,l=null,u=async n=>{o(a),o(r!==void 0);let i=Math.round((n-s)*r);for(let n=1;n<i;n++){let i=new er(a,{timestamp:s+n/r,duration:1/r});await this._registerVideoSample(e,t,c,i),i.close()}};for await(let{canvas:i,timestamp:o,duration:d}of n){if(this._canceled)return;let n=Math.max(o-this._startTimestamp,0);if(l=n+d,r!==void 0){let e=Math.floor(n*r)/r;if(a!==null)if(e<=s){a=i,s=e;continue}else await u(e);n=e}let f=new er(i,{timestamp:n,duration:r===void 0?d:1/r});await this._registerVideoSample(e,t,c,f),f.close(),r!==void 0&&(a=i,s=n)}a&&(o(l!==null),o(r!==void 0),await u(Math.floor(l*r)/r)),c.close(),this._synchronizer.closeTrack(e.id)})()):this._trackPromises.push((async()=>{await this._started;let n=new Tr(e),r=t.frameRate,i=null,a=null,s=null,l=async n=>{o(i),o(r!==void 0);let s=Math.round((n-a)*r);for(let n=1;n<s;n++)i.setTimestamp(a+n/r),i.setDuration(1/r),await this._registerVideoSample(e,t,c,i);i.close()};for await(let o of n.samples(this._startTimestamp,this._endTimestamp)){if(this._canceled){i?.close();return}let n=Math.max(o.timestamp-this._startTimestamp,0);if(s=n+o.duration,r!==void 0){let e=Math.floor(n*r)/r;if(i!==null)if(e<=a){i.close(),i=o,a=e;continue}else await l(e);n=e,o.setDuration(1/r)}o.setTimestamp(n),await this._registerVideoSample(e,t,c,o),r===void 0?o.close():(i=o,a=n)}i&&(o(s!==null),o(r!==void 0),await l(Math.floor(s*r)/r)),c.close(),this._synchronizer.closeTrack(e.id)})())}this.output.addVideoTrack(r,{frameRate:t.frameRate,languageCode:Oe(e.languageCode)?e.languageCode:void 0,name:e.name??void 0,disposition:e.disposition,rotation:y?0:i}),this._addedCounts.video++,this._totalTrackCount++,this.utilizedTracks.push(e)}async _registerVideoSample(e,t,n,r){if(this._canceled)return;this._reportProgress(e.id,r.timestamp);let i;if(!t.process)i=[r];else{let e=t.process(r);e instanceof Promise&&(e=await e),Array.isArray(e)||(e=e===null?[]:[e]),i=e.map(e=>e instanceof er?e:typeof VideoFrame<`u`&&e instanceof VideoFrame?new er(e):new er(e,{timestamp:r.timestamp,duration:r.duration}))}for(let t of i){if(this._canceled)break;await n.add(t),this._synchronizer.shouldWait(e.id,t.timestamp)&&await this._synchronizer.wait(t.timestamp)}for(let e of i)e!==r&&e.close()}async _processAudioTrack(e,t){let n=e.codec;if(!n){this.discardedTracks.push({track:e,reason:`unknown_source_codec`});return}let r,i=e.numberOfChannels,a=e.sampleRate,o=await e.getFirstTimestamp(),s=t.numberOfChannels??i,c=t.sampleRate??a,l=s!==i||c!==a||this._startTimestamp>0||o<0,u=this.output.format.getSupportedAudioCodecs();if(!t.forceTranscode&&!t.bitrate&&!l&&u.includes(n)&&(!t.codec||t.codec===n)&&!t.process){let t=new Iu(n);r=t,this._trackPromises.push((async()=>{await this._started;let n=new yr(e),r={decoderConfig:await e.getDecoderConfig()??void 0},i=Number.isFinite(this._endTimestamp)?await n.getPacket(this._endTimestamp,{metadataOnly:!0})??void 0:void 0;for await(let a of n.packets(void 0,i)){if(this._canceled)return;this._reportProgress(e.id,a.timestamp),await t.add(a,r),this._synchronizer.shouldWait(e.id,a.timestamp)&&await this._synchronizer.wait(a.timestamp)}t.close(),this._synchronizer.closeTrack(e.id)})())}else{if(!await e.canDecode()){this.discardedTracks.push({track:e,reason:`undecodable_source_codec`});return}let n=null;t.codec&&(u=u.filter(e=>e===t.codec));let i=t.bitrate??pu,a=await xu(u,{numberOfChannels:t.process&&t.processedNumberOfChannels?t.processedNumberOfChannels:s,sampleRate:t.process&&t.processedSampleRate?t.processedSampleRate:c,bitrate:i});if(!a.some(e=>ot.includes(e))&&u.some(e=>ot.includes(e))&&(s!==rd||c!==id)){let e=(await xu(u,{numberOfChannels:rd,sampleRate:id,bitrate:i})).find(e=>ot.includes(e));e&&(l=!0,n=e,s=rd,c=id)}else n=a[0]??null;if(n===null){this.discardedTracks.push({track:e,reason:`no_encodable_target_codec`});return}if(l)r=this._resampleAudio(e,t,n,s,c,i);else{let a=new Ru({codec:n,bitrate:i});r=a,this._trackPromises.push((async()=>{await this._started;let n=new kr(e);for await(let r of n.samples(void 0,this._endTimestamp)){if(this._canceled)return;await this._registerAudioSample(e,t,a,r),r.close()}a.close(),this._synchronizer.closeTrack(e.id)})())}}this.output.addAudioTrack(r,{languageCode:Oe(e.languageCode)?e.languageCode:void 0,name:e.name??void 0,disposition:e.disposition}),this._addedCounts.audio++,this._totalTrackCount++,this.utilizedTracks.push(e)}async _registerAudioSample(e,t,n,r){if(this._canceled)return;this._reportProgress(e.id,r.timestamp);let i;if(!t.process)i=[r];else{let e=t.process(r);if(e instanceof Promise&&(e=await e),Array.isArray(e)||(e=e===null?[]:[e]),!e.every(e=>e instanceof lr))throw TypeError(`The audio process function must return an AudioSample, null, or an array of AudioSamples.`);i=e}for(let t of i){if(this._canceled)break;await n.add(t),this._synchronizer.shouldWait(e.id,t.timestamp)&&await this._synchronizer.wait(t.timestamp)}for(let e of i)e!==r&&e.close()}_resampleAudio(e,t,n,r,i,a){let o=new Ru({codec:n,bitrate:a});return this._trackPromises.push((async()=>{await this._started;let n=new cd({targetNumberOfChannels:r,targetSampleRate:i,startTime:this._startTimestamp,endTime:this._endTimestamp,onSample:async n=>{await this._registerAudioSample(e,t,o,n),n.close()}}),a=new kr(e).samples(this._startTimestamp,this._endTimestamp);for await(let e of a){if(this._canceled)return;await n.add(e),e.close()}await n.finalize(),o.close(),this._synchronizer.closeTrack(e.id)})()),o}_reportProgress(e,t){if(!this._computeProgress)return;o(this._totalDuration!==null),this._maxTimestamps.set(e,Math.max(t,this._maxTimestamps.get(e)));let n=C(Math.min(...this._maxTimestamps.values())/this._totalDuration,0,1);n!==this._lastProgress&&(this._lastProgress=n,this.onProgress?.(n))}},od=5,sd=class{constructor(){this.maxTimestamps=new Map,this.resolvers=[]}computeMinAndMaybeResolve(){let e=1/0;for(let[,t]of this.maxTimestamps)e=Math.min(e,t);for(let t=0;t<this.resolvers.length;t++){let n=this.resolvers[t];n.timestamp-e<od&&(n.resolve(),this.resolvers.splice(t,1),t--)}return e}shouldWait(e,t){return this.maxTimestamps.set(e,Math.max(t,this.maxTimestamps.get(e)??-1/0)),t-this.computeMinAndMaybeResolve()>=od}wait(e){let{promise:t,resolve:n}=x();return this.resolvers.push({timestamp:e,resolve:n}),t}closeTrack(e){this.maxTimestamps.delete(e),this.computeMinAndMaybeResolve()}},cd=class{constructor(e){this.sourceSampleRate=null,this.sourceNumberOfChannels=null,this.targetSampleRate=e.targetSampleRate,this.targetNumberOfChannels=e.targetNumberOfChannels,this.startTime=e.startTime,this.endTime=e.endTime,this.onSample=e.onSample,this.bufferSizeInFrames=Math.floor(this.targetSampleRate*5),this.bufferSizeInSamples=this.bufferSizeInFrames*this.targetNumberOfChannels,this.outputBuffer=new Float32Array(this.bufferSizeInSamples),this.bufferStartFrame=0,this.maxWrittenFrame=-1}doChannelMixerSetup(){o(this.sourceNumberOfChannels!==null);let e=this.sourceNumberOfChannels,t=this.targetNumberOfChannels;e===1&&t===2?this.channelMixer=(t,n)=>t[n*e]:e===1&&t===4?this.channelMixer=(t,n,r)=>t[n*e]*+(r<2):e===1&&t===6?this.channelMixer=(t,n,r)=>t[n*e]*+(r===2):e===2&&t===1?this.channelMixer=(t,n)=>{let r=n*e;return .5*(t[r]+t[r+1])}:e===2&&t===4||e===2&&t===6?this.channelMixer=(t,n,r)=>t[n*e+r]*+(r<2):e===4&&t===1?this.channelMixer=(t,n)=>{let r=n*e;return .25*(t[r]+t[r+1]+t[r+2]+t[r+3])}:e===4&&t===2?this.channelMixer=(t,n,r)=>{let i=n*e;return .5*(t[i+r]+t[i+r+2])}:e===4&&t===6?this.channelMixer=(t,n,r)=>{let i=n*e;return r<2?t[i+r]:r===2||r===3?0:t[i+r-2]}:e===6&&t===1?this.channelMixer=(t,n)=>{let r=n*e;return Math.SQRT1_2*(t[r]+t[r+1])+t[r+2]+.5*(t[r+4]+t[r+5])}:e===6&&t===2?this.channelMixer=(t,n,r)=>{let i=n*e;return t[i+r]+Math.SQRT1_2*(t[i+2]+t[i+r+4])}:e===6&&t===4?this.channelMixer=(t,n,r)=>{let i=n*e;return r<2?t[i+r]+Math.SQRT1_2*t[i+2]:t[i+r+2]}:this.channelMixer=(t,n,r)=>r<e?t[n*e+r]:0}ensureTempBufferSize(e){let t=this.tempSourceBuffer.length;for(;t<e;)t*=2;if(t!==this.tempSourceBuffer.length){let e=new Float32Array(t);e.set(this.tempSourceBuffer),this.tempSourceBuffer=e}}async add(e){this.sourceSampleRate===null&&(this.sourceSampleRate=e.sampleRate,this.sourceNumberOfChannels=e.numberOfChannels,this.tempSourceBuffer=new Float32Array(this.sourceSampleRate*this.sourceNumberOfChannels),this.doChannelMixerSetup());let t=e.numberOfFrames*e.numberOfChannels;this.ensureTempBufferSize(t);let n=e.allocationSize({planeIndex:0,format:`f32`}),r=new Float32Array(this.tempSourceBuffer.buffer,0,n/4);e.copyTo(r,{planeIndex:0,format:`f32`});let i=e.timestamp-this.startTime,a=e.numberOfFrames/this.sourceSampleRate,s=Math.min(i+a,this.endTime-this.startTime),c=Math.floor(i*this.targetSampleRate),l=Math.ceil(s*this.targetSampleRate);for(let t=c;t<l;t++){if(t<this.bufferStartFrame)continue;for(;t>=this.bufferStartFrame+this.bufferSizeInFrames;)await this.finalizeCurrentBuffer(),this.bufferStartFrame+=this.bufferSizeInFrames;let n=t-this.bufferStartFrame;o(n<this.bufferSizeInFrames);let a=(t/this.targetSampleRate-i)*this.sourceSampleRate,s=Math.floor(a),c=Math.ceil(a),l=a-s;for(let t=0;t<this.targetNumberOfChannels;t++){let i=0,a=0;s>=0&&s<e.numberOfFrames&&(i=this.channelMixer(r,s,t)),c>=0&&c<e.numberOfFrames&&(a=this.channelMixer(r,c,t));let o=i+l*(a-i),u=n*this.targetNumberOfChannels+t;this.outputBuffer[u]+=o}this.maxWrittenFrame=Math.max(this.maxWrittenFrame,n)}}async finalizeCurrentBuffer(){if(this.maxWrittenFrame<0)return;let e=(this.maxWrittenFrame+1)*this.targetNumberOfChannels,t=new Float32Array(e);t.set(this.outputBuffer.subarray(0,e));let n=this.bufferStartFrame/this.targetSampleRate,r=new lr({format:`f32`,sampleRate:this.targetSampleRate,numberOfChannels:this.targetNumberOfChannels,timestamp:n,data:t});await this.onSample(r),this.outputBuffer.fill(0),this.maxWrittenFrame=-1}finalize(){return this.finalizeCurrentBuffer()}}})),ud=r({ADTS:()=>Eo,ALL_FORMATS:()=>Oo,ALL_TRACK_TYPES:()=>Zu,AUDIO_CODECS:()=>st,AdtsInputFormat:()=>vo,AdtsOutputFormat:()=>eu,AttachedFile:()=>$e,AudioBufferSink:()=>Ar,AudioBufferSource:()=>zu,AudioSample:()=>lr,AudioSampleSink:()=>kr,AudioSampleSource:()=>Ru,AudioSource:()=>Fu,BaseMediaSampleSink:()=>xr,BlobSource:()=>Fo,BufferSource:()=>Po,BufferTarget:()=>gl,CanvasSink:()=>Er,CanvasSource:()=>Nu,Conversion:()=>ad,CustomAudioDecoder:()=>Mn,CustomAudioEncoder:()=>Pn,CustomVideoDecoder:()=>jn,CustomVideoEncoder:()=>Nn,EncodedAudioPacketSource:()=>Iu,EncodedPacket:()=>D,EncodedPacketSink:()=>yr,EncodedVideoPacketSource:()=>ku,FLAC:()=>Do,FilePathSource:()=>zo,FilePathTarget:()=>vl,FlacInputFormat:()=>_o,FlacOutputFormat:()=>tu,Input:()=>Go,InputAudioTrack:()=>Pr,InputDisposedError:()=>Ko,InputFormat:()=>so,InputTrack:()=>Mr,InputVideoTrack:()=>Nr,IsobmffInputFormat:()=>co,IsobmffOutputFormat:()=>Kl,MATROSKA:()=>xo,MP3:()=>Co,MP4:()=>yo,MatroskaInputFormat:()=>fo,MediaSource:()=>Du,MediaStreamAudioTrackSource:()=>Bu,MediaStreamVideoTrackSource:()=>Pu,MkvOutputFormat:()=>Yl,MovOutputFormat:()=>Jl,Mp3InputFormat:()=>mo,Mp3OutputFormat:()=>Zl,Mp4InputFormat:()=>lo,Mp4OutputFormat:()=>ql,NON_PCM_AUDIO_CODECS:()=>ot,NullTarget:()=>yl,OGG:()=>To,OggInputFormat:()=>go,OggOutputFormat:()=>$l,Output:()=>$u,OutputFormat:()=>Gl,PCM_AUDIO_CODECS:()=>T,QTFF:()=>bo,QUALITY_HIGH:()=>pu,QUALITY_LOW:()=>du,QUALITY_MEDIUM:()=>fu,QUALITY_VERY_HIGH:()=>mu,QUALITY_VERY_LOW:()=>uu,Quality:()=>lu,QuickTimeInputFormat:()=>uo,ReadableStreamSource:()=>Vo,RichImageData:()=>Qe,SUBTITLE_CODECS:()=>ct,Source:()=>No,StreamSource:()=>Bo,StreamTarget:()=>_l,SubtitleSource:()=>Ju,Target:()=>hl,TextSubtitleSource:()=>Yu,UrlSource:()=>Ro,VIDEO_CODECS:()=>at,VIDEO_SAMPLE_PIXEL_FORMATS:()=>Qn,VideoSample:()=>er,VideoSampleColorSpace:()=>tr,VideoSampleSink:()=>Tr,VideoSampleSource:()=>Mu,VideoSource:()=>Ou,WAVE:()=>wo,WEBM:()=>So,WavOutputFormat:()=>Ql,WaveInputFormat:()=>ho,WebMInputFormat:()=>po,WebMOutputFormat:()=>Xl,canEncode:()=>hu,canEncodeAudio:()=>_u,canEncodeSubtitles:()=>vu,canEncodeVideo:()=>gu,getEncodableAudioCodecs:()=>xu,getEncodableCodecs:()=>yu,getEncodableSubtitleCodecs:()=>Su,getEncodableVideoCodecs:()=>bu,getFirstEncodableAudioCodec:()=>wu,getFirstEncodableSubtitleCodec:()=>Tu,getFirstEncodableVideoCodec:()=>Cu,registerDecoder:()=>zn,registerEncoder:()=>Bn}),dd=n((()=>{ed(),nu(),Xu(),E(),Eu(),bl(),Wo(),ko(),qo(),Fr(),Un(),hr(),jr(),ld(),Vn(),it()}));dd();let fd={mp4:`aac`,mov:`aac`,mkv:`opus`,webm:`opus`};function pd(e){return fd[e]}let md={sd:du,hd:fu,fhd:pu,"4k":mu},hd={sd:{width:854,height:480},hd:{width:1280,height:720},fhd:{width:1920,height:1080},"4k":{width:3840,height:2160}},gd=Object.freeze({format:`mp4`,fps:30,width:hd.fhd.width,height:hd.fhd.height,bitrate:md.fhd,audioCodec:`aac`,audioBitrate:96e3,watermark:{url:`https://avatars.githubusercontent.com/u/244247750?s=200&v=4`,opacity:1,position:`bottom-right`}});function _d(e){return{...gd,format:e,audioCodec:pd(e)}}function vd(e){let{preset:t,outputFormat:n,watermark:r}=e;if(!(t in md))throw Error(`Invalid preset: ${t}`);let{width:i,height:a}=hd[t],o=n||`mp4`,s=pd(o),c={format:o,width:i,height:a,bitrate:md[t],audioCodec:s,audioBitrate:128e3};return r&&(c.watermark={url:r.url,opacity:r.opacity,position:r.position}),c}let yd=new Map;function bd(e,t){return`${e}:${t}`}var xd=class e{constructor(e){if(this.cachedConfig=null,this.cacheTimestamp=0,this.fetchPromise=null,this.options=e,e.cacheTimeout!==void 0){if(typeof e.cacheTimeout!=`number`||e.cacheTimeout<=0)throw Error(`cacheTimeout must be a positive number`);this.cacheTimeout=e.cacheTimeout}else this.cacheTimeout=3e5}static getInstance(t){let n=bd(t.backendUrl,t.apiKey),r=yd.get(n);return r||(r=new e(t),yd.set(n,r)),r}async fetchConfig(){let e=Date.now();if(this.cachedConfig&&e-this.cacheTimestamp<this.cacheTimeout)return this.cachedConfig;if(this.fetchPromise)return this.fetchPromise;this.fetchPromise=this.fetchConfigFromBackend();try{let t=await this.fetchPromise;return this.cachedConfig=t,this.cacheTimestamp=e,this.fetchPromise=null,t}catch{return this.fetchPromise=null,gd}}clearCache(){let e=bd(this.options.backendUrl,this.options.apiKey);this.cachedConfig=null,this.cacheTimestamp=0,this.fetchPromise=null,yd.delete(e)}static clearAllInstances(){yd.clear()}getCurrentConfig(){if(!this.cachedConfig)throw Error(`No cached config available. Call fetchConfig() first.`);return this.cachedConfig}async fetchConfigFromBackend(){let e=`${this.options.backendUrl}/api/v1/videos/config`,t=await fetch(e,{method:`GET`,headers:{Authorization:`Bearer ${this.options.apiKey}`,"Content-Type":`application/json`}});if(!t.ok)throw Error(`Failed to fetch config: ${t.status} ${t.statusText}`);let n=await t.json();if(!n.presetEncoding)throw Error(`Invalid config response from backend: missing presetEncoding`);return vd({preset:n.presetEncoding,outputFormat:n.outputFormat,watermark:n.watermark})}},Sd=class{constructor(){this.configService=null,this.currentConfig=gd,this.configFetched=!1}async initialize(e,t){if(this.configService)return;if(!e)throw Error(`apiKey is required`);let n=t||`https://api.vidtreo.com`;this.configService=xd.getInstance({apiKey:e,backendUrl:n}),this.configService.fetchConfig().then(e=>{this.currentConfig=e,this.configFetched=!0}).catch(()=>{this.configFetched=!1})}async fetchConfig(){this.configService&&(this.currentConfig=await this.configService.fetchConfig(),this.configFetched=!0)}async getConfig(){return this.configService&&!this.configFetched&&await this.fetchConfig(),this.currentConfig}clearCache(){if(!this.configService)throw Error(`ConfigService is not initialized`);this.configService.clearCache()}},Cd=class{constructor(e,t){this.availableDevices={audioinput:[],videoinput:[]},this.selectedCameraDeviceId=null,this.selectedMicDeviceId=null,this.streamManager=e,this.callbacks=t}async getAvailableDevices(){return this.availableDevices=await this.streamManager.getAvailableDevices(),this.callbacks?.onDevicesChanged&&this.callbacks.onDevicesChanged(this.availableDevices),this.availableDevices}setCameraDevice(e){this.selectedCameraDeviceId=e,this.streamManager.setVideoDevice(e),this.callbacks?.onDeviceSelected&&this.callbacks.onDeviceSelected(`camera`,e)}setMicDevice(e){this.selectedMicDeviceId=e,this.streamManager.setAudioDevice(e),this.callbacks?.onDeviceSelected&&this.callbacks.onDeviceSelected(`mic`,e)}getSelectedCameraDeviceId(){return this.selectedCameraDeviceId}getSelectedMicDeviceId(){return this.selectedMicDeviceId}getAvailableDevicesList(){return this.availableDevices}};dd();async function wd(e){try{let t=new Fo(e),n=new Go({formats:[yo],source:t});if(typeof n.computeDuration!=`function`)throw Error(`computeDuration method is not available`);let r=await n.computeDuration();if(!r)throw Error(`Duration is missing from computeDuration`);if(r<=0)throw Error(`Invalid duration: must be greater than 0`);return r}catch{return Td(e)}}function Td(e){return new Promise((t,n)=>{let r=document.createElement(`video`),i=URL.createObjectURL(e),a=()=>{URL.revokeObjectURL(i)};r.addEventListener(`loadedmetadata`,()=>{a();let e=r.duration;if(!Number.isFinite(e)||e<=0){n(Error(`Invalid video duration`));return}t(e)}),r.addEventListener(`error`,()=>{a(),n(Error(`Failed to load video metadata`))}),r.src=i,r.load()})}let Ed=`pending-uploads`,Dd=`status`,Od=`createdAt`;var kd=class{constructor(){this.db=null}init(){return this.db?Promise.resolve():new Promise((e,t)=>{let n=indexedDB.open(`vidtreo-recorder`,1);n.onerror=()=>{n.error?t(n.error):t(Error(`Failed to open database`))},n.onsuccess=()=>{if(!n.result){t(Error(`Database result is null`));return}this.db=n.result,e()},n.onupgradeneeded=e=>{let n=e.target.result;if(!n){t(Error(`Database upgrade result is null`));return}if(!n.objectStoreNames.contains(Ed)){let e=n.createObjectStore(Ed,{keyPath:`id`});e.createIndex(Dd,Dd,{unique:!1}),e.createIndex(Od,Od,{unique:!1})}}})}isInitialized(){return this.db!==null}savePendingUpload(e){let t=this.generateUploadId(),n={...e,id:t,status:`pending`,retryCount:0,createdAt:Date.now(),updatedAt:Date.now()};return this.executeTransaction(`readwrite`,e=>{let r=e.add(n);return new Promise((e,n)=>{r.onsuccess=()=>e(t),r.onerror=()=>{r.error?r.error.name===`QuotaExceededError`?n(Error(`Storage quota exceeded. Please free up space or delete old uploads.`)):n(r.error):n(Error(`Failed to save upload`))}})})}getPendingUploads(e){return this.executeTransaction(`readonly`,t=>{let n=e?t.index(Dd).getAll(e):t.getAll();return new Promise((e,t)=>{n.onsuccess=()=>{if(n.result===void 0){t(Error(`Failed to get uploads: result is undefined`));return}e(n.result)},n.onerror=()=>{n.error?t(n.error):t(Error(`Failed to get uploads`))}})})}updateUploadStatus(e,t){return this.executeTransaction(`readwrite`,n=>{let r=n.get(e);return new Promise((e,i)=>{r.onsuccess=()=>{let a=r.result;if(!a){i(Error(`Upload not found`));return}let o={...a,...t,updatedAt:Date.now()},s=n.put(o);s.onsuccess=()=>e(),s.onerror=()=>{s.error?i(s.error):i(Error(`Failed to update upload`))}},r.onerror=()=>{r.error?i(r.error):i(Error(`Failed to get upload`))}})})}deleteUpload(e){return this.executeTransaction(`readwrite`,t=>{let n=t.delete(e);return new Promise((e,t)=>{n.onsuccess=()=>e(),n.onerror=()=>{n.error?t(n.error):t(Error(`Failed to delete upload`))}})})}async cleanupPermanentlyFailedUploads(e){let t=e===void 0?24:e;if(typeof t!=`number`||t<0)throw Error(`retentionHours must be a non-negative number`);let n=Date.now()-t*36e5,r=(await this.getPendingUploads()).filter(e=>e.status===`failed`&&e.retryCount>=10&&e.updatedAt<n);for(let e of r)await this.deleteUpload(e.id);return r.length}async getTotalStorageSize(){return(await this.getPendingUploads()).reduce((e,t)=>e+t.blob.size,0)}generateUploadId(){return`upload-${Date.now()}-${Math.random().toString(36).substring(2,11)}`}executeTransaction(e,t){if(!this.db)throw Error(`Database not initialized`);return t(this.db.transaction([Ed],e).objectStore(Ed))}},Ad=class{constructor(){this.storageService=null,this.cleanupIntervalId=null}async initialize(e){this.storageService||=new kd,this.storageService.isInitialized()||await this.storageService.init(),this.setupCleanupInterval(e)}setupCleanupInterval(e){this.cleanupIntervalId===null&&(this.cleanupIntervalId=window.setInterval(()=>{this.performCleanup().catch(t=>{e(i(t))})},36e5))}async performCleanup(){if(!this.storageService)throw Error(`StorageService not initialized`);await this.storageService.cleanupPermanentlyFailedUploads(24)}getStorageService(){return this.storageService}destroy(){this.cleanupIntervalId!==null&&(clearInterval(this.cleanupIntervalId),this.cleanupIntervalId=null)}};function jd(){let e=globalThis;if(e.__VIDTREO_DEBUG__===!0||e.__VIDTREO_DEV__===!0)return!0;let t=typeof process<`u`&&process?.env?`production`:void 0;return t===`development`||t===`test`||typeof localStorage<`u`&&localStorage.getItem(`VIDTREO_DEBUG`)===`true`}let Md=jd(),Nd={reset:`\x1B[0m`,bright:`\x1B[1m`,dim:`\x1B[2m`,red:`\x1B[31m`,green:`\x1B[32m`,yellow:`\x1B[33m`,blue:`\x1B[34m`,magenta:`\x1B[35m`,cyan:`\x1B[36m`,white:`\x1B[37m`,gray:`\x1B[90m`};function Pd(e,t,n){if(!Md)return``;let r=n?.prefix||`[${e.toUpperCase()}]`;return`${Nd[n?.color||Fd(e)]}${r}${Nd.reset} ${t}`}function Fd(e){switch(e){case`error`:return`red`;case`warn`:return`yellow`;case`info`:return`cyan`;case`debug`:return`gray`;default:return`white`}}function Id(e,t,...n){if(!Md)return;let r=Pd(e,t);console[e](r,...n)}let W={log:(e,...t)=>{Id(`log`,e,...t)},info:(e,...t)=>{Id(`info`,e,...t)},warn:(e,...t)=>{Id(`warn`,e,...t)},error:(e,...t)=>{Id(`error`,e,...t)},debug:(e,...t)=>{Id(`debug`,e,...t)},group:(e,t=`cyan`)=>{if(!Md)return;let n=Nd[t],r=Nd.reset;console.group(`${n}${e}${r}`)},groupEnd:()=>{Md&&console.groupEnd()}},Ld=`live`;var Rd=class{constructor(e,t={}){this.currentSourceType=`camera`,this.originalCameraStream=null,this.originalCameraConstraints=null,this.screenShareStream=null,this.screenShareTrackEndHandler=null,this.streamManager=e,this.callbacks=t}getCurrentSourceType(){return this.currentSourceType}getOriginalCameraStream(){return this.originalCameraStream}stopLiveTracks(e){for(let t of e)t.readyState===Ld&&t.stop()}stopStreamTracks(e){this.stopLiveTracks(e.getTracks())}stopStreamVideoTracks(e){this.stopLiveTracks(e.getVideoTracks())}isTrackLive(e){return e!==void 0&&e.readyState===Ld}areTracksLive(e,t){return this.isTrackLive(e)&&this.isTrackLive(t)}storeOriginalCameraConstraints(e){let t=e.getVideoTracks()[0];if(!t)return;let n=t.getSettings();this.originalCameraConstraints={width:n.width,height:n.height,aspectRatio:n.aspectRatio,frameRate:n.frameRate,deviceId:n.deviceId,facingMode:n.facingMode}}storeOriginalCameraStream(e){let t=e.getVideoTracks()[0],n=e.getAudioTracks()[0];this.areTracksLive(t,n)?this.originalCameraStream=new MediaStream([t,n]):this.originalCameraStream=e}createError(e){return e instanceof Error?e:Error(i(e))}waitForTracksToEnd(e){return new Promise(t=>{setTimeout(()=>{this.screenShareStream=null,t()},e)})}combineScreenShareWithOriginalAudio(e){let t=this.originalCameraStream?this.originalCameraStream.getAudioTracks()[0]:void 0;W.debug(`[SourceSwitchManager] combineScreenShareWithOriginalAudio`,{hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id,hasOriginalAudioTrack:!!t,originalAudioTrackId:t?.id,originalAudioTrackReadyState:t?.readyState,originalAudioTrackEnabled:t?.enabled,originalAudioTrackMuted:t?.muted,originalAudioTrackLabel:t?.label,isTrackLive:this.isTrackLive(t),screenVideoTrackId:e.id,screenVideoTrackReadyState:e.readyState});let n=[e];this.isTrackLive(t)&&t?(n.push(t),W.debug(`[SourceSwitchManager] Added original audio track to combined stream`,{audioTrackId:t.id,combinedTracksCount:n.length})):W.warn(`[SourceSwitchManager] Original audio track is not live, not adding to combined stream`,{audioTrackId:t?.id,audioTrackReadyState:t?.readyState,combinedTracksCount:n.length});let r=new MediaStream(n);return W.debug(`[SourceSwitchManager] Combined stream created`,{combinedStreamId:r.id,combinedStreamVideoTracksCount:r.getVideoTracks().length,combinedStreamAudioTracksCount:r.getAudioTracks().length,combinedStreamAudioTrackId:r.getAudioTracks()[0]?.id,combinedStreamAudioTrackReadyState:r.getAudioTracks()[0]?.readyState}),r}handleScreenSelectionError(){this.callbacks.onScreenSelectionEnd&&this.callbacks.onScreenSelectionEnd(),this.callbacks.onTransitionEnd&&this.callbacks.onTransitionEnd()}isPermissionDeniedError(e){let t=i(e);return t.includes(`NotAllowedError`)||t.includes(`AbortError`)||t.toLowerCase().includes(`permission denied`)||t.toLowerCase().includes(`user denied`)}async processScreenShareStream(e,t){this.screenShareStream=e;let n=e.getVideoTracks()[0];if(!n)throw this.stopStreamTracks(e),Error(`No video track found in screen share stream`);let r=this.combineScreenShareWithOriginalAudio(n);t&&t!==this.originalCameraStream&&this.stopStreamVideoTracks(t);let i=e.getAudioTracks();for(let e of i)e.stop();return this.currentSourceType=`screen`,this.callbacks.onSourceChange&&await this.callbacks.onSourceChange(this.currentSourceType),this.setupScreenShareTrackHandler(r),r}async switchToScreenCapture(){let e=this.streamManager.getStream();e&&(this.storeOriginalCameraConstraints(e),this.storeOriginalCameraStream(e)),this.callbacks.onTransitionStart&&this.callbacks.onTransitionStart(`Select screen to share...`),this.callbacks.onScreenSelectionStart&&this.callbacks.onScreenSelectionStart();try{let t=await navigator.mediaDevices.getDisplayMedia({video:!0,audio:!0});return await this.processScreenShareStream(t,e)}catch(e){if(this.handleScreenSelectionError(),this.isPermissionDeniedError(e))return null;throw e}}setupScreenShareTrackHandler(e){let t=e.getVideoTracks()[0];if(!t)throw Error(`No video track found in screen share stream`);let n=this.screenShareTrackEndHandler;if(n){let e=this.streamManager.getStream();if(e){let t=e.getVideoTracks()[0];t&&t.removeEventListener(`ended`,n)}}this.screenShareTrackEndHandler=async()=>{if(this.currentSourceType===`screen`)try{await this.switchToCamera()}catch(e){this.callbacks.onError&&this.callbacks.onError(this.createError(e))}},t.addEventListener(`ended`,this.screenShareTrackEndHandler)}removeScreenShareTrackHandler(e){if(!(this.screenShareTrackEndHandler&&e))return;let t=e.getVideoTracks()[0];t&&t.removeEventListener(`ended`,this.screenShareTrackEndHandler),this.screenShareTrackEndHandler=null}canReuseStream(e,t){if(!e||t&&e!==this.originalCameraStream)return!1;let n=e.getVideoTracks()[0],r=e.getAudioTracks()[0];return!(!this.areTracksLive(n,r)||this.callbacks.getSelectedCameraDeviceId&&this.callbacks.getSelectedCameraDeviceId()!==n.getSettings().deviceId)}canReuseOriginalStream(){return this.canReuseStream(this.originalCameraStream,!1)}canReuseManagerStream(){let e=this.streamManager.getStream();return e&&this.originalCameraStream?this.canReuseStream(e,!0):!1}getSelectedCameraDeviceId(){return this.callbacks.getSelectedCameraDeviceId?this.callbacks.getSelectedCameraDeviceId():this.streamManager.getVideoDevice()}getSelectedMicDeviceId(){return this.callbacks.getSelectedMicDeviceId?this.callbacks.getSelectedMicDeviceId():this.streamManager.getAudioDevice()}buildVideoConstraints(e){let t={};if(this.originalCameraConstraints){let{deviceId:e,...n}=this.originalCameraConstraints;Object.assign(t,n)}if(e)t.deviceId={exact:e};else if(!t.deviceId){let e=this.getSelectedCameraDeviceId();e&&(t.deviceId={exact:e})}return t}buildAudioConstraints(e){return e?{deviceId:{exact:e}}:!0}validateTrack(e,t,n){if(!this.isTrackLive(e)){this.stopStreamTracks(n);let r=e?e.readyState:`undefined`;throw Error(`Failed to get live camera ${t} track. ReadyState: ${r}`)}}async createCameraStreamWithOriginalAudio(e){let t=this.originalCameraStream?this.originalCameraStream.getAudioTracks()[0]:void 0;if(W.debug(`[SourceSwitchManager] createCameraStreamWithOriginalAudio`,{hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id,hasOriginalAudioTrack:!!t,originalAudioTrackId:t?.id,originalAudioTrackReadyState:t?.readyState,originalAudioTrackEnabled:t?.enabled,originalAudioTrackMuted:t?.muted,originalAudioTrackLabel:t?.label,isTrackLive:this.isTrackLive(t),cameraDeviceId:e}),!this.isTrackLive(t))return W.warn(`[SourceSwitchManager] Original audio track is not live, cannot reuse`,{originalAudioTrackId:t?.id,originalAudioTrackReadyState:t?.readyState}),null;let n=this.buildVideoConstraints(e),r={video:Object.keys(n).length>0?n:!0,audio:!1};W.debug(`[SourceSwitchManager] Requesting new video stream`,{constraints:r,cameraDeviceId:e});let i=await navigator.mediaDevices.getUserMedia(r),a=i.getVideoTracks()[0];this.validateTrack(a,`video`,i),W.debug(`[SourceSwitchManager] New video stream obtained`,{newStreamId:i.id,videoTrackId:a.id,videoTrackReadyState:a.readyState,newStreamAudioTracksCount:i.getAudioTracks().length});let o=[a];t&&o.push(t),W.debug(`[SourceSwitchManager] Creating combined stream with original audio`,{videoTrackId:a.id,audioTrackId:t?.id,audioTrackReadyState:t?.readyState,audioTrackEnabled:t?.enabled,audioTrackMuted:t?.muted,combinedTracksCount:o.length});let s=new MediaStream(o);this.stopLiveTracks(i.getAudioTracks());let c=this.originalCameraStream?.id;return this.originalCameraStream=s,W.debug(`[SourceSwitchManager] Combined stream created and assigned`,{combinedStreamId:s.id,previousOriginalCameraStreamId:c,newOriginalCameraStreamId:this.originalCameraStream.id,combinedStreamVideoTracksCount:s.getVideoTracks().length,combinedStreamAudioTracksCount:s.getAudioTracks().length,combinedStreamAudioTrackId:s.getAudioTracks()[0]?.id,combinedStreamAudioTrackReadyState:s.getAudioTracks()[0]?.readyState,audioTrackStillSame:s.getAudioTracks()[0]===t}),s}async createCameraStreamWithNewAudio(e){let t=this.getSelectedMicDeviceId(),n=this.buildVideoConstraints(e),r=this.buildAudioConstraints(t),i={video:Object.keys(n).length>0?n:!0,audio:r},a=await navigator.mediaDevices.getUserMedia(i),o=a.getVideoTracks()[0],s=a.getAudioTracks()[0];return this.validateTrack(o,`video`,a),this.validateTrack(s,`audio`,a),this.originalCameraStream=a,a}async createNewCameraStreamForRecording(){let e=this.getSelectedCameraDeviceId();return await this.createCameraStreamWithOriginalAudio(e)||this.createCameraStreamWithNewAudio(e)}async getCameraStream(){let e=this.streamManager.isRecording(),t=this.getSelectedCameraDeviceId(),n=this.getSelectedMicDeviceId();if(this.streamManager.setVideoDevice(t),this.streamManager.setAudioDevice(n),this.canReuseOriginalStream()){if(!this.originalCameraStream)throw Error(`Original camera stream is null`);return this.originalCameraStream}if(this.canReuseManagerStream()){let e=this.streamManager.getStream();if(!e)throw Error(`Manager stream is null`);return e}!e&&this.originalCameraStream&&(this.originalCameraStream=null);let r=this.streamManager.getStream();if(!e&&r&&r!==this.originalCameraStream&&(this.stopStreamTracks(r),this.streamManager.setMediaStream(null)),e)return this.streamManager.setVideoDevice(this.getSelectedCameraDeviceId()),this.streamManager.setAudioDevice(this.getSelectedMicDeviceId()),this.createNewCameraStreamForRecording();let i=await this.streamManager.startStream();return this.originalCameraStream=i,i}async switchToCamera(){let e=this.streamManager.isRecording();if(!(!e&&this.currentSourceType===`camera`))try{this.notifyTransitionStart(`Switching to camera...`),await this.handleScreenShareStop();let t=await this.getCameraStream();if(!t)throw Error(`Failed to get camera stream`);await this.applyCameraStream(t,e),this.notifyTransitionEnd()}catch(e){throw this.notifyTransitionEnd(),e}}notifyTransitionStart(e){this.callbacks.onTransitionStart&&this.callbacks.onTransitionStart(e)}notifyTransitionEnd(){this.callbacks.onTransitionEnd&&this.callbacks.onTransitionEnd()}stopScreenShareStreamTracks(e){let t=e.getVideoTracks(),n=e.getAudioTracks();W.debug(`[SourceSwitchManager] stopping screen share tracks`,{videoTracks:t.map(e=>({id:e.id,readyState:e.readyState,displaySurface:e.getSettings().displaySurface,constraints:e.getConstraints()})),audioTracks:n.map(e=>({id:e.id,readyState:e.readyState,constraints:e.getConstraints()}))});for(let e of t)e.stop();for(let e of n)e.stop()}stopDisplayTracks(e){if(e)for(let t of e.getVideoTracks())typeof t.getSettings().displaySurface==`string`&&t.readyState===Ld&&(W.debug(`[SourceSwitchManager] stopping display track`,{id:t.id,readyState:t.readyState,constraints:t.getConstraints(),settings:t.getSettings()}),t.stop())}async handleScreenShareStop(){if(this.currentSourceType!==`screen`)return;W.debug(`[SourceSwitchManager] handleScreenShareStop invoked`,{currentSourceType:this.currentSourceType,hasScreenShareStream:!!this.screenShareStream,screenShareStreamId:this.screenShareStream?.id,hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id});let e=this.screenShareStream,t=this.streamManager.getStream();if(W.debug(`[SourceSwitchManager] Current stream state before stop`,{currentStreamId:t?.id,currentStreamVideoTracksCount:t?.getVideoTracks().length,currentStreamAudioTracksCount:t?.getAudioTracks().length,currentStreamAudioTrackId:t?.getAudioTracks()[0]?.id,currentStreamAudioTrackReadyState:t?.getAudioTracks()[0]?.readyState,originalCameraStreamAudioTrackId:this.originalCameraStream?.getAudioTracks()[0]?.id,originalCameraStreamAudioTrackReadyState:this.originalCameraStream?.getAudioTracks()[0]?.readyState}),e){let t=e.getAudioTracks();W.debug(`[SourceSwitchManager] Screen share stream audio tracks before stop`,{screenShareStreamId:e.id,screenShareAudioTracksCount:t.length,screenShareAudioTrackIds:t.map(e=>({id:e.id,readyState:e.readyState,enabled:e.enabled}))}),this.removeScreenShareTrackHandler(e),this.stopScreenShareStreamTracks(e),this.stopDisplayTracks(e),this.screenShareStream=null,await this.waitForTracksToEnd(0),W.debug(`[SourceSwitchManager] Screen share stream stopped`,{screenShareAudioTracksAfterStop:t.map(e=>({id:e.id,readyState:e.readyState}))})}if(t){let e=t.getAudioTracks();W.debug(`[SourceSwitchManager] Current stream audio tracks before video stop`,{currentStreamId:t.id,currentStreamAudioTracksCount:e.length,currentStreamAudioTrackIds:e.map(e=>({id:e.id,readyState:e.readyState,enabled:e.enabled}))}),this.stopStreamVideoTracks(t),this.stopDisplayTracks(t),W.debug(`[SourceSwitchManager] Current stream audio tracks after video stop`,{currentStreamId:t.id,currentStreamAudioTracksCount:t.getAudioTracks().length,currentStreamAudioTrackIds:t.getAudioTracks().map(e=>({id:e.id,readyState:e.readyState,enabled:e.enabled}))})}W.debug(`[SourceSwitchManager] Original camera stream state before source change`,{hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id,originalCameraStreamAudioTracksCount:this.originalCameraStream?.getAudioTracks().length,originalCameraStreamAudioTrackId:this.originalCameraStream?.getAudioTracks()[0]?.id,originalCameraStreamAudioTrackReadyState:this.originalCameraStream?.getAudioTracks()[0]?.readyState,originalCameraStreamAudioTrackEnabled:this.originalCameraStream?.getAudioTracks()[0]?.enabled}),this.currentSourceType=`camera`,this.callbacks.onSourceChange&&await this.callbacks.onSourceChange(this.currentSourceType),W.debug(`[SourceSwitchManager] handleScreenShareStop completed`,{hasScreenShareStream:!!this.screenShareStream,currentSourceType:this.currentSourceType,hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id,originalCameraStreamAudioTracksCount:this.originalCameraStream?.getAudioTracks().length,originalCameraStreamAudioTrackId:this.originalCameraStream?.getAudioTracks()[0]?.id,originalCameraStreamAudioTrackReadyState:this.originalCameraStream?.getAudioTracks()[0]?.readyState})}async applyCameraStream(e,t){this.streamManager.setMediaStream(e);let n=this.currentSourceType!==`camera`;this.currentSourceType=`camera`,n&&this.callbacks.onSourceChange&&await this.callbacks.onSourceChange(this.currentSourceType),t&&await this.streamManager.switchVideoSource(e),this.callbacks.onPreviewUpdate&&await this.callbacks.onPreviewUpdate(e)}async toggleSource(){if(this.streamManager.isRecording())try{this.currentSourceType===`camera`?await this.switchToScreen():await this.switchToCamera()}catch(e){this.handleToggleError(e)}}async switchToScreen(){let e=await this.switchToScreenCapture();if(!e){this.notifyTransitionEnd();return}this.notifyTransitionStart(`Switching to screen...`),await this.streamManager.switchVideoSource(e),this.callbacks.onPreviewUpdate&&await this.callbacks.onPreviewUpdate(e),this.notifyTransitionEnd()}handleToggleError(e){this.notifyTransitionEnd();let t=i(e);t.includes(`NotAllowedError`)||t.includes(`AbortError`)?this.currentSourceType===`screen`&&this.switchToCamera().catch(e=>{this.callbacks.onError&&this.callbacks.onError(this.createError(e))}):this.callbacks.onError&&this.callbacks.onError(this.createError(e))}async handleRecordingStop(){if(this.currentSourceType!==`screen`){this.cleanup();return}try{let e=this.streamManager.getStream();e&&(this.removeScreenShareTrackHandler(e),this.stopStreamVideoTracks(e));let t=await this.getCameraStream();if(!t)throw Error(`Failed to get camera stream`);this.streamManager.setMediaStream(t),this.currentSourceType=`camera`,this.callbacks.onSourceChange&&await this.callbacks.onSourceChange(this.currentSourceType),this.callbacks.onPreviewUpdate&&await this.callbacks.onPreviewUpdate(t)}catch(e){throw this.callbacks.onError&&this.callbacks.onError(this.createError(e)),e}this.cleanup()}cleanup(){this.screenShareStream&&=(this.removeScreenShareTrackHandler(this.screenShareStream),this.stopScreenShareStreamTracks(this.screenShareStream),null);let e=this.streamManager.getStream();e&&this.removeScreenShareTrackHandler(e),this.screenShareTrackEndHandler=null,this.originalCameraStream=null,this.originalCameraConstraints=null}setCallbacks(e){this.callbacks={...this.callbacks,...e}}};let zd=Object.freeze({width:{ideal:gd.width||1920},height:{ideal:gd.height||1080},frameRate:{ideal:gd.fps||30}}),Bd=Object.freeze({video:zd,audio:!0});Object.freeze({mimeType:`video/webm;codecs=vp9,opus`});var Vd=class{constructor(e={}){this.mediaStream=null,this.state=`idle`,this.eventListeners=new Map,this.selectedAudioDeviceId=null,this.selectedVideoDeviceId=null,this.streamConfig={...Bd,...e}}getState(){return this.state}getStream(){return this.mediaStream}getAudioStreamForAnalysis(){return this.mediaStream&&this.mediaStream.getAudioTracks().length>0?this.mediaStream:null}isActive(){return this.state===`active`||this.state===`recording`}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set);let n=this.eventListeners.get(e);return n&&n.add(t),()=>{this.off(e,t)}}off(e,t){let n=this.eventListeners.get(e);n&&n.delete(t)}once(e,t){let n=(r=>{t(r),this.off(e,n)});return this.on(e,n)}emit(e,t){let n=this.eventListeners.get(e);if(n)for(let e of n)try{e(t)}catch{}}setState(e){if(this.state===e)return;let t=this.state;this.state=e,this.emit(`statechange`,{state:e,previousState:t})}setAudioDevice(e){this.selectedAudioDeviceId=e}setVideoDevice(e){this.selectedVideoDeviceId=e}getAudioDevice(){return this.selectedAudioDeviceId}getVideoDevice(){return this.selectedVideoDeviceId}async getAvailableDevices(){try{let e=await navigator.mediaDevices.enumerateDevices();return{audioinput:e.filter(e=>e.kind===`audioinput`),videoinput:e.filter(e=>e.kind===`videoinput`)}}catch(e){throw Error(`Failed to enumerate devices: ${i(e)}`)}}buildDeviceConstraints(e,t){return e?typeof t==`object`?{...t,deviceId:{exact:e}}:{deviceId:{exact:e}}:t}buildVideoConstraints(e){return this.buildDeviceConstraints(e,this.streamConfig.video)}buildAudioConstraints(e){return this.buildDeviceConstraints(e,this.streamConfig.audio)}async startStream(){if(W.debug(`[StreamManager] startStream called`,{hasExistingStream:!!this.mediaStream,selectedVideoDeviceId:this.selectedVideoDeviceId,selectedAudioDeviceId:this.selectedAudioDeviceId}),this.mediaStream){let e=this.mediaStream.getVideoTracks()[0];if(this.selectedVideoDeviceId===null)if(e?.getSettings?.()?.deviceId)W.debug(`[StreamManager] Stopping existing stream to recreate`),this.stopStream();else return W.debug(`[StreamManager] Reusing existing stream`),this.mediaStream;if(e?.getSettings&&e.getSettings().deviceId===this.selectedVideoDeviceId)return W.debug(`[StreamManager] Existing stream matches device, reusing`),this.mediaStream;W.debug(`[StreamManager] Device changed, stopping existing stream`),this.stopStream()}this.setState(`starting`),W.debug(`[StreamManager] State set to 'starting'`);try{W.debug(`[StreamManager] Building constraints`,{selectedVideoDeviceId:this.selectedVideoDeviceId,selectedAudioDeviceId:this.selectedAudioDeviceId});let e={video:this.buildVideoConstraints(this.selectedVideoDeviceId),audio:this.buildAudioConstraints(this.selectedAudioDeviceId)};return W.debug(`[StreamManager] Requesting media stream with constraints`,{hasVideo:!!e.video,hasAudio:!!e.audio}),this.mediaStream=await navigator.mediaDevices.getUserMedia(e),W.info(`[StreamManager] Media stream obtained`,{streamId:this.mediaStream.id,videoTracks:this.mediaStream.getVideoTracks().length,audioTracks:this.mediaStream.getAudioTracks().length}),this.setState(`active`),W.debug(`[StreamManager] State set to 'active'`),W.debug(`[StreamManager] Emitting streamstart event`),this.emit(`streamstart`,{stream:this.mediaStream}),this.mediaStream}catch(e){let t=e instanceof Error?e:Error(i(e));throw W.error(`[StreamManager] Failed to start stream`,t),this.setState(`error`),this.emit(`error`,{error:t}),t}}stopStream(){if(this.mediaStream){for(let e of this.mediaStream.getTracks())e.stop();this.mediaStream=null}this.state!==`idle`&&(this.setState(`idle`),this.emit(`streamstop`,void 0))}stopStreamTracks(e){for(let t of e.getTracks())t.stop()}isTrackLive(e){return e!==void 0&&e.readyState===`live`}async tryReplaceTrack(e,t,n){let r=e.replaceTrack;if(typeof r!=`function`)return!1;try{await r.call(e,t),e.stop();for(let e of n.getTracks())e!==t&&e.stop();return t.stop(),!0}catch{return!1}}recreateStreamWithNewTrack(e,t,n){for(let t of n.getTracks())t!==e&&t.stop();let r=[e];this.isTrackLive(t)&&t&&r.push(t);let i=new MediaStream(r);if(this.mediaStream)for(let e of this.mediaStream.getTracks())e!==t&&e.stop();return i}async switchDeviceTrack(e,t,n){if(!this.mediaStream)throw Error(`No active stream to switch device`);let r=t===`video`?this.mediaStream.getVideoTracks()[0]:this.mediaStream.getAudioTracks()[0],i=t===`video`?this.mediaStream.getAudioTracks()[0]:this.mediaStream.getVideoTracks()[0];if(!r){let e=t===`video`?`video`:`audio`;throw Error(`No ${e} track in current stream`)}let a={[t]:this.buildDeviceConstraints(e,n)},o=await navigator.mediaDevices.getUserMedia(a),s=t===`video`?o.getVideoTracks()[0]:o.getAudioTracks()[0];if(!s){this.stopStreamTracks(o);let e=t===`video`?`video`:`audio`;throw Error(`Failed to get new ${e} track`)}return await this.tryReplaceTrack(r,s,o)||(r.stop(),this.mediaStream=this.recreateStreamWithNewTrack(s,i,o)),t===`video`?(this.selectedVideoDeviceId=e,this.emit(`videosourcechange`,{stream:this.mediaStream})):this.selectedAudioDeviceId=e,this.mediaStream}switchVideoDevice(e){return this.switchDeviceTrack(e,`video`,this.streamConfig.video)}switchAudioDevice(e){return this.switchDeviceTrack(e,`audio`,this.streamConfig.audio)}setMediaStream(e){this.mediaStream=e}setAudioTracksEnabled(e){if(!this.mediaStream)return;let t=this.mediaStream.getAudioTracks();for(let n of t)n.enabled=e}destroy(){this.stopStream(),this.eventListeners.clear(),this.setState(`idle`)}};let Hd=[`Bytes`,`KB`,`MB`,`GB`],Ud=1024;function Wd(e){if(e===0)return`0 Bytes`;let t=Math.floor(Math.log(e)/Math.log(Ud));return`${Math.round(e/Ud**t*100)/100} ${Hd[t]}`}function Gd(e){let t=Math.floor(e/3600),n=Math.floor(e%3600/60),r=e%60;return t>0?`${t.toString().padStart(2,`0`)}:${n.toString().padStart(2,`0`)}:${r.toString().padStart(2,`0`)}`:`${n.toString().padStart(2,`0`)}:${r.toString().padStart(2,`0`)}`}var Kd=class{constructor(){this.recordingStartTime=0,this.totalPausedTime=0,this.pauseStartTime=null,this.intervals=[],this.currentIntervalStart=null,this.isTracking=!1,this.visibilityChangeHandler=this.handleVisibilityChange.bind(this),this.blurHandler=this.handleBlur.bind(this),this.focusHandler=this.handleFocus.bind(this)}start(e){this.isTracking||(this.recordingStartTime=e,this.totalPausedTime=0,this.pauseStartTime=null,this.intervals=[],this.currentIntervalStart=null,this.isTracking=!0,typeof document<`u`&&document.addEventListener(`visibilitychange`,this.visibilityChangeHandler),typeof window<`u`&&(window.addEventListener(`blur`,this.blurHandler),window.addEventListener(`focus`,this.focusHandler)),this.checkInitialState())}pause(){!this.isTracking||this.pauseStartTime!==null||(this.pauseStartTime=Date.now(),this.endCurrentIntervalIfActive())}resume(){if(!this.isTracking||this.pauseStartTime===null)return;let e=Date.now()-this.pauseStartTime;this.totalPausedTime+=e,this.pauseStartTime=null}getIntervals(){return this.endCurrentIntervalIfActive(),this.intervals.map(e=>({start:this.normalizeTimestamp(e.start),end:this.normalizeTimestamp(e.end)}))}reset(){this.intervals=[],this.currentIntervalStart=null,this.totalPausedTime=0,this.pauseStartTime=null}cleanup(){this.isTracking=!1,this.endCurrentIntervalIfActive(),typeof document<`u`&&document.removeEventListener(`visibilitychange`,this.visibilityChangeHandler),typeof window<`u`&&(window.removeEventListener(`blur`,this.blurHandler),window.removeEventListener(`focus`,this.focusHandler)),this.reset()}checkInitialState(){typeof document>`u`||document.visibilityState===`hidden`&&this.startInterval()}handleVisibilityChange(){typeof document>`u`||(document.visibilityState===`hidden`?this.startInterval():this.endCurrentIntervalIfActive())}handleBlur(){this.startInterval()}handleFocus(){this.endCurrentIntervalIfActive()}startInterval(){this.currentIntervalStart!==null||!this.isTracking||this.pauseStartTime===null&&(this.currentIntervalStart=Date.now())}endCurrentIntervalIfActive(){if(this.currentIntervalStart===null)return;let e=Date.now(),t=this.currentIntervalStart;e>t&&this.intervals.push({start:t,end:e}),this.currentIntervalStart=null}normalizeTimestamp(e){let t=(e-this.recordingStartTime-this.totalPausedTime)/1e3;return Math.max(0,t)}};function qd(e,t){if(e==null)throw Error(t);return e}function Jd(e,t=`StreamProcessor`){if(!e)throw Error(`${t} is required`);return e}let Yd=1e3;var Xd=class{constructor(e){this.recordingStartTime=0,this.recordingTimer=null,this.pauseStartTime=null,this.totalPausedTime=0,this.streamProcessor=null,this.bufferSizeUpdateInterval=null,this.tabVisibilityTracker=null,this.visibilityChangeHandler=null,this.blurHandler=null,this.focusHandler=null,this.streamManager=e}isRecording(){return this.streamManager.getState()===`recording`}getStreamProcessor(){return this.streamProcessor}getAudioStreamForAnalysis(){if(this.streamProcessor){let e=this.streamProcessor.getAudioStreamForAnalysis();if(e)return e}return this.streamManager.getAudioStreamForAnalysis()}async startRecording(e,t,n,r){let i=this.streamManager.getStream();if(W.debug(`[StreamRecordingState] startRecording called`,{hasMediaStream:!!i,isRecording:this.isRecording(),hasProcessor:!!e,audioTracks:i?.getAudioTracks().length||0}),!i)throw Error(`Stream must be started before recording`);if(this.isRecording())return W.debug(`[StreamRecordingState] Already recording, returning`),Promise.resolve();this.streamProcessor=e,W.debug(`[StreamRecordingState] StreamProcessor assigned, setting callbacks`),e.setOnMuteStateChange(e=>{this.streamManager.emit(`audiomutetoggle`,{muted:e})}),e.setOnSourceChange(e=>{this.streamManager.emit(`videosourcechange`,{stream:e})}),this.bufferSizeUpdateInterval=window.setInterval(()=>{if(!this.streamProcessor)return;let e=this.streamProcessor.getBufferSize(),t=Wd(e);this.streamManager.emit(`recordingbufferupdate`,{size:e,formatted:t})},Yd),this.resetRecordingState();let a=n&&r?{enabled:!0,text:r,recordingStartTime:this.recordingStartTime}:void 0;W.debug(`[StreamRecordingState] Overlay config`,{enableTabVisibilityOverlay:n,hasOverlayText:!!r,overlayText:r,overlayConfig:a}),W.debug(`[StreamRecordingState] Starting processing`),await e.startProcessing(i,t,a),W.info(`[StreamRecordingState] Processing started and worker ready`),n&&(W.debug(`[StreamRecordingState] Setting up tab visibility tracking`,{recordingStartTime:this.recordingStartTime}),this.tabVisibilityTracker=new Kd,this.tabVisibilityTracker.start(this.recordingStartTime),this.setupVisibilityUpdates(e)),this.streamManager.setState(`recording`),this.streamManager.emit(`recordingstart`,{recorder:null}),this.startRecordingTimer()}async stopRecording(){if(W.debug(`[StreamRecordingState] stopRecording called`,{hasStreamProcessor:!!this.streamProcessor,isRecording:this.isRecording()}),!(this.streamProcessor&&this.isRecording()))throw Error(`Not currently recording`);this.streamManager.setState(`stopping`),this.clearRecordingTimer(),this.clearBufferSizeInterval(),this.resetPauseState(),this.cleanupVisibilityUpdates();let e=[];this.tabVisibilityTracker?(e=this.tabVisibilityTracker.getIntervals(),W.debug(`[StreamRecordingState] Tab visibility intervals collected`,{intervalsCount:e.length,intervals:e}),this.tabVisibilityTracker.cleanup(),this.tabVisibilityTracker=null):W.debug(`[StreamRecordingState] No tab visibility tracker was active`),W.debug(`[StreamRecordingState] Finalizing stream processor`);let t=await this.streamProcessor.finalize();return W.info(`[StreamRecordingState] Stream processor finalized`,{blobSize:t.blob.size,hasBlob:!!t.blob}),this.streamManager.setState(`active`),this.streamManager.emit(`recordingstop`,{blob:t.blob,mimeType:`video/mp4`}),this.streamProcessor=null,W.debug(`[StreamRecordingState] StreamProcessor cleared`),{blob:t.blob,tabVisibilityIntervals:e}}pauseRecording(){this.clearRecordingTimer(),this.pauseStartTime===null&&(this.pauseStartTime=Date.now()),this.tabVisibilityTracker&&this.tabVisibilityTracker.pause(),this.streamProcessor&&this.isRecording()&&this.streamProcessor.pause()}resumeRecording(){if(this.pauseStartTime!==null){let e=Date.now()-this.pauseStartTime;this.totalPausedTime+=e,this.pauseStartTime=null}this.tabVisibilityTracker&&this.tabVisibilityTracker.resume(),this.startRecordingTimer(),this.streamProcessor&&this.isRecording()&&this.streamProcessor.resume()}toggleMute(){Jd(this.streamProcessor,`StreamProcessor`).toggleMute()}muteAudio(){this.streamProcessor?(this.streamProcessor.isMutedState()||this.streamProcessor.toggleMute(),this.streamManager.setAudioTracksEnabled(!1)):this.streamManager.getStream()&&(this.streamManager.setAudioTracksEnabled(!1),this.streamManager.emit(`audiomutetoggle`,{muted:!0}))}unmuteAudio(){this.streamProcessor?(this.streamProcessor.isMutedState()&&this.streamProcessor.toggleMute(),this.streamManager.setAudioTracksEnabled(!0)):this.streamManager.getStream()&&(this.streamManager.setAudioTracksEnabled(!0),this.streamManager.emit(`audiomutetoggle`,{muted:!1}))}isMuted(){if(this.streamProcessor)return this.streamProcessor.isMutedState();let e=this.streamManager.getStream();if(e){let t=e.getAudioTracks();return t.length>0&&t.every(e=>!e.enabled)}return!1}async switchVideoSource(e){await Jd(this.streamProcessor,`StreamProcessor`).switchVideoSource(e)}getCurrentVideoSource(){return qd(Jd(this.streamProcessor,`StreamProcessor`).getCurrentVideoSource(),`Current video source is not available`)}formatTimeElapsed(e){let t=Math.floor(e/60),n=Math.floor(e%60);return`${t.toString().padStart(2,`0`)}:${n.toString().padStart(2,`0`)}`}startRecordingTimer(){this.recordingTimer=window.setInterval(()=>{let e=(Date.now()-this.recordingStartTime-this.totalPausedTime)/1e3,t=this.formatTimeElapsed(e);this.streamManager.emit(`recordingtimeupdate`,{elapsed:e,formatted:t})},Yd)}clearRecordingTimer(){this.recordingTimer!==null&&(clearInterval(this.recordingTimer),this.recordingTimer=null)}clearBufferSizeInterval(){this.bufferSizeUpdateInterval!==null&&(clearInterval(this.bufferSizeUpdateInterval),this.bufferSizeUpdateInterval=null)}resetRecordingState(){this.recordingStartTime=performance.now(),this.totalPausedTime=0,this.pauseStartTime=null}resetPauseState(){this.totalPausedTime=0,this.pauseStartTime=null}setupVisibilityUpdates(e){if(typeof document>`u`||typeof window>`u`){W.warn(`[StreamRecordingState] Cannot setup visibility updates - document/window not available`);return}if(this.visibilityChangeHandler=()=>{if(typeof document>`u`)return;let t=document.visibilityState===`hidden`,n=performance.now();W.debug(`[StreamRecordingState] Visibility change`,{isHidden:t,timestamp:n,visibilityState:document.visibilityState}),e.updateTabVisibility(t,n)},this.blurHandler=()=>{let t=performance.now();W.debug(`[StreamRecordingState] Window blur`,{timestamp:t}),e.updateTabVisibility(!0,t)},this.focusHandler=()=>{let t=performance.now();W.debug(`[StreamRecordingState] Window focus`,{timestamp:t}),e.updateTabVisibility(!1,t)},document.addEventListener(`visibilitychange`,this.visibilityChangeHandler),window.addEventListener(`blur`,this.blurHandler),window.addEventListener(`focus`,this.focusHandler),document.visibilityState===`hidden`){let t=performance.now();W.debug(`[StreamRecordingState] Initial state is hidden`,{timestamp:t}),e.updateTabVisibility(!0,t)}else W.debug(`[StreamRecordingState] Initial state is visible`)}cleanupVisibilityUpdates(){this.visibilityChangeHandler&&typeof document<`u`&&(document.removeEventListener(`visibilitychange`,this.visibilityChangeHandler),this.visibilityChangeHandler=null),this.blurHandler&&typeof window<`u`&&(window.removeEventListener(`blur`,this.blurHandler),this.blurHandler=null),this.focusHandler&&typeof window<`u`&&(window.removeEventListener(`focus`,this.focusHandler),this.focusHandler=null)}destroy(){this.streamProcessor&&=(this.streamProcessor.cancel().catch(()=>{}),null),this.cleanupVisibilityUpdates(),this.tabVisibilityTracker&&=(this.tabVisibilityTracker.cleanup(),null),this.clearRecordingTimer(),this.clearBufferSizeInterval()}},Zd=class{constructor(e={}){this.streamManager=new Vd(e),this.recordingState=new Xd(this.streamManager)}getState(){return this.streamManager.getState()}getStream(){return this.streamManager.getStream()}getAudioStreamForAnalysis(){return this.recordingState.getAudioStreamForAnalysis()}isRecording(){return this.recordingState.isRecording()}isActive(){return this.streamManager.isActive()}on(e,t){return this.streamManager.on(e,t)}off(e,t){this.streamManager.off(e,t)}once(e,t){return this.streamManager.once(e,t)}setAudioDevice(e){this.streamManager.setAudioDevice(e)}setVideoDevice(e){this.streamManager.setVideoDevice(e)}getAudioDevice(){return this.streamManager.getAudioDevice()}getVideoDevice(){return this.streamManager.getVideoDevice()}async getAvailableDevices(){return await this.streamManager.getAvailableDevices()}async startStream(){return await this.streamManager.startStream()}stopStream(){this.streamManager.stopStream()}switchVideoDevice(e){return this.streamManager.switchVideoDevice(e)}switchAudioDevice(e){return this.streamManager.switchAudioDevice(e)}async startRecording(e,t,n,r){return await this.recordingState.startRecording(e,t,n,r)}async stopRecording(){return await this.recordingState.stopRecording()}pauseRecording(){this.recordingState.pauseRecording()}resumeRecording(){this.recordingState.resumeRecording()}toggleMute(){this.recordingState.toggleMute()}muteAudio(){this.recordingState.muteAudio()}unmuteAudio(){this.recordingState.unmuteAudio()}isMuted(){return this.recordingState.isMuted()}async switchVideoSource(e){return await this.recordingState.switchVideoSource(e)}setMediaStream(e){this.streamManager.setMediaStream(e)}getCurrentVideoSource(){return this.recordingState.getCurrentVideoSource()}destroy(){this.recordingState.destroy(),this.streamManager.destroy()}},Qd=class{constructor(e,t){this.isProcessing=!1,this.retryTimeoutId=null,this.callbacks={},this.storageService=e,this.uploadService=t,this.networkOnlineHandler=()=>{this.processQueue().catch(e=>{let t=i(e);this.callbacks.onUploadError?.(`network-recovery`,Error(t))})},window.addEventListener(`online`,this.networkOnlineHandler),this.processingIntervalId=window.setInterval(()=>{this.processQueue().catch(e=>{let t=i(e);this.callbacks.onUploadError?.(`processing-loop`,Error(t))})},5e3)}destroy(){this.clearTimer(this.processingIntervalId,clearInterval),this.clearTimer(this.retryTimeoutId,clearTimeout),window.removeEventListener(`online`,this.networkOnlineHandler)}setCallbacks(e){this.callbacks=e}async queueUpload(e){let t=await this.storageService.savePendingUpload(e);return this.processQueue(),t}async processQueue(){if(!this.isProcessing){this.isProcessing=!0;try{if(!this.storageService.isInitialized())throw Error(`Database not initialized`);let e=await this.storageService.getPendingUploads(`pending`);if(e.length>0){let t=this.getOldestUpload(e);await this.processUpload(t),this.isProcessing=!1;return}let t=(await this.storageService.getPendingUploads(`failed`)).filter(e=>e.retryCount<10);if(t.length>0){let e=this.getOldestFailedUpload(t),n=this.calculateRetryDelay(e.retryCount),r=Date.now()-e.updatedAt;if(r>=n)await this.storageService.updateUploadStatus(e.id,{status:`pending`,retryCount:e.retryCount}),await this.processUpload(e);else{let e=n-r;this.scheduleRetry(e)}}this.isProcessing=!1}catch(e){throw this.isProcessing=!1,Error(`Error processing upload queue: ${i(e)}`)}}}getPendingUploads(){return this.storageService.getPendingUploads()}async getStats(){let e=await this.storageService.getPendingUploads(),t={pending:0,uploading:0,failed:0,total:e.length};for(let n of e)n.status===`pending`?t.pending+=1:n.status===`uploading`?t.uploading+=1:n.status===`failed`&&(t.failed+=1);return t}getOldestUpload(e){if(e.length===0)throw Error(`Cannot get oldest upload from empty array`);return e.sort((e,t)=>e.createdAt-t.createdAt)[0]}getOldestFailedUpload(e){if(e.length===0)throw Error(`Cannot get oldest failed upload from empty array`);return e.sort((e,t)=>e.updatedAt-t.updatedAt)[0]}async processUpload(e){try{await this.storageService.updateUploadStatus(e.id,{status:`uploading`});let t=await this.uploadService.uploadVideo(e.blob,{apiKey:e.apiKey,backendUrl:e.backendUrl,filename:e.filename,duration:e.duration,metadata:e.metadata,userMetadata:e.userMetadata,onProgress:t=>{this.callbacks.onUploadProgress?.(e.id,t)}});await this.storageService.deleteUpload(e.id),this.callbacks.onUploadComplete?.(e.id,t)}catch(t){let n=i(t),r=e.retryCount+1;if(await this.storageService.updateUploadStatus(e.id,{status:`failed`,retryCount:r,lastError:n}),r>=10)this.callbacks.onUploadError?.(e.id,Error(`Upload failed after 10 attempts: ${n}`));else{let e=this.calculateRetryDelay(r);this.scheduleRetry(e)}}}calculateRetryDelay(e){let t=2e3*1.5**(e-1);return Math.min(t,3e5)}scheduleRetry(e){this.clearTimer(this.retryTimeoutId,clearTimeout),this.retryTimeoutId=window.setTimeout(()=>{this.retryTimeoutId=null,this.processQueue()},e)}clearTimer(e,t){e!==null&&t(e)}},$d=class{async uploadVideo(e,t){if(!t.filename)throw Error(`Filename is required`);if(!e.type||e.type.trim()===``)throw Error(`Blob type is required`);let n=await this.initVideoUpload({apiKey:t.apiKey,backendUrl:t.backendUrl,filename:t.filename,fileSize:e.size,mimeType:e.type,metadata:t.metadata,userMetadata:t.userMetadata});return this.uploadVideoFile(e,n.uploadUrl,{apiKey:t.apiKey,duration:t.duration,onProgress:t.onProgress})}async initVideoUpload(e){let t=`${e.backendUrl}/api/v1/videos/init`,n={filename:e.filename,fileSize:e.fileSize,mimeType:e.mimeType,preProcessed:!0};e.metadata&&(n.metadata=e.metadata),e.userMetadata&&(n.userMetadata=e.userMetadata);let r=await fetch(t,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(n)});if(!r.ok){let e=await this.extractErrorFromResponse(r,`Failed to initialize video upload`);throw Error(e)}return await r.json()}async extractErrorFromResponse(e,t){let n=await this.parseJsonResponse(e);return n&&typeof n==`object`&&`error`in n&&typeof n.error==`string`?n.error:`${t}: ${e.status} ${e.statusText}`}async parseJsonResponse(e){let t=await e.json();return typeof t==`object`&&t?t:null}uploadVideoFile(e,t,n){return new Promise((r,i)=>{let a=new XMLHttpRequest;if(n.onProgress){let e=n.onProgress;a.upload.addEventListener(`progress`,t=>{t.lengthComputable&&e(t.loaded/t.total)})}a.addEventListener(`load`,()=>{if(a.status>=200&&a.status<=299){this.parseSuccessResponse(a,r,i);return}this.parseErrorResponse(a,i)}),a.addEventListener(`error`,()=>{i(Error(`Network error during upload`))}),a.addEventListener(`abort`,()=>{i(Error(`Upload was aborted`))}),a.open(`PUT`,t),a.setRequestHeader(`Authorization`,`Bearer ${n.apiKey}`),a.setRequestHeader(`Content-Type`,e.type),n.duration!==void 0&&a.setRequestHeader(`X-Video-Duration`,n.duration.toString()),a.send(e)})}parseSuccessResponse(e,t,n){let r=this.safeParseJsonFromXhr(e);if(!r){n(Error(`Failed to parse upload response: invalid JSON`));return}t(r)}parseErrorResponse(e,t){let n=this.safeParseJsonFromXhr(e);if(n&&typeof n==`object`&&`error`in n&&typeof n.error==`string`){t(Error(n.error));return}t(Error(`Upload failed: ${e.status} ${e.statusText}`))}safeParseJsonFromXhr(e){if(!e.responseText||e.responseText.trim()===``)return null;let t=e.responseText.trim();if(!(t.startsWith(`{`)&&t.endsWith(`}`))||t.length<2)return null;let n=JSON.parse(e.responseText);return typeof n==`object`&&n?n:null}};function ef(e){let t=e.getVideoTracks();if(t.length===0)return!1;let n=t[0];return`displaySurface`in n.getSettings()||n.label.toLowerCase().includes(`screen`)||n.label.toLowerCase().includes(`display`)}dd();function tf(e){if(e!==void 0)return typeof e==`number`?e:e===du?`low`:e===fu?`medium`:e===pu?`high`:e===mu?`very-high`:`high`}async function nf(e,t,n){try{let{canEncodeVideo:r}=await Promise.resolve().then(()=>(dd(),ud));if(typeof r==`function`){let i={};if(e!==void 0&&(i.width=e),t!==void 0&&(i.height=t),n!==void 0&&(i.bitrate=n),await r(`hevc`,i))return`hevc`}}catch{}return`avc`}let rf=null;function af(){if(rf)return rf;if(typeof Blob>`u`||typeof URL>`u`)throw Error(`Blob and URL APIs are required for worker loading`);let e=new Blob([`// ../../node_modules/mediabunny/dist/modules/src/misc.js
|
|
107
|
+
`+this._getInvalidityExplanation().join(``));if(this._executed)throw Error(`Conversion cannot be executed twice.`);if(this._executed=!0,this.onProgress){this._computeProgress=!0,this._totalDuration=Math.min(await this.input.computeDuration()-this._startTimestamp,this._endTimestamp-this._startTimestamp);for(let e of this.utilizedTracks)this._maxTimestamps.set(e.id,0);this.onProgress?.(0)}await this.output.start(),this._start();try{await Promise.all(this._trackPromises)}catch(e){throw this._canceled||this.cancel(),e}this._canceled&&await new Promise(()=>{}),await this.output.finalize(),this._computeProgress&&this.onProgress?.(1)}async cancel(){if(!(this.output.state===`finalizing`||this.output.state===`finalized`)){if(this._canceled){console.warn(`Conversion already canceled.`);return}this._canceled=!0,await this.output.cancel()}}async _processVideoTrack(e,t){let n=e.codec;if(!n){this.discardedTracks.push({track:e,reason:`unknown_source_codec`});return}let r,i=s(e.rotation+(t.rotate??0)),a=this.output.format.supportsVideoRotationMetadata&&(t.allowRotationMetadata??!0),[c,l]=i%180==0?[e.codedWidth,e.codedHeight]:[e.codedHeight,e.codedWidth],u=t.crop;u&&rr(u,c,l);let[d,f]=u?[u.width,u.height]:[c,l],p=d,m=f,h=p/m,g=e=>Math.ceil(e/2)*2;t.width!==void 0&&t.height===void 0?(p=g(t.width),m=g(Math.round(p/h))):t.width===void 0&&t.height!==void 0?(m=g(t.height),p=g(Math.round(m*h))):t.width!==void 0&&t.height!==void 0&&(p=g(t.width),m=g(t.height));let _=await e.getFirstTimestamp(),v=!!t.forceTranscode||this._startTimestamp>0||_<0||!!t.frameRate||t.keyFrameInterval!==void 0||t.process!==void 0,y=p!==d||m!==f||i!==0&&(!a||t.process!==void 0)||!!u,ee=t.alpha??`discard`,te=this.output.format.getSupportedVideoCodecs();if(!v&&!t.bitrate&&!y&&te.includes(n)&&(!t.codec||t.codec===n)){let t=new ku(n);r=t,this._trackPromises.push((async()=>{await this._started;let n=new yr(e),r={decoderConfig:await e.getDecoderConfig()??void 0},i=Number.isFinite(this._endTimestamp)?await n.getPacket(this._endTimestamp,{metadataOnly:!0})??void 0:void 0;for await(let a of n.packets(void 0,i,{verifyKeyPackets:!0})){if(this._canceled)return;ee===`discard`&&(delete a.sideData.alpha,delete a.sideData.alphaByteLength),this._reportProgress(e.id,a.timestamp),await t.add(a,r),this._synchronizer.shouldWait(e.id,a.timestamp)&&await this._synchronizer.wait(a.timestamp)}t.close(),this._synchronizer.closeTrack(e.id)})())}else{if(!await e.canDecode()){this.discardedTracks.push({track:e,reason:`undecodable_source_codec`});return}t.codec&&(te=te.filter(e=>e===t.codec));let n=t.bitrate??pu,a=await Cu(te,{width:t.process&&t.processedWidth?t.processedWidth:p,height:t.process&&t.processedHeight?t.processedHeight:m,bitrate:n});if(!a){this.discardedTracks.push({track:e,reason:`no_encodable_target_codec`});return}let s={codec:a,bitrate:n,keyFrameInterval:t.keyFrameInterval,sizeChangeBehavior:t.fit??`passThrough`,alpha:ee,hardwareAcceleration:t.hardwareAcceleration},c=new Mu(s);if(r=c,!y){let t=new $u({format:new ql,target:new yl}),n=new Mu(s);t.addVideoTrack(n),await t.start();let r=await new Tr(e).getSample(_);if(r)try{await n.add(r),r.close(),await t.finalize()}catch(e){console.info(`Error when probing encoder support. Falling back to rerender path.`,e),y=!0,t.cancel()}else await t.cancel()}y?this._trackPromises.push((async()=>{await this._started;let n=new Er(e,{width:p,height:m,fit:t.fit??`fill`,rotation:i,crop:t.crop,poolSize:1,alpha:ee===`keep`}).canvases(this._startTimestamp,this._endTimestamp),r=t.frameRate,a=null,s=null,l=null,u=async n=>{o(a),o(r!==void 0);let i=Math.round((n-s)*r);for(let n=1;n<i;n++){let i=new er(a,{timestamp:s+n/r,duration:1/r});await this._registerVideoSample(e,t,c,i),i.close()}};for await(let{canvas:i,timestamp:o,duration:d}of n){if(this._canceled)return;let n=Math.max(o-this._startTimestamp,0);if(l=n+d,r!==void 0){let e=Math.floor(n*r)/r;if(a!==null)if(e<=s){a=i,s=e;continue}else await u(e);n=e}let f=new er(i,{timestamp:n,duration:r===void 0?d:1/r});await this._registerVideoSample(e,t,c,f),f.close(),r!==void 0&&(a=i,s=n)}a&&(o(l!==null),o(r!==void 0),await u(Math.floor(l*r)/r)),c.close(),this._synchronizer.closeTrack(e.id)})()):this._trackPromises.push((async()=>{await this._started;let n=new Tr(e),r=t.frameRate,i=null,a=null,s=null,l=async n=>{o(i),o(r!==void 0);let s=Math.round((n-a)*r);for(let n=1;n<s;n++)i.setTimestamp(a+n/r),i.setDuration(1/r),await this._registerVideoSample(e,t,c,i);i.close()};for await(let o of n.samples(this._startTimestamp,this._endTimestamp)){if(this._canceled){i?.close();return}let n=Math.max(o.timestamp-this._startTimestamp,0);if(s=n+o.duration,r!==void 0){let e=Math.floor(n*r)/r;if(i!==null)if(e<=a){i.close(),i=o,a=e;continue}else await l(e);n=e,o.setDuration(1/r)}o.setTimestamp(n),await this._registerVideoSample(e,t,c,o),r===void 0?o.close():(i=o,a=n)}i&&(o(s!==null),o(r!==void 0),await l(Math.floor(s*r)/r)),c.close(),this._synchronizer.closeTrack(e.id)})())}this.output.addVideoTrack(r,{frameRate:t.frameRate,languageCode:Oe(e.languageCode)?e.languageCode:void 0,name:e.name??void 0,disposition:e.disposition,rotation:y?0:i}),this._addedCounts.video++,this._totalTrackCount++,this.utilizedTracks.push(e)}async _registerVideoSample(e,t,n,r){if(this._canceled)return;this._reportProgress(e.id,r.timestamp);let i;if(!t.process)i=[r];else{let e=t.process(r);e instanceof Promise&&(e=await e),Array.isArray(e)||(e=e===null?[]:[e]),i=e.map(e=>e instanceof er?e:typeof VideoFrame<`u`&&e instanceof VideoFrame?new er(e):new er(e,{timestamp:r.timestamp,duration:r.duration}))}for(let t of i){if(this._canceled)break;await n.add(t),this._synchronizer.shouldWait(e.id,t.timestamp)&&await this._synchronizer.wait(t.timestamp)}for(let e of i)e!==r&&e.close()}async _processAudioTrack(e,t){let n=e.codec;if(!n){this.discardedTracks.push({track:e,reason:`unknown_source_codec`});return}let r,i=e.numberOfChannels,a=e.sampleRate,o=await e.getFirstTimestamp(),s=t.numberOfChannels??i,c=t.sampleRate??a,l=s!==i||c!==a||this._startTimestamp>0||o<0,u=this.output.format.getSupportedAudioCodecs();if(!t.forceTranscode&&!t.bitrate&&!l&&u.includes(n)&&(!t.codec||t.codec===n)&&!t.process){let t=new Iu(n);r=t,this._trackPromises.push((async()=>{await this._started;let n=new yr(e),r={decoderConfig:await e.getDecoderConfig()??void 0},i=Number.isFinite(this._endTimestamp)?await n.getPacket(this._endTimestamp,{metadataOnly:!0})??void 0:void 0;for await(let a of n.packets(void 0,i)){if(this._canceled)return;this._reportProgress(e.id,a.timestamp),await t.add(a,r),this._synchronizer.shouldWait(e.id,a.timestamp)&&await this._synchronizer.wait(a.timestamp)}t.close(),this._synchronizer.closeTrack(e.id)})())}else{if(!await e.canDecode()){this.discardedTracks.push({track:e,reason:`undecodable_source_codec`});return}let n=null;t.codec&&(u=u.filter(e=>e===t.codec));let i=t.bitrate??pu,a=await xu(u,{numberOfChannels:t.process&&t.processedNumberOfChannels?t.processedNumberOfChannels:s,sampleRate:t.process&&t.processedSampleRate?t.processedSampleRate:c,bitrate:i});if(!a.some(e=>ot.includes(e))&&u.some(e=>ot.includes(e))&&(s!==rd||c!==id)){let e=(await xu(u,{numberOfChannels:rd,sampleRate:id,bitrate:i})).find(e=>ot.includes(e));e&&(l=!0,n=e,s=rd,c=id)}else n=a[0]??null;if(n===null){this.discardedTracks.push({track:e,reason:`no_encodable_target_codec`});return}if(l)r=this._resampleAudio(e,t,n,s,c,i);else{let a=new Ru({codec:n,bitrate:i});r=a,this._trackPromises.push((async()=>{await this._started;let n=new kr(e);for await(let r of n.samples(void 0,this._endTimestamp)){if(this._canceled)return;await this._registerAudioSample(e,t,a,r),r.close()}a.close(),this._synchronizer.closeTrack(e.id)})())}}this.output.addAudioTrack(r,{languageCode:Oe(e.languageCode)?e.languageCode:void 0,name:e.name??void 0,disposition:e.disposition}),this._addedCounts.audio++,this._totalTrackCount++,this.utilizedTracks.push(e)}async _registerAudioSample(e,t,n,r){if(this._canceled)return;this._reportProgress(e.id,r.timestamp);let i;if(!t.process)i=[r];else{let e=t.process(r);if(e instanceof Promise&&(e=await e),Array.isArray(e)||(e=e===null?[]:[e]),!e.every(e=>e instanceof lr))throw TypeError(`The audio process function must return an AudioSample, null, or an array of AudioSamples.`);i=e}for(let t of i){if(this._canceled)break;await n.add(t),this._synchronizer.shouldWait(e.id,t.timestamp)&&await this._synchronizer.wait(t.timestamp)}for(let e of i)e!==r&&e.close()}_resampleAudio(e,t,n,r,i,a){let o=new Ru({codec:n,bitrate:a});return this._trackPromises.push((async()=>{await this._started;let n=new cd({targetNumberOfChannels:r,targetSampleRate:i,startTime:this._startTimestamp,endTime:this._endTimestamp,onSample:async n=>{await this._registerAudioSample(e,t,o,n),n.close()}}),a=new kr(e).samples(this._startTimestamp,this._endTimestamp);for await(let e of a){if(this._canceled)return;await n.add(e),e.close()}await n.finalize(),o.close(),this._synchronizer.closeTrack(e.id)})()),o}_reportProgress(e,t){if(!this._computeProgress)return;o(this._totalDuration!==null),this._maxTimestamps.set(e,Math.max(t,this._maxTimestamps.get(e)));let n=C(Math.min(...this._maxTimestamps.values())/this._totalDuration,0,1);n!==this._lastProgress&&(this._lastProgress=n,this.onProgress?.(n))}},od=5,sd=class{constructor(){this.maxTimestamps=new Map,this.resolvers=[]}computeMinAndMaybeResolve(){let e=1/0;for(let[,t]of this.maxTimestamps)e=Math.min(e,t);for(let t=0;t<this.resolvers.length;t++){let n=this.resolvers[t];n.timestamp-e<od&&(n.resolve(),this.resolvers.splice(t,1),t--)}return e}shouldWait(e,t){return this.maxTimestamps.set(e,Math.max(t,this.maxTimestamps.get(e)??-1/0)),t-this.computeMinAndMaybeResolve()>=od}wait(e){let{promise:t,resolve:n}=x();return this.resolvers.push({timestamp:e,resolve:n}),t}closeTrack(e){this.maxTimestamps.delete(e),this.computeMinAndMaybeResolve()}},cd=class{constructor(e){this.sourceSampleRate=null,this.sourceNumberOfChannels=null,this.targetSampleRate=e.targetSampleRate,this.targetNumberOfChannels=e.targetNumberOfChannels,this.startTime=e.startTime,this.endTime=e.endTime,this.onSample=e.onSample,this.bufferSizeInFrames=Math.floor(this.targetSampleRate*5),this.bufferSizeInSamples=this.bufferSizeInFrames*this.targetNumberOfChannels,this.outputBuffer=new Float32Array(this.bufferSizeInSamples),this.bufferStartFrame=0,this.maxWrittenFrame=-1}doChannelMixerSetup(){o(this.sourceNumberOfChannels!==null);let e=this.sourceNumberOfChannels,t=this.targetNumberOfChannels;e===1&&t===2?this.channelMixer=(t,n)=>t[n*e]:e===1&&t===4?this.channelMixer=(t,n,r)=>t[n*e]*+(r<2):e===1&&t===6?this.channelMixer=(t,n,r)=>t[n*e]*+(r===2):e===2&&t===1?this.channelMixer=(t,n)=>{let r=n*e;return .5*(t[r]+t[r+1])}:e===2&&t===4||e===2&&t===6?this.channelMixer=(t,n,r)=>t[n*e+r]*+(r<2):e===4&&t===1?this.channelMixer=(t,n)=>{let r=n*e;return .25*(t[r]+t[r+1]+t[r+2]+t[r+3])}:e===4&&t===2?this.channelMixer=(t,n,r)=>{let i=n*e;return .5*(t[i+r]+t[i+r+2])}:e===4&&t===6?this.channelMixer=(t,n,r)=>{let i=n*e;return r<2?t[i+r]:r===2||r===3?0:t[i+r-2]}:e===6&&t===1?this.channelMixer=(t,n)=>{let r=n*e;return Math.SQRT1_2*(t[r]+t[r+1])+t[r+2]+.5*(t[r+4]+t[r+5])}:e===6&&t===2?this.channelMixer=(t,n,r)=>{let i=n*e;return t[i+r]+Math.SQRT1_2*(t[i+2]+t[i+r+4])}:e===6&&t===4?this.channelMixer=(t,n,r)=>{let i=n*e;return r<2?t[i+r]+Math.SQRT1_2*t[i+2]:t[i+r+2]}:this.channelMixer=(t,n,r)=>r<e?t[n*e+r]:0}ensureTempBufferSize(e){let t=this.tempSourceBuffer.length;for(;t<e;)t*=2;if(t!==this.tempSourceBuffer.length){let e=new Float32Array(t);e.set(this.tempSourceBuffer),this.tempSourceBuffer=e}}async add(e){this.sourceSampleRate===null&&(this.sourceSampleRate=e.sampleRate,this.sourceNumberOfChannels=e.numberOfChannels,this.tempSourceBuffer=new Float32Array(this.sourceSampleRate*this.sourceNumberOfChannels),this.doChannelMixerSetup());let t=e.numberOfFrames*e.numberOfChannels;this.ensureTempBufferSize(t);let n=e.allocationSize({planeIndex:0,format:`f32`}),r=new Float32Array(this.tempSourceBuffer.buffer,0,n/4);e.copyTo(r,{planeIndex:0,format:`f32`});let i=e.timestamp-this.startTime,a=e.numberOfFrames/this.sourceSampleRate,s=Math.min(i+a,this.endTime-this.startTime),c=Math.floor(i*this.targetSampleRate),l=Math.ceil(s*this.targetSampleRate);for(let t=c;t<l;t++){if(t<this.bufferStartFrame)continue;for(;t>=this.bufferStartFrame+this.bufferSizeInFrames;)await this.finalizeCurrentBuffer(),this.bufferStartFrame+=this.bufferSizeInFrames;let n=t-this.bufferStartFrame;o(n<this.bufferSizeInFrames);let a=(t/this.targetSampleRate-i)*this.sourceSampleRate,s=Math.floor(a),c=Math.ceil(a),l=a-s;for(let t=0;t<this.targetNumberOfChannels;t++){let i=0,a=0;s>=0&&s<e.numberOfFrames&&(i=this.channelMixer(r,s,t)),c>=0&&c<e.numberOfFrames&&(a=this.channelMixer(r,c,t));let o=i+l*(a-i),u=n*this.targetNumberOfChannels+t;this.outputBuffer[u]+=o}this.maxWrittenFrame=Math.max(this.maxWrittenFrame,n)}}async finalizeCurrentBuffer(){if(this.maxWrittenFrame<0)return;let e=(this.maxWrittenFrame+1)*this.targetNumberOfChannels,t=new Float32Array(e);t.set(this.outputBuffer.subarray(0,e));let n=this.bufferStartFrame/this.targetSampleRate,r=new lr({format:`f32`,sampleRate:this.targetSampleRate,numberOfChannels:this.targetNumberOfChannels,timestamp:n,data:t});await this.onSample(r),this.outputBuffer.fill(0),this.maxWrittenFrame=-1}finalize(){return this.finalizeCurrentBuffer()}}})),ud=r({ADTS:()=>Eo,ALL_FORMATS:()=>Oo,ALL_TRACK_TYPES:()=>Zu,AUDIO_CODECS:()=>st,AdtsInputFormat:()=>vo,AdtsOutputFormat:()=>eu,AttachedFile:()=>$e,AudioBufferSink:()=>Ar,AudioBufferSource:()=>zu,AudioSample:()=>lr,AudioSampleSink:()=>kr,AudioSampleSource:()=>Ru,AudioSource:()=>Fu,BaseMediaSampleSink:()=>xr,BlobSource:()=>Fo,BufferSource:()=>Po,BufferTarget:()=>gl,CanvasSink:()=>Er,CanvasSource:()=>Nu,Conversion:()=>ad,CustomAudioDecoder:()=>Mn,CustomAudioEncoder:()=>Pn,CustomVideoDecoder:()=>jn,CustomVideoEncoder:()=>Nn,EncodedAudioPacketSource:()=>Iu,EncodedPacket:()=>D,EncodedPacketSink:()=>yr,EncodedVideoPacketSource:()=>ku,FLAC:()=>Do,FilePathSource:()=>zo,FilePathTarget:()=>vl,FlacInputFormat:()=>_o,FlacOutputFormat:()=>tu,Input:()=>Go,InputAudioTrack:()=>Pr,InputDisposedError:()=>Ko,InputFormat:()=>so,InputTrack:()=>Mr,InputVideoTrack:()=>Nr,IsobmffInputFormat:()=>co,IsobmffOutputFormat:()=>Kl,MATROSKA:()=>xo,MP3:()=>Co,MP4:()=>yo,MatroskaInputFormat:()=>fo,MediaSource:()=>Du,MediaStreamAudioTrackSource:()=>Bu,MediaStreamVideoTrackSource:()=>Pu,MkvOutputFormat:()=>Yl,MovOutputFormat:()=>Jl,Mp3InputFormat:()=>mo,Mp3OutputFormat:()=>Zl,Mp4InputFormat:()=>lo,Mp4OutputFormat:()=>ql,NON_PCM_AUDIO_CODECS:()=>ot,NullTarget:()=>yl,OGG:()=>To,OggInputFormat:()=>go,OggOutputFormat:()=>$l,Output:()=>$u,OutputFormat:()=>Gl,PCM_AUDIO_CODECS:()=>T,QTFF:()=>bo,QUALITY_HIGH:()=>pu,QUALITY_LOW:()=>du,QUALITY_MEDIUM:()=>fu,QUALITY_VERY_HIGH:()=>mu,QUALITY_VERY_LOW:()=>uu,Quality:()=>lu,QuickTimeInputFormat:()=>uo,ReadableStreamSource:()=>Vo,RichImageData:()=>Qe,SUBTITLE_CODECS:()=>ct,Source:()=>No,StreamSource:()=>Bo,StreamTarget:()=>_l,SubtitleSource:()=>Ju,Target:()=>hl,TextSubtitleSource:()=>Yu,UrlSource:()=>Ro,VIDEO_CODECS:()=>at,VIDEO_SAMPLE_PIXEL_FORMATS:()=>Qn,VideoSample:()=>er,VideoSampleColorSpace:()=>tr,VideoSampleSink:()=>Tr,VideoSampleSource:()=>Mu,VideoSource:()=>Ou,WAVE:()=>wo,WEBM:()=>So,WavOutputFormat:()=>Ql,WaveInputFormat:()=>ho,WebMInputFormat:()=>po,WebMOutputFormat:()=>Xl,canEncode:()=>hu,canEncodeAudio:()=>_u,canEncodeSubtitles:()=>vu,canEncodeVideo:()=>gu,getEncodableAudioCodecs:()=>xu,getEncodableCodecs:()=>yu,getEncodableSubtitleCodecs:()=>Su,getEncodableVideoCodecs:()=>bu,getFirstEncodableAudioCodec:()=>wu,getFirstEncodableSubtitleCodec:()=>Tu,getFirstEncodableVideoCodec:()=>Cu,registerDecoder:()=>zn,registerEncoder:()=>Bn}),dd=n((()=>{ed(),nu(),Xu(),E(),Eu(),bl(),Wo(),ko(),qo(),Fr(),Un(),hr(),jr(),ld(),Vn(),it()}));dd();let fd={mp4:`aac`,mov:`aac`,mkv:`opus`,webm:`opus`};function pd(e){return fd[e]}let md={sd:du,hd:fu,fhd:pu,"4k":mu},hd={sd:{width:854,height:480},hd:{width:1280,height:720},fhd:{width:1920,height:1080},"4k":{width:3840,height:2160}},gd=Object.freeze({format:`mp4`,fps:30,width:hd.fhd.width,height:hd.fhd.height,bitrate:md.fhd,audioCodec:`aac`,audioBitrate:96e3,watermark:{url:`https://avatars.githubusercontent.com/u/244247750?s=200&v=4`,opacity:1,position:`bottom-right`}});function _d(e){return{...gd,format:e,audioCodec:pd(e)}}function vd(e){let{preset:t,outputFormat:n,watermark:r}=e;if(!(t in md))throw Error(`Invalid preset: ${t}`);let{width:i,height:a}=hd[t],o=n||`mp4`,s=pd(o),c={format:o,width:i,height:a,bitrate:md[t],audioCodec:s,audioBitrate:128e3};return r&&(c.watermark={url:r.url,opacity:r.opacity,position:r.position}),c}let yd=new Map;function bd(e,t){return`${e}:${t}`}var xd=class e{constructor(e){if(this.cachedConfig=null,this.cacheTimestamp=0,this.fetchPromise=null,this.options=e,e.cacheTimeout!==void 0){if(typeof e.cacheTimeout!=`number`||e.cacheTimeout<=0)throw Error(`cacheTimeout must be a positive number`);this.cacheTimeout=e.cacheTimeout}else this.cacheTimeout=3e5}static getInstance(t){let n=bd(t.backendUrl,t.apiKey),r=yd.get(n);return r||(r=new e(t),yd.set(n,r)),r}async fetchConfig(){let e=Date.now();if(this.cachedConfig&&e-this.cacheTimestamp<this.cacheTimeout)return this.cachedConfig;if(this.fetchPromise)return this.fetchPromise;this.fetchPromise=this.fetchConfigFromBackend();try{let t=await this.fetchPromise;return this.cachedConfig=t,this.cacheTimestamp=e,this.fetchPromise=null,t}catch{return this.fetchPromise=null,gd}}clearCache(){let e=bd(this.options.backendUrl,this.options.apiKey);this.cachedConfig=null,this.cacheTimestamp=0,this.fetchPromise=null,yd.delete(e)}static clearAllInstances(){yd.clear()}getCurrentConfig(){if(!this.cachedConfig)throw Error(`No cached config available. Call fetchConfig() first.`);return this.cachedConfig}async fetchConfigFromBackend(){let e=`${this.options.backendUrl}/api/v1/videos/config`,t=await fetch(e,{method:`GET`,headers:{Authorization:`Bearer ${this.options.apiKey}`,"Content-Type":`application/json`}});if(!t.ok)throw Error(`Failed to fetch config: ${t.status} ${t.statusText}`);let n=await t.json();if(!n.presetEncoding)throw Error(`Invalid config response from backend: missing presetEncoding`);return vd({preset:n.presetEncoding,outputFormat:n.outputFormat,watermark:n.watermark})}},Sd=class{constructor(){this.configService=null,this.currentConfig=gd,this.configFetched=!1}async initialize(e,t){if(this.configService)return;if(!e)throw Error(`apiKey is required`);let n=t||`https://core.vidtreo.com`;this.configService=xd.getInstance({apiKey:e,backendUrl:n}),this.configService.fetchConfig().then(e=>{this.currentConfig=e,this.configFetched=!0}).catch(()=>{this.configFetched=!1})}async fetchConfig(){this.configService&&(this.currentConfig=await this.configService.fetchConfig(),this.configFetched=!0)}async getConfig(){return this.configService&&!this.configFetched&&await this.fetchConfig(),this.currentConfig}clearCache(){if(!this.configService)throw Error(`ConfigService is not initialized`);this.configService.clearCache()}},Cd=class{constructor(e,t){this.availableDevices={audioinput:[],videoinput:[]},this.selectedCameraDeviceId=null,this.selectedMicDeviceId=null,this.streamManager=e,this.callbacks=t}async getAvailableDevices(){return this.availableDevices=await this.streamManager.getAvailableDevices(),this.callbacks?.onDevicesChanged&&this.callbacks.onDevicesChanged(this.availableDevices),this.availableDevices}setCameraDevice(e){this.selectedCameraDeviceId=e,this.streamManager.setVideoDevice(e),this.callbacks?.onDeviceSelected&&this.callbacks.onDeviceSelected(`camera`,e)}setMicDevice(e){this.selectedMicDeviceId=e,this.streamManager.setAudioDevice(e),this.callbacks?.onDeviceSelected&&this.callbacks.onDeviceSelected(`mic`,e)}getSelectedCameraDeviceId(){return this.selectedCameraDeviceId}getSelectedMicDeviceId(){return this.selectedMicDeviceId}getAvailableDevicesList(){return this.availableDevices}};dd();async function wd(e){try{let t=new Fo(e),n=new Go({formats:[yo],source:t});if(typeof n.computeDuration!=`function`)throw Error(`computeDuration method is not available`);let r=await n.computeDuration();if(!r)throw Error(`Duration is missing from computeDuration`);if(r<=0)throw Error(`Invalid duration: must be greater than 0`);return r}catch{return Td(e)}}function Td(e){return new Promise((t,n)=>{let r=document.createElement(`video`),i=URL.createObjectURL(e),a=()=>{URL.revokeObjectURL(i)};r.addEventListener(`loadedmetadata`,()=>{a();let e=r.duration;if(!Number.isFinite(e)||e<=0){n(Error(`Invalid video duration`));return}t(e)}),r.addEventListener(`error`,()=>{a(),n(Error(`Failed to load video metadata`))}),r.src=i,r.load()})}let Ed=`pending-uploads`,Dd=`status`,Od=`createdAt`;var kd=class{constructor(){this.db=null}init(){return this.db?Promise.resolve():new Promise((e,t)=>{let n=indexedDB.open(`vidtreo-recorder`,1);n.onerror=()=>{n.error?t(n.error):t(Error(`Failed to open database`))},n.onsuccess=()=>{if(!n.result){t(Error(`Database result is null`));return}this.db=n.result,e()},n.onupgradeneeded=e=>{let n=e.target.result;if(!n){t(Error(`Database upgrade result is null`));return}if(!n.objectStoreNames.contains(Ed)){let e=n.createObjectStore(Ed,{keyPath:`id`});e.createIndex(Dd,Dd,{unique:!1}),e.createIndex(Od,Od,{unique:!1})}}})}isInitialized(){return this.db!==null}savePendingUpload(e){let t=this.generateUploadId(),n={...e,id:t,status:`pending`,retryCount:0,createdAt:Date.now(),updatedAt:Date.now()};return this.executeTransaction(`readwrite`,e=>{let r=e.add(n);return new Promise((e,n)=>{r.onsuccess=()=>e(t),r.onerror=()=>{r.error?r.error.name===`QuotaExceededError`?n(Error(`Storage quota exceeded. Please free up space or delete old uploads.`)):n(r.error):n(Error(`Failed to save upload`))}})})}getPendingUploads(e){return this.executeTransaction(`readonly`,t=>{let n=e?t.index(Dd).getAll(e):t.getAll();return new Promise((e,t)=>{n.onsuccess=()=>{if(n.result===void 0){t(Error(`Failed to get uploads: result is undefined`));return}e(n.result)},n.onerror=()=>{n.error?t(n.error):t(Error(`Failed to get uploads`))}})})}updateUploadStatus(e,t){return this.executeTransaction(`readwrite`,n=>{let r=n.get(e);return new Promise((e,i)=>{r.onsuccess=()=>{let a=r.result;if(!a){i(Error(`Upload not found`));return}let o={...a,...t,updatedAt:Date.now()},s=n.put(o);s.onsuccess=()=>e(),s.onerror=()=>{s.error?i(s.error):i(Error(`Failed to update upload`))}},r.onerror=()=>{r.error?i(r.error):i(Error(`Failed to get upload`))}})})}deleteUpload(e){return this.executeTransaction(`readwrite`,t=>{let n=t.delete(e);return new Promise((e,t)=>{n.onsuccess=()=>e(),n.onerror=()=>{n.error?t(n.error):t(Error(`Failed to delete upload`))}})})}async cleanupPermanentlyFailedUploads(e){let t=e===void 0?24:e;if(typeof t!=`number`||t<0)throw Error(`retentionHours must be a non-negative number`);let n=Date.now()-t*36e5,r=(await this.getPendingUploads()).filter(e=>e.status===`failed`&&e.retryCount>=10&&e.updatedAt<n);for(let e of r)await this.deleteUpload(e.id);return r.length}async getTotalStorageSize(){return(await this.getPendingUploads()).reduce((e,t)=>e+t.blob.size,0)}generateUploadId(){return`upload-${Date.now()}-${Math.random().toString(36).substring(2,11)}`}executeTransaction(e,t){if(!this.db)throw Error(`Database not initialized`);return t(this.db.transaction([Ed],e).objectStore(Ed))}},Ad=class{constructor(){this.storageService=null,this.cleanupIntervalId=null}async initialize(e){this.storageService||=new kd,this.storageService.isInitialized()||await this.storageService.init(),this.setupCleanupInterval(e)}setupCleanupInterval(e){this.cleanupIntervalId===null&&(this.cleanupIntervalId=window.setInterval(()=>{this.performCleanup().catch(t=>{e(i(t))})},36e5))}async performCleanup(){if(!this.storageService)throw Error(`StorageService not initialized`);await this.storageService.cleanupPermanentlyFailedUploads(24)}getStorageService(){return this.storageService}destroy(){this.cleanupIntervalId!==null&&(clearInterval(this.cleanupIntervalId),this.cleanupIntervalId=null)}};function jd(){let e=globalThis;if(e.__VIDTREO_DEBUG__===!0||e.__VIDTREO_DEV__===!0)return!0;let t=typeof process<`u`&&process?.env?`production`:void 0;return t===`development`||t===`test`||typeof localStorage<`u`&&localStorage.getItem(`VIDTREO_DEBUG`)===`true`}let Md=jd(),Nd={reset:`\x1B[0m`,bright:`\x1B[1m`,dim:`\x1B[2m`,red:`\x1B[31m`,green:`\x1B[32m`,yellow:`\x1B[33m`,blue:`\x1B[34m`,magenta:`\x1B[35m`,cyan:`\x1B[36m`,white:`\x1B[37m`,gray:`\x1B[90m`};function Pd(e,t,n){if(!Md)return``;let r=n?.prefix||`[${e.toUpperCase()}]`;return`${Nd[n?.color||Fd(e)]}${r}${Nd.reset} ${t}`}function Fd(e){switch(e){case`error`:return`red`;case`warn`:return`yellow`;case`info`:return`cyan`;case`debug`:return`gray`;default:return`white`}}function Id(e,t,...n){if(!Md)return;let r=Pd(e,t);console[e](r,...n)}let W={log:(e,...t)=>{Id(`log`,e,...t)},info:(e,...t)=>{Id(`info`,e,...t)},warn:(e,...t)=>{Id(`warn`,e,...t)},error:(e,...t)=>{Id(`error`,e,...t)},debug:(e,...t)=>{Id(`debug`,e,...t)},group:(e,t=`cyan`)=>{if(!Md)return;let n=Nd[t],r=Nd.reset;console.group(`${n}${e}${r}`)},groupEnd:()=>{Md&&console.groupEnd()}},Ld=`live`;var Rd=class{constructor(e,t={}){this.currentSourceType=`camera`,this.originalCameraStream=null,this.originalCameraConstraints=null,this.screenShareStream=null,this.screenShareTrackEndHandler=null,this.streamManager=e,this.callbacks=t}getCurrentSourceType(){return this.currentSourceType}getOriginalCameraStream(){return this.originalCameraStream}stopLiveTracks(e){for(let t of e)t.readyState===Ld&&t.stop()}stopStreamTracks(e){this.stopLiveTracks(e.getTracks())}stopStreamVideoTracks(e){this.stopLiveTracks(e.getVideoTracks())}isTrackLive(e){return e!==void 0&&e.readyState===Ld}areTracksLive(e,t){return this.isTrackLive(e)&&this.isTrackLive(t)}storeOriginalCameraConstraints(e){let t=e.getVideoTracks()[0];if(!t)return;let n=t.getSettings();this.originalCameraConstraints={width:n.width,height:n.height,aspectRatio:n.aspectRatio,frameRate:n.frameRate,deviceId:n.deviceId,facingMode:n.facingMode}}storeOriginalCameraStream(e){let t=e.getVideoTracks()[0],n=e.getAudioTracks()[0];this.areTracksLive(t,n)?this.originalCameraStream=new MediaStream([t,n]):this.originalCameraStream=e}createError(e){return e instanceof Error?e:Error(i(e))}waitForTracksToEnd(e){return new Promise(t=>{setTimeout(()=>{this.screenShareStream=null,t()},e)})}combineScreenShareWithOriginalAudio(e){let t=this.originalCameraStream?this.originalCameraStream.getAudioTracks()[0]:void 0;W.debug(`[SourceSwitchManager] combineScreenShareWithOriginalAudio`,{hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id,hasOriginalAudioTrack:!!t,originalAudioTrackId:t?.id,originalAudioTrackReadyState:t?.readyState,originalAudioTrackEnabled:t?.enabled,originalAudioTrackMuted:t?.muted,originalAudioTrackLabel:t?.label,isTrackLive:this.isTrackLive(t),screenVideoTrackId:e.id,screenVideoTrackReadyState:e.readyState});let n=[e];this.isTrackLive(t)&&t?(n.push(t),W.debug(`[SourceSwitchManager] Added original audio track to combined stream`,{audioTrackId:t.id,combinedTracksCount:n.length})):W.warn(`[SourceSwitchManager] Original audio track is not live, not adding to combined stream`,{audioTrackId:t?.id,audioTrackReadyState:t?.readyState,combinedTracksCount:n.length});let r=new MediaStream(n);return W.debug(`[SourceSwitchManager] Combined stream created`,{combinedStreamId:r.id,combinedStreamVideoTracksCount:r.getVideoTracks().length,combinedStreamAudioTracksCount:r.getAudioTracks().length,combinedStreamAudioTrackId:r.getAudioTracks()[0]?.id,combinedStreamAudioTrackReadyState:r.getAudioTracks()[0]?.readyState}),r}handleScreenSelectionError(){this.callbacks.onScreenSelectionEnd&&this.callbacks.onScreenSelectionEnd(),this.callbacks.onTransitionEnd&&this.callbacks.onTransitionEnd()}isPermissionDeniedError(e){let t=i(e);return t.includes(`NotAllowedError`)||t.includes(`AbortError`)||t.toLowerCase().includes(`permission denied`)||t.toLowerCase().includes(`user denied`)}async processScreenShareStream(e,t){this.screenShareStream=e;let n=e.getVideoTracks()[0];if(!n)throw this.stopStreamTracks(e),Error(`No video track found in screen share stream`);let r=this.combineScreenShareWithOriginalAudio(n);t&&t!==this.originalCameraStream&&this.stopStreamVideoTracks(t);let i=e.getAudioTracks();for(let e of i)e.stop();return this.currentSourceType=`screen`,this.callbacks.onSourceChange&&await this.callbacks.onSourceChange(this.currentSourceType),this.setupScreenShareTrackHandler(r),r}async switchToScreenCapture(){let e=this.streamManager.getStream();e&&(this.storeOriginalCameraConstraints(e),this.storeOriginalCameraStream(e)),this.callbacks.onTransitionStart&&this.callbacks.onTransitionStart(`Select screen to share...`),this.callbacks.onScreenSelectionStart&&this.callbacks.onScreenSelectionStart();try{let t=await navigator.mediaDevices.getDisplayMedia({video:!0,audio:!0});return await this.processScreenShareStream(t,e)}catch(e){if(this.handleScreenSelectionError(),this.isPermissionDeniedError(e))return null;throw e}}setupScreenShareTrackHandler(e){let t=e.getVideoTracks()[0];if(!t)throw Error(`No video track found in screen share stream`);let n=this.screenShareTrackEndHandler;if(n){let e=this.streamManager.getStream();if(e){let t=e.getVideoTracks()[0];t&&t.removeEventListener(`ended`,n)}}this.screenShareTrackEndHandler=async()=>{if(this.currentSourceType===`screen`)try{await this.switchToCamera()}catch(e){this.callbacks.onError&&this.callbacks.onError(this.createError(e))}},t.addEventListener(`ended`,this.screenShareTrackEndHandler)}removeScreenShareTrackHandler(e){if(!(this.screenShareTrackEndHandler&&e))return;let t=e.getVideoTracks()[0];t&&t.removeEventListener(`ended`,this.screenShareTrackEndHandler),this.screenShareTrackEndHandler=null}canReuseStream(e,t){if(!e||t&&e!==this.originalCameraStream)return!1;let n=e.getVideoTracks()[0],r=e.getAudioTracks()[0];return!(!this.areTracksLive(n,r)||this.callbacks.getSelectedCameraDeviceId&&this.callbacks.getSelectedCameraDeviceId()!==n.getSettings().deviceId)}canReuseOriginalStream(){return this.canReuseStream(this.originalCameraStream,!1)}canReuseManagerStream(){let e=this.streamManager.getStream();return e&&this.originalCameraStream?this.canReuseStream(e,!0):!1}getSelectedCameraDeviceId(){return this.callbacks.getSelectedCameraDeviceId?this.callbacks.getSelectedCameraDeviceId():this.streamManager.getVideoDevice()}getSelectedMicDeviceId(){return this.callbacks.getSelectedMicDeviceId?this.callbacks.getSelectedMicDeviceId():this.streamManager.getAudioDevice()}buildVideoConstraints(e){let t={};if(this.originalCameraConstraints){let{deviceId:e,...n}=this.originalCameraConstraints;Object.assign(t,n)}if(e)t.deviceId={exact:e};else if(!t.deviceId){let e=this.getSelectedCameraDeviceId();e&&(t.deviceId={exact:e})}return t}buildAudioConstraints(e){return e?{deviceId:{exact:e}}:!0}validateTrack(e,t,n){if(!this.isTrackLive(e)){this.stopStreamTracks(n);let r=e?e.readyState:`undefined`;throw Error(`Failed to get live camera ${t} track. ReadyState: ${r}`)}}async createCameraStreamWithOriginalAudio(e){let t=this.originalCameraStream?this.originalCameraStream.getAudioTracks()[0]:void 0;if(W.debug(`[SourceSwitchManager] createCameraStreamWithOriginalAudio`,{hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id,hasOriginalAudioTrack:!!t,originalAudioTrackId:t?.id,originalAudioTrackReadyState:t?.readyState,originalAudioTrackEnabled:t?.enabled,originalAudioTrackMuted:t?.muted,originalAudioTrackLabel:t?.label,isTrackLive:this.isTrackLive(t),cameraDeviceId:e}),!this.isTrackLive(t))return W.warn(`[SourceSwitchManager] Original audio track is not live, cannot reuse`,{originalAudioTrackId:t?.id,originalAudioTrackReadyState:t?.readyState}),null;let n=this.buildVideoConstraints(e),r={video:Object.keys(n).length>0?n:!0,audio:!1};W.debug(`[SourceSwitchManager] Requesting new video stream`,{constraints:r,cameraDeviceId:e});let i=await navigator.mediaDevices.getUserMedia(r),a=i.getVideoTracks()[0];this.validateTrack(a,`video`,i),W.debug(`[SourceSwitchManager] New video stream obtained`,{newStreamId:i.id,videoTrackId:a.id,videoTrackReadyState:a.readyState,newStreamAudioTracksCount:i.getAudioTracks().length});let o=[a];t&&o.push(t),W.debug(`[SourceSwitchManager] Creating combined stream with original audio`,{videoTrackId:a.id,audioTrackId:t?.id,audioTrackReadyState:t?.readyState,audioTrackEnabled:t?.enabled,audioTrackMuted:t?.muted,combinedTracksCount:o.length});let s=new MediaStream(o);this.stopLiveTracks(i.getAudioTracks());let c=this.originalCameraStream?.id;return this.originalCameraStream=s,W.debug(`[SourceSwitchManager] Combined stream created and assigned`,{combinedStreamId:s.id,previousOriginalCameraStreamId:c,newOriginalCameraStreamId:this.originalCameraStream.id,combinedStreamVideoTracksCount:s.getVideoTracks().length,combinedStreamAudioTracksCount:s.getAudioTracks().length,combinedStreamAudioTrackId:s.getAudioTracks()[0]?.id,combinedStreamAudioTrackReadyState:s.getAudioTracks()[0]?.readyState,audioTrackStillSame:s.getAudioTracks()[0]===t}),s}async createCameraStreamWithNewAudio(e){let t=this.getSelectedMicDeviceId(),n=this.buildVideoConstraints(e),r=this.buildAudioConstraints(t),i={video:Object.keys(n).length>0?n:!0,audio:r},a=await navigator.mediaDevices.getUserMedia(i),o=a.getVideoTracks()[0],s=a.getAudioTracks()[0];return this.validateTrack(o,`video`,a),this.validateTrack(s,`audio`,a),this.originalCameraStream=a,a}async createNewCameraStreamForRecording(){let e=this.getSelectedCameraDeviceId();return await this.createCameraStreamWithOriginalAudio(e)||this.createCameraStreamWithNewAudio(e)}async getCameraStream(){let e=this.streamManager.isRecording(),t=this.getSelectedCameraDeviceId(),n=this.getSelectedMicDeviceId();if(this.streamManager.setVideoDevice(t),this.streamManager.setAudioDevice(n),this.canReuseOriginalStream()){if(!this.originalCameraStream)throw Error(`Original camera stream is null`);return this.originalCameraStream}if(this.canReuseManagerStream()){let e=this.streamManager.getStream();if(!e)throw Error(`Manager stream is null`);return e}!e&&this.originalCameraStream&&(this.originalCameraStream=null);let r=this.streamManager.getStream();if(!e&&r&&r!==this.originalCameraStream&&(this.stopStreamTracks(r),this.streamManager.setMediaStream(null)),e)return this.streamManager.setVideoDevice(this.getSelectedCameraDeviceId()),this.streamManager.setAudioDevice(this.getSelectedMicDeviceId()),this.createNewCameraStreamForRecording();let i=await this.streamManager.startStream();return this.originalCameraStream=i,i}async switchToCamera(){let e=this.streamManager.isRecording();if(!(!e&&this.currentSourceType===`camera`))try{this.notifyTransitionStart(`Switching to camera...`),await this.handleScreenShareStop();let t=await this.getCameraStream();if(!t)throw Error(`Failed to get camera stream`);await this.applyCameraStream(t,e),this.notifyTransitionEnd()}catch(e){throw this.notifyTransitionEnd(),e}}notifyTransitionStart(e){this.callbacks.onTransitionStart&&this.callbacks.onTransitionStart(e)}notifyTransitionEnd(){this.callbacks.onTransitionEnd&&this.callbacks.onTransitionEnd()}stopScreenShareStreamTracks(e){let t=e.getVideoTracks(),n=e.getAudioTracks();W.debug(`[SourceSwitchManager] stopping screen share tracks`,{videoTracks:t.map(e=>({id:e.id,readyState:e.readyState,displaySurface:e.getSettings().displaySurface,constraints:e.getConstraints()})),audioTracks:n.map(e=>({id:e.id,readyState:e.readyState,constraints:e.getConstraints()}))});for(let e of t)e.stop();for(let e of n)e.stop()}stopDisplayTracks(e){if(e)for(let t of e.getVideoTracks())typeof t.getSettings().displaySurface==`string`&&t.readyState===Ld&&(W.debug(`[SourceSwitchManager] stopping display track`,{id:t.id,readyState:t.readyState,constraints:t.getConstraints(),settings:t.getSettings()}),t.stop())}async handleScreenShareStop(){if(this.currentSourceType!==`screen`)return;W.debug(`[SourceSwitchManager] handleScreenShareStop invoked`,{currentSourceType:this.currentSourceType,hasScreenShareStream:!!this.screenShareStream,screenShareStreamId:this.screenShareStream?.id,hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id});let e=this.screenShareStream,t=this.streamManager.getStream();if(W.debug(`[SourceSwitchManager] Current stream state before stop`,{currentStreamId:t?.id,currentStreamVideoTracksCount:t?.getVideoTracks().length,currentStreamAudioTracksCount:t?.getAudioTracks().length,currentStreamAudioTrackId:t?.getAudioTracks()[0]?.id,currentStreamAudioTrackReadyState:t?.getAudioTracks()[0]?.readyState,originalCameraStreamAudioTrackId:this.originalCameraStream?.getAudioTracks()[0]?.id,originalCameraStreamAudioTrackReadyState:this.originalCameraStream?.getAudioTracks()[0]?.readyState}),e){let t=e.getAudioTracks();W.debug(`[SourceSwitchManager] Screen share stream audio tracks before stop`,{screenShareStreamId:e.id,screenShareAudioTracksCount:t.length,screenShareAudioTrackIds:t.map(e=>({id:e.id,readyState:e.readyState,enabled:e.enabled}))}),this.removeScreenShareTrackHandler(e),this.stopScreenShareStreamTracks(e),this.stopDisplayTracks(e),this.screenShareStream=null,await this.waitForTracksToEnd(0),W.debug(`[SourceSwitchManager] Screen share stream stopped`,{screenShareAudioTracksAfterStop:t.map(e=>({id:e.id,readyState:e.readyState}))})}if(t){let e=t.getAudioTracks();W.debug(`[SourceSwitchManager] Current stream audio tracks before video stop`,{currentStreamId:t.id,currentStreamAudioTracksCount:e.length,currentStreamAudioTrackIds:e.map(e=>({id:e.id,readyState:e.readyState,enabled:e.enabled}))}),this.stopStreamVideoTracks(t),this.stopDisplayTracks(t),W.debug(`[SourceSwitchManager] Current stream audio tracks after video stop`,{currentStreamId:t.id,currentStreamAudioTracksCount:t.getAudioTracks().length,currentStreamAudioTrackIds:t.getAudioTracks().map(e=>({id:e.id,readyState:e.readyState,enabled:e.enabled}))})}W.debug(`[SourceSwitchManager] Original camera stream state before source change`,{hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id,originalCameraStreamAudioTracksCount:this.originalCameraStream?.getAudioTracks().length,originalCameraStreamAudioTrackId:this.originalCameraStream?.getAudioTracks()[0]?.id,originalCameraStreamAudioTrackReadyState:this.originalCameraStream?.getAudioTracks()[0]?.readyState,originalCameraStreamAudioTrackEnabled:this.originalCameraStream?.getAudioTracks()[0]?.enabled}),this.currentSourceType=`camera`,this.callbacks.onSourceChange&&await this.callbacks.onSourceChange(this.currentSourceType),W.debug(`[SourceSwitchManager] handleScreenShareStop completed`,{hasScreenShareStream:!!this.screenShareStream,currentSourceType:this.currentSourceType,hasOriginalCameraStream:!!this.originalCameraStream,originalCameraStreamId:this.originalCameraStream?.id,originalCameraStreamAudioTracksCount:this.originalCameraStream?.getAudioTracks().length,originalCameraStreamAudioTrackId:this.originalCameraStream?.getAudioTracks()[0]?.id,originalCameraStreamAudioTrackReadyState:this.originalCameraStream?.getAudioTracks()[0]?.readyState})}async applyCameraStream(e,t){this.streamManager.setMediaStream(e);let n=this.currentSourceType!==`camera`;this.currentSourceType=`camera`,n&&this.callbacks.onSourceChange&&await this.callbacks.onSourceChange(this.currentSourceType),t&&await this.streamManager.switchVideoSource(e),this.callbacks.onPreviewUpdate&&await this.callbacks.onPreviewUpdate(e)}async toggleSource(){if(this.streamManager.isRecording())try{this.currentSourceType===`camera`?await this.switchToScreen():await this.switchToCamera()}catch(e){this.handleToggleError(e)}}async switchToScreen(){let e=await this.switchToScreenCapture();if(!e){this.notifyTransitionEnd();return}this.notifyTransitionStart(`Switching to screen...`),await this.streamManager.switchVideoSource(e),this.callbacks.onPreviewUpdate&&await this.callbacks.onPreviewUpdate(e),this.notifyTransitionEnd()}handleToggleError(e){this.notifyTransitionEnd();let t=i(e);t.includes(`NotAllowedError`)||t.includes(`AbortError`)?this.currentSourceType===`screen`&&this.switchToCamera().catch(e=>{this.callbacks.onError&&this.callbacks.onError(this.createError(e))}):this.callbacks.onError&&this.callbacks.onError(this.createError(e))}async handleRecordingStop(){if(this.currentSourceType!==`screen`){this.cleanup();return}try{let e=this.streamManager.getStream();e&&(this.removeScreenShareTrackHandler(e),this.stopStreamVideoTracks(e));let t=await this.getCameraStream();if(!t)throw Error(`Failed to get camera stream`);this.streamManager.setMediaStream(t),this.currentSourceType=`camera`,this.callbacks.onSourceChange&&await this.callbacks.onSourceChange(this.currentSourceType),this.callbacks.onPreviewUpdate&&await this.callbacks.onPreviewUpdate(t)}catch(e){throw this.callbacks.onError&&this.callbacks.onError(this.createError(e)),e}this.cleanup()}cleanup(){this.screenShareStream&&=(this.removeScreenShareTrackHandler(this.screenShareStream),this.stopScreenShareStreamTracks(this.screenShareStream),null);let e=this.streamManager.getStream();e&&this.removeScreenShareTrackHandler(e),this.screenShareTrackEndHandler=null,this.originalCameraStream=null,this.originalCameraConstraints=null}setCallbacks(e){this.callbacks={...this.callbacks,...e}}};let zd=Object.freeze({width:{ideal:gd.width||1920},height:{ideal:gd.height||1080},frameRate:{ideal:gd.fps||30}}),Bd=Object.freeze({video:zd,audio:!0});Object.freeze({mimeType:`video/webm;codecs=vp9,opus`});var Vd=class{constructor(e={}){this.mediaStream=null,this.state=`idle`,this.eventListeners=new Map,this.selectedAudioDeviceId=null,this.selectedVideoDeviceId=null,this.streamConfig={...Bd,...e}}getState(){return this.state}getStream(){return this.mediaStream}getAudioStreamForAnalysis(){return this.mediaStream&&this.mediaStream.getAudioTracks().length>0?this.mediaStream:null}isActive(){return this.state===`active`||this.state===`recording`}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set);let n=this.eventListeners.get(e);return n&&n.add(t),()=>{this.off(e,t)}}off(e,t){let n=this.eventListeners.get(e);n&&n.delete(t)}once(e,t){let n=(r=>{t(r),this.off(e,n)});return this.on(e,n)}emit(e,t){let n=this.eventListeners.get(e);if(n)for(let e of n)try{e(t)}catch{}}setState(e){if(this.state===e)return;let t=this.state;this.state=e,this.emit(`statechange`,{state:e,previousState:t})}setAudioDevice(e){this.selectedAudioDeviceId=e}setVideoDevice(e){this.selectedVideoDeviceId=e}getAudioDevice(){return this.selectedAudioDeviceId}getVideoDevice(){return this.selectedVideoDeviceId}async getAvailableDevices(){try{let e=await navigator.mediaDevices.enumerateDevices();return{audioinput:e.filter(e=>e.kind===`audioinput`),videoinput:e.filter(e=>e.kind===`videoinput`)}}catch(e){throw Error(`Failed to enumerate devices: ${i(e)}`)}}buildDeviceConstraints(e,t){return e?typeof t==`object`?{...t,deviceId:{exact:e}}:{deviceId:{exact:e}}:t}buildVideoConstraints(e){return this.buildDeviceConstraints(e,this.streamConfig.video)}buildAudioConstraints(e){return this.buildDeviceConstraints(e,this.streamConfig.audio)}async startStream(){if(W.debug(`[StreamManager] startStream called`,{hasExistingStream:!!this.mediaStream,selectedVideoDeviceId:this.selectedVideoDeviceId,selectedAudioDeviceId:this.selectedAudioDeviceId}),this.mediaStream){let e=this.mediaStream.getVideoTracks()[0];if(this.selectedVideoDeviceId===null)if(e?.getSettings?.()?.deviceId)W.debug(`[StreamManager] Stopping existing stream to recreate`),this.stopStream();else return W.debug(`[StreamManager] Reusing existing stream`),this.mediaStream;if(e?.getSettings&&e.getSettings().deviceId===this.selectedVideoDeviceId)return W.debug(`[StreamManager] Existing stream matches device, reusing`),this.mediaStream;W.debug(`[StreamManager] Device changed, stopping existing stream`),this.stopStream()}this.setState(`starting`),W.debug(`[StreamManager] State set to 'starting'`);try{W.debug(`[StreamManager] Building constraints`,{selectedVideoDeviceId:this.selectedVideoDeviceId,selectedAudioDeviceId:this.selectedAudioDeviceId});let e={video:this.buildVideoConstraints(this.selectedVideoDeviceId),audio:this.buildAudioConstraints(this.selectedAudioDeviceId)};return W.debug(`[StreamManager] Requesting media stream with constraints`,{hasVideo:!!e.video,hasAudio:!!e.audio}),this.mediaStream=await navigator.mediaDevices.getUserMedia(e),W.info(`[StreamManager] Media stream obtained`,{streamId:this.mediaStream.id,videoTracks:this.mediaStream.getVideoTracks().length,audioTracks:this.mediaStream.getAudioTracks().length}),this.setState(`active`),W.debug(`[StreamManager] State set to 'active'`),W.debug(`[StreamManager] Emitting streamstart event`),this.emit(`streamstart`,{stream:this.mediaStream}),this.mediaStream}catch(e){let t=e instanceof Error?e:Error(i(e));throw W.error(`[StreamManager] Failed to start stream`,t),this.setState(`error`),this.emit(`error`,{error:t}),t}}stopStream(){if(this.mediaStream){for(let e of this.mediaStream.getTracks())e.stop();this.mediaStream=null}this.state!==`idle`&&(this.setState(`idle`),this.emit(`streamstop`,void 0))}stopStreamTracks(e){for(let t of e.getTracks())t.stop()}isTrackLive(e){return e!==void 0&&e.readyState===`live`}async tryReplaceTrack(e,t,n){let r=e.replaceTrack;if(typeof r!=`function`)return!1;try{await r.call(e,t),e.stop();for(let e of n.getTracks())e!==t&&e.stop();return t.stop(),!0}catch{return!1}}recreateStreamWithNewTrack(e,t,n){for(let t of n.getTracks())t!==e&&t.stop();let r=[e];this.isTrackLive(t)&&t&&r.push(t);let i=new MediaStream(r);if(this.mediaStream)for(let e of this.mediaStream.getTracks())e!==t&&e.stop();return i}async switchDeviceTrack(e,t,n){if(!this.mediaStream)throw Error(`No active stream to switch device`);let r=t===`video`?this.mediaStream.getVideoTracks()[0]:this.mediaStream.getAudioTracks()[0],i=t===`video`?this.mediaStream.getAudioTracks()[0]:this.mediaStream.getVideoTracks()[0];if(!r){let e=t===`video`?`video`:`audio`;throw Error(`No ${e} track in current stream`)}let a={[t]:this.buildDeviceConstraints(e,n)},o=await navigator.mediaDevices.getUserMedia(a),s=t===`video`?o.getVideoTracks()[0]:o.getAudioTracks()[0];if(!s){this.stopStreamTracks(o);let e=t===`video`?`video`:`audio`;throw Error(`Failed to get new ${e} track`)}return await this.tryReplaceTrack(r,s,o)||(r.stop(),this.mediaStream=this.recreateStreamWithNewTrack(s,i,o)),t===`video`?(this.selectedVideoDeviceId=e,this.emit(`videosourcechange`,{stream:this.mediaStream})):this.selectedAudioDeviceId=e,this.mediaStream}switchVideoDevice(e){return this.switchDeviceTrack(e,`video`,this.streamConfig.video)}switchAudioDevice(e){return this.switchDeviceTrack(e,`audio`,this.streamConfig.audio)}setMediaStream(e){this.mediaStream=e}setAudioTracksEnabled(e){if(!this.mediaStream)return;let t=this.mediaStream.getAudioTracks();for(let n of t)n.enabled=e}destroy(){this.stopStream(),this.eventListeners.clear(),this.setState(`idle`)}};let Hd=[`Bytes`,`KB`,`MB`,`GB`],Ud=1024;function Wd(e){if(e===0)return`0 Bytes`;let t=Math.floor(Math.log(e)/Math.log(Ud));return`${Math.round(e/Ud**t*100)/100} ${Hd[t]}`}function Gd(e){let t=Math.floor(e/3600),n=Math.floor(e%3600/60),r=e%60;return t>0?`${t.toString().padStart(2,`0`)}:${n.toString().padStart(2,`0`)}:${r.toString().padStart(2,`0`)}`:`${n.toString().padStart(2,`0`)}:${r.toString().padStart(2,`0`)}`}var Kd=class{constructor(){this.recordingStartTime=0,this.totalPausedTime=0,this.pauseStartTime=null,this.intervals=[],this.currentIntervalStart=null,this.isTracking=!1,this.visibilityChangeHandler=this.handleVisibilityChange.bind(this),this.blurHandler=this.handleBlur.bind(this),this.focusHandler=this.handleFocus.bind(this)}start(e){this.isTracking||(this.recordingStartTime=e,this.totalPausedTime=0,this.pauseStartTime=null,this.intervals=[],this.currentIntervalStart=null,this.isTracking=!0,typeof document<`u`&&document.addEventListener(`visibilitychange`,this.visibilityChangeHandler),typeof window<`u`&&(window.addEventListener(`blur`,this.blurHandler),window.addEventListener(`focus`,this.focusHandler)),this.checkInitialState())}pause(){!this.isTracking||this.pauseStartTime!==null||(this.pauseStartTime=Date.now(),this.endCurrentIntervalIfActive())}resume(){if(!this.isTracking||this.pauseStartTime===null)return;let e=Date.now()-this.pauseStartTime;this.totalPausedTime+=e,this.pauseStartTime=null}getIntervals(){return this.endCurrentIntervalIfActive(),this.intervals.map(e=>({start:this.normalizeTimestamp(e.start),end:this.normalizeTimestamp(e.end)}))}reset(){this.intervals=[],this.currentIntervalStart=null,this.totalPausedTime=0,this.pauseStartTime=null}cleanup(){this.isTracking=!1,this.endCurrentIntervalIfActive(),typeof document<`u`&&document.removeEventListener(`visibilitychange`,this.visibilityChangeHandler),typeof window<`u`&&(window.removeEventListener(`blur`,this.blurHandler),window.removeEventListener(`focus`,this.focusHandler)),this.reset()}checkInitialState(){typeof document>`u`||document.visibilityState===`hidden`&&this.startInterval()}handleVisibilityChange(){typeof document>`u`||(document.visibilityState===`hidden`?this.startInterval():this.endCurrentIntervalIfActive())}handleBlur(){this.startInterval()}handleFocus(){this.endCurrentIntervalIfActive()}startInterval(){this.currentIntervalStart!==null||!this.isTracking||this.pauseStartTime===null&&(this.currentIntervalStart=Date.now())}endCurrentIntervalIfActive(){if(this.currentIntervalStart===null)return;let e=Date.now(),t=this.currentIntervalStart;e>t&&this.intervals.push({start:t,end:e}),this.currentIntervalStart=null}normalizeTimestamp(e){let t=(e-this.recordingStartTime-this.totalPausedTime)/1e3;return Math.max(0,t)}};function qd(e,t){if(e==null)throw Error(t);return e}function Jd(e,t=`StreamProcessor`){if(!e)throw Error(`${t} is required`);return e}let Yd=1e3;var Xd=class{constructor(e){this.recordingStartTime=0,this.recordingTimer=null,this.pauseStartTime=null,this.totalPausedTime=0,this.streamProcessor=null,this.bufferSizeUpdateInterval=null,this.tabVisibilityTracker=null,this.visibilityChangeHandler=null,this.blurHandler=null,this.focusHandler=null,this.streamManager=e}isRecording(){return this.streamManager.getState()===`recording`}getStreamProcessor(){return this.streamProcessor}getAudioStreamForAnalysis(){if(this.streamProcessor){let e=this.streamProcessor.getAudioStreamForAnalysis();if(e)return e}return this.streamManager.getAudioStreamForAnalysis()}async startRecording(e,t,n,r){let i=this.streamManager.getStream();if(W.debug(`[StreamRecordingState] startRecording called`,{hasMediaStream:!!i,isRecording:this.isRecording(),hasProcessor:!!e,audioTracks:i?.getAudioTracks().length||0}),!i)throw Error(`Stream must be started before recording`);if(this.isRecording())return W.debug(`[StreamRecordingState] Already recording, returning`),Promise.resolve();this.streamProcessor=e,W.debug(`[StreamRecordingState] StreamProcessor assigned, setting callbacks`),e.setOnMuteStateChange(e=>{this.streamManager.emit(`audiomutetoggle`,{muted:e})}),e.setOnSourceChange(e=>{this.streamManager.emit(`videosourcechange`,{stream:e})}),this.bufferSizeUpdateInterval=window.setInterval(()=>{if(!this.streamProcessor)return;let e=this.streamProcessor.getBufferSize(),t=Wd(e);this.streamManager.emit(`recordingbufferupdate`,{size:e,formatted:t})},Yd),this.resetRecordingState();let a=n&&r?{enabled:!0,text:r,recordingStartTime:this.recordingStartTime}:void 0;W.debug(`[StreamRecordingState] Overlay config`,{enableTabVisibilityOverlay:n,hasOverlayText:!!r,overlayText:r,overlayConfig:a}),W.debug(`[StreamRecordingState] Starting processing`),await e.startProcessing(i,t,a),W.info(`[StreamRecordingState] Processing started and worker ready`),n&&(W.debug(`[StreamRecordingState] Setting up tab visibility tracking`,{recordingStartTime:this.recordingStartTime}),this.tabVisibilityTracker=new Kd,this.tabVisibilityTracker.start(this.recordingStartTime),this.setupVisibilityUpdates(e)),this.streamManager.setState(`recording`),this.streamManager.emit(`recordingstart`,{recorder:null}),this.startRecordingTimer()}async stopRecording(){if(W.debug(`[StreamRecordingState] stopRecording called`,{hasStreamProcessor:!!this.streamProcessor,isRecording:this.isRecording()}),!(this.streamProcessor&&this.isRecording()))throw Error(`Not currently recording`);this.streamManager.setState(`stopping`),this.clearRecordingTimer(),this.clearBufferSizeInterval(),this.resetPauseState(),this.cleanupVisibilityUpdates();let e=[];this.tabVisibilityTracker?(e=this.tabVisibilityTracker.getIntervals(),W.debug(`[StreamRecordingState] Tab visibility intervals collected`,{intervalsCount:e.length,intervals:e}),this.tabVisibilityTracker.cleanup(),this.tabVisibilityTracker=null):W.debug(`[StreamRecordingState] No tab visibility tracker was active`),W.debug(`[StreamRecordingState] Finalizing stream processor`);let t=await this.streamProcessor.finalize();return W.info(`[StreamRecordingState] Stream processor finalized`,{blobSize:t.blob.size,hasBlob:!!t.blob}),this.streamManager.setState(`active`),this.streamManager.emit(`recordingstop`,{blob:t.blob,mimeType:`video/mp4`}),this.streamProcessor=null,W.debug(`[StreamRecordingState] StreamProcessor cleared`),{blob:t.blob,tabVisibilityIntervals:e}}pauseRecording(){this.clearRecordingTimer(),this.pauseStartTime===null&&(this.pauseStartTime=Date.now()),this.tabVisibilityTracker&&this.tabVisibilityTracker.pause(),this.streamProcessor&&this.isRecording()&&this.streamProcessor.pause()}resumeRecording(){if(this.pauseStartTime!==null){let e=Date.now()-this.pauseStartTime;this.totalPausedTime+=e,this.pauseStartTime=null}this.tabVisibilityTracker&&this.tabVisibilityTracker.resume(),this.startRecordingTimer(),this.streamProcessor&&this.isRecording()&&this.streamProcessor.resume()}toggleMute(){Jd(this.streamProcessor,`StreamProcessor`).toggleMute()}muteAudio(){this.streamProcessor?(this.streamProcessor.isMutedState()||this.streamProcessor.toggleMute(),this.streamManager.setAudioTracksEnabled(!1)):this.streamManager.getStream()&&(this.streamManager.setAudioTracksEnabled(!1),this.streamManager.emit(`audiomutetoggle`,{muted:!0}))}unmuteAudio(){this.streamProcessor?(this.streamProcessor.isMutedState()&&this.streamProcessor.toggleMute(),this.streamManager.setAudioTracksEnabled(!0)):this.streamManager.getStream()&&(this.streamManager.setAudioTracksEnabled(!0),this.streamManager.emit(`audiomutetoggle`,{muted:!1}))}isMuted(){if(this.streamProcessor)return this.streamProcessor.isMutedState();let e=this.streamManager.getStream();if(e){let t=e.getAudioTracks();return t.length>0&&t.every(e=>!e.enabled)}return!1}async switchVideoSource(e){await Jd(this.streamProcessor,`StreamProcessor`).switchVideoSource(e)}getCurrentVideoSource(){return qd(Jd(this.streamProcessor,`StreamProcessor`).getCurrentVideoSource(),`Current video source is not available`)}formatTimeElapsed(e){let t=Math.floor(e/60),n=Math.floor(e%60);return`${t.toString().padStart(2,`0`)}:${n.toString().padStart(2,`0`)}`}startRecordingTimer(){this.recordingTimer=window.setInterval(()=>{let e=(Date.now()-this.recordingStartTime-this.totalPausedTime)/1e3,t=this.formatTimeElapsed(e);this.streamManager.emit(`recordingtimeupdate`,{elapsed:e,formatted:t})},Yd)}clearRecordingTimer(){this.recordingTimer!==null&&(clearInterval(this.recordingTimer),this.recordingTimer=null)}clearBufferSizeInterval(){this.bufferSizeUpdateInterval!==null&&(clearInterval(this.bufferSizeUpdateInterval),this.bufferSizeUpdateInterval=null)}resetRecordingState(){this.recordingStartTime=performance.now(),this.totalPausedTime=0,this.pauseStartTime=null}resetPauseState(){this.totalPausedTime=0,this.pauseStartTime=null}setupVisibilityUpdates(e){if(typeof document>`u`||typeof window>`u`){W.warn(`[StreamRecordingState] Cannot setup visibility updates - document/window not available`);return}if(this.visibilityChangeHandler=()=>{if(typeof document>`u`)return;let t=document.visibilityState===`hidden`,n=performance.now();W.debug(`[StreamRecordingState] Visibility change`,{isHidden:t,timestamp:n,visibilityState:document.visibilityState}),e.updateTabVisibility(t,n)},this.blurHandler=()=>{let t=performance.now();W.debug(`[StreamRecordingState] Window blur`,{timestamp:t}),e.updateTabVisibility(!0,t)},this.focusHandler=()=>{let t=performance.now();W.debug(`[StreamRecordingState] Window focus`,{timestamp:t}),e.updateTabVisibility(!1,t)},document.addEventListener(`visibilitychange`,this.visibilityChangeHandler),window.addEventListener(`blur`,this.blurHandler),window.addEventListener(`focus`,this.focusHandler),document.visibilityState===`hidden`){let t=performance.now();W.debug(`[StreamRecordingState] Initial state is hidden`,{timestamp:t}),e.updateTabVisibility(!0,t)}else W.debug(`[StreamRecordingState] Initial state is visible`)}cleanupVisibilityUpdates(){this.visibilityChangeHandler&&typeof document<`u`&&(document.removeEventListener(`visibilitychange`,this.visibilityChangeHandler),this.visibilityChangeHandler=null),this.blurHandler&&typeof window<`u`&&(window.removeEventListener(`blur`,this.blurHandler),this.blurHandler=null),this.focusHandler&&typeof window<`u`&&(window.removeEventListener(`focus`,this.focusHandler),this.focusHandler=null)}destroy(){this.streamProcessor&&=(this.streamProcessor.cancel().catch(()=>{}),null),this.cleanupVisibilityUpdates(),this.tabVisibilityTracker&&=(this.tabVisibilityTracker.cleanup(),null),this.clearRecordingTimer(),this.clearBufferSizeInterval()}},Zd=class{constructor(e={}){this.streamManager=new Vd(e),this.recordingState=new Xd(this.streamManager)}getState(){return this.streamManager.getState()}getStream(){return this.streamManager.getStream()}getAudioStreamForAnalysis(){return this.recordingState.getAudioStreamForAnalysis()}isRecording(){return this.recordingState.isRecording()}isActive(){return this.streamManager.isActive()}on(e,t){return this.streamManager.on(e,t)}off(e,t){this.streamManager.off(e,t)}once(e,t){return this.streamManager.once(e,t)}setAudioDevice(e){this.streamManager.setAudioDevice(e)}setVideoDevice(e){this.streamManager.setVideoDevice(e)}getAudioDevice(){return this.streamManager.getAudioDevice()}getVideoDevice(){return this.streamManager.getVideoDevice()}async getAvailableDevices(){return await this.streamManager.getAvailableDevices()}async startStream(){return await this.streamManager.startStream()}stopStream(){this.streamManager.stopStream()}switchVideoDevice(e){return this.streamManager.switchVideoDevice(e)}switchAudioDevice(e){return this.streamManager.switchAudioDevice(e)}async startRecording(e,t,n,r){return await this.recordingState.startRecording(e,t,n,r)}async stopRecording(){return await this.recordingState.stopRecording()}pauseRecording(){this.recordingState.pauseRecording()}resumeRecording(){this.recordingState.resumeRecording()}toggleMute(){this.recordingState.toggleMute()}muteAudio(){this.recordingState.muteAudio()}unmuteAudio(){this.recordingState.unmuteAudio()}isMuted(){return this.recordingState.isMuted()}async switchVideoSource(e){return await this.recordingState.switchVideoSource(e)}setMediaStream(e){this.streamManager.setMediaStream(e)}getCurrentVideoSource(){return this.recordingState.getCurrentVideoSource()}destroy(){this.recordingState.destroy(),this.streamManager.destroy()}},Qd=class{constructor(e,t){this.isProcessing=!1,this.retryTimeoutId=null,this.callbacks={},this.storageService=e,this.uploadService=t,this.networkOnlineHandler=()=>{this.processQueue().catch(e=>{let t=i(e);this.callbacks.onUploadError?.(`network-recovery`,Error(t))})},window.addEventListener(`online`,this.networkOnlineHandler),this.processingIntervalId=window.setInterval(()=>{this.processQueue().catch(e=>{let t=i(e);this.callbacks.onUploadError?.(`processing-loop`,Error(t))})},5e3)}destroy(){this.clearTimer(this.processingIntervalId,clearInterval),this.clearTimer(this.retryTimeoutId,clearTimeout),window.removeEventListener(`online`,this.networkOnlineHandler)}setCallbacks(e){this.callbacks=e}async queueUpload(e){let t=await this.storageService.savePendingUpload(e);return this.processQueue(),t}async processQueue(){if(!this.isProcessing){this.isProcessing=!0;try{if(!this.storageService.isInitialized())throw Error(`Database not initialized`);let e=await this.storageService.getPendingUploads(`pending`);if(e.length>0){let t=this.getOldestUpload(e);await this.processUpload(t),this.isProcessing=!1;return}let t=(await this.storageService.getPendingUploads(`failed`)).filter(e=>e.retryCount<10);if(t.length>0){let e=this.getOldestFailedUpload(t),n=this.calculateRetryDelay(e.retryCount),r=Date.now()-e.updatedAt;if(r>=n)await this.storageService.updateUploadStatus(e.id,{status:`pending`,retryCount:e.retryCount}),await this.processUpload(e);else{let e=n-r;this.scheduleRetry(e)}}this.isProcessing=!1}catch(e){throw this.isProcessing=!1,Error(`Error processing upload queue: ${i(e)}`)}}}getPendingUploads(){return this.storageService.getPendingUploads()}async getStats(){let e=await this.storageService.getPendingUploads(),t={pending:0,uploading:0,failed:0,total:e.length};for(let n of e)n.status===`pending`?t.pending+=1:n.status===`uploading`?t.uploading+=1:n.status===`failed`&&(t.failed+=1);return t}getOldestUpload(e){if(e.length===0)throw Error(`Cannot get oldest upload from empty array`);return e.sort((e,t)=>e.createdAt-t.createdAt)[0]}getOldestFailedUpload(e){if(e.length===0)throw Error(`Cannot get oldest failed upload from empty array`);return e.sort((e,t)=>e.updatedAt-t.updatedAt)[0]}async processUpload(e){try{await this.storageService.updateUploadStatus(e.id,{status:`uploading`});let t=await this.uploadService.uploadVideo(e.blob,{apiKey:e.apiKey,backendUrl:e.backendUrl,filename:e.filename,duration:e.duration,metadata:e.metadata,userMetadata:e.userMetadata,onProgress:t=>{this.callbacks.onUploadProgress?.(e.id,t)}});await this.storageService.deleteUpload(e.id),this.callbacks.onUploadComplete?.(e.id,t)}catch(t){let n=i(t),r=e.retryCount+1;if(await this.storageService.updateUploadStatus(e.id,{status:`failed`,retryCount:r,lastError:n}),r>=10)this.callbacks.onUploadError?.(e.id,Error(`Upload failed after 10 attempts: ${n}`));else{let e=this.calculateRetryDelay(r);this.scheduleRetry(e)}}}calculateRetryDelay(e){let t=2e3*1.5**(e-1);return Math.min(t,3e5)}scheduleRetry(e){this.clearTimer(this.retryTimeoutId,clearTimeout),this.retryTimeoutId=window.setTimeout(()=>{this.retryTimeoutId=null,this.processQueue()},e)}clearTimer(e,t){e!==null&&t(e)}},$d=class{async uploadVideo(e,t){if(!t.filename)throw Error(`Filename is required`);if(!e.type||e.type.trim()===``)throw Error(`Blob type is required`);let n=await this.initVideoUpload({apiKey:t.apiKey,backendUrl:t.backendUrl,filename:t.filename,fileSize:e.size,mimeType:e.type,metadata:t.metadata,userMetadata:t.userMetadata});return this.uploadVideoFile(e,n.uploadUrl,{apiKey:t.apiKey,duration:t.duration,onProgress:t.onProgress})}async initVideoUpload(e){let t=`${e.backendUrl}/api/v1/videos/init`,n={filename:e.filename,fileSize:e.fileSize,mimeType:e.mimeType,preProcessed:!0};e.metadata&&(n.metadata=e.metadata),e.userMetadata&&(n.userMetadata=e.userMetadata);let r=await fetch(t,{method:`POST`,headers:{Authorization:`Bearer ${e.apiKey}`,"Content-Type":`application/json`},body:JSON.stringify(n)});if(!r.ok){let e=await this.extractErrorFromResponse(r,`Failed to initialize video upload`);throw Error(e)}return await r.json()}async extractErrorFromResponse(e,t){let n=await this.parseJsonResponse(e);return n&&typeof n==`object`&&`error`in n&&typeof n.error==`string`?n.error:`${t}: ${e.status} ${e.statusText}`}async parseJsonResponse(e){let t=await e.json();return typeof t==`object`&&t?t:null}uploadVideoFile(e,t,n){return new Promise((r,i)=>{let a=new XMLHttpRequest;if(n.onProgress){let e=n.onProgress;a.upload.addEventListener(`progress`,t=>{t.lengthComputable&&e(t.loaded/t.total)})}a.addEventListener(`load`,()=>{if(a.status>=200&&a.status<=299){this.parseSuccessResponse(a,r,i);return}this.parseErrorResponse(a,i)}),a.addEventListener(`error`,()=>{i(Error(`Network error during upload`))}),a.addEventListener(`abort`,()=>{i(Error(`Upload was aborted`))}),a.open(`PUT`,t),a.setRequestHeader(`Authorization`,`Bearer ${n.apiKey}`),a.setRequestHeader(`Content-Type`,e.type),n.duration!==void 0&&a.setRequestHeader(`X-Video-Duration`,n.duration.toString()),a.send(e)})}parseSuccessResponse(e,t,n){let r=this.safeParseJsonFromXhr(e);if(!r){n(Error(`Failed to parse upload response: invalid JSON`));return}t(r)}parseErrorResponse(e,t){let n=this.safeParseJsonFromXhr(e);if(n&&typeof n==`object`&&`error`in n&&typeof n.error==`string`){t(Error(n.error));return}t(Error(`Upload failed: ${e.status} ${e.statusText}`))}safeParseJsonFromXhr(e){if(!e.responseText||e.responseText.trim()===``)return null;let t=e.responseText.trim();if(!(t.startsWith(`{`)&&t.endsWith(`}`))||t.length<2)return null;let n=JSON.parse(e.responseText);return typeof n==`object`&&n?n:null}};function ef(e){let t=e.getVideoTracks();if(t.length===0)return!1;let n=t[0];return`displaySurface`in n.getSettings()||n.label.toLowerCase().includes(`screen`)||n.label.toLowerCase().includes(`display`)}dd();function tf(e){if(e!==void 0)return typeof e==`number`?e:e===du?`low`:e===fu?`medium`:e===pu?`high`:e===mu?`very-high`:`high`}async function nf(e,t,n){try{let{canEncodeVideo:r}=await Promise.resolve().then(()=>(dd(),ud));if(typeof r==`function`){let i={};if(e!==void 0&&(i.width=e),t!==void 0&&(i.height=t),n!==void 0&&(i.bitrate=n),await r(`hevc`,i))return`hevc`}}catch{}return`avc`}let rf=null;function af(){if(rf)return rf;if(typeof Blob>`u`||typeof URL>`u`)throw Error(`Blob and URL APIs are required for worker loading`);let e=new Blob([`// ../../node_modules/mediabunny/dist/modules/src/misc.js
|
|
108
108
|
/*!
|
|
109
109
|
* Copyright (c) 2025-present, Vanilagy and contributors
|
|
110
110
|
*
|
|
@@ -8610,7 +8610,7 @@ new RecorderWorker;
|
|
|
8610
8610
|
<!-- Error Message -->
|
|
8611
8611
|
<div class="vidtreo-error" id="error" style="display: none;"></div>
|
|
8612
8612
|
</div>
|
|
8613
|
-
`;function ym(e,t){return e.querySelector(t)}let bm=/^https?:\/\//i;function xm(e){return e?bm.test(e)?e:`https://${e}`:`https://api.vidtreo.com`}function Sm(e,t){let n={apiKey:e.getAttribute(`api-key`),backendUrl:xm(e.getAttribute(`backend-url`))},r=e.getAttribute(`countdown-duration`);if(r){let e=Number.parseInt(r,10);Number.isNaN(e)||(n.countdownDuration=e)}let a=e.getAttribute(`max-recording-time`);if(a){let e=Number.parseInt(a,10);Number.isNaN(e)||(n.maxRecordingTime=e)}let o=e.getAttribute(`user-metadata`);if(o)try{let e=JSON.parse(o);Object.assign(t,e),n.userMetadata=t}catch(e){throw Error(`Invalid user-metadata JSON: ${i(e)}`)}let s=e.getAttribute(`enable-source-switching`);n.enableSourceSwitching=s===null||s!==`false`;let c=e.getAttribute(`enable-mute`);n.enableMute=c===null||c!==`false`;let l=e.getAttribute(`enable-pause`);n.enablePause=l===null||l!==`false`;let u=e.getAttribute(`enable-device-change`);n.enableDeviceChange=u===null||u!==`false`;let d=e.getAttribute(`enable-tab-visibility-overlay`);return n.enableTabVisibilityOverlay=d!==null&&d!==`false`,n}function Cm(){if(typeof document>`u`||document.querySelector(`script[src*="@phosphor-icons/web"]`))return;let e=document.createElement(`script`);e.src=`https://unpkg.com/@phosphor-icons/web`,e.async=!0,document.head.appendChild(e)}let wm={recordingState:`idle`,stream:null,isMuted:!1,isPaused:!1,error:null,countdown:null,timer:`00:00`,isFinishing:!1,uploadProgress:null,transitionMessage:null,recordedBlob:null,devices:{cameras:[],microphones:[],selectedCamera:null,selectedMic:null},configError:null};var Tm=class extends HTMLElement{constructor(...e){super(...e),this.controller=null,this.uploadService=null,this.state={...wm},this.config={},this.initialized=!1,this.isInitializing=!1,this.isProcessingBlob=!1,this.videoPreview=null,this.audioBarsContainer=null,this.audioContext=null,this.analyser=null,this.animationFrameId=null,this.settingsView=`main`,this.slideDirection=`none`}static{this.observedAttributes=[`api-key`,`backend-url`,`countdown-duration`,`max-recording-time`,`user-metadata`,`enable-source-switching`,`enable-mute`,`enable-pause`,`enable-device-change`,`enable-tab-visibility-overlay`,`demo`]}get isDemo(){return this.hasAttribute(`demo`)&&this.getAttribute(`demo`)!==`false`}connectedCallback(){this.innerHTML=vm(),this.init()}disconnectedCallback(){this.cleanup()}attributeChangedCallback(e,t,n){t!==n&&[`api-key`,`backend-url`,`demo`].includes(e)&&(this.initialized&&this.cleanup(),this.init())}async init(){if(!this.isInitializing){this.isInitializing=!0;try{this.initialized&&this.cleanup(),this.config=Sm(this,{});let e=this.config.apiKey||``,t=this.config.backendUrl||``;if(!(this.isDemo||e)){this.updateState({configError:Error(`apiKey is required. Provide it as an attribute or ensure demo mode is enabled.`)}),this.isInitializing=!1;return}this.isDemo||(this.uploadService=new gm({apiKey:e,backendUrl:t})),this.controller=new wf(om(this));let n={...this.config};await this.controller.initialize(n),this.initialized=!0,this.updateState({configError:null}),this.videoPreview=ym(this,`#videoPreview`),this.audioBarsContainer=ym(this,`#audioLevelBars`),this.setupEventListeners(),Cm(),setTimeout(()=>this.startPreview(),100)}catch(e){this.updateState({error:i(e)})}finally{this.isInitializing=!1}}}renderConfigError(){let e=this.state,t=!!e.configError;if(this.toggleDisplay(`#configErrorOverlay`,t),t&&e.configError){let t=e.configError.message.includes(`apiKey is required`);this.toggleDisplay(`#configErrorMessageDefault`,!t),this.toggleDisplay(`#configErrorDetails`,t),t||this.setText(`#configErrorMessageDefault`,e.configError.message)}}cleanup(){this.controller&&=(this.controller.cleanup(),null),this.stopAudioAnalysis(),this.initialized=!1,this.state={...wm}}updateState(e){this.state={...this.state,...e},this.render(),e.stream!==void 0&&this.handleStreamUpdate(this.state.stream),this.state.devices.cameras.length===0&&this.state.stream&&this.updateDevices()}async updateDevices(){if(!this.controller)return;let e=this.controller.getDeviceManager(),t=await e.getAvailableDevices();this.updateState({devices:{cameras:t.videoinput,microphones:t.audioinput,selectedCamera:e.getSelectedCameraDeviceId(),selectedMic:e.getSelectedMicDeviceId()}})}handleStreamUpdate(e){this.videoPreview&&(e?(this.videoPreview.srcObject=e,this.videoPreview.style.display=`block`,this.videoPreview.play().catch(console.error),this.startAudioAnalysis(e)):(this.videoPreview.srcObject=null,this.videoPreview.style.display=`none`,this.stopAudioAnalysis()))}startAudioAnalysis(e){if(this.stopAudioAnalysis(),e.getAudioTracks().length!==0)try{this.audioContext=new AudioContext;let t=this.audioContext.createMediaStreamSource(e);this.analyser=this.audioContext.createAnalyser(),this.analyser.fftSize=64,t.connect(this.analyser);let n=new Uint8Array(this.analyser.frequencyBinCount),r=()=>{if(!this.analyser)return;this.analyser.getByteFrequencyData(n);let e=0;for(let t of n)e+=t;let t=e/n.length,i=Math.min(1,t/128);this.renderAudioBars(i),this.animationFrameId=requestAnimationFrame(r)};r()}catch(e){console.error(`Audio analysis setup failed`,e)}}stopAudioAnalysis(){this.animationFrameId&&=(cancelAnimationFrame(this.animationFrameId),null),this.audioContext&&=(this.audioContext.close(),null)}renderAudioBars(e){if(!this.audioBarsContainer)return;let t=[.8,1.2,.9],n=``;this.state.isMuted||t.forEach((t,r)=>{let i=Math.max(4,e*24*t);n+=`<div class="vidtreo-audio-level-bar" style="height: ${i}px;"></div>`}),this.audioBarsContainer.innerHTML=n}render(){this.renderPreviewSection(),this.renderIndicatorsSection(),this.renderButtonsSection(),this.renderStatusSection(),this.renderConfigError()}renderPreviewSection(){let e=this.state;this.toggleDisplay(`#startCameraArea`,!e.stream),this.toggleDisplay(`#videoPreview`,!!e.stream&&!e.transitionMessage),this.toggleClass(`#sourceTransitionOverlay`,`vidtreo-active`,!!e.transitionMessage),this.setText(`#transitionMessage`,e.transitionMessage||``)}renderIndicatorsSection(){let e=this.state,t=e.recordingState===`recording`||e.isPaused;this.toggleClass(`#countdownOverlay`,`vidtreo-active`,e.recordingState===`countdown`),this.setText(`#countdownNumber`,e.countdown?.toString()||``),this.toggleDisplay(`#recIndicatorTop`,t),this.toggleDisplay(`#recordingTimerRow`,t),this.setText(`#recordingTimer`,e.timer),this.toggleDisplay(`#audioLevelBars`,t),this.toggleDisplay(`#recordingControls`,!!e.stream)}renderButtonsSection(){let e=this.state,t=e.recordingState===`recording`||e.isPaused;this.toggleDisplay(`#btnSettings`,!t&&this.config.enableDeviceChange!==!1),this.toggleDisplay(`#btnRecord`,e.recordingState===`idle`),this.toggleDisplay(`#btnMute`,t&&this.config.enableMute!==!1),this.toggleDisplay(`#btnStop`,t),this.toggleDisplay(`#btnSwitchSource`,t&&this.config.enableSourceSwitching!==!1),this.renderPauseButton(t),this.renderMuteButton();let n=this.isDemo&&!t&&e.recordingState===`idle`&&e.recordedBlob!==null;this.toggleDisplay(`#btnDownload`,n)}renderPauseButton(e){let t=this.state,n=ym(this,`#btnPause`),r=this.querySelector(`#iconPause`);n&&(t.isPaused?(n.title=`Resume`,r&&(r.className=`ph-fill ph-play`)):(n.title=`Pause`,r&&(r.className=`ph-fill ph-pause`)),n.style.display=e&&this.config.enablePause!==!1?`inline-flex`:`none`)}renderMuteButton(){let e=this.state,t=ym(this,`#btnMute`),n=this.querySelector(`#iconMute`);t&&(n&&(n.className=e.isMuted?`ph-fill ph-microphone-slash`:`ph-fill ph-microphone`),t.classList.toggle(`vidtreo-muted`,e.isMuted))}renderStatusSection(){let e=this.state;if(this.toggleDisplay(`#error`,!!e.error),this.setText(`#error`,e.error||``),this.renderUploadStatus(),e.recordingState!==`idle`){let e=this.querySelector(`#settingsPanel`);e&&e.classList.remove(`vidtreo-active`)}}renderUploadStatus(){let e=this.state;this.toggleDisplay(`#finishingProgress`,e.isFinishing),this.toggleDisplay(`#uploadProgress`,e.uploadProgress!==null&&!e.isFinishing);let t=this.querySelector(`#uploadProgressFill`);t&&e.uploadProgress!==null&&(t.style.width=`${Math.round(e.uploadProgress*100)}%`);let n=this.querySelector(`#uploadProgressText`);n&&e.uploadProgress!==null&&(n.textContent=`${n.textContent?.split(` `)[0]||`Uploading...`} ${Math.round(e.uploadProgress*100)}%`)}toggleDisplay(e,t){let n=this.querySelector(e);if(n)if(t){let t=n.tagName===`BUTTON`,r=e.includes(`row`)||e.includes(`controls`)||e.includes(`Overlay`)||e.includes(`Indicator`)||e.includes(`Timer`)||e.includes(`Bars`);t?n.style.display=`inline-flex`:r?n.style.display=`flex`:n.style.display=`block`}else n.style.display=`none`}toggleClass(e,t,n){let r=this.querySelector(e);r&&r.classList.toggle(t,n)}setText(e,t){let n=this.querySelector(e);n&&(n.textContent=t)}async startPreview(){if(this.controller)try{await this.controller.startStream(),this.updateState({stream:this.controller.getStream()})}catch(e){this.updateState({error:i(e)})}}async handleRecord(){if(this.controller)try{await lm(this.controller,`camera`)}catch(e){this.updateState({error:i(e)})}}async processRecordingBlob(e){if(!this.isProcessingBlob){this.isProcessingBlob=!0;try{if(this.isDemo){this.updateState({recordedBlob:e});return}if(!this.uploadService)throw Error(`Upload service not ready`);this.updateState({isFinishing:!0});let t=await wd(e),n=`recording-${Date.now()}.mp4`;try{let r=await this.uploadService.uploadVideo(e,{apiKey:this.config.apiKey||``,backendUrl:this.config.backendUrl||``,filename:n,duration:t,userMetadata:this.config.userMetadata,onProgress:e=>{this.updateState({isFinishing:!1,uploadProgress:e})}});this.updateState({isFinishing:!1,uploadProgress:null}),this.dispatchEvent(new CustomEvent(`upload-complete`,{detail:r}))}catch(e){throw this.updateState({isFinishing:!1,uploadProgress:null}),e}}finally{this.isProcessingBlob=!1}}}async handleStop(){if(this.controller)try{let e=await um(this.controller,this.isDemo,()=>{},()=>{});e&&await this.processRecordingBlob(e)}catch(e){this.updateState({error:i(e)})}}handlePauseToggle(){this.controller&&(this.state.isPaused?fm(this.controller):dm(this.controller),this.updateState({isPaused:this.controller.isPaused()}))}handleDownload(){this.state.recordedBlob&&hm(this.state.recordedBlob)}handleMute(){this.controller&&(mm(this.controller),this.updateState({isMuted:this.controller.getIsMuted()}))}async handleSwitch(){if(!this.controller)return;let e=this.controller.getCurrentSourceType()===`camera`?`screen`:`camera`;try{await pm(this.controller,e)}catch(e){this.updateState({error:i(e)})}}setupEventListeners(){let e=(e,t)=>{let n=ym(this,e);n&&n.addEventListener(`click`,t)};e(`#btnRecord`,()=>this.handleRecord()),e(`#btnStop`,()=>this.handleStop()),e(`#btnPause`,()=>this.handlePauseToggle()),e(`#btnDownload`,()=>this.handleDownload()),e(`#btnMute`,()=>this.handleMute()),e(`#btnSwitchSource`,()=>this.handleSwitch());let t=this.querySelector(`#startCameraArea`);t&&t.addEventListener(`click`,()=>this.startPreview());let n=this.querySelector(`#btnSettings`),r=this.querySelector(`#settingsPanel`);n&&r&&n.addEventListener(`click`,()=>{r.classList.toggle(`vidtreo-active`),this.populateSettings()});let i=this.querySelector(`#btnSettingsBack`);i&&r&&i.addEventListener(`click`,()=>{}),this.setupSettingsListeners()}setupSettingsListeners(){let e=this.querySelector(`#btnCameraMenu`);e&&e.addEventListener(`click`,()=>this.navigateSettings(`camera`));let t=this.querySelector(`#btnMicMenu`);t&&t.addEventListener(`click`,()=>this.navigateSettings(`microphone`));let n=this.querySelector(`#btnSettingsBack`);n&&n.addEventListener(`click`,e=>{e.stopPropagation(),this.settingsView!==`main`&&this.navigateSettings(`main`)})}navigateSettings(e){e===`main`?this.slideDirection=`left`:this.slideDirection=`right`,this.settingsView=e,this.renderSettings(),setTimeout(()=>{this.slideDirection=`none`,this.renderSettings()},300)}renderSettings(){this.updateSettingsContent(),this.renderSettingsView()}updateSettingsContent(){let e=this.querySelector(`#settingsContent`);e&&(e.classList.remove(`vidtreo-slide-left`,`vidtreo-slide-right`,`vidtreo-slide-none`),this.slideDirection!==`none`&&e.classList.add(`vidtreo-slide-${this.slideDirection}`))}renderSettingsView(){let e=this.querySelector(`#settingsMain`),t=this.querySelector(`#cameraList`),n=this.querySelector(`#micList`),r=this.querySelector(`#btnSettingsBack`);e&&(e.style.display=`none`),t&&(t.style.display=`none`),n&&(n.style.display=`none`),r&&(r.style.display=`none`),this.settingsView===`main`?this.renderSettingsMain(e,r):this.settingsView===`camera`?this.renderSettingsCamera(t,r):this.settingsView===`microphone`&&this.renderSettingsMicrophone(n,r)}renderSettingsMain(e,t){e&&(e.style.display=`flex`),t&&(t.style.display=`none`),this.updateCurrentDeviceLabels()}updateCurrentDeviceLabels(){let e=this.state.devices.cameras.filter(e=>e.deviceId&&e.deviceId.trim()!==``),t=this.state.devices.microphones.filter(e=>e.deviceId&&e.deviceId.trim()!==``),n=e.find(e=>e.deviceId===this.state.devices.selectedCamera),r=t.find(e=>e.deviceId===this.state.devices.selectedMic),i=n?.label||e[0]?.label||`Camera`,a=r?.label||t[0]?.label||`Microphone`;this.setText(`#currentCameraName`,i),this.setText(`#currentMicName`,a)}renderSettingsCamera(e,t){e&&(e.style.display=`flex`,this.renderDeviceList(e,this.state.devices.cameras,this.state.devices.selectedCamera,`camera`));let n=this.querySelector(`.vidtreo-settings-title`),r=this.querySelector(`.vidtreo-settings-back-icon`);t&&(t.style.display=`flex`,t.style.cursor=`pointer`,t.onclick=()=>this.navigateSettings(`main`)),n&&(n.textContent=`Camera`),r&&(r.style.display=`flex`)}renderSettingsMicrophone(e,t){e&&(e.style.display=`flex`,this.renderDeviceList(e,this.state.devices.microphones,this.state.devices.selectedMic,`mic`));let n=this.querySelector(`.vidtreo-settings-title`),r=this.querySelector(`.vidtreo-settings-back-icon`);t&&(t.style.display=`flex`,t.style.cursor=`pointer`,t.onclick=()=>this.navigateSettings(`main`)),n&&(n.textContent=`Microphone`),r&&(r.style.display=`flex`)}renderDeviceList(e,t,n,r){if(!t||t.length===0){e.innerHTML=`<div class="vidtreo-device-empty">No devices found</div>`;return}e.innerHTML=``;for(let a of t){let t=document.createElement(`button`);t.className=`vidtreo-device-option`,t.innerHTML=`
|
|
8613
|
+
`;function ym(e,t){return e.querySelector(t)}let bm=/^https?:\/\//i;function xm(e){return e?bm.test(e)?e:`https://${e}`:`https://core.vidtreo.com`}function Sm(e,t){let n={apiKey:e.getAttribute(`api-key`),backendUrl:xm(e.getAttribute(`backend-url`))},r=e.getAttribute(`countdown-duration`);if(r){let e=Number.parseInt(r,10);Number.isNaN(e)||(n.countdownDuration=e)}let a=e.getAttribute(`max-recording-time`);if(a){let e=Number.parseInt(a,10);Number.isNaN(e)||(n.maxRecordingTime=e)}let o=e.getAttribute(`user-metadata`);if(o)try{let e=JSON.parse(o);Object.assign(t,e),n.userMetadata=t}catch(e){throw Error(`Invalid user-metadata JSON: ${i(e)}`)}let s=e.getAttribute(`enable-source-switching`);n.enableSourceSwitching=s===null||s!==`false`;let c=e.getAttribute(`enable-mute`);n.enableMute=c===null||c!==`false`;let l=e.getAttribute(`enable-pause`);n.enablePause=l===null||l!==`false`;let u=e.getAttribute(`enable-device-change`);n.enableDeviceChange=u===null||u!==`false`;let d=e.getAttribute(`enable-tab-visibility-overlay`);return n.enableTabVisibilityOverlay=d!==null&&d!==`false`,n}function Cm(){if(typeof document>`u`||document.querySelector(`script[src*="@phosphor-icons/web"]`))return;let e=document.createElement(`script`);e.src=`https://unpkg.com/@phosphor-icons/web`,e.async=!0,document.head.appendChild(e)}let wm={recordingState:`idle`,stream:null,isMuted:!1,isPaused:!1,error:null,countdown:null,timer:`00:00`,isFinishing:!1,uploadProgress:null,transitionMessage:null,recordedBlob:null,devices:{cameras:[],microphones:[],selectedCamera:null,selectedMic:null},configError:null};var Tm=class extends HTMLElement{constructor(...e){super(...e),this.controller=null,this.uploadService=null,this.state={...wm},this.config={},this.initialized=!1,this.isInitializing=!1,this.isProcessingBlob=!1,this.videoPreview=null,this.audioBarsContainer=null,this.audioContext=null,this.analyser=null,this.animationFrameId=null,this.settingsView=`main`,this.slideDirection=`none`}static{this.observedAttributes=[`api-key`,`backend-url`,`countdown-duration`,`max-recording-time`,`user-metadata`,`enable-source-switching`,`enable-mute`,`enable-pause`,`enable-device-change`,`enable-tab-visibility-overlay`,`demo`]}get isDemo(){return this.hasAttribute(`demo`)&&this.getAttribute(`demo`)!==`false`}connectedCallback(){this.innerHTML=vm(),this.init()}disconnectedCallback(){this.cleanup()}attributeChangedCallback(e,t,n){t!==n&&[`api-key`,`backend-url`,`demo`].includes(e)&&(this.initialized&&this.cleanup(),this.init())}async init(){if(!this.isInitializing){this.isInitializing=!0;try{this.initialized&&this.cleanup(),this.config=Sm(this,{});let e=this.config.apiKey||``,t=this.config.backendUrl||``;if(!(this.isDemo||e)){this.updateState({configError:Error(`apiKey is required. Provide it as an attribute or ensure demo mode is enabled.`)}),this.isInitializing=!1;return}this.isDemo||(this.uploadService=new gm({apiKey:e,backendUrl:t})),this.controller=new wf(om(this));let n={...this.config};await this.controller.initialize(n),this.initialized=!0,this.updateState({configError:null}),this.videoPreview=ym(this,`#videoPreview`),this.audioBarsContainer=ym(this,`#audioLevelBars`),this.setupEventListeners(),Cm(),setTimeout(()=>this.startPreview(),100)}catch(e){this.updateState({error:i(e)})}finally{this.isInitializing=!1}}}renderConfigError(){let e=this.state,t=!!e.configError;if(this.toggleDisplay(`#configErrorOverlay`,t),t&&e.configError){let t=e.configError.message.includes(`apiKey is required`);this.toggleDisplay(`#configErrorMessageDefault`,!t),this.toggleDisplay(`#configErrorDetails`,t),t||this.setText(`#configErrorMessageDefault`,e.configError.message)}}cleanup(){this.controller&&=(this.controller.cleanup(),null),this.stopAudioAnalysis(),this.initialized=!1,this.state={...wm}}updateState(e){this.state={...this.state,...e},this.render(),e.stream!==void 0&&this.handleStreamUpdate(this.state.stream),this.state.devices.cameras.length===0&&this.state.stream&&this.updateDevices()}async updateDevices(){if(!this.controller)return;let e=this.controller.getDeviceManager(),t=await e.getAvailableDevices();this.updateState({devices:{cameras:t.videoinput,microphones:t.audioinput,selectedCamera:e.getSelectedCameraDeviceId(),selectedMic:e.getSelectedMicDeviceId()}})}handleStreamUpdate(e){this.videoPreview&&(e?(this.videoPreview.srcObject=e,this.videoPreview.style.display=`block`,this.videoPreview.play().catch(console.error),this.startAudioAnalysis(e)):(this.videoPreview.srcObject=null,this.videoPreview.style.display=`none`,this.stopAudioAnalysis()))}startAudioAnalysis(e){if(this.stopAudioAnalysis(),e.getAudioTracks().length!==0)try{this.audioContext=new AudioContext;let t=this.audioContext.createMediaStreamSource(e);this.analyser=this.audioContext.createAnalyser(),this.analyser.fftSize=64,t.connect(this.analyser);let n=new Uint8Array(this.analyser.frequencyBinCount),r=()=>{if(!this.analyser)return;this.analyser.getByteFrequencyData(n);let e=0;for(let t of n)e+=t;let t=e/n.length,i=Math.min(1,t/128);this.renderAudioBars(i),this.animationFrameId=requestAnimationFrame(r)};r()}catch(e){console.error(`Audio analysis setup failed`,e)}}stopAudioAnalysis(){this.animationFrameId&&=(cancelAnimationFrame(this.animationFrameId),null),this.audioContext&&=(this.audioContext.close(),null)}renderAudioBars(e){if(!this.audioBarsContainer)return;let t=[.8,1.2,.9],n=``;this.state.isMuted||t.forEach((t,r)=>{let i=Math.max(4,e*24*t);n+=`<div class="vidtreo-audio-level-bar" style="height: ${i}px;"></div>`}),this.audioBarsContainer.innerHTML=n}render(){this.renderPreviewSection(),this.renderIndicatorsSection(),this.renderButtonsSection(),this.renderStatusSection(),this.renderConfigError()}renderPreviewSection(){let e=this.state;this.toggleDisplay(`#startCameraArea`,!e.stream),this.toggleDisplay(`#videoPreview`,!!e.stream&&!e.transitionMessage),this.toggleClass(`#sourceTransitionOverlay`,`vidtreo-active`,!!e.transitionMessage),this.setText(`#transitionMessage`,e.transitionMessage||``)}renderIndicatorsSection(){let e=this.state,t=e.recordingState===`recording`||e.isPaused;this.toggleClass(`#countdownOverlay`,`vidtreo-active`,e.recordingState===`countdown`),this.setText(`#countdownNumber`,e.countdown?.toString()||``),this.toggleDisplay(`#recIndicatorTop`,t),this.toggleDisplay(`#recordingTimerRow`,t),this.setText(`#recordingTimer`,e.timer),this.toggleDisplay(`#audioLevelBars`,t),this.toggleDisplay(`#recordingControls`,!!e.stream)}renderButtonsSection(){let e=this.state,t=e.recordingState===`recording`||e.isPaused;this.toggleDisplay(`#btnSettings`,!t&&this.config.enableDeviceChange!==!1),this.toggleDisplay(`#btnRecord`,e.recordingState===`idle`),this.toggleDisplay(`#btnMute`,t&&this.config.enableMute!==!1),this.toggleDisplay(`#btnStop`,t),this.toggleDisplay(`#btnSwitchSource`,t&&this.config.enableSourceSwitching!==!1),this.renderPauseButton(t),this.renderMuteButton();let n=this.isDemo&&!t&&e.recordingState===`idle`&&e.recordedBlob!==null;this.toggleDisplay(`#btnDownload`,n)}renderPauseButton(e){let t=this.state,n=ym(this,`#btnPause`),r=this.querySelector(`#iconPause`);n&&(t.isPaused?(n.title=`Resume`,r&&(r.className=`ph-fill ph-play`)):(n.title=`Pause`,r&&(r.className=`ph-fill ph-pause`)),n.style.display=e&&this.config.enablePause!==!1?`inline-flex`:`none`)}renderMuteButton(){let e=this.state,t=ym(this,`#btnMute`),n=this.querySelector(`#iconMute`);t&&(n&&(n.className=e.isMuted?`ph-fill ph-microphone-slash`:`ph-fill ph-microphone`),t.classList.toggle(`vidtreo-muted`,e.isMuted))}renderStatusSection(){let e=this.state;if(this.toggleDisplay(`#error`,!!e.error),this.setText(`#error`,e.error||``),this.renderUploadStatus(),e.recordingState!==`idle`){let e=this.querySelector(`#settingsPanel`);e&&e.classList.remove(`vidtreo-active`)}}renderUploadStatus(){let e=this.state;this.toggleDisplay(`#finishingProgress`,e.isFinishing),this.toggleDisplay(`#uploadProgress`,e.uploadProgress!==null&&!e.isFinishing);let t=this.querySelector(`#uploadProgressFill`);t&&e.uploadProgress!==null&&(t.style.width=`${Math.round(e.uploadProgress*100)}%`);let n=this.querySelector(`#uploadProgressText`);n&&e.uploadProgress!==null&&(n.textContent=`${n.textContent?.split(` `)[0]||`Uploading...`} ${Math.round(e.uploadProgress*100)}%`)}toggleDisplay(e,t){let n=this.querySelector(e);if(n)if(t){let t=n.tagName===`BUTTON`,r=e.includes(`row`)||e.includes(`controls`)||e.includes(`Overlay`)||e.includes(`Indicator`)||e.includes(`Timer`)||e.includes(`Bars`);t?n.style.display=`inline-flex`:r?n.style.display=`flex`:n.style.display=`block`}else n.style.display=`none`}toggleClass(e,t,n){let r=this.querySelector(e);r&&r.classList.toggle(t,n)}setText(e,t){let n=this.querySelector(e);n&&(n.textContent=t)}async startPreview(){if(this.controller)try{await this.controller.startStream(),this.updateState({stream:this.controller.getStream()})}catch(e){this.updateState({error:i(e)})}}async handleRecord(){if(this.controller)try{await lm(this.controller,`camera`)}catch(e){this.updateState({error:i(e)})}}async processRecordingBlob(e){if(!this.isProcessingBlob){this.isProcessingBlob=!0;try{if(this.isDemo){this.updateState({recordedBlob:e});return}if(!this.uploadService)throw Error(`Upload service not ready`);this.updateState({isFinishing:!0});let t=await wd(e),n=`recording-${Date.now()}.mp4`;try{let r=await this.uploadService.uploadVideo(e,{apiKey:this.config.apiKey||``,backendUrl:this.config.backendUrl||``,filename:n,duration:t,userMetadata:this.config.userMetadata,onProgress:e=>{this.updateState({isFinishing:!1,uploadProgress:e})}});this.updateState({isFinishing:!1,uploadProgress:null}),this.dispatchEvent(new CustomEvent(`upload-complete`,{detail:r}))}catch(e){throw this.updateState({isFinishing:!1,uploadProgress:null}),e}}finally{this.isProcessingBlob=!1}}}async handleStop(){if(this.controller)try{let e=await um(this.controller,this.isDemo,()=>{},()=>{});e&&await this.processRecordingBlob(e)}catch(e){this.updateState({error:i(e)})}}handlePauseToggle(){this.controller&&(this.state.isPaused?fm(this.controller):dm(this.controller),this.updateState({isPaused:this.controller.isPaused()}))}handleDownload(){this.state.recordedBlob&&hm(this.state.recordedBlob)}handleMute(){this.controller&&(mm(this.controller),this.updateState({isMuted:this.controller.getIsMuted()}))}async handleSwitch(){if(!this.controller)return;let e=this.controller.getCurrentSourceType()===`camera`?`screen`:`camera`;try{await pm(this.controller,e)}catch(e){this.updateState({error:i(e)})}}setupEventListeners(){let e=(e,t)=>{let n=ym(this,e);n&&n.addEventListener(`click`,t)};e(`#btnRecord`,()=>this.handleRecord()),e(`#btnStop`,()=>this.handleStop()),e(`#btnPause`,()=>this.handlePauseToggle()),e(`#btnDownload`,()=>this.handleDownload()),e(`#btnMute`,()=>this.handleMute()),e(`#btnSwitchSource`,()=>this.handleSwitch());let t=this.querySelector(`#startCameraArea`);t&&t.addEventListener(`click`,()=>this.startPreview());let n=this.querySelector(`#btnSettings`),r=this.querySelector(`#settingsPanel`);n&&r&&n.addEventListener(`click`,()=>{r.classList.toggle(`vidtreo-active`),this.populateSettings()});let i=this.querySelector(`#btnSettingsBack`);i&&r&&i.addEventListener(`click`,()=>{}),this.setupSettingsListeners()}setupSettingsListeners(){let e=this.querySelector(`#btnCameraMenu`);e&&e.addEventListener(`click`,()=>this.navigateSettings(`camera`));let t=this.querySelector(`#btnMicMenu`);t&&t.addEventListener(`click`,()=>this.navigateSettings(`microphone`));let n=this.querySelector(`#btnSettingsBack`);n&&n.addEventListener(`click`,e=>{e.stopPropagation(),this.settingsView!==`main`&&this.navigateSettings(`main`)})}navigateSettings(e){e===`main`?this.slideDirection=`left`:this.slideDirection=`right`,this.settingsView=e,this.renderSettings(),setTimeout(()=>{this.slideDirection=`none`,this.renderSettings()},300)}renderSettings(){this.updateSettingsContent(),this.renderSettingsView()}updateSettingsContent(){let e=this.querySelector(`#settingsContent`);e&&(e.classList.remove(`vidtreo-slide-left`,`vidtreo-slide-right`,`vidtreo-slide-none`),this.slideDirection!==`none`&&e.classList.add(`vidtreo-slide-${this.slideDirection}`))}renderSettingsView(){let e=this.querySelector(`#settingsMain`),t=this.querySelector(`#cameraList`),n=this.querySelector(`#micList`),r=this.querySelector(`#btnSettingsBack`);e&&(e.style.display=`none`),t&&(t.style.display=`none`),n&&(n.style.display=`none`),r&&(r.style.display=`none`),this.settingsView===`main`?this.renderSettingsMain(e,r):this.settingsView===`camera`?this.renderSettingsCamera(t,r):this.settingsView===`microphone`&&this.renderSettingsMicrophone(n,r)}renderSettingsMain(e,t){e&&(e.style.display=`flex`),t&&(t.style.display=`none`),this.updateCurrentDeviceLabels()}updateCurrentDeviceLabels(){let e=this.state.devices.cameras.filter(e=>e.deviceId&&e.deviceId.trim()!==``),t=this.state.devices.microphones.filter(e=>e.deviceId&&e.deviceId.trim()!==``),n=e.find(e=>e.deviceId===this.state.devices.selectedCamera),r=t.find(e=>e.deviceId===this.state.devices.selectedMic),i=n?.label||e[0]?.label||`Camera`,a=r?.label||t[0]?.label||`Microphone`;this.setText(`#currentCameraName`,i),this.setText(`#currentMicName`,a)}renderSettingsCamera(e,t){e&&(e.style.display=`flex`,this.renderDeviceList(e,this.state.devices.cameras,this.state.devices.selectedCamera,`camera`));let n=this.querySelector(`.vidtreo-settings-title`),r=this.querySelector(`.vidtreo-settings-back-icon`);t&&(t.style.display=`flex`,t.style.cursor=`pointer`,t.onclick=()=>this.navigateSettings(`main`)),n&&(n.textContent=`Camera`),r&&(r.style.display=`flex`)}renderSettingsMicrophone(e,t){e&&(e.style.display=`flex`,this.renderDeviceList(e,this.state.devices.microphones,this.state.devices.selectedMic,`mic`));let n=this.querySelector(`.vidtreo-settings-title`),r=this.querySelector(`.vidtreo-settings-back-icon`);t&&(t.style.display=`flex`,t.style.cursor=`pointer`,t.onclick=()=>this.navigateSettings(`main`)),n&&(n.textContent=`Microphone`),r&&(r.style.display=`flex`)}renderDeviceList(e,t,n,r){if(!t||t.length===0){e.innerHTML=`<div class="vidtreo-device-empty">No devices found</div>`;return}e.innerHTML=``;for(let a of t){let t=document.createElement(`button`);t.className=`vidtreo-device-option`,t.innerHTML=`
|
|
8614
8614
|
<div class="vidtreo-device-option-check-container">${a.deviceId===n?`<i class="ph-fill ph-check vidtreo-device-checkmark" style="display: flex; font-size: 20px;"></i>`:`<span class="vidtreo-device-checkmark-placeholder"></span>`}</div>
|
|
8615
8615
|
<span class="vidtreo-device-option-label">${a.label||`Device ${a.deviceId.slice(0,8)}`}</span>
|
|
8616
8616
|
`,t.onclick=()=>{this.controller&&(r===`camera`?sm(this.controller,a.deviceId).then(e=>this.updateState({stream:e})).catch(e=>this.updateState({error:i(e)})):cm(this.controller,a.deviceId).then(e=>this.updateState({stream:e})).catch(e=>this.updateState({error:i(e)})),r===`camera`&&(this.state.devices.selectedCamera=a.deviceId),r===`mic`&&(this.state.devices.selectedMic=a.deviceId),this.navigateSettings(`main`))},e.appendChild(t)}}populateSettings(){this.settingsView=`main`,this.slideDirection=`none`,this.renderSettings()}};return customElements.get(`vidtreo-recorder`)||customElements.define(`vidtreo-recorder`,Tm),e.VidtreoRecorder=Tm,e})({});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vidtreo/recorder-wc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-rc1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Web component for @vidtreo/recorder - video recording SDK",
|
|
6
6
|
"main": "./dist/vidtreo-recorder.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"author": "cfonseca@vidtreo.com",
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@vidtreo/recorder": ">=0.
|
|
30
|
+
"@vidtreo/recorder": ">=1.0.0-rc1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^24.10.1",
|