Stream Management
Learn how to publish and receive audio, video, and screen-share streams, pause or resume incoming media, and control video quality.
A stream represents one piece of media published by a participant, such as microphone audio, camera video, or screen share.
Streams live in the client SDKs only. The Server SDK has no stream operations.
Streams and tracks
A track is the raw media captured on the publishing device. A stream is the published representation of that track inside a VideoSDK room.
| Track | Stream | |
|---|---|---|
| What it represents | Raw media captured from a camera, microphone, screen, or custom media source. | A published media track with information such as kind, codec, and paused. |
| Where it exists | On the publishing participant's device. | On clients that receive the published media. |
| What you use it for | Configure capture devices and encoding. | Render media, pause or resume receiving it, and inspect its state. |
Custom tracks give you more control over how media is captured and encoded before it is published.
Stream kinds
VideoSDK uses the following stream kinds:
| Kind | Media source | React property | Published with |
|---|---|---|---|
video | Camera | webcamStream | enableWebcam() |
audio | Microphone | micStream | unmuteMic() |
share | Screen share | screenShareStream | enableScreenShare() |
shareAudio | Audio captured with a screen share | Delivered alongside share | enableScreenShare() on platforms that support system audio |
Stream properties
A stream exposes information about the published media and its current state.
| Property | Type | Description |
|---|---|---|
kind | string | Media type: audio, video, share, or shareAudio. |
codec | string | Codec currently used to encode the media. |
track | MediaStreamTrack | Underlying media track that can be attached to a media element or platform-specific view. |
paused | boolean | Indicates whether the local client has paused receiving this stream. |
Publish media
The local participant publishes microphone, camera, and screen-share media through the meeting or room object.
When a stream becomes available, clients receive an onStreamEnabled event. When that stream stops, they receive onStreamDisabled.
- React
- JavaScript
- React Native
- Flutter
- Android
- iOS
const {
enableWebcam,
disableWebcam,
toggleWebcam,
unmuteMic,
muteMic,
toggleMic,
enableScreenShare,
disableScreenShare,
toggleScreenShare,
} = useMeeting();
await meeting.unmuteMic();
await meeting.muteMic();
await meeting.enableWebcam();
await meeting.disableWebcam();
await meeting.enableScreenShare();
await meeting.disableScreenShare();
const {
enableWebcam,
disableWebcam,
toggleWebcam,
unmuteMic,
muteMic,
toggleMic,
enableScreenShare,
disableScreenShare,
} = useMeeting();
await enableScreenShare({ enableAudio: true });
room.unmuteMic();
room.muteMic();
room.enableCam();
room.disableCam();
room.enableScreenShare(enableAudio: true); // enableAudio is Android only
room.disableScreenShare();
meeting!!.unmuteMic()
meeting!!.muteMic()
meeting!!.enableWebcam()
meeting!!.disableWebcam()
// after startActivityForResult(
// mediaProjectionManager.createScreenCaptureIntent(),
// ...
// )
meeting!!.enableScreenShare(data, true) // true shares system audio
meeting!!.disableScreenShare()
meeting?.unmuteMic()
meeting?.muteMic()
meeting?.enableWebcam()
meeting?.disableWebcam()
meeting?.enableScreenShare()
meeting?.disableScreenShare()
When a participant starts screen sharing, VideoSDK also triggers onPresenterChanged with that participant's participantId.
When screen sharing stops, the same event is triggered with null.
Publish media when joining
You can configure whether the microphone and camera start enabled when the participant joins using:
micEnabledwebcamEnabled
The participant's mode determines whether they are allowed to publish realtime media.
Participants in RECV_ONLY or SIGNALLING_ONLY mode do not publish media.
Use custom tracks
Custom tracks let you configure media capture and encoding before publishing the media to a room.
In React, VideoSDK provides helpers for camera, microphone, and screen-share tracks.
Camera track
createCameraVideoTrack() lets you configure:
- Camera device.
- Encoder configuration, from
h90p_w160pthroughh720p_w1280p. - Camera facing mode.
- Optimization mode:
motion,text, ordetail.
Microphone track
createMicrophoneAudioTrack() lets you configure:
- Microphone device.
- Audio encoder configuration.
- Noise suppression options.
Screen-share track
createScreenShareVideoTrack() lets you configure the screen-share encoder settings.
The default configuration is h720p_15fps.
You can provide custom tracks while joining or replace media during an active session.
For example, custom tracks can be passed through:
customCameraVideoTrack
customMicrophoneAudioTrack
Or supplied when changing published media:
enableWebcam(track)
changeWebcam(track)
enableScreenShare(track)
See the platform-specific custom track documentation:
Receive and render streams
When another participant publishes media, your client receives the corresponding stream.
For example, when a remote participant enables their camera, onStreamEnabled is triggered. Your application can then attach the stream's underlying track to a video element or platform-specific video view.
- React
- JavaScript
- React Native
- Flutter
- Android
- iOS
import {
useParticipant,
VideoPlayer,
} from "@videosdk.live/react-sdk";
const ParticipantView = ({ participantId }) => {
const { webcamOn } = useParticipant(participantId);
return (
<VideoPlayer
participantId={participantId}
type="video" // "video" or "share"
containerStyle={{
height: "100%",
width: "100%",
}}
/>
);
};
VideoPlayer attaches the video track for you.
For microphone audio, you can place micStream.track inside a MediaStream and attach it to an <audio> element.
Display audio and video is the complete rendering guide.
participant.on("stream-enabled", (stream) => {
if (stream.kind == "video") {
const videoElement = document.createElement("video");
videoElement.setAttribute("playsinline", true);
const mediaStream = new MediaStream();
mediaStream.addTrack(stream.track);
videoElement.srcObject = mediaStream;
videoElement.play();
videoContainer.appendChild(videoElement);
}
});
Display audio and video is the complete rendering guide.
const ParticipantView = ({ participantId }) => {
const {
webcamOn,
webcamStream,
} = useParticipant(participantId);
return webcamOn && webcamStream ? (
<RTCView
streamURL={
new MediaStream([webcamStream.track]).toURL()
}
objectFit={"cover"}
style={{ height: 200 }}
/>
) : null;
};
Display video is the complete rendering guide.
participant.on(Events.streamEnabled, (Stream stream) {
if (stream.kind == 'video') {
setState(() => videoStream = stream);
}
});
if (videoStream != null)
RTCVideoView(
videoStream?.renderer as RTCVideoRenderer,
objectFit:
RTCVideoViewObjectFit.RTCVideoViewObjectFitCover,
),
Display video is the complete rendering guide.
participant.addEventListener(
object : ParticipantEventListener() {
override fun onStreamEnabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
val videoTrack = stream.track as VideoTrack
holder.participantView.addTrack(videoTrack)
}
}
override fun onStreamDisabled(stream: Stream) {
if (stream.kind.equals("video", ignoreCase = true)) {
holder.participantView.removeTrack()
}
}
}
)
participantView is a live.videosdk.rtc.android.VideoView.
Render participant is the complete rendering guide.
extension MeetingViewController: ParticipantEventListener {
func onStreamEnabled(
_ stream: MediaStream,
forParticipant participant: Participant
) {
if case .state(value: .video) = stream.kind,
let videoTrack = stream.track as? RTCVideoTrack {
videoTrack.add(remoteParticipantVideoContainer)
}
}
}
remoteParticipantVideoContainer can be an RTCMTLVideoView.
Display video is the complete rendering guide.
Layout and grid management covers arranging participant tiles.
Pause and resume incoming streams
You can temporarily stop receiving a remote stream without affecting the publisher or other participants.
Calling pause() stops receiving that stream on the local client. Calling resume() starts receiving it again.
This is useful when:
- A participant tile is outside the visible viewport.
- Your interface temporarily displays participant names without video.
- You want to reduce unnecessary media consumption for hidden elements.
- React
- JavaScript
- React Native
- Flutter
- Android
- iOS
const {
webcamStream,
micStream,
} = useParticipant(participantId);
webcamStream.pause();
micStream.resume();
const participant =
meeting.participants.get(participantId);
participant.streams.forEach(async (stream) => {
await stream.pause();
});
const {
webcamStream,
micStream,
} = useParticipant(participantId);
webcamStream.pause();
micStream.resume();
Stream videoStream = participant.streams
.where((e) => e.kind == 'video')
.first;
videoStream.track.pause();
videoStream.track.resume();
for ((_, stream) in participant.streams) {
stream.pause()
}
for ((_, stream) in participant.streams) {
stream.resume()
}
meeting.pauseAllStreams(kind: "video")
meeting.resumeAllStreams(kind: "video")
Per-stream pause() and resume() methods are available on the Stream class.
You can also pause or resume multiple remote streams at once using:
pauseAllStreams(kind)
resumeAllStreams(kind)
The optional kind can be:
"audio""video""share"
The stream's paused property reflects its current state, and onStreamStateChanged is triggered when that state changes.
See the useStream methods reference for pause() and resume().
Control received video quality
VideoSDK supports multiple video quality layers through multiStream, which is enabled by default.
A publisher can send multiple resolutions of the same video. Each receiving participant can then use the layer best suited to their layout and network conditions.
Use:
setQuality("low")
setQuality("med")
setQuality("high")
to request a specific video quality.
If the network cannot sustain the selected quality, VideoSDK may temporarily use a lower quality. onVideoQualityChanged reports changes to the received video quality.
- React
- JavaScript
- React Native
- Flutter
- Android
- iOS
const {
setViewPort,
setQuality,
} = useParticipant(participantId);
setViewPort(
videoDivWrapperRef.offsetWidth,
videoDivWrapperRef.offsetHeight
);
await setQuality("low");
await participant.setViewPort(
videoElem.offsetWidth,
videoElem.offsetHeight
);
await participant.setQuality("low");
const {
setViewPort,
setQuality,
} = useParticipant(participantId);
<RTCView
onLayout={(event) => {
const { width, height } =
event.nativeEvent.layout;
setViewPort(width, height);
}}
/>;
await setQuality("low");
final RenderBox renderBox =
_widgetKey.currentContext?.findRenderObject()
as RenderBox;
participant.setViewPort(
renderBox.size.width,
renderBox.size.height,
);
participant.setQuality('low');
participant.setViewPort(
holder.itemView.width,
holder.itemView.height
)
participant.quality = "low"
participant.setQuality(.low)
// .low, .medium, .high
The iOS SDK does not provide setViewPort(). Use setQuality() when you need to adjust the received video layer.
See the useParticipant methods reference for setQuality().
Disable, pause, or leave
Disabling media, pausing a stream, and leaving a room solve different problems.
| What you want to do | Method | Who is affected |
|---|---|---|
| Stop publishing your camera or microphone | disableWebcam() / muteMic() | Everyone stops receiving that media, and onStreamDisabled is triggered. |
| Stop receiving one participant's stream | stream.pause() | Only the local client stops receiving it. The publisher and other participants are unaffected. |
| Disconnect from the room entirely | leave() | The local participant leaves, and other clients receive onParticipantLeft. |
Turn a stream off or pause it rather than leaving and rejoining. Reconnecting renegotiates every stream in the room; toggling one stream does not.
Next steps
useStream reference
Explore stream properties, methods, and events in the React SDK.
useParticipant reference
Access participant media streams, state, and controls in React.
Custom tracks
Configure camera, microphone, encoder settings, and media optimization.
Participant management
Access participants, change modes, and moderate users from your client or server.

