Skip to content

Media Control

All media operations are async — they resolve once LiveKit has processed the track change.

Microphone

ts
// Toggle mic on/off
await call.toggleMic()

// Check current state
call.localParticipant?.isMicMuted  // boolean

Camera

ts
await call.toggleCamera()
call.localParticipant?.isCameraMuted  // boolean

Screen Share

ts
// Start screen share — browser will show a picker
await call.startScreenShare()

// Stop screen share
await call.stopScreenShare()

call.localParticipant?.isScreenSharing  // boolean

Screen share uses the browser's getDisplayMedia() API. On mobile, this may not be available.

Device Selection

ts
// List available devices
call.devices
// {
//   audioinput: MediaDeviceInfo[]
//   audiooutput: MediaDeviceInfo[]
//   videoinput: MediaDeviceInfo[]
// }

// Switch to a specific device
await call.switchDevice('audioinput', deviceId)
await call.switchDevice('audiooutput', deviceId)
await call.switchDevice('videoinput', deviceId)

Listen for device changes (plug/unplug):

ts
call.on('devicesChanged', (devices) => {
  // Update your device selector UI
})

Rendering Video

Tracks are exposed on each Participant object. Wire them to <video> elements manually, or use the UI kits which handle this automatically.

ts
function attachTrack(participant: Participant, videoEl: HTMLVideoElement) {
  const stream = new MediaStream()
  if (participant.videoTrack) stream.addTrack(participant.videoTrack)
  if (participant.audioTrack) stream.addTrack(participant.audioTrack)
  videoEl.srcObject = stream
}

Active Speakers

ts
call.activeSpeakers  // Participant[] — ordered by speaking volume

call.on('activeSpeakerChanged', (speakers) => {
  // Highlight speaking participants in your UI
})

Layout

The SDK tracks a layout preference that your UI can use to switch between views:

ts
call.setLayout('grid')       // all participants equally sized
call.setLayout('speaker')    // dominant speaker large, others small
call.setLayout('spotlight')  // pinned participant fills the view

call.pin('participantId')    // pin a specific participant
call.pin(null)               // unpin

call.layout            // 'grid' | 'speaker' | 'spotlight'
call.pinnedParticipant // string | null

These are purely client-side preferences — they don't affect other participants' views.

iOS Safari Notes

  • Camera and microphone access must be triggered inside a user gesture (button click). Never call call.connect() from a useEffect or onMounted without a prior user interaction.
  • Screen share (getDisplayMedia) is not supported on iOS Safari. Hide the screen-share button on mobile.
  • Audio output selection (audiooutput device switching) is not supported on iOS.

Chrome Android Notes

  • Background tab behaviour: Chrome Android aggressively suspends background tabs. The SDK will emit reconnecting if the tab is backgrounded during a call. Surface a "Reconnecting..." indicator in your UI.