Skip to content
Sensors

useUserMedia

Reactive wrapper around the MediaDevices.getUserMedia() API. Provides start/stop/restart controls and exposes the media stream as an observable.

User Media
Not Supported

Access the camera via getUserMedia. Click Start to begin streaming.

No stream
import {
const useUserMedia: (options?: DeepMaybeObservable<UseUserMediaOptions>) => UseUserMediaReturn
useUserMedia
} from "@usels/web";
function
function CameraFeed(): JSX.Element
CameraFeed
() {
const {
const isSupported$: ReadonlyObservable<boolean>
isSupported$
,
const stream$: ReadonlyObservable<OpaqueObject<MediaStream> | null>

Current media stream

stream$
,
const enabled$: ReadonlyObservable<boolean>

Whether stream is currently active

enabled$
,
const start: () => Promise<MediaStream>

Start the media stream. Throws if getUserMedia fails.

start
,
const stop: () => void

Stop the media stream

stop
} =
function useUserMedia(options?: DeepMaybeObservable<UseUserMediaOptions>): UseUserMediaReturn

Framework-agnostic reactive wrapper around MediaDevices.getUserMedia().

Exposes the active MediaStream as an observable with start() / stop() / restart() controls. Constraints are read at each start() call, so reactive updates take effect on the next stream acquisition. Cleanup (stopping all tracks) is registered via onMount so it fires on unmount.

useUserMedia
({
constraints: {
audio: boolean;
video: boolean;
}
constraints
: {
audio: boolean
audio
: false,
video: boolean
video
: true },
});
return (
<
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Supported: {
const isSupported$: ReadonlyObservable<boolean>
isSupported$
.
ImmutableObservableBase<boolean>.get(trackingType?: TrackingType | GetOptions): {}
get
() ? "Yes" : "No"}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Streaming: {
const enabled$: ReadonlyObservable<boolean>

Whether stream is currently active

enabled$
.
ImmutableObservableBase<boolean>.get(trackingType?: TrackingType | GetOptions): {}
get
() ? "Yes" : "No"}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const start: () => Promise<MediaStream>

Start the media stream. Throws if getUserMedia fails.

start
()}>Start</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const stop: () => void

Stop the media stream

stop
()}>Stop</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
</
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}
// @noErrors
import { useUserMedia } from "@usels/web";
function AutoCamera() {
const { stream$, stop } = useUserMedia({
constraints: { audio: false, video: true },
immediate: true,
});
// Stream starts automatically on mount
// Stops automatically on unmount
return <button onClick={() => stop()}>Stop</button>;
}
// @noErrors
import { useUserMedia } from "@usels/web";
function Microphone() {
const { stream$, start, stop, enabled$ } = useUserMedia({
constraints: { audio: true, video: false },
});
return (
<button onClick={() => (enabled$.get() ? stop() : start())}>
{enabled$.get() ? "Stop Recording" : "Start Recording"}
</button>
);
}

Options can be passed as plain values, per-field Observables, or a single Observable<UseUserMediaOptions>. constraints are read at each start() / restart() call.

import { observable } from "@usels/core";
import { useUserMedia } from "@usels/web";
const constraints$ = observable<MediaStreamConstraints>({ audio: false, video: true });
const { start, restart } = useUserMedia({ constraints: constraints$ });
// Later: switch to audio+video reactively
constraints$.set({ audio: true, video: true });
restart(); // uses updated constraints

options is DeepMaybeObservable. Each option field can be a plain value or an Observable. constraints are read at each start() / restart() call time. immediate is read at mount-time.

ParameterTypeDescription
optionsUseUserMediaOptions (optional)-
OptionTypeDefaultDescription
constraintsMediaStreamConstraints-Media constraints for getUserMedia. Default: { audio: false, video: true }
immediateboolean-Auto-start stream on mount. Default: false

UseUserMediaReturn

NameTypeDescription
stream$ReadonlyObservable<OpaqueObject<MediaStream> | null>Current media stream
enabled$ReadonlyObservable<boolean>Whether stream is currently active
start() => Promise<MediaStream>Start the media stream. Throws if getUserMedia fails.
stop() => voidStop the media stream
restart() => Promise<MediaStream>Restart the media stream. Throws if getUserMedia fails.
isSupported$ReadonlyObservable<boolean>-

View on GitHub