Connecting to a Session
This guide walks through the complete flow for joining an EnableX video session from an Android app — from querying available audio devices through publishing your stream and finally disconnecting cleanly. Follow these steps in order; each step depends on the previous one succeeding.
Joining an EnableX session from Android involves these steps in sequence:
- Query audio devices — get the list of available microphones and speakers.
- Create the room object — instantiate
EnxRoomwith your observer implementations. - Initialize the room — call
room.init(context)to prepare the Android media stack. - Register observers — set up all callbacks before connecting.
- Connect to the room — call
room.connect(token, roomInfo, advancedOptions). - Initialize and publish your stream — inside
onRoomConnected, get the local stream and publish it. - Subscribe to remote streams — inside
onStreamAdded, subscribe and attach to your UI. - Disconnect — call
room.disconnect()when the session ends.
If you want a one-call shortcut that wraps steps 2–6, use EnxRtc.joinRoom().
Get Available Audio Devices
EnxRoom.getDevices() returns a list of audio output devices currently connected to the Android device. Use this to let the user choose their preferred audio route — earpiece, speaker, wired headset, or Bluetooth — before or during a session.
- Class:
EnxRoom - Method:
public List<String> getDevices() - Returns: List of device type strings
val devices: List<String> = room.devices
// Returns a list such as: ["SPEAKER_PHONE", "WIRED_HEADSET", "EARPIECE", "BLUETOOTH", "NONE"]
To get the device currently in use:
val currentDevice: String = room.selectedDevice
// e.g. "SPEAKER_PHONE"
Device Change Callbacks
If a headset is plugged in or unplugged, or a Bluetooth device connects/disconnects, the SDK notifies your observer:
override fun onDeviceAdded(deviceName: String?) {
// A new audio device was connected (e.g. Bluetooth headset paired)
Log.d("ENX", "Device added: $deviceName")
}
override fun onDeviceRemoved(deviceName: String?) {
// An audio device was disconnected
Log.d("ENX", "Device removed: $deviceName")
}
override fun onNotifyDeviceUpdate(deviceName: String?) {
// The active audio device changed
Log.d("ENX", "Now using: $deviceName")
}
Create and Initialise the Room Object
The EnxRoom constructor takes two observer instances — one for room-level callbacks (EnxRoomObserver) and one for stream-level callbacks (EnxStreamObserver). Your Activity or Fragment typically implements both interfaces.
After instantiating, call room.init(context) to prepare the Android media stack. This step is mandatory before connect().
class VideoActivity : AppCompatActivity(), EnxRoomObserver, EnxStreamObserver {
private var room: EnxRoom? = null
private var localStream: EnxStream? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Step 2: Create the room object
room = EnxRoom(
this, // EnxRoomObserver
this // EnxStreamObserver
)
// Step 3: Init with Android context
room?.init(this)
// Step 4: Register feature observers before connecting
room?.setRecordingObserver(this)
room?.setTalkerObserver(this)
// Step 5: Connect (see below)
connectToRoom(YOUR_JWT_TOKEN)
}
}
connect(). Callbacks like onRoomConnected and onStreamAdded fire immediately on connection. If observers are registered after connecting, those initial callbacks will be missed.
room.connect()
EnxRoom.connect() authenticates with the JWT token and establishes the signalling channel to the EnableX server. It accepts optional reconnection settings and advanced options.
- Class:
EnxRoom - Method:
public void connect(String token, JSONObject roomInfo, JSONObject advancedOptions)
roomInfo Parameters
| Parameter | Type | Description |
|---|---|---|
allow_reconnect | Boolean | Enable auto-reconnect on network drop. Default: true. |
number_of_attempts | Number | Max reconnect attempts. Default: 3. Minimum: 1. |
timeout_interval | Number | Milliseconds to wait between reconnect attempts. |
audio_only | Boolean | Set true to join as audio-only (no video). |
advancedOptions Parameters
| Option ID | Type | Description |
|---|---|---|
battery_updates | Boolean | Enable battery level update notifications. |
notify-video-resolution-change | Boolean | Enable video resolution change notifications. |
fun connectToRoom(token: String) {
val roomInfo = JSONObject().apply {
put("allow_reconnect", true)
put("number_of_attempts", 3)
put("timeout_interval", 10000)
put("audio_only", false)
}
val advancedOptions = JSONArray().apply {
put(JSONObject().apply {
put("id", "notify-video-resolution-change")
put("enable", true)
})
}
room?.connect(token, roomInfo, advancedOptions)
}
// ── Callbacks ───────────────────────────────────────────────────────────────
override fun onRoomConnected(room: EnxRoom?, roomMetaData: JSONObject?) {
// Successfully connected — proceed to init and publish local stream
initAndPublishStream()
}
override fun onRoomError(errorData: JSONObject?) {
// Connection failed
Log.e("ENX", "Room error: ${errorData?.toString()}")
}
override fun onUserConnected(userData: JSONObject?) {
// A new participant joined the room — update your participant list UI
Log.d("ENX", "User joined: ${userData?.optString("name")}")
}
override fun onRoomAwaited(data: JSONObject?) {
// You are waiting for moderator approval (knock room) or
// waiting for moderator to arrive (wait-for-moderator room).
// data: { "event_type": "knock" } or { "event_type": "wait_for_moderator" }
}
override fun onUserAwaited(userData: JSONObject?) {
// Moderator only: a participant is waiting at the door
// Show approve/deny UI
}
Network Disconnection & Reconnection Callbacks
If the network drops during a session, the SDK fires these callbacks. With auto-reconnect enabled, it attempts to recover silently:
override fun onConnectionLost(json: JSONObject?) {
// Network connection lost — show "Reconnecting..." UI
}
override fun onConnectionInterrupted(json: JSONObject?) {
// Connection interrupted (e.g. switched from WiFi to 4G)
}
override fun onUserReconnectSuccess(room: EnxRoom?, roomMetaData: JSONObject?) {
// Auto-reconnect succeeded — restore UI
}
override fun onReconnect(message: String?) {
// Reconnect attempt in progress
}
| Error Code | Description |
|---|---|
| 5073 | Connection switched to alternate network |
| 5074 | Network disconnected; reconnection timed out |
| 5086 | Method called while room is not connected |
| 5087 | Reconnection failed |
Initialize a Local Stream
EnxRoom.getLocalStream() creates a local media stream with the audio, video, and data tracks you configure. Call this inside onRoomConnected, then immediately publish it.
- Class:
EnxRoom - Method:
public EnxStream getLocalStream(JSONObject publishStreamInfo)
publishStreamInfo Options
| Option | Type | Description |
|---|---|---|
audio | Boolean | Include audio track. Default: true. |
video | Boolean | Include video track. Default: true. |
data | Boolean | Include data channel (required for chat/signalling). |
audioMuted | Boolean | Join with microphone muted. |
videoMuted | Boolean | Join with camera off. |
attributes | JSONObject | Custom key/value metadata attached to this stream. |
maxVideoLayers | Number | 1=HD only, 2=HD+SD, 3=HD+SD+LD. More layers = better adaptive quality for receivers. |
Publish the Stream
fun initAndPublishStream() {
val streamInfo = JSONObject().apply {
put("audio", true)
put("video", true)
put("data", true)
put("audioMuted", false)
put("videoMuted", false)
put("maxVideoLayers", 3) // publish HD + SD + LD layers
put("attributes", JSONObject().apply { put("name", "Alice") })
}
// Get the local stream
localStream = room?.getLocalStream(streamInfo)
// Attach local stream to your preview SurfaceView/TextureView
localStream?.attachRenderer(localPreviewView)
// Publish into the room
room?.publish(localStream)
}
// Callback: your stream is now live in the room
override fun onPublishedStream(stream: EnxStream?) {
Log.d("ENX", "Stream published, ID: ${stream?.id}")
}
// Callback: a stream was published — everyone receives this
override fun onStreamAdded(stream: EnxStream?) {
// Subscribe to remote streams (Step 7)
if (stream?.isLocal == false) {
room?.subscribe(stream)
}
}
| Error Code | Description |
|---|---|
| 5013 | Failed to publish stream |
| 5015 | Cannot publish without audio, video, or data track |
| 5022 | Cannot publish — floor access not yet granted (Lecture mode) |
| 5023 | Stream is already published |
| 5017 | Failed to access camera and microphone |
Subscribe and Render Remote Streams
When a remote stream becomes available, onStreamAdded fires. Subscribe to it with room.subscribe() and then attach it to an EnxPlayerView in your layout once onSubscribedStream confirms the subscription.
override fun onStreamAdded(stream: EnxStream?) {
if (stream?.isLocal == false) {
room?.subscribe(stream)
}
}
override fun onSubscribedStream(stream: EnxStream?) {
// Successfully subscribed — attach the stream to a player view
runOnUiThread {
val playerView = stream?.mEnxPlayerView
remoteVideoContainer.addView(playerView)
}
}
Active Talker Updates
As participants speak, the server updates the active talker list and delivers it through either onActiveTalkerList (when using custom view mode) or onActiveTalkerView (predefined RecyclerView mode). See Stream Management — Active Talkers for full details.
EnxRtc.joinRoom()
EnxRtc.joinRoom() is a convenience method that collapses steps 2–6 into a single call. It creates the room, connects, initializes a local stream, and publishes it automatically. Use it when you want to get into a session as fast as possible with minimal boilerplate.
- Class:
EnxRtc - Method:
public EnxStream joinRoom(String token, JSONObject publishStreamInfo, JSONObject roomInfo, JSONArray advancedOptions)
val enxRtc = EnxRtc(
this, // Context
this, // EnxRoomObserver
this // EnxStreamObserver
)
val streamInfo = JSONObject().apply {
put("audio", true)
put("video", true)
put("data", true)
}
val roomInfo = JSONObject().apply {
put("allow_reconnect", true)
put("number_of_attempts", 3)
put("timeout_interval", 10000)
put("activeviews", "view") // "view" = predefined RecyclerView, "list" = manual list
}
val localStream: EnxStream? = enxRtc.joinRoom(token, streamInfo, roomInfo, null)
// onRoomConnected and onStreamAdded fire as before
override fun onRoomConnected(room: EnxRoom?, roomMetaData: JSONObject?) {
Log.d("ENX", "Joined room: ${roomMetaData?.optString("roomId")}")
}
activeviews: "view" for the SDK to provide a ready-made RecyclerView of participant videos. Set activeviews: "list" to receive individual streams and build your own layout. You cannot change this after joining.
room.disconnect()
EnxRoom.disconnect() closes the session, releases media tracks, and tears down the signalling connection. Call this when the user leaves the session — in onBackPressed(), a "Leave" button handler, or onDestroy().
- Class:
EnxRoom - Method:
public void disconnect()
room?.disconnect()
// Callback: you are now disconnected
override fun onRoomDisConnected(json: JSONObject?) {
// Clean up UI, navigate back to lobby
runOnUiThread { finish() }
}
// Callback: delivered to everyone else in the room
override fun onUserDisConnected(userData: JSONObject?) {
// Remove the departed user from your participant list
Log.d("ENX", "User left: ${userData?.optString("clientId")}")
}
| Error Code | Description |
|---|---|
| 5031 | Repeated disconnect() call while previous disconnection is in progress |
| 5032 | disconnect() called after already disconnected |