Overview
Meeting video comes in three kinds, each with its own entry point:
Local video doesn’t need a subscription; just render the track directly. Remote video must be subscribed first before it has any data.
Local video
SwiftUI
Don’t passview when turning on the camera; afterward, pass the track directly to SRTCVideoView:
meeting.screenTrack:
SMeetingEngineis not anObservableObject, socameraTrack/screenTrackchanging fromnilto a value doesn’t trigger a SwiftUI refresh by itself. Keep a “camera is on” flag in your own@Publishedstate and let it drive view updates.
UIKit / AppKit
Pass the preview view when turning on the camera:
The view you pass must be an object that is actually attached to the view hierarchy. Passing a temporarily created local variable that hasn’t been added to any superview leaves the rendering pipeline running with nothing to show.
Remote video (SwiftUI)
SMeetingRemoteVideoView is the recommended entry point for SwiftUI. It handles the entire subscription lifecycle: it subscribes by uid + trackDesc when the view appears and unsubscribes when the view disappears.
trackDesc to .screen:
- Rendering the same
(uid, trackDesc)in multiple places doesn’t make them knock out each other’s subscriptions - When a layout change recreates the view (the old instance disappears and a new one appears), no extra unsubscribe + resubscribe happens, so the video doesn’t flicker
- The subscription result and the arrival of the underlying media don’t happen at the same moment; the component binds automatically once the data actually arrives, so you don’t need delays or retries
Remote video (UIKit / AppKit)
If you already hold anSRTCVideoRenderer attached to the view hierarchy, use this pair of convenience methods:
stopPlayRemoteVideo removes only the one renderer view you pass in; it actually unsubscribes only when the track no longer has any renderer view. So when the same video is shown in several windows, closing one of them doesn’t affect the others.
Control subscriptions yourself
When you need to separate subscription timing from rendering timing (for example, pre-subscribe and then decide the layout), use the core APIs:unsubscribeRemoteVideoTrack unsubscribes unconditionally, regardless of whether any renderer view is still using it. When rendering the same video in multiple places, use SMeetingRemoteVideoView or stopPlayRemoteVideo.
To just check whether a given track of a given member exists (without subscribing), use:
When to subscribe
Remote video is subscribed on demand; the SDK doesn’t subscribe to everyone automatically for you. Base the decision on member state and events:MeetingUserInfo.cameraState == .on→ this member has camera videoMeetingUserInfo.shareState == ShareType.screen.rawValue→ this member is sharing their screen- Refresh the layout when you receive
userCameraStateDidChangeorroomShareDidStart/roomShareDidStop
SMeetingRemoteVideoView, you only need to make the views appear / disappear along with these states, and the subscriptions follow automatically.
Server-side composite video (MCU)
When the meeting has a server-side composite task running, you can pull a single composite video instead of subscribing to members one by one:adminUpdateLayout(_:). See Recording and composite layout.