Handle call events
Listen for WASM SDK call invitation, participant, and media-stream events in one place.
Register invitation lifecycle, participant connection, and media-stream listeners in a central call-state layer. Most events expose the room ID as data.invitation.roomID; stream events expose it directly as data.roomID. A participant event can have a null invitation and provide only groupID. In that case, look up the room in the current group-call state and query the room by group ID if the local state cannot resolve it.
Event data
| Event | data type | Fields used to locate and process the update |
|---|---|---|
OnReceiveNewInvitation | SignalingInvitationEvent | invitation.roomID, invitation.groupID, participant, and userID. |
OnInviteeAccepted | SignalingActionEvent | invitation.roomID, userID, participant, and opUserPlatformID. |
OnInviteeRejected | SignalingActionEvent | invitation.roomID, userID, and opUserPlatformID. |
OnInvitationCancelled | SignalingInvitationEvent | invitation.roomID and userID. |
OnInvitationTimeout | SignalingInvitationEvent | invitation.roomID and userID. |
OnInviteeAcceptedByOtherDevice | SignalingActionEvent | invitation.roomID, userID, and opUserPlatformID. |
OnInviteeRejectedByOtherDevice | SignalingActionEvent | invitation.roomID, userID, and opUserPlatformID. |
OnHangUp | SignalingHungUpEvent | invitation.roomID and userID. |
OnRoomParticipantConnected | SignalingRoomParticipantChangedEvent | invitation?.roomID, groupID, and participant. |
OnRoomParticipantDisconnected | SignalingRoomParticipantChangedEvent | invitation?.roomID, groupID, and participant. |
OnStreamChange | SignalingStreamChangeEvent | Direct roomID, plus streamType and mute. |
For invitation events, data is not a SignalingInvitation itself; read the invitation from data.invitation. Identify each user in a participant list by participant.userInfo.userID, combined with roomID for the participant-state key.
import { SdkEvent } from '@openim/wasm-client-sdk';
function getCallRoomID(data) {
return (
data.roomID ??
data.invitation?.roomID ??
(data.groupID ? getActiveRoomIDByGroupID(data.groupID) : undefined)
);
}
function mergeParticipantEvent(data, action) {
const roomID = getCallRoomID(data);
if (!roomID) {
refreshGroupCall(data.groupID);
return;
}
action(roomID, data.participant ?? []);
}
const handlers = {
invitation: ({ data }) =>
upsertCall({
roomID: data.invitation.roomID,
invitation: data.invitation,
participant: data.participant,
state: 'ringing',
}),
accepted: ({ data }) =>
mergeCallEvent(data.invitation.roomID, 'accepted', data),
rejected: ({ data }) =>
mergeCallEvent(data.invitation.roomID, 'rejected', data),
cancelled: ({ data }) =>
mergeCallEvent(data.invitation.roomID, 'cancelled', data),
timeout: ({ data }) =>
mergeCallEvent(data.invitation.roomID, 'timeout', data),
acceptedByOtherDevice: ({ data }) =>
mergeCallEvent(data.invitation.roomID, 'accepted-by-other-device', data),
rejectedByOtherDevice: ({ data }) =>
mergeCallEvent(data.invitation.roomID, 'rejected-by-other-device', data),
hangUp: ({ data }) => finishCall(data.invitation.roomID, data.userID),
participantConnected: ({ data }) =>
mergeParticipantEvent(data, addParticipants),
participantDisconnected: ({ data }) =>
mergeParticipantEvent(data, removeParticipants),
streamChanged: ({ data }) => updateRoomStream(data.roomID, data),
};
openimsdk.on(SdkEvent.OnReceiveNewInvitation, handlers.invitation);
openimsdk.on(SdkEvent.OnInviteeAccepted, handlers.accepted);
openimsdk.on(SdkEvent.OnInviteeRejected, handlers.rejected);
openimsdk.on(SdkEvent.OnInvitationCancelled, handlers.cancelled);
openimsdk.on(SdkEvent.OnInvitationTimeout, handlers.timeout);
openimsdk.on(SdkEvent.OnInviteeAcceptedByOtherDevice, handlers.acceptedByOtherDevice);
openimsdk.on(SdkEvent.OnInviteeRejectedByOtherDevice, handlers.rejectedByOtherDevice);
openimsdk.on(SdkEvent.OnHangUp, handlers.hangUp);
openimsdk.on(SdkEvent.OnRoomParticipantConnected, handlers.participantConnected);
openimsdk.on(SdkEvent.OnRoomParticipantDisconnected, handlers.participantDisconnected);
openimsdk.on(SdkEvent.OnStreamChange, handlers.streamChanged);
function removeCallListeners() {
openimsdk.off(SdkEvent.OnReceiveNewInvitation, handlers.invitation);
openimsdk.off(SdkEvent.OnInviteeAccepted, handlers.accepted);
openimsdk.off(SdkEvent.OnInviteeRejected, handlers.rejected);
openimsdk.off(SdkEvent.OnInvitationCancelled, handlers.cancelled);
openimsdk.off(SdkEvent.OnInvitationTimeout, handlers.timeout);
openimsdk.off(SdkEvent.OnInviteeAcceptedByOtherDevice, handlers.acceptedByOtherDevice);
openimsdk.off(SdkEvent.OnInviteeRejectedByOtherDevice, handlers.rejectedByOtherDevice);
openimsdk.off(SdkEvent.OnHangUp, handlers.hangUp);
openimsdk.off(SdkEvent.OnRoomParticipantConnected, handlers.participantConnected);
openimsdk.off(SdkEvent.OnRoomParticipantDisconnected, handlers.participantDisconnected);
openimsdk.off(SdkEvent.OnStreamChange, handlers.streamChanged);
}This page provides the complete listener examples for the 11 call events above. refreshGroupCall(groupID) should call Get a group call room and refresh the current call state for that group from the query result. Merge participant state by roomID:userID. Do not identify calls or participants by event order, display name, or array index. Call removeCallListeners() when the user logs out, the active account changes, or the call-state layer is destroyed.
Was this page helpful?