Registering and unregistering
All meeting events are reported throughSMeetingDelegate:
delegatesis a weak-reference multicast, so you can register multiple observers; the SDK doesn’t extend your object’s lifetime because you registered it- Every method in the protocol has a default empty implementation, so you only implement the events you care about
- Call
meeting.delegates.remove(delegate:)when you no longer need it - Callbacks are always dispatched on the main thread, so you can update the UI directly
@MainActor type, declare the protocol methods as nonisolated, then hop back to the main actor context inside them:
Connection events
The
reason of DisconnectEventData is a DisconnectReason, which tells you whether you exited on your own or were disconnected; error carries the underlying error when the disconnection is abnormal.
Member events
When
byAdmin in a media state event is true, the change was caused by a host action, and opUid is the operator. You can use this to show the user a hint such as “The host turned off your microphone.”
UserHandupEventData.step tells you which step it is: .request raise hand, .cancel lower hand, .confirmOpen accept the request, .rejectOpen decline the request.
Room state events
For screen sharing,
roomShareDidStart is based on the RTC media track: it’s reported as soon as the remote screen track arrives, so you can render the shared video directly when you receive it.
shareBroadcastDidStart / shareBroadcastDidFinish fire only for iOS full-screen sharing, and only on the sharer’s own side. They distinguish “the listener is attached” from “there is actually video”; for how to wire them up, see Screen sharing.
When the host turns on “mute all” or “camera off for everyone,” the SDK automatically turns off the local devices of non-host members and additionally reports the corresponding member media state event.
The payload of roomTitleDidChange carries title and previousTitle, and both main meeting renames and sub-meeting renames (adminUpdateSubMeetingTitle) trigger it. It has no opUid: renaming a meeting has no dedicated broadcast command, and the event is derived by comparing titles after the channel properties are updated. The properties contain only the result, not the operator, and making up an operator would only mislead callers.
Message events
Both have an
isPrivate flag indicating whether it’s a private message, and uid is the sender.
Host command events
For how to handle them, see Raise hand and turn-on requests.
Waiting room events
Sub-meeting events
For all three events, you need to perform the switch yourself: “exit the current meeting, then enter the target meeting.”
Sign-in and roll call events
Device events
Device events don’t depend on meeting state; the SDK starts reporting them once the instance is created, so you can use them on a pre-meeting device check page.
Audio routing events (iOS)
Both callbacks exist only on iOS (their declarations are wrapped in
#if os(iOS)), and like device events, they don’t depend on meeting state.
AudioRouteChangeEventData.reason is the change reason given by the system, and it’s more useful than the result itself when troubleshooting routing issues. Recovery from an interruption may be delayed because a system call hasn’t ended or the app is still in the background; the SDK fires the event only once, after audio has actually recovered. For details, see Audio routing.
Call quality events
Quality is reported through two separate feeds; pick one based on what you need, and don’t use both to drive the same UI:
didReceiveQualityReportfires on every report with the raw values (packet loss, RTT, jitter, bitrate, MOS), suitable for signal bar icons and detailed diagnostics panelsconnectionQualityDidChangefires only when the level jumps to a different tier, suitable for “your network is poor” hints and proactive downgrade decisions
activeSpeakersDidChange gives a full snapshot (already sorted by volume in descending order), so just overwrite your UI with it; you don’t need to merge increments yourself. When no one is speaking, speakers is an empty array.
The data structures of these four events are defined in the underlying SRTC module, so you need import SRTC to use them; for the fields, see Types. For level determination, cold-start values, and proactive layer switching, see SRTC · Call quality and active speakers.
These four events are available only when the meeting uses the SeaStart (SFU) engine—meetings that go through the CDN (Wangsu) don’t have this signaling path and receive none of them.
Receive stream status events
It’s determined per track: when a video track produces no frames for a period of time, a timeout is reported (
timedOut == true), and as soon as frames resume, it’s reported again (timedOut == false). A typical use is toggling the “loading” indicator on a video tile. When the first frame arrives after you subscribe, you first receive a recovery, which you can use to turn off the initial loading indicator.
The payload directly reuses the underlying SRTC ReceiveStreamStatus (requires import SRTC); for the fields, see Types. It corresponds to onReceiveStreamStatusChange:streamType:status: in the old MeetingKit.
Unlike the four quality events above, this event is available with both engines—it’s determined by whether video frames are received locally and doesn’t depend on the SFU’s signaling path.
Out-of-meeting message events
You need to callenableIm() first; see Out-of-meeting messages.
These connection events and the meeting connection events above belong to two independent paths; don’t mix them up.
Event identifier enums
The SDK also exposes two enums that list the string identifier of each event:RoomEventType—in-meeting event identifiers, such asuser_enterandroom_share_startImEventType—out-of-meeting message event identifiers, such ascall_calling
SMeetingDelegate methods above. You don’t need these two enums in a normal integration; they’re useful only when you need logging instrumentation or want to align event naming with other platforms.