Connecting to a Session
This page walks through the complete flow for joining an EnableX video session from a Flutter app — selecting an audio output device, joining the room via EnxRtc.joinRoom(), handling connection events, and disconnecting cleanly. Follow the steps in order; each depends on the previous one completing successfully.
Joining an EnableX session from Flutter involves these steps in sequence:
- Optionally query audio devices — find out which output devices are available and let the user choose one.
- Assign all callback handlers — register your response functions on
EnxRtcbefore connecting so no early events are missed. - Call
EnxRtc.joinRoom()— pass the session token, local stream settings, room settings, and advanced options to initiate the connection. - Handle
onRoomConnected— confirm the connection succeeded and proceed to publish your local stream. - Publish your local stream — covered in detail in Stream Management.
- Call
EnxRtc.disconnect()— cleanly end the session when the user leaves.
Before joining, you can query which audio output devices are currently available on the device and allow the user to select their preferred route. This is especially useful when multiple devices are connected — for example, when a Bluetooth headset is paired alongside the built-in speaker.
The Flutter SDK exposes two methods for this:
EnxRtc.getDevices()— returns aList<dynamic>of all available audio output devices.EnxRtc.getSelectedDevice()— returns the currently active device as aString.
Possible device values returned by getDevices():
SPEAKER_PHONE— built-in loudspeakerWIRED_HEADSET— wired headphones or headsetEARPIECE— phone earpiece (quiet, held-to-ear)BLUETOOTH— Bluetooth audio deviceNONE— no audio device available
// Get all available audio output devices
List<dynamic> devices = EnxRtc.getDevices();
print('Available devices: $devices');
// Get the currently active audio output device
String currentDevice = await EnxRtc.getSelectedDevice();
print('Active device: $currentDevice');
getDevices() before joining and present the result to the user when a Bluetooth headset is detected. This ensures they start the session on their preferred audio route rather than the system default.
Register Callbacks First
The EnableX Flutter SDK communicates all connection events through callbacks assigned directly on the EnxRtc class. Because some callbacks — such as onRoomConnected — fire immediately when the connection is established, you must register all handlers before calling joinRoom().
joinRoom(). If you assign handlers after the connection is established, early events such as onRoomConnected and onUserConnected will already have fired and your app will not receive them.
EnxRtc.joinRoom()
EnxRtc.joinRoom() is the single call that connects your Flutter app to an EnableX video session. It authenticates with the JWT token, negotiates the WebRTC connection, and prepares the local media stack. The call is async — your app receives the outcome through the onRoomConnected or onRoomError callbacks.
The method accepts four parameters:
- token — the JWT session token issued by your server.
- localInfo — a map describing the local stream: which media tracks to capture and the participant's display name.
- roomInfo — a map controlling reconnection behaviour and audio-only mode.
- advanceOptions — a list of optional feature flags (pass an empty list if unused).
Method Signature
static Future<void> joinRoom(
String token,
Map<String, dynamic> localInfo,
Map<String, dynamic> roomInfo,
List<dynamic> advanceOptions
)
localInfo — Configuring the Local Stream
The localInfo map tells the SDK what media to capture from the device and how to identify this participant in the room.
| Field | Type | Description |
|---|---|---|
audio |
bool | Capture audio from the microphone. |
video |
bool | Capture video from the camera. |
data |
bool | Enable the data channel (required for chat and custom signalling). |
name |
String | Display name shown to other participants. |
audioMuted |
bool | Join with the microphone muted. Audio is still captured but not transmitted. |
videoMuted |
bool | Join with the camera off. Video is still captured but not transmitted. |
Map<String, dynamic> localInfo = {
'audio': true,
'video': true,
'data': true,
'name': 'Alice',
'audioMuted': false,
'videoMuted': false,
};
roomInfo — Reconnection and Audio-Only Settings
The roomInfo map controls how the SDK handles network disruptions and whether video should be active at all.
| Field | Type | Description |
|---|---|---|
allow_reconnect |
bool | Attempt automatic reconnection if the network drops. |
number_of_attempts |
int | Maximum number of reconnection attempts before giving up. |
timeout_interval |
int | Seconds to wait between reconnection attempts. |
audio_only |
bool | Set true to join in audio-only mode — no video is captured or received. |
forceTurn |
bool | Force TURN relay for all connections, even when a direct peer connection is possible. Useful in restrictive network environments. |
Map<String, dynamic> roomInfo = {
'allow_reconnect': true,
'number_of_attempts': 3,
'timeout_interval': 20,
'audio_only': false,
'forceTurn': false,
};
Full Join Example
The example below shows a complete Flutter StatefulWidget that registers all necessary callbacks in initState() and then calls joinRoom(). This is the recommended pattern — it guarantees that no early events are missed.
import 'package:enx_flutter_plugin/enx_flutter_plugin.dart';
class VideoSessionPage extends StatefulWidget {
final String token;
const VideoSessionPage({required this.token, super.key});
@override
State<VideoSessionPage> createState() => _VideoSessionPageState();
}
class _VideoSessionPageState extends State<VideoSessionPage> {
@override
void initState() {
super.initState();
_registerCallbacks();
_joinRoom();
}
void _registerCallbacks() {
EnxRtc.onRoomConnected = (Map<dynamic, dynamic> map) {
print('Room connected: $map');
// Proceed to publish local stream here
};
EnxRtc.onRoomError = (Map<dynamic, dynamic> map) {
print('Room error: ${map['msg']}');
};
EnxRtc.onUserConnected = (Map<dynamic, dynamic> map) {
print('User joined: ${map['name']}');
};
EnxRtc.onUserDisConnected = (Map<dynamic, dynamic> map) {
print('User left: ${map['clientId']}');
};
EnxRtc.onRoomDisConnected = (Map<dynamic, dynamic> map) {
print('Disconnected from room');
};
}
Future<void> _joinRoom() async {
Map<String, dynamic> localInfo = {
'audio': true,
'video': true,
'data': true,
'name': 'Alice',
'audioMuted': false,
'videoMuted': false,
};
Map<String, dynamic> roomInfo = {
'allow_reconnect': true,
'number_of_attempts': 3,
'timeout_interval': 20,
'audio_only': false,
'forceTurn': false,
};
await EnxRtc.joinRoom(widget.token, localInfo, roomInfo, []);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Video Session')),
body: Container(), // Add EnxPlayerWidget here for video
);
}
}
Callbacks Fired on Connection
Once joinRoom() is called, the SDK fires the following callbacks to report the outcome and participant activity:
| Callback | Fires when |
|---|---|
onRoomConnected |
Connection established successfully; the map contains room metadata. |
onRoomError |
Connection attempt failed; the map contains an error message. |
onUserConnected |
A new participant has joined the room. |
onUserDisConnected |
A participant has left the room. |
onPublishedStream |
The local stream was successfully published to the room. |
onUnPublishedStream |
The local stream was unpublished from the room. |
When the user ends the session — by tapping a leave button, navigating away, or closing the app — your app should call EnxRtc.disconnect(). This method stops local media capture, closes the WebRTC peer connection, and signals the server to remove this participant from the room. The SDK confirms the teardown through the onRoomDisConnected callback.
EnxRtc.disconnect()
// Disconnect when the user taps "End Call"
void endSession() {
EnxRtc.disconnect();
}
Listen for onRoomDisConnected to confirm the teardown is complete, then navigate away from the video screen:
EnxRtc.onRoomDisConnected = (Map<dynamic, dynamic> map) {
// Session fully ended — navigate back to the previous screen
Navigator.of(context).pop();
};
EnxRtc.disconnect() before disposing the widget. This ensures the camera and microphone are released and the server cleans up the participant slot. Disposing the widget without disconnecting can leave a ghost participant in the room and keep media hardware locked.
When allow_reconnect: true is set in roomInfo, the SDK automatically attempts to restore the connection if the network drops — without any additional code required from your app. Your job is to listen to the reconnection lifecycle callbacks and update the UI accordingly so the user knows what is happening.
The SDK fires the following callbacks during a reconnection sequence:
| Callback | Fires when |
|---|---|
onConnectionLost |
The network connection was lost and reconnection is being attempted. |
onConnectionInterrupted |
The connection was interrupted — for example, the device switched from Wi-Fi to mobile data. |
onReconnect |
The SDK is actively attempting to reconnect (fires once per attempt). |
onUserReconnectSuccess |
This endpoint reconnected successfully and the session is restored. |
A typical pattern is to show a status message while reconnecting and clear it once the SDK reports success:
EnxRtc.onConnectionLost = (Map<dynamic, dynamic> map) {
setState(() {
_status = 'Reconnecting...';
});
};
EnxRtc.onConnectionInterrupted = (Map<dynamic, dynamic> map) {
setState(() {
_status = 'Connection interrupted. Trying to restore...';
});
};
EnxRtc.onReconnect = (Map<dynamic, dynamic> map) {
// Fired for each reconnection attempt — useful for showing attempt count
print('Reconnection attempt in progress');
};
EnxRtc.onUserReconnectSuccess = (Map<dynamic, dynamic> map) {
setState(() {
_status = 'Connected';
});
};
number_of_attempts without success, onRoomDisConnected fires and the session ends. Handle this the same way as a normal disconnect — navigate the user back to the lobby and prompt them to rejoin.
The EnableX server continuously monitors the network quality of all participants. When available bandwidth degrades to the point where it can no longer support the current number of active video streams, the SDK notifies your app through onRoomBandwidthAlert.
This callback is your signal to adapt the experience — for example, reducing the number of visible video panels, switching the session to audio-only mode, or informing the user that their connection quality is low.
onRoomBandwidthAlert
EnxRtc.onRoomBandwidthAlert = (Map<dynamic, dynamic> map) {
// The map contains details about the current bandwidth condition
print('Bandwidth alert: $map');
// Example adaptive response: switch to audio-only mode
// or reduce the active talker count in your UI
};