Video Optimization

Properly managing video bandwidth is essential for delivering high-quality video in your application. Every video track you receive consumes a portion of the user's available bandwidth. If the total bandwidth demand exceeds what the network can handle, the Stream service will automatically downgrade video quality for all participants — lowering resolution, reducing framerate, or in extreme cases, pausing video entirely to preserve audio.

This means that receiving video you don't actually need (e.g., from participants not visible on screen) directly degrades the quality of the video you do need. Bandwidth optimization is not a nice-to-have — it is required to ensure participants see each other in the quality you intend.

Dynamic resolution scaling

The Stream service automatically adjusts the video resolution and framerate delivered to each call participant based on current network conditions. When a participant's available bandwidth decreases, the server will reduce the quality of incoming video streams. If bandwidth is critically low, the server may pause video entirely to preserve audio.

While Stream's media servers handle this automatically, the quality they can deliver is constrained by how much bandwidth is already being consumed. The fewer unnecessary tracks you subscribe to and the closer you match requested resolution to actual rendering size, the more bandwidth is available for the tracks that matter.

Control track subscriptions

By default, the SDK automatically subscribes to video for up to 5 participants. Audio is always auto-subscribed with no limit. Beyond the 5-participant threshold, incoming video is not requested automatically — you must explicitly enable it.

If you enable video for all participants regardless of whether they are visible, you will consume bandwidth on tracks the user never sees. This directly reduces the quality available for tracks they are watching. In calls with many participants, this can cause noticeable quality degradation, stuttering, or video being paused by the server.

Use SetIncomingVideoEnabled on each participant to control whether their video is received:

// Enable incoming video for a participant that is visible on screen
participant.SetIncomingVideoEnabled(true);

// Disable incoming video for a participant that is not visible
participant.SetIncomingVideoEnabled(false);

You can also control incoming audio per participant:

participant.SetIncomingAudioEnabled(false);
participant.SetIncomingAudioEnabled(true);

Example: Managing video subscriptions based on visibility

The recommended pattern is to only subscribe to video for participants currently visible in your UI. When a participant scrolls out of view or is otherwise not rendered, disable their video. When they come back into view, re-enable it.

var streamCall = await _client.JoinCallAsync(callType, callId, create: true, ring: false, notify: false);

foreach (var participant in streamCall.Participants)
{
    if (participant.IsLocalParticipant)
    {
        continue;
    }

    participant.SetIncomingVideoEnabled(IsParticipantVisibleOnScreen(participant));
}

streamCall.ParticipantJoined += participant =>
{
    participant.SetIncomingVideoEnabled(IsParticipantVisibleOnScreen(participant));
};

Control requested video resolution per participant

Even for participants whose video you do subscribe to, you should request only the resolution you actually render. Receiving 1080p video for a thumbnail that displays at 240x135 pixels wastes bandwidth and reduces quality for other streams.

By default, video is delivered at 1080p (1920x1080). Use UpdateRequestedVideoResolution to match the actual rendering size:

participant.UpdateRequestedVideoResolution(new VideoResolution(1280, 720));

Call this method whenever the rendered size changes (e.g., when switching between grid and spotlight layouts).

For example, if your UI shows one large video at 720p and several thumbnails at 240p:

spotlightParticipant.UpdateRequestedVideoResolution(VideoResolution.Res_720p);

foreach (var thumbnail in thumbnailParticipants)
{
    thumbnail.UpdateRequestedVideoResolution(VideoResolution.Res_240p);
}

Video Frame Rate recommendations

The ideal frames per second (FPS) for video transmission varies by use case. Below are general recommendations:

Use caseFPS (frames per second)Comment
Video Calling & Broadcasting30Typically, 30FPS is sufficient for standard video calls and broadcasting.
Screen-sharing10-15A lower FPS is usually adequate, but a high resolution is recommended to prevent artifacts and ensure clarity.
E-Sports streaming50-60Fast-paced action requires a higher frame rate for smooth playback.