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.

Connection Flow

Joining an EnableX session from Android involves these steps in sequence:

  1. Query audio devices — get the list of available microphones and speakers.
  2. Create the room object — instantiate EnxRoom with your observer implementations.
  3. Initialize the room — call room.init(context) to prepare the Android media stack.
  4. Register observers — set up all callbacks before connecting.
  5. Connect to the room — call room.connect(token, roomInfo, advancedOptions).
  6. Initialize and publish your stream — inside onRoomConnected, get the local stream and publish it.
  7. Subscribe to remote streams — inside onStreamAdded, subscribe and attach to your UI.
  8. Disconnect — call room.disconnect() when the session ends.

If you want a one-call shortcut that wraps steps 2–6, use EnxRtc.joinRoom().

Step 1 — Query Audio Devices

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.

List<String> devices = room.getDevices();
// Returns a list such as: ["SPEAKER_PHONE", "WIRED_HEADSET", "EARPIECE", "BLUETOOTH", "NONE"]

To get the device currently in use:

String currentDevice = room.getSelectedDevice();
// 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
public void onDeviceAdded(String deviceName) {
    // A new audio device was connected (e.g. Bluetooth headset paired)
    Log.d("ENX", "Device added: " + deviceName);
}

@Override
public void onDeviceRemoved(String deviceName) {
    // An audio device was disconnected
    Log.d("ENX", "Device removed: " + deviceName);
}

@Override
public void onNotifyDeviceUpdate(String deviceName) {
    // The active audio device changed
    Log.d("ENX", "Now using: " + deviceName);
}
Steps 2–4 — Create Room, Init, Register Observers

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().

public class VideoActivity extends AppCompatActivity
        implements EnxRoomObserver, EnxStreamObserver {

    private EnxRoom room;
    private EnxStream localStream;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Step 2: Create the room object
        room = new 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);
    }
}
Register all observers before calling connect(). Callbacks like onRoomConnected and onStreamAdded fire immediately on connection. If observers are registered after connecting, those initial callbacks will be missed.
Step 5 — Connect to the Room

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.

roomInfo Parameters

ParameterTypeDescription
allow_reconnectBooleanEnable auto-reconnect on network drop. Default: true.
number_of_attemptsNumberMax reconnect attempts. Default: 3. Minimum: 1.
timeout_intervalNumberMilliseconds to wait between reconnect attempts.
audio_onlyBooleanSet true to join as audio-only (no video).

advancedOptions Parameters

Option IDTypeDescription
battery_updatesBooleanEnable battery level update notifications.
notify-video-resolution-changeBooleanEnable video resolution change notifications.
void connectToRoom(String token) {
    JSONObject roomInfo = new JSONObject();
    roomInfo.put("allow_reconnect", true);
    roomInfo.put("number_of_attempts", 3);
    roomInfo.put("timeout_interval", 10000);
    roomInfo.put("audio_only", false);

    JSONArray advancedOptions = new JSONArray();
    JSONObject opt1 = new JSONObject();
    opt1.put("id", "notify-video-resolution-change");
    opt1.put("enable", true);
    advancedOptions.put(opt1);

    room.connect(token, roomInfo, advancedOptions);
}

// ── Callbacks ───────────────────────────────────────────────────────────────

@Override
public void onRoomConnected(EnxRoom room, JSONObject roomMetaData) {
    // Successfully connected — proceed to init and publish local stream
    initAndPublishStream();
}

@Override
public void onRoomError(JSONObject errorData) {
    // Connection failed
    Log.e("ENX", "Room error: " + errorData.toString());
}

@Override
public void onUserConnected(JSONObject userData) {
    // A new participant joined the room — update your participant list UI
    Log.d("ENX", "User joined: " + userData.optString("name"));
}

@Override
public void onRoomAwaited(JSONObject data) {
    // 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
public void onUserAwaited(JSONObject userData) {
    // 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
public void onConnectionLost(JSONObject json) {
    // Network connection lost — show "Reconnecting..." UI
}

@Override
public void onConnectionInterrupted(JSONObject json) {
    // Connection interrupted (e.g. switched from WiFi to 4G)
}

@Override
public void onUserReconnectSuccess(EnxRoom room, JSONObject roomMetaData) {
    // Auto-reconnect succeeded — restore UI
}

@Override
public void onReconnect(String message) {
    // Reconnect attempt in progress
}
Error CodeDescription
5073Connection switched to alternate network
5074Network disconnected; reconnection timed out
5086Method called while room is not connected
5087Reconnection failed
Step 6 — Initialize and Publish Your Stream

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.

publishStreamInfo Options

OptionTypeDescription
audioBooleanInclude audio track. Default: true.
videoBooleanInclude video track. Default: true.
dataBooleanInclude data channel (required for chat/signalling).
audioMutedBooleanJoin with microphone muted.
videoMutedBooleanJoin with camera off.
attributesJSONObjectCustom key/value metadata attached to this stream.
maxVideoLayersNumber1=HD only, 2=HD+SD, 3=HD+SD+LD. More layers = better adaptive quality for receivers.

Publish the Stream

void initAndPublishStream() {
    JSONObject streamInfo = new JSONObject();
    streamInfo.put("audio", true);
    streamInfo.put("video", true);
    streamInfo.put("data", true);
    streamInfo.put("audioMuted", false);
    streamInfo.put("videoMuted", false);
    streamInfo.put("maxVideoLayers", 3); // publish HD + SD + LD layers
    JSONObject attributes = new JSONObject();
    attributes.put("name", "Alice");
    streamInfo.put("attributes", attributes);

    // 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
public void onPublishedStream(EnxStream stream) {
    Log.d("ENX", "Stream published, ID: " + stream.getId());
}

// Callback: a stream was published — everyone receives this
@Override
public void onStreamAdded(EnxStream stream) {
    // Subscribe to remote streams (Step 7)
    if (!stream.isLocal()) {
        room.subscribe(stream);
    }
}
Error CodeDescription
5013Failed to publish stream
5015Cannot publish without audio, video, or data track
5022Cannot publish — floor access not yet granted (Lecture mode)
5023Stream is already published
5017Failed to access camera and microphone
Step 7 — Subscribe to Remote Streams

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
public void onStreamAdded(EnxStream stream) {
    if (!stream.isLocal()) {
        room.subscribe(stream);
    }
}

@Override
public void onSubscribedStream(EnxStream stream) {
    // Successfully subscribed — attach the stream to a player view
    runOnUiThread(() -> {
        EnxPlayerView 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.

Alternative — Quick Join with joinRoom()

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.

EnxRtc enxRtc = new EnxRtc(
    this,   // Context
    this,   // EnxRoomObserver
    this    // EnxStreamObserver
);

JSONObject streamInfo = new JSONObject();
streamInfo.put("audio", true);
streamInfo.put("video", true);
streamInfo.put("data", true);

JSONObject roomInfo = new JSONObject();
roomInfo.put("allow_reconnect", true);
roomInfo.put("number_of_attempts", 3);
roomInfo.put("timeout_interval", 10000);
roomInfo.put("activeviews", "view");  // "view" = predefined RecyclerView, "list" = manual list

EnxStream localStream = enxRtc.joinRoom(token, streamInfo, roomInfo, null);

// onRoomConnected and onStreamAdded fire as before
@Override
public void onRoomConnected(EnxRoom room, JSONObject roomMetaData) {
    Log.d("ENX", "Joined room: " + roomMetaData.optString("roomId"));
}
activeviews setting matters. Set 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.
Step 8 — Disconnect

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().

room.disconnect();

// Callback: you are now disconnected
@Override
public void onRoomDisConnected(JSONObject json) {
    // Clean up UI, navigate back to lobby
    runOnUiThread(() -> finish());
}

// Callback: delivered to everyone else in the room
@Override
public void onUserDisConnected(JSONObject userData) {
    // Remove the departed user from your participant list
    Log.d("ENX", "User left: " + userData.optString("clientId"));
}
Error CodeDescription
5031Repeated disconnect() call while previous disconnection is in progress
5032disconnect() called after already disconnected