Docs
React SDK

useMediaTrack

Attach a local or remote media track and observe when it actually plays.

Import

React
import { useMediaTrack, MediaLoader } from '@relayrtc/react'
import type { RoomRemoteTrack } from '@relayrtc/react'

Requirements

Use inside RelayProvider. Pass a RoomRemoteTrack, a local MediaStreamTrack, or null/undefined while waiting for one.

Bind ref to a mounted video or audio element. Keep that element mounted while displaying a loading overlay.

Arguments

ArgumentDefaultPurpose
trackRequiredLocal capture track or remote publication. Null returns idle.
options.enabledtrueAttach/receive when true. False detaches the element; use track.unsubscribe() to stop the subscription too.
options.pausedfalseMark playback paused for your UI. Does not mute the sender or unsubscribe. Useful for local capture previews.

Returns

FieldTypeMeaning
refRefCallback<HTMLMediaElement>Attach to your video/audio element.
stateMediaPlaybackStatePlayback status listed below.
isLoadingbooleanTrue only when state is loading.
isPausedbooleanTrue only when state is paused.
errorError or nullPlayback/attachment error for blocked or failed state.
play() => Promise<void>Retry browser playback from a user gesture.

States

StateMeaning
idleNo track, attachment disabled, data track, or playback manually paused.
loadingWaiting for attachment, playable data, incoming media or room recovery.
playingThe element is playing with playable media data.
pausedExplicit paused option or a paused publication.
blockedThe browser rejected autoplay. Offer a play button.
failedAttachment or playback failed. Display the error.
endedThe track ended, closed or was unpublished.

Remote video example

React
function RemoteVideo({ track }: { track: RoomRemoteTrack }) {
  const media = useMediaTrack(track)
 
  return (
    <div>
      <video
        ref={media.ref}
        autoPlay
        playsInline
        style={{ visibility: media.isPaused ? 'hidden' : 'visible' }}
      />
      {media.isLoading && <MediaLoader label="Loading camera" />}
      {media.isPaused && <p>Video is paused</p>}
      {media.state === 'blocked' && (
        <button onClick={() => void media.play().catch(console.error)}>Play video</button>
      )}
      {media.state === 'failed' && <p role="alert">{media.error?.message}</p>}
    </div>
  )
}

Audio and local preview

Use <audio ref={media.ref} autoPlay /> for a remote audio track. Use a muted video element for local preview, passing camera?.track and { paused: camera?.muted }.

The hook detaches its element on cleanup. It does not stop local capture or unsubscribe a remote track solely because the UI unmounted.

Camera-off behavior

Turning the camera off with camera.disable() removes its remote publication. Your participant tile should show a placeholder when there is no camera track. Do not wait for a paused state when the publication no longer exists.

The current server does not signal remote pause/resume for local camera.mute(). See camera-off controls.