Skip to main content
Version: 4.x.x

Handle Large Rooms - iOS

Managing large rooms requires specific strategies to keep performance and stability. This section provides best practices for optimizing VideoSDK applications to handle high participant volumes effectively. By implementing these recommendations, you can reduce lag, maintain video and audio quality, and provide a smooth experience even in large rooms.

User Interface Optimization​

When hosting large rooms, an optimized UI helps manage participant visibility and ensures smooth performance.

Recommended Practices:

  • Limit Visible Participants: Display only a limited number of participants on screen at any given time, adapting the view based on screen size. Use pagination to allow users to browse or switch between additional participants. For example, you could display only users whose video stream is enabled, or you could choose to display all active speakers. This approach helps manage screen space efficiently, ensuring that the most relevant participants are visible without overwhelming the interface.
  • Prioritize Active Speakers: Ensure all active speakers are displayed on the screen to highlight who is currently talking, helping participants stay engaged and aware of ongoing discussions. To identify which participant is speaking, you can use the onSpeakerChanged() event.

Optimizing Media Streams​

In large video calls, it’s important to manage media streams effectively to optimize system resources while maintaining a smooth user experience.

Recommended Practices:

  • Pause Streams for Non-Visible Participants: To optimize performance, pause the video and/or audio streams of participants who are not currently visible on the screen. This reduces unnecessary resource consumption.
  • Resume Streams When Visible: Once a participant comes into view, resume their stream to provide an uninterrupted experience as they appear on the screen.

For detailed setup instructions on how to achieve this, check out our in-depth documentation pause() & resume(). Both methods are async throws, so call them with try await inside a Task.

Receive Only the Streams You Show​

In large rooms, each device should receive only the audio and video it shows.

Recommended Practices:

  • Turn Off Automatic Receiving: Pass autoConsume: false to createRoom(). The device then receives a participant's audio and video only after you call consumeMicStreams() or consumeWebcamStreams() on that participant. Call them after the room is joined. When a participant leaves the screen, call stopConsumingWebcamStreams(). These methods take effect only when the room was created with autoConsume set to false.
  • Match Video Quality to the View Size: Call setViewPort(width:height:) on a remote participant with the size of their video view, in pixels. The server then sends a video quality that fits the view. Call it again when the view is resized.
  • Lower the Upload When No One Watches: Pass dynaCast: true to createRoom() on the hosts' devices. The server then lowers the quality of the camera video a host sends while no one is watching it at its higher qualities. It has no effect when multiStream is off.

consumeMicStreams(), consumeWebcamStreams(), stopConsumingWebcamStreams() and setViewPort() are async throws, so call them with try await inside a Task.

Media Stream Quality Adjustment​

In large rooms, managing media stream quality is essential to balance performance and user experience.

Recommended Practices:

  • High Quality for Active Speakers: For all active speakers, set the video stream quality to a higher level using the setQuality method (e.g., setQuality(.high)). This ensures that participants will receive higher-quality video for active speakers, providing a clearer and more engaging experience.
  • Lower Quality for Non-Speaking Participants: For other participants who are not actively speaking, set their video stream quality to a lower level (e.g., setQuality(.low)). This helps conserve bandwidth and system resources while maintaining overall room performance.

setQuality() is async throws, so call it with try await inside a Task. It throws ERROR_ACTION_NOT_SUPPORTED when your device receives no video from that participant, for example while their camera is off.

extension LiveStreamViewController: RoomEventListener {
func onSpeakerChanged(activeSpeakerId: String?) {
guard let room = room else { return }
for participant in room.participants.values {
// Skip participants whose camera video you do not receive.
guard participant.streams.values.contains(where: { $0.kind == .video }) else { continue }
let quality: VideoQuality = participant.id == activeSpeakerId ? .high : .low
Task {
do {
try await participant.setQuality(quality)
} catch {
print("setQuality failed for \(participant.displayName): \(error)")
}
}
}
}
}

Check out the documentation for setQuality() method here

Got a Question? Ask us on discord