Skip to main content

Camera and microphone playground

Editable examples of the real capture components — pick a device, toggle it, preview it locally.

The capture half of @video/video-client-react — choosing a camera and microphone, enabling and disabling them, and previewing the result locally. Playback components are on the player playground.

Nothing here reaches a server. The preview is a local getUserMedia stream, so the examples run without a token, a call, or an account — and nothing starts until you ask it to.

Try it

One button each, switching itself between the two states. Like TogglePlayButton, the prop names describe the state moved TO.

Live Editor
Editable code. Tab moves focus to the next control instead of inserting an indent.
<Encoder>
  <ToggleCameraButton />
  <ToggleMicButton />
</Encoder>
Result
Loading...

The local Encoder helper

Encoder is the one thing on this page the SDK does not ship. It composes usePreviewPlayer — which returns both a MediaStreamControllerAPI (the capture side) and a PlayerAPI (a local preview of it) — with the two providers the controls read from.

import { components, context, hooks } from '@video/video-client-react';

function Encoder({ children }) {
const { mediaStreamController, previewPlayer } = hooks.usePreviewPlayer({});

// Both arrive asynchronously. Mounting a control against a null controller
// throws inside useMediaStreamControllerAPI, so render nothing until both exist.
if (!mediaStreamController || !previewPlayer) return <div className="placeholder" />;

return (
<context.MediaStreamControllerAPIProvider
mediaStreamControllerAPI={mediaStreamController}>
<context.PlayerAPIProvider playerAPI={previewPlayer}>
<components.Video muted playsInline />
{children}
</context.PlayerAPIProvider>
</context.MediaStreamControllerAPIProvider>
);
}
usePreviewPlayer calls getUserMedia as soon as it mounts

There is no "start" option to pass it. If you render it on load, the browser asks for camera permission on load. The playground above wraps it in a gate for that reason — the hook lives in a child that is not mounted until you press Start camera. A conditional guard is not enough: hooks cannot be called conditionally, so only leaving the component unmounted actually prevents the prompt.

Components

Each control finds the capture controller through context. All of them require MediaStreamControllerAPIProvider, which Encoder supplies.

ComponentWhat it doesRequires
ToggleCameraButtonEnable/disable the camera in one button, named for the state moved to
EnableCameraButtonEnables the camera — one half of the toggle
DisableCameraButtonDisables it — the other half
ToggleMicButtonEnable/disable the microphone in one button
EnableMicButtonEnables the microphone
DisableMicButtonDisables it
VideoSourceSelectCamera picker, listing the devices the browser reportsDevice permission before the list populates
AudioSourceSelectMicrophone pickerDevice permission before the list populates
ResolutionSelectRequests a capture resolutionA camera that advertises more than one
ResolutionInUseSelectReports the resolution actually being captured, which can differ from the one requested
VideoSourceInUseSelectReports the camera actually in use
VideoThe preview element. Encoder renders one; use it directly for your own chrome

Customizing a control

Identical to the playback controls: children replace a label, style and other DOM props pass through, and className replaces the SDK's class. See the Customizations presets above.

Symptoms and causes

SymptomCause
The device selects are emptyThe browser has not granted permission yet. Device labels — and often the devices themselves — are withheld until a stream has been opened once
Error: must be used within a <PlayerProvider />A control is rendered beside Encoder rather than inside it. Every control calls a context hook that throws rather than returning null
The camera prompt appears without being asked forusePreviewPlayer was mounted on load — see the warning above
ResolutionInUseSelect disagrees with ResolutionSelectExpected. The first reports what the device actually delivered; a camera may not honour the requested mode

Broadcasting

Broadcast and call controls — StartBroadcastButton, PauseBroadcastButton, UnpauseBroadcastButton, EndBroadcastButton, CreateCallButton, JoinCallButton, EndCallButton — read useBroadcastAPI() and useCallAPI(), which need an authenticated call. They are not live on this page: without credentials they would throw, which would read as a broken example rather than an unavailable one.

The shape is the same as everything above — a provider supplying an API, and controls that find it through context:

<context.BroadcastAPIProvider broadcastAPI={broadcastAPI}>
<components.StartBroadcastButton />
<components.PauseBroadcastButton />
<components.EndBroadcastButton />
</context.BroadcastAPIProvider>

Getting a broadcastAPI requires authentication — see Broadcast a stream and the SDK reference.