> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-feat-rn-pin-save-thread-subscription-uik.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Events

> Handle CometChat Calls SDK v5 events on Flutter for call lifecycle, participants, media state, errors, and real-time updates.

Handle call session events to build responsive UIs. The SDK provides five event listener interfaces to monitor session status, participant activities, media changes, button clicks, and layout changes. Unlike Android, Flutter listeners are not lifecycle-aware and must be manually removed in `dispose()` to prevent memory leaks.

## Get CallSession Instance

The `CallSession` is a singleton that manages the active call. All event listener registrations and session control methods are accessed through this instance.

```dart theme={null}
CallSession? callSession = CallSession.getInstance();
```

<Warning>
  Flutter listeners are **not** lifecycle-aware. You must manually remove all listeners in your widget's `dispose()` method to prevent memory leaks. Failing to do so may cause callbacks to fire on disposed widgets.
</Warning>

***

## Session Events

Monitor the call session lifecycle including join/leave events and connection status.

```dart theme={null}
class _SessionStatusListener extends SessionStatusListeners {
  @override
  void onSessionJoined() {
    // Successfully connected to the session
  }

  @override
  void onSessionLeft() {
    // Navigate away
  }

  @override
  void onSessionTimedOut() {
    // Session ended due to inactivity
  }

  @override
  void onConnectionLost() {
    // Network interrupted, attempting reconnection
  }

  @override
  void onConnectionRestored() {
    // Connection restored after being lost
  }

  @override
  void onConnectionClosed() {
    // Connection permanently closed
  }
}

final sessionStatusListener = _SessionStatusListener();

CallSession.getInstance()?.addSessionStatusListener(sessionStatusListener);
```

| Event                  | Description                                          |
| ---------------------- | ---------------------------------------------------- |
| `onSessionJoined`      | Successfully connected and joined the session        |
| `onSessionLeft`        | Left the session via `leaveSession()` or was removed |
| `onSessionTimedOut`    | Session ended due to inactivity timeout              |
| `onConnectionLost`     | Network interrupted, SDK attempting reconnection     |
| `onConnectionRestored` | Connection restored after being lost                 |
| `onConnectionClosed`   | Connection permanently closed, cannot reconnect      |

Remove the listener when no longer needed:

```dart theme={null}
@override
void dispose() {
  CallSession.getInstance()?.removeSessionStatusListener(sessionStatusListener);
  super.dispose();
}
```

***

## Participant Events

Monitor participant activities including join/leave, audio/video state, hand raise, screen sharing, and recording.

```dart theme={null}
class _ParticipantEventListener extends ParticipantEventListeners {
  @override
  void onParticipantJoined(Participant participant) {
    // A participant joined the call
  }

  @override
  void onParticipantLeft(Participant participant) {
    // A participant left the call
  }

  @override
  void onParticipantListChanged(List<Participant> participants) {
    // Participant list updated
  }
  // every other callback already defaults to a no-op on the abstract class —
  // override only what you need (onParticipantAudioMuted, onParticipantAudioUnmuted, onParticipantVideoPaused, onParticipantVideoResumed, …).
}

final participantEventListener = _ParticipantEventListener();

CallSession.getInstance()?.addParticipantEventListener(participantEventListener);
```

| Event                             | Parameter           | Description                              |
| --------------------------------- | ------------------- | ---------------------------------------- |
| `onParticipantJoined`             | `Participant`       | A participant connected to the call      |
| `onParticipantLeft`               | `Participant`       | A participant disconnected from the call |
| `onParticipantListChanged`        | `List<Participant>` | Participant list updated                 |
| `onParticipantAudioMuted`         | `Participant`       | A participant muted their microphone     |
| `onParticipantAudioUnmuted`       | `Participant`       | A participant unmuted their microphone   |
| `onParticipantVideoPaused`        | `Participant`       | A participant turned off their camera    |
| `onParticipantVideoResumed`       | `Participant`       | A participant turned on their camera     |
| `onParticipantHandRaised`         | `Participant`       | A participant raised their hand          |
| `onParticipantHandLowered`        | `Participant`       | A participant lowered their hand         |
| `onParticipantStartedScreenShare` | `Participant`       | A participant started screen sharing     |
| `onParticipantStoppedScreenShare` | `Participant`       | A participant stopped screen sharing     |
| `onParticipantStartedRecording`   | `Participant`       | A participant started recording          |
| `onParticipantStoppedRecording`   | `Participant`       | A participant stopped recording          |
| `onDominantSpeakerChanged`        | `Participant`       | The active speaker changed               |

Remove the listener when no longer needed:

```dart theme={null}
@override
void dispose() {
  CallSession.getInstance()?.removeParticipantEventListener(participantEventListener);
  super.dispose();
}
```

***

## Media Events

Monitor your local media state changes including audio/video status, recording, and device changes.

```dart theme={null}
class _MediaEventListener extends MediaEventListeners {
  @override
  void onAudioMuted() {
    // Your microphone was muted
  }

  @override
  void onAudioUnMuted() {
    // Your microphone was unmuted
  }

  @override
  void onVideoPaused() {
    // Your camera was turned off
  }

  @override
  void onVideoResumed() {
    // Your camera was turned on
  }

  @override
  void onRecordingStarted() {
    // Call recording started
  }

  @override
  void onRecordingStopped() {
    // Call recording stopped
  }

  @override
  void onScreenShareStarted() {
    // You started screen sharing
  }

  @override
  void onScreenShareStopped() {
    // You stopped screen sharing
  }

  @override
  void onAudioModeChanged(AudioMode audioMode) {
    // Audio output device changed
  }

  @override
  void onCameraFacingChanged(CameraFacing facing) {
    // Camera switched between front and rear
  }
}

final mediaEventsListener = _MediaEventListener();

CallSession.getInstance()?.addMediaEventsListener(mediaEventsListener);
```

| Event                   | Parameter      | Description                            |
| ----------------------- | -------------- | -------------------------------------- |
| `onAudioMuted`          | -              | Your microphone was muted              |
| `onAudioUnMuted`        | -              | Your microphone was unmuted            |
| `onVideoPaused`         | -              | Your camera was turned off             |
| `onVideoResumed`        | -              | Your camera was turned on              |
| `onRecordingStarted`    | -              | Call recording started                 |
| `onRecordingStopped`    | -              | Call recording stopped                 |
| `onScreenShareStarted`  | -              | You started screen sharing             |
| `onScreenShareStopped`  | -              | You stopped screen sharing             |
| `onAudioModeChanged`    | `AudioMode`    | Audio output device changed            |
| `onCameraFacingChanged` | `CameraFacing` | Camera switched between front and rear |

<AccordionGroup>
  <Accordion title="AudioMode Values">
    | Value                 | Description                                     |
    | --------------------- | ----------------------------------------------- |
    | `AudioMode.speaker`   | Audio routed through device loudspeaker         |
    | `AudioMode.earpiece`  | Audio routed through phone earpiece             |
    | `AudioMode.bluetooth` | Audio routed through connected Bluetooth device |
  </Accordion>

  <Accordion title="CameraFacing Values">
    | Value                | Description                            |
    | -------------------- | -------------------------------------- |
    | `CameraFacing.front` | Front-facing (selfie) camera is active |
    | `CameraFacing.rear`  | Rear-facing (main) camera is active    |
  </Accordion>
</AccordionGroup>

Remove the listener when no longer needed:

```dart theme={null}
@override
void dispose() {
  CallSession.getInstance()?.removeMediaEventsListener(mediaEventsListener);
  super.dispose();
}
```

***

## Button Click Events

Intercept UI button clicks from the default call interface to add custom behavior or analytics.

```dart theme={null}
class _ButtonClickListener extends ButtonClickListeners {
  @override
  void onLeaveSessionButtonClicked() {
    // Leave button tapped
  }

  @override
  void onToggleAudioButtonClicked() {
    // Mute/unmute button tapped
  }

  @override
  void onToggleVideoButtonClicked() {
    // Video on/off button tapped
  }
  // every other callback already defaults to a no-op on the abstract class —
  // override only what you need (onSwitchCameraButtonClicked, onRaiseHandButtonClicked, onShareInviteButtonClicked, onChangeLayoutButtonClicked, …).
}

final buttonClickListener = _ButtonClickListener();

CallSession.getInstance()?.addButtonClickListener(buttonClickListener);
```

| Event                            | Description                        |
| -------------------------------- | ---------------------------------- |
| `onLeaveSessionButtonClicked`    | Leave/end call button was tapped   |
| `onToggleAudioButtonClicked`     | Mute/unmute button was tapped      |
| `onToggleVideoButtonClicked`     | Video on/off button was tapped     |
| `onSwitchCameraButtonClicked`    | Camera switch button was tapped    |
| `onRaiseHandButtonClicked`       | Raise hand button was tapped       |
| `onShareInviteButtonClicked`     | Share/invite button was tapped     |
| `onChangeLayoutButtonClicked`    | Layout change button was tapped    |
| `onParticipantListButtonClicked` | Participant list button was tapped |
| `onChatButtonClicked`            | In-call chat button was tapped     |
| `onRecordingToggleButtonClicked` | Recording toggle button was tapped |

<Note>
  Button click events fire before the SDK's default action executes. Use these to add custom logic alongside default behavior.
</Note>

Remove the listener when no longer needed:

```dart theme={null}
@override
void dispose() {
  CallSession.getInstance()?.removeButtonClickListener(buttonClickListener);
  super.dispose();
}
```

***

## Layout Events

Monitor layout changes including layout type switches and Picture-in-Picture mode transitions.

```dart theme={null}
class _LayoutListener extends LayoutListeners {
  @override
  void onCallLayoutChanged(LayoutType layoutType) {
    // Layout changed (tile, spotlight)
  }

  @override
  void onParticipantListVisible() {
    // Participant list panel opened
  }

  @override
  void onParticipantListHidden() {
    // Participant list panel closed
  }

  @override
  void onPictureInPictureLayoutEnabled() {
    // Entered PiP mode
  }

  @override
  void onPictureInPictureLayoutDisabled() {
    // Exited PiP mode
  }
}

final layoutListener = _LayoutListener();

CallSession.getInstance()?.layoutListener = layoutListener;
```

| Event                              | Parameter    | Description                          |
| ---------------------------------- | ------------ | ------------------------------------ |
| `onCallLayoutChanged`              | `LayoutType` | Call layout changed                  |
| `onParticipantListVisible`         | -            | Participant list panel was opened    |
| `onParticipantListHidden`          | -            | Participant list panel was closed    |
| `onPictureInPictureLayoutEnabled`  | -            | Call entered Picture-in-Picture mode |
| `onPictureInPictureLayoutDisabled` | -            | Call exited Picture-in-Picture mode  |

<Accordion title="LayoutType Values">
  | Value                  | Description                                           | Best For                         |
  | ---------------------- | ----------------------------------------------------- | -------------------------------- |
  | `LayoutType.tile`      | Grid layout with equally-sized tiles                  | Group discussions, team meetings |
  | `LayoutType.spotlight` | Large view for active speaker, small tiles for others | Presentations, one-on-one calls  |
</Accordion>

Remove the listener when no longer needed:

```dart theme={null}
@override
void dispose() {
  CallSession.getInstance()?.layoutListener = null;
  super.dispose();
}
```
