Skip to content
Cloudflare Docs

Local Participant

This guide covers how to manage the local user's media devices, control audio/video/screenshare, handle events, and work with media tracks in your RealtimeKit meetings.

Introduction

The local user is accessible via meeting.self and contains all information and methods related to the current participant. This includes media controls, device management, participant metadata, and state information.

Properties

Metadata Properties

JavaScript
// Participant identifiers
meeting.self.id; // Peer ID (unique per session)
meeting.self.userId; // User ID (persistent across sessions)
meeting.self.customParticipantId; // Custom identifier set by developer
meeting.self.name; // Display name
meeting.self.picture; // Display picture URL

Media Properties

The local user's media tracks and states:

JavaScript
// Media state flags
meeting.self.audioEnabled; // Boolean: Is audio enabled?
meeting.self.videoEnabled; // Boolean: Is video enabled?
meeting.self.screenShareEnabled; // Boolean: Is screen share active?
// Media tracks (MediaStreamTrack objects)
meeting.self.audioTrack; // Audio MediaStreamTrack (available when audioEnabled is true)
meeting.self.videoTrack; // Video MediaStreamTrack (available when videoEnabled is true)
meeting.self.screenShareTracks; // Object: { video: MediaStreamTrack, audio?: MediaStreamTrack }
// Permissions granted by user
meeting.self.mediaPermissions; // Current audio/video permissions

State Properties

JavaScript
// Room state
meeting.self.roomJoined; // Boolean: Has joined the meeting?
meeting.self.roomState; // Current room state (see possible values below)
meeting.self.isPinned; // Boolean: Is the local user pinned?
// Permissions and config
meeting.self.permissions; // Capabilities defined by preset
meeting.self.config; // Configuration for meeting appearance

Room State Values:

The roomState property can have the following values:

  • 'init' - Initialized but not joined
  • 'joined' - Successfully joined the meeting
  • 'waitlisted' - Waiting in the waiting room
  • 'rejected' - Entry rejected
  • 'kicked' - Removed from meeting
  • 'left' - Left the meeting
  • 'ended' - Meeting has ended
  • 'disconnected' - Disconnected from meeting

Media Controls

Audio Control

Mute and unmute the microphone:

JavaScript
// Enable audio (unmute)
await meeting.self.enableAudio();
// Disable audio (mute)
await meeting.self.disableAudio();
// Check current status
const isAudioEnabled = meeting.self.audioEnabled;

Video Control

Enable and disable the camera:

JavaScript
// Enable video
await meeting.self.enableVideo();
// Disable video
await meeting.self.disableVideo();
// Check current status
const isVideoEnabled = meeting.self.videoEnabled;

Screen Share Control

Start and stop screen sharing:

JavaScript
// Enable screen share
await meeting.self.enableScreenShare();
// Disable screen share
await meeting.self.disableScreenShare();
// Check current status
const isScreenShareEnabled = meeting.self.screenShareEnabled;

Change Display Name

Change the user's display name (only works before joining):

JavaScript
await meeting.self.setName("New Name");

Manage Media Devices

Get Available Devices

JavaScript
// Get all media devices
const devices = await meeting.self.getAllDevices();
// Get all audio input devices (microphones)
const audioDevices = await meeting.self.getAudioDevices();
// Get all video input devices (cameras)
const videoDevices = await meeting.self.getVideoDevices();
// Get all audio output devices (speakers)
const speakerDevices = await meeting.self.getSpeakerDevices();
// Get device by ID
const device = await meeting.self.getDeviceById("device-id", "audio");
// Get current devices being used
const currentDevices = meeting.self.getCurrentDevices();
// Returns: { audio: MediaDeviceInfo, video: MediaDeviceInfo, speaker: MediaDeviceInfo }

Change Device

Switch to a different media device:

JavaScript
// Get all devices
const devices = await meeting.self.getAllDevices();
// Set a specific device (replaces device of the same kind)
await meeting.self.setDevice(devices[0]);

Display Local Video

Register Video Element

Play the local user's video track on a <video> element:

<video id="local-video" autoplay playsinline></video>
JavaScript
const videoElement = document.getElementById("local-video");
// Register the video element to display video
meeting.self.registerVideoElement(videoElement);
// For local preview (not sent to other users), pass true as second argument
meeting.self.registerVideoElement(videoElement, true);

Deregister Video Element

Clean up when the video element is no longer needed:

JavaScript
meeting.self.deregisterVideoElement(videoElement);

Events

Room Joined

Triggered when the local user successfully joins the meeting:

JavaScript
meeting.self.on("roomJoined", () => {
console.log("Successfully joined the meeting");
});

Room Left

Triggered when the local user leaves the meeting:

JavaScript
meeting.self.on("roomLeft", ({ state }) => {
console.log("Left the meeting with state:", state);
// Handle different leave states
if (state === "left") {
console.log("User voluntarily left");
} else if (state === "kicked") {
console.log("User was kicked from the meeting");
} else if (state === "ended") {
console.log("Meeting has ended");
} else if (state === "disconnected") {
console.log("Lost connection to meeting");
}
});

Possible state values: 'left', 'kicked', 'ended', 'rejected', 'disconnected', 'failed'

Video Update

Triggered when video is enabled or disabled:

JavaScript
meeting.self.on("videoUpdate", ({ videoEnabled, videoTrack }) => {
console.log("Video state:", videoEnabled);
if (videoEnabled) {
// Video track is available, can display it
const videoElement = document.getElementById("my-video");
const stream = new MediaStream();
stream.addTrack(videoTrack);
videoElement.srcObject = stream;
videoElement.play();
}
});

Audio Update

Triggered when audio is enabled or disabled:

JavaScript
meeting.self.on("audioUpdate", ({ audioEnabled, audioTrack }) => {
console.log("Audio state:", audioEnabled);
if (audioEnabled) {
// Audio track is available
console.log("Microphone is on");
}
});

Screen Share Update

Triggered when screen sharing starts or stops:

JavaScript
meeting.self.on(
"screenShareUpdate",
({ screenShareEnabled, screenShareTracks }) => {
console.log("Screen share state:", screenShareEnabled);
if (screenShareEnabled) {
// Screen share tracks are available
const screenElement = document.getElementById("my-screen-share");
const stream = new MediaStream();
stream.addTrack(screenShareTracks.video);
if (screenShareTracks.audio) {
stream.addTrack(screenShareTracks.audio);
}
screenElement.srcObject = stream;
screenElement.play();
}
},
);

Device Update

Triggered when the active device changes:

JavaScript
meeting.self.on("deviceUpdate", ({ device }) => {
// Handle device change
if (device.kind === "audioinput") {
console.log("Microphone changed:", device.label);
} else if (device.kind === "videoinput") {
console.log("Camera changed:", device.label);
} else if (device.kind === "audiooutput") {
console.log("Speaker changed:", device.label);
}
});

Device List Update

Triggered when the list of available devices changes (device plugged in/out):

JavaScript
meeting.self.on("deviceListUpdate", ({ added, removed, devices }) => {
console.log("Device list updated");
console.log("Added devices:", added);
console.log("Removed devices:", removed);
console.log("All devices:", devices);
});

Network Quality Score

Monitor your own network quality:

JavaScript
meeting.self.on(
"mediaScoreUpdate",
({ kind, isScreenshare, score, scoreStats }) => {
if (kind === "video") {
console.log(
`Your ${isScreenshare ? "screenshare" : "video"} quality score is`,
score,
);
}
if (kind === "audio") {
console.log("Your audio quality score is", score);
}
if (score < 5) {
console.log("Your media quality is poor");
}
},
);

The scoreStats object provides detailed statistics:

JavaScript
// Audio Producer
{
"kind": "audio",
"isScreenshare": false,
"score": 10,
"participantId": "meeting.self.id",
"scoreStats": {
"score": 10,
"bitrate": 22452,
"packetsLostPercentage": 0,
"jitter": 0,
"isScreenShare": false
}
}
// Video Producer
{
"kind": "video",
"isScreenshare": false,
"score": 10,
"participantId": "meeting.self.id",
"scoreStats": {
"score": 10,
"frameWidth": 640,
"frameHeight": 480,
"framesPerSecond": 24,
"jitter": 0,
"isScreenShare": false,
"packetsLostPercentage": 0,
"bitrate": 576195,
"cpuLimitations": false,
"bandwidthLimitations": false
}
}

Permission Updates

Triggered when permissions are updated dynamically:

JavaScript
// Listen to specific permission updates
meeting.self.permissions.on("chatUpdate", () => {
console.log("Chat permissions updated");
// Check meeting.self.permissions for updated permissions
});
meeting.self.permissions.on("pollsUpdate", () => {
console.log("Polls permissions updated");
});
meeting.self.permissions.on("pluginsUpdate", () => {
console.log("Plugins permissions updated");
});
// Listen to all permission updates
meeting.self.permissions.on("*", () => {
console.log("Permissions updated");
});

Media Permission Errors

Triggered when media permissions are denied or media capture fails:

JavaScript
meeting.self.on("mediaPermissionError", ({ message, kind }) => {
console.log(`Failed to capture ${kind}: ${message}`);
// Handle different error types
if (message === "DENIED") {
console.log("User denied permission");
} else if (message === "SYSTEM_DENIED") {
console.log("System denied permission");
} else if (message === "COULD_NOT_START") {
console.log("Failed to start media stream");
}
});

Possible values:

  • message: 'DENIED', 'SYSTEM_DENIED', 'COULD_NOT_START'
  • kind: 'audio', 'video', 'screenshare'

Advanced Features

Update Media Resolution

Change video or screen share resolution at runtime:

JavaScript
// Update camera resolution
await meeting.self.updateVideoConstraints({
width: { ideal: 1920 },
height: { ideal: 1080 },
});
// Update screen share resolution
await meeting.self.updateScreenshareConstraints({
width: { ideal: 1920 },
height: { ideal: 1080 },
});

Video Middlewares

Add effects and filters to your video stream:

JavaScript
// Create a middleware (e.g., retro filter)
function RetroTheme() {
return (canvas, ctx) => {
ctx.filter = "grayscale(1)";
ctx.shadowColor = "#000";
ctx.shadowBlur = 20;
ctx.lineWidth = 50;
ctx.strokeStyle = "#000";
ctx.strokeRect(0, 0, canvas.width, canvas.height);
};
}
// Add the video middleware
meeting.self.addVideoMiddleware(RetroTheme);
// Remove the video middleware
meeting.self.removeVideoMiddleware(RetroTheme);

Audio Middlewares

Process audio streams with custom middlewares:

JavaScript
// Add audio middleware
meeting.self.addAudioMiddleware(YourAudioMiddleware);
// Remove audio middleware
meeting.self.removeAudioMiddleware(YourAudioMiddleware);

Pin/Unpin Self

Pin or unpin yourself in the meeting:

JavaScript
// Pin yourself
await meeting.self.pin();
// Unpin yourself
await meeting.self.unpin();
// Check pinned status
const isPinned = meeting.self.isPinned;