Enums
String-backed enums used across the API. Both the enum constant and the underlying string value are accepted everywhere โ pick whichever style you prefer.
MediaKind
Identifies the kind of media. Used in subscribe / unsubscribe calls.
Screen audio is bundled into Screen โ there is no separate ScreenAudio kind. Whether screen audio is included is controlled at publish time via PublishScreenOpts.audio.
import { MediaKind } from '@videosdk/js';
await p.subscribe([MediaKind.Audio, MediaKind.Video]);
await p.subscribe(['audio', 'video']); // strings also work
StreamState
Combined state of a remote stream. Read via stream.streamState; transitions are delivered via the stream's state-changed event. Two sources are merged into one value: server-driven routing state (always present) and client-observed decoder health (RemoteVideoStream / RemoteScreenStream).
Per-stream-type unions โ each subtype only ever produces values that make sense for its medium:
- RemoteVideoStream:
"active" | "paused" | "frozen" | "stuck" | "ended" - RemoteScreenStream:
"active" | "paused" | "frozen" | "stuck" | "ended" - RemoteAudioStream:
"active" | "paused" | "ended"
| Value | Source | Meaning | Recoverable |
|---|---|---|---|
"active" | routing | Bytes flowing, decoding normally. | โ |
"paused" | routing | Server stopped sending bytes (subscriber called pause(), publisher unpublished, etc.). | Yes โ call resume() or wait for publisher. |
"frozen" | decoder | Decoder stuck on a frame; user sees a freeze. Detected from WebRTC stats. Video / screen only. | Yes โ clears when frames flow again. |
"stuck" | decoder | Bytes arriving but decoder isn't producing frames. Video / screen only. | Yes โ clears when decoder recovers. |
"ended" | routing | Track permanently terminated (publisher unpublished, network died, device unplugged). | No โ re-subscribe is required. |
No separate frozen / unfrozen / stuck / ended events. All transitions flow through the single state-changed event with the corresponding state value.
Bandwidth-driven simulcast layer changes are a separate axis โ see MediaQuality and the quality-changed event on RemoteVideoStream / RemoteScreenStream. The stream stays "active" when the layer switches.
Routing vs decoder priority: when both axes have non-default values (e.g. routing is paused AND decoder was frozen at the time), the merged streamState reports the routing value โ routing is server-authoritative.
MediaQuality
Receive-side simulcast layer selection. Used in setPreferredQuality (pick preferred layer to receive) and reported back via currentQuality + the quality-changed event.
| Value | Receiving meaning |
|---|---|
"high" | Receive the high simulcast layer. |
"medium" | Receive the middle layer. |
"low" | Receive the lowest layer. |
"auto" | SDK picks based on attached element size. |
Receive-side only. Publish-side layer count is configured via PublishVideoOpts.maxLayer + multiStream; capture height via resolution; bitrate via bitrateMode / maxBitrate.
"auto" is only an input value (to setPreferredQuality). The reported currentQuality getter and quality-changed event payload always carry a concrete layer โ "high", "medium", or "low".
VideoCodec
Preferred video codec for publishing. Used in PublishVideoOpts.codec. Best-effort โ if the chosen codec isn't supported by the browser or SFU, the SDK falls back silently. Apps that need a guarantee read stream.codec after publish.
| Value | When to consider |
|---|---|
"h264" | Widest hardware-encode support; good for mobile battery life. |
"vp8" | Universal compatibility baseline. |
"vp9" | Better compression than VP8 at similar quality; good fit for screen share. |
"av1" | Best compression at the cost of CPU; limited browser support. |
DegradationPreference
What to drop first under bandwidth pressure. Used in PublishVideoOpts.degradationPreference. Maps to the WebRTC native RTCDegradationPreference concept; values renamed for brevity.
| Value | Behavior under bandwidth pressure | Good fit for |
|---|---|---|
"fps" | Drop resolution to maintain framerate. | Sports, dance, gaming, anything with motion. |
"resolution" | Drop framerate to maintain resolution. | Slides, screen share, document review. |
"balanced" | SDK adapts both axes (default). | General video calls. |
"off" | No automatic degradation. | Recording / streaming where you want consistent output. |
ContentHint
Encoder optimization hint. Used in PublishVideoOpts.contentHint. Mirrors the WebRTC MediaStreamTrack.contentHint property.
| Value | When to use |
|---|---|
"motion" | High-motion content where smoothness matters more than per-frame sharpness (sports, dance, video calls). |
"detail" | General sharpness โ balanced default for camera content. |
"text" | High-detail static content (slides, code, shared documents). Encoder optimizes for sharp edges and lower frame rate. |
PreCallPhase
Phases of the pre-call diagnostic. Used in PreCallTestOpts.tests to select which to run, and on onProgress events to identify which phase fired.
NetworkQuality
Quality score for a network direction (uplink or downlink) and per-kind (audio / video). Returned in PreCallTestResult.quality.
QualityFactor
Reasons a quality score is degraded. Populated in quality.uplink.factors / quality.downlink.factors when the score is Fair or below.
Protocol
Network transport preference. Set via JoinOptions.preferredProtocol. Useful for restrictive networks (corporate firewalls that block UDP).
LogLevel
SDK logging verbosity. Set via VideoSDK.setLogLevel(). Affects console / dashboard logging only โ does not affect data sent to apps.
ConnectionState
Current connection state of a Room. Read sync via room.state; observe transitions via connection-state-changed. Only three values โ idle / connecting are unobservable in our one-step model since VideoSDK.join() returns the Room only after it's connected.
DisconnectReason
Why the room transitioned to ConnectionState.Disconnected. Delivered as reason on the connection-state-changed event when the new state is Disconnected (and on the disconnected alias event). Mirrors v0's reason codes 1001โ1104, converted from numeric to string for refactor-safety.
{ code: 1102, message: '...' } on onMeetingLeft. v1 delivers them as { reason: DisconnectReason.WebsocketConnectionAttemptsExhausted } on connection-state-changed. The set of reasons is unchanged from v0; only the format and delivery channel differ. Numeric-to-string mapping is preserved as comments above for migration.ServiceState
Run state of a room server-side service โ recording, HLS, livestream, transcription. Read via Room.recordingState / hlsState / livestreamState / transcriptionState; transitions are delivered via the matching *-state-changed event.
| Value | Running | Used by | Meaning |
|---|---|---|---|
"stopped" | No | all | Not running โ ended cleanly, or never started. |
"starting" | No | all | Start requested; the server is spinning the service up. |
"started" | Yes | all | Running. For HLS, pipeline is up and URLs are minted (populated on room.hlsUrls) but not yet playable โ the HLS segment buffer is still filling (~6 s). |
"playable" | Yes | HLS only | HLS-specific sub-state. Reached ~6 s after started, when the buffer has filled and the URLs are safe to hand to hls.js. Recording / livestream / transcription never reach this state โ their started is already the usable state. |
"stopping" | Yes | all | Stop requested; the server is finalizing. |
"failed" | No | all | Not running โ ended because of an error. |
Generic lifecycle. A normal run progresses stopped โ starting โ started, then started โ stopping โ stopped. Any active state can transition to failed on error. A fresh start call from failed (or stopped) goes back to starting.
HLS lifecycle extends this with one extra step: stopped โ starting โ started โ playable โ stopping โ stopped. The buffer-fill phase between started and playable is intrinsic to HLS segment delivery and isn't a transition apps can shorten โ they listen for playable to know when to call hls.loadSource(room.hlsUrls.playbackUrl).
Failed, the corresponding *-state-changed event carries an error describing why the service stopped.Playable is in the shared enum (even though only HLS uses it). Putting it on ServiceState keeps every service on the same single-event channel (*-state-changed) โ no separate hls-playable event to learn. Apps that don't care about HLS never see Playable in their recordingState / livestreamState / transcriptionState; apps that do care just add one more branch to their hlsState switch.ErrorKind
Category of an SDKError. Lets apps write a single handler for an entire class of errors without listing every code. Read via err.kind on every error the SDK surfaces (Promise rejections, event payloads).
MEDIA_PERMISSION_DENIED โ is it media or permission?). The SDK picks one and documents the choice with the error code definition. The boundary, once set, is stable across releases.LocalEvent
Event names fired on LocalParticipant. Both the enum value and the underlying string work in .on() / .off(). Three categories: publish lifecycle (your own publishes), incoming requests from other participants, and pin events.
me.publishVideo(), async JoinOptions.publishVideo, and pre-call auto-promote. stream-published delivers a LocalPublication with kind + the matching video? / audio? / screen? stream slot. stream-unpublished delivers { kind: MediaKind }. stream-publish-failed delivers a PublishFailure with { kind, error } โ covers both initial publish failures and mid-call runtime failures (camera unplug, encoder die). For explicit calls, the Promise also resolves/rejects โ both channels work; app picks.Operational events (frozen, unfrozen, stuck, ended, silent-detected) fire on the stream object itself โ see LocalVideoStream / LocalAudioStream / LocalScreenStream.
import { LocalEvent, MediaKind } from '@videosdk/js';
me.on(LocalEvent.StreamPublishRequested, async (req) => {
// req: PublishRequest โ { kind, from, accept, reject }
const label = req.kind === MediaKind.Video ? 'camera' : 'microphone';
if (confirm(`${req.from.displayName} asks you to enable ${label}`)) {
const pub = await req.accept(); // resolves with LocalPublication
if (pub.video) pub.video.attach(localCamEl);
} else {
req.reject();
}
});
me.on('stream-publish-requested', async (req) => await req.accept()); // identical
RemoteEvent
Event names fired on RemoteParticipant. Both the enum value and the underlying string work in .on() / .off(). Three categories: publish notifications (remote published a kind), subscribe-completion events (your subscribe got the stream), pin events.
import { RemoteEvent, MediaKind } from '@videosdk/js';
p.on(RemoteEvent.StreamPublished, ({ kind }) => p.subscribe(kind));
p.on('stream-published', ({ kind }) => p.subscribe(kind)); // identical
p.on(RemoteEvent.StreamSubscribed, sub => sub.video?.attach(el));
p.on('stream-subscribed', sub => sub.video?.attach(el)); // identical
See also: Types LocalParticipant RemoteParticipant