Monitor local media state changes with MediaEventListeners. This listener provides callbacks for your own audio/video state changes, recording events, screen sharing, audio mode changes, and camera facing changes.
Prerequisites
Register Listener
Register a MediaEventListeners to receive media event callbacks:
final callSession = CallSession . getInstance ();
callSession ? . addMediaEventsListener ( MediaEventListeners (
onAudioMuted : () {
debugPrint ( "Audio muted" );
},
onAudioUnMuted : () {
debugPrint ( "Audio unmuted" );
},
onVideoPaused : () {
debugPrint ( "Video paused" );
},
onVideoResumed : () {
debugPrint ( "Video resumed" );
},
// Additional callbacks...
));
Flutter listeners are not lifecycle-aware. You must manually remove listeners in your widget’s dispose() method to prevent memory leaks.
Callbacks
onAudioMuted
Triggered when your local audio is muted.
onAudioMuted : () {
debugPrint ( "Audio muted" );
// Update mute button UI state
setState (() {
_isAudioMuted = true ;
});
}
Use Cases:
Update mute button icon/state
Show muted indicator in UI
Sync UI with actual audio state
onAudioUnMuted
Triggered when your local audio is unmuted.
onAudioUnMuted : () {
debugPrint ( "Audio unmuted" );
// Update mute button UI state
setState (() {
_isAudioMuted = false ;
});
}
Use Cases:
Update mute button icon/state
Hide muted indicator
Sync UI with actual audio state
onVideoPaused
Triggered when your local video is paused.
onVideoPaused : () {
debugPrint ( "Video paused" );
// Update video button UI state
setState (() {
_isVideoPaused = true ;
});
// Show avatar instead of video preview
}
Use Cases:
Update video toggle button state
Show avatar/placeholder in local preview
Sync UI with actual video state
onVideoResumed
Triggered when your local video is resumed.
onVideoResumed : () {
debugPrint ( "Video resumed" );
// Update video button UI state
setState (() {
_isVideoPaused = false ;
});
// Show video preview
}
Use Cases:
Update video toggle button state
Show local video preview
Sync UI with actual video state
onRecordingStarted
Triggered when session recording starts.
onRecordingStarted : () {
debugPrint ( "Recording started" );
// Show recording indicator
setState (() {
_isRecording = true ;
});
// Notify user that recording is active
}
Use Cases:
Display recording indicator (red dot)
Update recording button state
Show notification to participants
onRecordingStopped
Triggered when session recording stops.
onRecordingStopped : () {
debugPrint ( "Recording stopped" );
// Hide recording indicator
setState (() {
_isRecording = false ;
});
}
Use Cases:
Hide recording indicator
Update recording button state
Show recording saved notification
onScreenShareStarted
Triggered when you start sharing your screen.
onScreenShareStarted : () {
debugPrint ( "Screen sharing started" );
// Update screen share button state
setState (() {
_isScreenSharing = true ;
});
// Show screen share preview
}
Use Cases:
Update screen share button state
Show “You are sharing” indicator
Minimize local video preview
onScreenShareStopped
Triggered when you stop sharing your screen.
onScreenShareStopped : () {
debugPrint ( "Screen sharing stopped" );
// Update screen share button state
setState (() {
_isScreenSharing = false ;
});
// Restore normal view
}
Use Cases:
Update screen share button state
Hide “You are sharing” indicator
Restore local video preview
onAudioModeChanged
Triggered when the audio output mode changes (speaker, earpiece, bluetooth).
onAudioModeChanged : ( AudioMode audioMode) {
debugPrint ( "Audio mode changed to: $ audioMode " );
// Update audio mode button/icon
setState (() {
_currentAudioMode = audioMode;
});
}
AudioMode Values:
Value Description AudioMode.speakerAudio output through device speaker AudioMode.earpieceAudio output through earpiece AudioMode.bluetoothAudio output through connected Bluetooth device
Use Cases:
Update audio mode button icon
Show current audio output device
Handle Bluetooth connection/disconnection
onCameraFacingChanged
Triggered when the camera facing changes (front/rear).
onCameraFacingChanged : ( CameraFacing facing) {
debugPrint ( "Camera facing changed to: $ facing " );
// Update camera switch button state
setState (() {
_currentCameraFacing = facing;
});
}
CameraFacing Values:
Value Description CameraFacing.frontFront-facing camera (selfie camera) CameraFacing.rearRear-facing camera (main camera)
Use Cases:
Update camera switch button icon
Adjust UI for mirrored/non-mirrored preview
Track camera state
Complete Example
Here’s a complete example handling all media events:
import 'package:cometchat_calls_sdk/cometchat_calls_sdk.dart' ;
import 'package:flutter/material.dart' ;
class CallScreen extends StatefulWidget {
const CallScreen ({ super .key});
@override
State < CallScreen > createState () => _CallScreenState ();
}
class _CallScreenState extends State < CallScreen > {
CallSession ? _callSession;
MediaEventListeners ? _mediaEventsListener;
bool _isAudioMuted = false ;
bool _isVideoPaused = false ;
bool _isRecording = false ;
bool _isScreenSharing = false ;
AudioMode _currentAudioMode = AudioMode .speaker;
CameraFacing _currentCameraFacing = CameraFacing .front;
@override
void initState () {
super . initState ();
_callSession = CallSession . getInstance ();
_setupMediaEventsListener ();
}
void _setupMediaEventsListener () {
_mediaEventsListener = MediaEventListeners (
onAudioMuted : () {
if (mounted) {
setState (() => _isAudioMuted = true );
}
},
onAudioUnMuted : () {
if (mounted) {
setState (() => _isAudioMuted = false );
}
},
onVideoPaused : () {
if (mounted) {
setState (() => _isVideoPaused = true );
}
},
onVideoResumed : () {
if (mounted) {
setState (() => _isVideoPaused = false );
}
},
onRecordingStarted : () {
if (mounted) {
setState (() => _isRecording = true );
ScaffoldMessenger . of (context). showSnackBar (
const SnackBar (content : Text ( "Recording started" )),
);
}
},
onRecordingStopped : () {
if (mounted) {
setState (() => _isRecording = false );
ScaffoldMessenger . of (context). showSnackBar (
const SnackBar (content : Text ( "Recording stopped" )),
);
}
},
onScreenShareStarted : () {
if (mounted) {
setState (() => _isScreenSharing = true );
ScaffoldMessenger . of (context). showSnackBar (
const SnackBar (content : Text ( "You are sharing your screen" )),
);
}
},
onScreenShareStopped : () {
if (mounted) {
setState (() => _isScreenSharing = false );
}
},
onAudioModeChanged : ( AudioMode audioMode) {
if (mounted) {
setState (() => _currentAudioMode = audioMode);
}
},
onCameraFacingChanged : ( CameraFacing facing) {
if (mounted) {
setState (() => _currentCameraFacing = facing);
debugPrint ( "Camera switched to: $ facing " );
}
},
);
_callSession ? . addMediaEventsListener (_mediaEventsListener ! );
}
@override
void dispose () {
// Must manually remove listener to prevent memory leaks
if (_mediaEventsListener != null ) {
_callSession ? . removeMediaEventsListener (_mediaEventsListener ! );
}
super . dispose ();
}
@override
Widget build ( BuildContext context) {
return Scaffold (
body : Column (
children : [
// Call UI content here
if (_isRecording)
Container (
padding : const EdgeInsets . all ( 8 ),
color : Colors .red,
child : const Row (
mainAxisSize : MainAxisSize .min,
children : [
Icon ( Icons .fiber_manual_record, color : Colors .white, size : 12 ),
SizedBox (width : 4 ),
Text ( "Recording" , style : TextStyle (color : Colors .white)),
],
),
),
],
),
bottomNavigationBar : Row (
mainAxisAlignment : MainAxisAlignment .spaceEvenly,
children : [
IconButton (
icon : Icon (_isAudioMuted ? Icons .mic_off : Icons .mic),
onPressed : () async {
await _callSession ? . toggleMuteAudio ();
},
),
IconButton (
icon : Icon (_isVideoPaused ? Icons .videocam_off : Icons .videocam),
onPressed : () async {
await _callSession ? . togglePauseVideo ();
},
),
IconButton (
icon : Icon (
_currentAudioMode == AudioMode .speaker
? Icons .volume_up
: _currentAudioMode == AudioMode .bluetooth
? Icons .bluetooth_audio
: Icons .phone_in_talk,
),
onPressed : () {
// Show audio mode picker
},
),
],
),
);
}
}
Remove Listener
Remove the listener in your widget’s dispose() method to prevent memory leaks:
@override
void dispose () {
if (_mediaEventsListener != null ) {
_callSession ? . removeMediaEventsListener (_mediaEventsListener ! );
}
super . dispose ();
}
Callbacks Summary
Callback Parameter Description onAudioMuted- Local audio was muted onAudioUnMuted- Local audio was unmuted onVideoPaused- Local video was paused onVideoResumed- Local video was resumed onRecordingStarted- Session recording started onRecordingStopped- Session recording stopped onScreenShareStarted- Local screen sharing started onScreenShareStopped- Local screen sharing stopped onAudioModeChangedAudioModeAudio output mode changed onCameraFacingChangedCameraFacingCamera facing changed
Next Steps
Button Click Listener Handle UI button click events
Audio Controls Control audio programmatically