Files
skills/docs/ui/react/react-audio-stream/src/provider/stream-provider.md
2026-05-29 08:20:56 +01:00

2.8 KiB

stream-provider

Purpose

<StreamProvider> is the singleton React surface that owns the live StreamSession for a tree. It calls the caller-supplied sessionFactory exactly once per provider instance, subscribes to the seven session event channels (state-changed, interruption, peers-changed, mixer-changed, levels-changed, recording-changed, permission-changed), and increments a render-bump counter on every tick so descendant hooks observe a fresh snapshot of session state.

The factory pattern keeps @suaveplan/react-audio-stream transport-agnostic: the consumer decides whether the underlying transport is WebRTC, WebSocket, Trystero, or a test fake, and the provider never imports any transport directly. Cleanup on unmount calls session.disconnect() so the audio engine + socket are torn down deterministically.

Features

  • StrictMode-safe singleton via useRef-guarded lazy construction.
  • Caller-injected sessionFactory — zero transport coupling at provider tier.
  • Render-bump counter fans seven event channels into one re-render path.
  • Cleanup-on-unmount disconnects the session and detaches every listener.
  • Memoised context value — only the version field changes per tick.

Usage: Basic

import { StreamProvider } from "@suaveplan/react-audio-stream/provider";
import { createStreamSession } from "./my-session-factory";

export function App({ children }: { children: React.ReactNode }) {
    return (
        <StreamProvider sessionFactory={() => createStreamSession({ transport: "webrtc" })}>
            {children}
        </StreamProvider>
    );
}

Usage: Advanced

import { StreamProvider } from "@suaveplan/react-audio-stream/provider";
import { useMemo } from "react";

export function ScopedRoom({ roomId, children }: { roomId: string; children: React.ReactNode }) {
    const factory = useMemo(
        () => () => createStreamSession({ transport: "trystero", initialRoomId: roomId }),
        [roomId]
    );
    return <StreamProvider sessionFactory={factory}>{children}</StreamProvider>;
}

Keying the provider on roomId (<StreamProvider key={roomId} …>) forces a fresh session when the room changes, because the singleton is per-instance.

API Reference

  • StreamProviderProps — { sessionFactory: StreamSessionFactory; children?: ReactNode }
  • StreamProvider(props) — renders a StreamReactContext.Provider with { session, version }.

Implementation Notes

The seven event subscriptions all funnel into a single setVersion((v) => v + 1) call, which collapses bursts into a single React render pass thanks to automatic batching. The disconnect call on unmount is wrapped in Promise.resolve so the same code path handles both sync and async session implementations, and the rejection branch swallows errors (any failure already surfaced as an interruption event before the listener detach).