@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/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { HelloWorld, HelloWorldProps } from './hello-world.mjs';
2
2
  export { A as ApiClientConfig, h as AudioWaveform, B as Broadcast, C as CDN_DOMAIN, d as DIALTRIBE_API_BASE, c as DialtribeClient, a as DialtribeContextValue, i as DialtribeOverlay, k as DialtribeOverlayMode, j as DialtribeOverlayProps, e as DialtribePlayer, g as DialtribePlayerErrorBoundary, f as DialtribePlayerProps, D as DialtribeProvider, b as DialtribeProviderProps, E as ENDPOINTS, H as HTTP_STATUS, q as HttpStatusCode, L as LoadingSpinner, m as TranscriptData, l as TranscriptSegment, T as TranscriptWord, o as buildBroadcastCdnUrl, p as buildBroadcastS3KeyPrefix, n as formatTime, u as useDialtribe } from './dialtribe-player-CNriUtNi.mjs';
3
- export { j as DEFAULT_ENCODER_SERVER_URL, D as DialtribeStreamer, a as DialtribeStreamerProps, M as MediaConstraintsOptions, O as OpenDialtribeStreamerPopupOptions, P as PopupDimensions, w as PopupFallbackMode, l as StreamDiagnostics, f as StreamKeyDisplay, g as StreamKeyDisplayProps, h as StreamKeyInput, i as StreamKeyInputProps, e as StreamingControlState, c as StreamingControls, d as StreamingControlsProps, S as StreamingPreview, b as StreamingPreviewProps, t as UseDialtribeStreamerLauncherOptions, v as UseDialtribeStreamerLauncherReturn, U as UseDialtribeStreamerPopupReturn, W as WebSocketStreamer, k as WebSocketStreamerOptions, r as calculatePopupDimensions, o as checkBrowserCompatibility, m as getMediaConstraints, n as getMediaRecorderOptions, q as openBroadcastPopup, p as openDialtribeStreamerPopup, s as useDialtribeStreamerLauncher, u as useDialtribeStreamerPopup } from './dialtribe-streamer-DH23BseY.mjs';
3
+ export { j as DEFAULT_ENCODER_SERVER_URL, D as DialtribeStreamer, a as DialtribeStreamerProps, M as MediaConstraintsOptions, O as OpenDialtribeStreamerPopupOptions, P as PopupDimensions, w as PopupFallbackMode, l as StreamDiagnostics, f as StreamKeyDisplay, g as StreamKeyDisplayProps, h as StreamKeyInput, i as StreamKeyInputProps, e as StreamingControlState, c as StreamingControls, d as StreamingControlsProps, S as StreamingPreview, b as StreamingPreviewProps, t as UseDialtribeStreamerLauncherOptions, v as UseDialtribeStreamerLauncherReturn, U as UseDialtribeStreamerPopupReturn, W as WebSocketStreamer, k as WebSocketStreamerOptions, r as calculatePopupDimensions, o as checkBrowserCompatibility, m as getMediaConstraints, n as getMediaRecorderOptions, q as openBroadcastPopup, p as openDialtribeStreamerPopup, s as useDialtribeStreamerLauncher, u as useDialtribeStreamerPopup } from './dialtribe-streamer-Do-8Oavc.mjs';
4
4
  import 'react/jsx-runtime';
5
5
  import 'react';
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { HelloWorld, HelloWorldProps } from './hello-world.js';
2
2
  export { A as ApiClientConfig, h as AudioWaveform, B as Broadcast, C as CDN_DOMAIN, d as DIALTRIBE_API_BASE, c as DialtribeClient, a as DialtribeContextValue, i as DialtribeOverlay, k as DialtribeOverlayMode, j as DialtribeOverlayProps, e as DialtribePlayer, g as DialtribePlayerErrorBoundary, f as DialtribePlayerProps, D as DialtribeProvider, b as DialtribeProviderProps, E as ENDPOINTS, H as HTTP_STATUS, q as HttpStatusCode, L as LoadingSpinner, m as TranscriptData, l as TranscriptSegment, T as TranscriptWord, o as buildBroadcastCdnUrl, p as buildBroadcastS3KeyPrefix, n as formatTime, u as useDialtribe } from './dialtribe-player-CNriUtNi.js';
3
- export { j as DEFAULT_ENCODER_SERVER_URL, D as DialtribeStreamer, a as DialtribeStreamerProps, M as MediaConstraintsOptions, O as OpenDialtribeStreamerPopupOptions, P as PopupDimensions, w as PopupFallbackMode, l as StreamDiagnostics, f as StreamKeyDisplay, g as StreamKeyDisplayProps, h as StreamKeyInput, i as StreamKeyInputProps, e as StreamingControlState, c as StreamingControls, d as StreamingControlsProps, S as StreamingPreview, b as StreamingPreviewProps, t as UseDialtribeStreamerLauncherOptions, v as UseDialtribeStreamerLauncherReturn, U as UseDialtribeStreamerPopupReturn, W as WebSocketStreamer, k as WebSocketStreamerOptions, r as calculatePopupDimensions, o as checkBrowserCompatibility, m as getMediaConstraints, n as getMediaRecorderOptions, q as openBroadcastPopup, p as openDialtribeStreamerPopup, s as useDialtribeStreamerLauncher, u as useDialtribeStreamerPopup } from './dialtribe-streamer-D9ulVBVb.js';
3
+ export { j as DEFAULT_ENCODER_SERVER_URL, D as DialtribeStreamer, a as DialtribeStreamerProps, M as MediaConstraintsOptions, O as OpenDialtribeStreamerPopupOptions, P as PopupDimensions, w as PopupFallbackMode, l as StreamDiagnostics, f as StreamKeyDisplay, g as StreamKeyDisplayProps, h as StreamKeyInput, i as StreamKeyInputProps, e as StreamingControlState, c as StreamingControls, d as StreamingControlsProps, S as StreamingPreview, b as StreamingPreviewProps, t as UseDialtribeStreamerLauncherOptions, v as UseDialtribeStreamerLauncherReturn, U as UseDialtribeStreamerPopupReturn, W as WebSocketStreamer, k as WebSocketStreamerOptions, r as calculatePopupDimensions, o as checkBrowserCompatibility, m as getMediaConstraints, n as getMediaRecorderOptions, q as openBroadcastPopup, p as openDialtribeStreamerPopup, s as useDialtribeStreamerLauncher, u as useDialtribeStreamerPopup } from './dialtribe-streamer-DOhD-r_F.js';
4
4
  import 'react/jsx-runtime';
5
5
  import 'react';
package/dist/index.js CHANGED
@@ -2344,8 +2344,11 @@ var WebSocketStreamer = class {
2344
2344
  * Set up canvas-based rendering pipeline for video streams.
2345
2345
  * This allows seamless camera flips by changing the video source
2346
2346
  * without affecting MediaRecorder (which records from the canvas).
2347
+ *
2348
+ * This is async to ensure the video is producing frames before returning,
2349
+ * which prevents black initial thumbnails.
2347
2350
  */
2348
- setupCanvasRendering() {
2351
+ async setupCanvasRendering() {
2349
2352
  console.log("\u{1F3A8} Setting up canvas-based rendering for seamless camera flips");
2350
2353
  const videoTrack = this.mediaStream.getVideoTracks()[0];
2351
2354
  const settings = videoTrack?.getSettings() || {};
@@ -2363,7 +2366,27 @@ var WebSocketStreamer = class {
2363
2366
  videoElement.srcObject = this.mediaStream;
2364
2367
  videoElement.muted = true;
2365
2368
  videoElement.playsInline = true;
2366
- videoElement.play().catch((e) => console.warn("Video autoplay warning:", e));
2369
+ await new Promise((resolve) => {
2370
+ const checkReady = () => {
2371
+ if (videoElement.videoWidth > 0 && videoElement.videoHeight > 0) {
2372
+ console.log(`\u{1F4F9} Video ready: ${videoElement.videoWidth}x${videoElement.videoHeight}`);
2373
+ resolve();
2374
+ } else {
2375
+ requestAnimationFrame(checkReady);
2376
+ }
2377
+ };
2378
+ videoElement.addEventListener("loadeddata", () => {
2379
+ checkReady();
2380
+ }, { once: true });
2381
+ videoElement.play().catch((e) => {
2382
+ console.warn("Video autoplay warning:", e);
2383
+ resolve();
2384
+ });
2385
+ setTimeout(() => {
2386
+ console.warn("\u26A0\uFE0F Video ready timeout - continuing anyway");
2387
+ resolve();
2388
+ }, 2e3);
2389
+ });
2367
2390
  const frameRate = settings.frameRate || 30;
2368
2391
  const stream = canvas.captureStream(frameRate);
2369
2392
  const audioTracks = this.mediaStream.getAudioTracks();
@@ -2527,7 +2550,7 @@ Please check encoder server logs and DATABASE_URL configuration.`
2527
2550
  });
2528
2551
  console.log("\u2705 WebSocket connected");
2529
2552
  this.setupWebSocketHandlers();
2530
- const streamToRecord = this.isVideo ? this.setupCanvasRendering() : this.mediaStream;
2553
+ const streamToRecord = this.isVideo ? await this.setupCanvasRendering() : this.mediaStream;
2531
2554
  const recorderOptions = getMediaRecorderOptions(this.isVideo);
2532
2555
  this.mimeType = recorderOptions.mimeType;
2533
2556
  this.mediaRecorder = new MediaRecorder(streamToRecord, recorderOptions);
@@ -2605,20 +2628,50 @@ Please check encoder server logs and DATABASE_URL configuration.`
2605
2628
  /**
2606
2629
  * Replace the video track for camera flips.
2607
2630
  *
2608
- * When using canvas-based rendering (video streams), this updates the video
2609
- * element source. The canvas continues drawing, and MediaRecorder is unaffected.
2631
+ * When using canvas-based rendering (video streams), this preloads the new
2632
+ * camera in a temporary video element, waits for it to be ready, then swaps
2633
+ * it in. This ensures continuous frame output with no gaps.
2610
2634
  *
2611
2635
  * @param newVideoTrack - The new video track from the flipped camera
2636
+ * @returns Promise that resolves when the swap is complete
2612
2637
  */
2613
- replaceVideoTrack(newVideoTrack) {
2638
+ async replaceVideoTrack(newVideoTrack) {
2614
2639
  console.log("\u{1F504} Replacing video track");
2615
2640
  if (this.canvasState) {
2616
- console.log("\u{1F3A8} Using canvas-based swap (MediaRecorder unaffected)");
2641
+ console.log("\u{1F3A8} Using canvas-based swap with preloading (no frame gaps)");
2617
2642
  const audioTracks = this.mediaStream.getAudioTracks();
2618
2643
  const newStream = new MediaStream([newVideoTrack, ...audioTracks]);
2644
+ const preloadVideo = document.createElement("video");
2645
+ preloadVideo.srcObject = newStream;
2646
+ preloadVideo.muted = true;
2647
+ preloadVideo.playsInline = true;
2648
+ await new Promise((resolve, reject) => {
2649
+ const timeout = setTimeout(() => {
2650
+ console.warn("\u26A0\uFE0F Video preload timeout - switching anyway");
2651
+ resolve();
2652
+ }, 3e3);
2653
+ preloadVideo.addEventListener("loadeddata", () => {
2654
+ if (preloadVideo.videoWidth > 0 && preloadVideo.videoHeight > 0) {
2655
+ clearTimeout(timeout);
2656
+ console.log(`\u{1F4F9} New camera ready: ${preloadVideo.videoWidth}x${preloadVideo.videoHeight}`);
2657
+ resolve();
2658
+ }
2659
+ }, { once: true });
2660
+ preloadVideo.addEventListener("error", (e) => {
2661
+ clearTimeout(timeout);
2662
+ reject(new Error(`Video preload failed: ${e}`));
2663
+ }, { once: true });
2664
+ preloadVideo.play().catch((e) => {
2665
+ clearTimeout(timeout);
2666
+ console.warn("Video preload play warning:", e);
2667
+ resolve();
2668
+ });
2669
+ });
2619
2670
  this.mediaStream.getVideoTracks().forEach((track) => track.stop());
2620
- this.canvasState.videoElement.srcObject = newStream;
2621
- this.canvasState.videoElement.play().catch((e) => console.warn("Video play warning:", e));
2671
+ const oldVideoElement = this.canvasState.videoElement;
2672
+ this.canvasState.videoElement = preloadVideo;
2673
+ oldVideoElement.pause();
2674
+ oldVideoElement.srcObject = null;
2622
2675
  this.mediaStream = newStream;
2623
2676
  this.invalidateScalingCache();
2624
2677
  const settings = newVideoTrack.getSettings();
@@ -2682,7 +2735,7 @@ Please check encoder server logs and DATABASE_URL configuration.`
2682
2735
  let streamToRecord = this.mediaStream;
2683
2736
  if (this.isVideo) {
2684
2737
  this.cleanupCanvasRendering();
2685
- streamToRecord = this.setupCanvasRendering();
2738
+ streamToRecord = await this.setupCanvasRendering();
2686
2739
  console.log("\u{1F3A8} Canvas rendering recreated for new stream");
2687
2740
  }
2688
2741
  const recorderOptions = getMediaRecorderOptions(this.isVideo);
@@ -3658,7 +3711,7 @@ function DialtribeStreamer({
3658
3711
  console.log("\u{1F4F7} Got new camera stream:", newFacingMode);
3659
3712
  const newVideoTrack = newStream.getVideoTracks()[0];
3660
3713
  if (newVideoTrack) {
3661
- streamer.replaceVideoTrack(newVideoTrack);
3714
+ await streamer.replaceVideoTrack(newVideoTrack);
3662
3715
  }
3663
3716
  const updatedStream = streamer.getMediaStream();
3664
3717
  setMediaStream(updatedStream);