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
versionfield 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 aStreamReactContext.Providerwith{ 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).