@dialtribe/react-sdk 0.1.0-alpha.21 → 0.1.0-alpha.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{dialtribe-streamer-D9ulVBVb.d.ts → dialtribe-streamer-DOhD-r_F.d.ts} +8 -3
- package/dist/{dialtribe-streamer-DH23BseY.d.mts → dialtribe-streamer-Do-8Oavc.d.mts} +8 -3
- package/dist/dialtribe-streamer.d.mts +1 -1
- package/dist/dialtribe-streamer.d.ts +1 -1
- package/dist/dialtribe-streamer.js +64 -11
- package/dist/dialtribe-streamer.js.map +1 -1
- package/dist/dialtribe-streamer.mjs +64 -11
- package/dist/dialtribe-streamer.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +64 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2337,8 +2337,11 @@ var WebSocketStreamer = class {
|
|
|
2337
2337
|
* Set up canvas-based rendering pipeline for video streams.
|
|
2338
2338
|
* This allows seamless camera flips by changing the video source
|
|
2339
2339
|
* without affecting MediaRecorder (which records from the canvas).
|
|
2340
|
+
*
|
|
2341
|
+
* This is async to ensure the video is producing frames before returning,
|
|
2342
|
+
* which prevents black initial thumbnails.
|
|
2340
2343
|
*/
|
|
2341
|
-
setupCanvasRendering() {
|
|
2344
|
+
async setupCanvasRendering() {
|
|
2342
2345
|
console.log("\u{1F3A8} Setting up canvas-based rendering for seamless camera flips");
|
|
2343
2346
|
const videoTrack = this.mediaStream.getVideoTracks()[0];
|
|
2344
2347
|
const settings = videoTrack?.getSettings() || {};
|
|
@@ -2356,7 +2359,27 @@ var WebSocketStreamer = class {
|
|
|
2356
2359
|
videoElement.srcObject = this.mediaStream;
|
|
2357
2360
|
videoElement.muted = true;
|
|
2358
2361
|
videoElement.playsInline = true;
|
|
2359
|
-
|
|
2362
|
+
await new Promise((resolve) => {
|
|
2363
|
+
const checkReady = () => {
|
|
2364
|
+
if (videoElement.videoWidth > 0 && videoElement.videoHeight > 0) {
|
|
2365
|
+
console.log(`\u{1F4F9} Video ready: ${videoElement.videoWidth}x${videoElement.videoHeight}`);
|
|
2366
|
+
resolve();
|
|
2367
|
+
} else {
|
|
2368
|
+
requestAnimationFrame(checkReady);
|
|
2369
|
+
}
|
|
2370
|
+
};
|
|
2371
|
+
videoElement.addEventListener("loadeddata", () => {
|
|
2372
|
+
checkReady();
|
|
2373
|
+
}, { once: true });
|
|
2374
|
+
videoElement.play().catch((e) => {
|
|
2375
|
+
console.warn("Video autoplay warning:", e);
|
|
2376
|
+
resolve();
|
|
2377
|
+
});
|
|
2378
|
+
setTimeout(() => {
|
|
2379
|
+
console.warn("\u26A0\uFE0F Video ready timeout - continuing anyway");
|
|
2380
|
+
resolve();
|
|
2381
|
+
}, 2e3);
|
|
2382
|
+
});
|
|
2360
2383
|
const frameRate = settings.frameRate || 30;
|
|
2361
2384
|
const stream = canvas.captureStream(frameRate);
|
|
2362
2385
|
const audioTracks = this.mediaStream.getAudioTracks();
|
|
@@ -2520,7 +2543,7 @@ Please check encoder server logs and DATABASE_URL configuration.`
|
|
|
2520
2543
|
});
|
|
2521
2544
|
console.log("\u2705 WebSocket connected");
|
|
2522
2545
|
this.setupWebSocketHandlers();
|
|
2523
|
-
const streamToRecord = this.isVideo ? this.setupCanvasRendering() : this.mediaStream;
|
|
2546
|
+
const streamToRecord = this.isVideo ? await this.setupCanvasRendering() : this.mediaStream;
|
|
2524
2547
|
const recorderOptions = getMediaRecorderOptions(this.isVideo);
|
|
2525
2548
|
this.mimeType = recorderOptions.mimeType;
|
|
2526
2549
|
this.mediaRecorder = new MediaRecorder(streamToRecord, recorderOptions);
|
|
@@ -2598,20 +2621,50 @@ Please check encoder server logs and DATABASE_URL configuration.`
|
|
|
2598
2621
|
/**
|
|
2599
2622
|
* Replace the video track for camera flips.
|
|
2600
2623
|
*
|
|
2601
|
-
* When using canvas-based rendering (video streams), this
|
|
2602
|
-
*
|
|
2624
|
+
* When using canvas-based rendering (video streams), this preloads the new
|
|
2625
|
+
* camera in a temporary video element, waits for it to be ready, then swaps
|
|
2626
|
+
* it in. This ensures continuous frame output with no gaps.
|
|
2603
2627
|
*
|
|
2604
2628
|
* @param newVideoTrack - The new video track from the flipped camera
|
|
2629
|
+
* @returns Promise that resolves when the swap is complete
|
|
2605
2630
|
*/
|
|
2606
|
-
replaceVideoTrack(newVideoTrack) {
|
|
2631
|
+
async replaceVideoTrack(newVideoTrack) {
|
|
2607
2632
|
console.log("\u{1F504} Replacing video track");
|
|
2608
2633
|
if (this.canvasState) {
|
|
2609
|
-
console.log("\u{1F3A8} Using canvas-based swap (
|
|
2634
|
+
console.log("\u{1F3A8} Using canvas-based swap with preloading (no frame gaps)");
|
|
2610
2635
|
const audioTracks = this.mediaStream.getAudioTracks();
|
|
2611
2636
|
const newStream = new MediaStream([newVideoTrack, ...audioTracks]);
|
|
2637
|
+
const preloadVideo = document.createElement("video");
|
|
2638
|
+
preloadVideo.srcObject = newStream;
|
|
2639
|
+
preloadVideo.muted = true;
|
|
2640
|
+
preloadVideo.playsInline = true;
|
|
2641
|
+
await new Promise((resolve, reject) => {
|
|
2642
|
+
const timeout = setTimeout(() => {
|
|
2643
|
+
console.warn("\u26A0\uFE0F Video preload timeout - switching anyway");
|
|
2644
|
+
resolve();
|
|
2645
|
+
}, 3e3);
|
|
2646
|
+
preloadVideo.addEventListener("loadeddata", () => {
|
|
2647
|
+
if (preloadVideo.videoWidth > 0 && preloadVideo.videoHeight > 0) {
|
|
2648
|
+
clearTimeout(timeout);
|
|
2649
|
+
console.log(`\u{1F4F9} New camera ready: ${preloadVideo.videoWidth}x${preloadVideo.videoHeight}`);
|
|
2650
|
+
resolve();
|
|
2651
|
+
}
|
|
2652
|
+
}, { once: true });
|
|
2653
|
+
preloadVideo.addEventListener("error", (e) => {
|
|
2654
|
+
clearTimeout(timeout);
|
|
2655
|
+
reject(new Error(`Video preload failed: ${e}`));
|
|
2656
|
+
}, { once: true });
|
|
2657
|
+
preloadVideo.play().catch((e) => {
|
|
2658
|
+
clearTimeout(timeout);
|
|
2659
|
+
console.warn("Video preload play warning:", e);
|
|
2660
|
+
resolve();
|
|
2661
|
+
});
|
|
2662
|
+
});
|
|
2612
2663
|
this.mediaStream.getVideoTracks().forEach((track) => track.stop());
|
|
2613
|
-
this.canvasState.videoElement
|
|
2614
|
-
this.canvasState.videoElement
|
|
2664
|
+
const oldVideoElement = this.canvasState.videoElement;
|
|
2665
|
+
this.canvasState.videoElement = preloadVideo;
|
|
2666
|
+
oldVideoElement.pause();
|
|
2667
|
+
oldVideoElement.srcObject = null;
|
|
2615
2668
|
this.mediaStream = newStream;
|
|
2616
2669
|
this.invalidateScalingCache();
|
|
2617
2670
|
const settings = newVideoTrack.getSettings();
|
|
@@ -2675,7 +2728,7 @@ Please check encoder server logs and DATABASE_URL configuration.`
|
|
|
2675
2728
|
let streamToRecord = this.mediaStream;
|
|
2676
2729
|
if (this.isVideo) {
|
|
2677
2730
|
this.cleanupCanvasRendering();
|
|
2678
|
-
streamToRecord = this.setupCanvasRendering();
|
|
2731
|
+
streamToRecord = await this.setupCanvasRendering();
|
|
2679
2732
|
console.log("\u{1F3A8} Canvas rendering recreated for new stream");
|
|
2680
2733
|
}
|
|
2681
2734
|
const recorderOptions = getMediaRecorderOptions(this.isVideo);
|
|
@@ -3651,7 +3704,7 @@ function DialtribeStreamer({
|
|
|
3651
3704
|
console.log("\u{1F4F7} Got new camera stream:", newFacingMode);
|
|
3652
3705
|
const newVideoTrack = newStream.getVideoTracks()[0];
|
|
3653
3706
|
if (newVideoTrack) {
|
|
3654
|
-
streamer.replaceVideoTrack(newVideoTrack);
|
|
3707
|
+
await streamer.replaceVideoTrack(newVideoTrack);
|
|
3655
3708
|
}
|
|
3656
3709
|
const updatedStream = streamer.getMediaStream();
|
|
3657
3710
|
setMediaStream(updatedStream);
|