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 // booleanCamera
ts
await call.toggleCamera()
call.localParticipant?.isCameraMuted // booleanScreen Share
ts
// Start screen share — browser will show a picker
await call.startScreenShare()
// Stop screen share
await call.stopScreenShare()
call.localParticipant?.isScreenSharing // booleanScreen 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 | nullThese 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 auseEffectoronMountedwithout a prior user interaction. - Screen share (
getDisplayMedia) is not supported on iOS Safari. Hide the screen-share button on mobile. - Audio output selection (
audiooutputdevice switching) is not supported on iOS.
Chrome Android Notes
- Background tab behaviour: Chrome Android aggressively suspends background tabs. The SDK will emit
reconnectingif the tab is backgrounded during a call. Surface a "Reconnecting..." indicator in your UI.

