Stream Management

This page covers all APIs for controlling local streams, working with Active Talkers, customizing the player view, setting receive video quality, and querying stream information in an EnableX Android video session.

Local Stream Controls

The EnxStream and EnxRoom classes provide the following methods to manage a local stream after it has been initialized and published.

Switch Camera Preview

EnxStream.switchCameraPreview() switches between available camera feeds in the preview — before or after publishing — without interrupting the session.

stream.switchCameraPreview();

Publish a Local Stream

EnxRoom.publish() publishes the initialized local stream into the connected room, making your audio and video visible to all other participants. You can unpublish and republish multiple times within the same session.

ObserverDescription
onPublishedStreamAcknowledgment to the publisher when the stream is successfully published.
onStreamAddedNotification delivered to everyone in the room when a new stream is published.
room.publish(localStream);

@Override
public void onPublishedStream(EnxStream stream) {
    // Your stream is now published in the room
}

@Override
public void onStreamAdded(EnxStream stream) {
    // A new stream has been added to the room — subscribe to it
    room.subscribe(stream);
}
Error CodeDescription
5013Failed to publish stream.
5015Unable to publish a stream without audio, video, and data.
5016Unable to publish a stream with illegible attributes.
5022Failed to publish — floor access not received in lecture mode room.
5023The stream has already been published.
5024Repeated publish() call while stream publishing is in process.
5025Failed to publish — publish() called on a remote stream.
1170Current subscription does not support publishing.

Unpublish a Local Stream

EnxRoom.unpublish() disconnects your local stream from the room. Device access is not released, so republishing does not require re-granting permissions.

ObserverDescription
onRemoveStreamNotification to everyone in the room when a stream is removed.
room.unpublish();

@Override
public void onRemoveStream(EnxStream stream) {
    // A stream has been removed from the room
}
Error CodeDescription
5029Repeated unpublish() called while a previous unpublish request is in process.
5030unpublish() called before the stream was published.

Switch Between Rear and Front Camera

EnxStream.switchCamera() toggles between the device's rear and front cameras as the source for the published stream. The switch happens on the fly without interrupting the session.

localStream.switchCamera();
Error CodeDescription
5021Unable to switch camera in audio-only call mode.
5097Unable to switch camera in a chat-only room.

Switch to Alternate Microphone

EnxRoom.switchMediaDevice() switches the audio source of the published stream to an alternate microphone. Retrieve available device IDs using EnxRoom.getDevices() before calling this method.

ObserverDescription
onNotifyDeviceUpdateAcknowledgment sent with the new audio device ID after the switch completes.
room.switchMediaDevice(micDeviceId);

@Override
public void onNotifyDeviceUpdate(String micDeviceId) {
    // Audio input is now using micDeviceId
}

Mute / Unmute Audio

EnxStream.muteSelfAudio() mutes or unmutes the audio track of your local stream. Pass true to mute and false to unmute — the same method handles both operations.

CallbackDelivered ToDescription
onAudioEventSelfAcknowledgment that your own audio was muted or unmuted.
onRemoteStreamAudioMuteEveryone in roomNotification when any user mutes their audio.
onRemoteStreamAudioUnMuteEveryone in roomNotification when any user unmutes their audio.
localStream.muteSelfAudio(true);  // Mute audio
localStream.muteSelfAudio(false); // Unmute audio

// To self — audio muted or unmuted
@Override
public void onAudioEvent(JSONObject json) {
    // json: { "result": 0, "msg": "Audio Off" }
    // json: { "result": 0, "msg": "Audio On" }
}

// To all — a remote user muted their audio
@Override
public void onRemoteStreamAudioMute(JSONObject json) {
    // json: { "result": 0, "msg": "User muted audio", "clientId": "XXX" }
}

// To all — a remote user unmuted their audio
@Override
public void onRemoteStreamAudioUnMute(JSONObject json) {
    // json: { "result": 0, "msg": "User unmuted audio", "clientId": "XXX" }
}
Error CodeDescription
5058Repeated muteSelfAudio() while a previous mute request is in process.
5059Repeated muteSelfAudio() while a previous unmute request is in process.
5060Called to mute audio that is already muted.
5061Trying to unmute audio without muting it first.
5062Unable to unmute — audio has been hard-muted by the moderator.

Mute / Unmute Video

EnxStream.muteSelfVideo() mutes or unmutes the video track of your local stream. Pass true to mute and false to unmute.

CallbackDelivered ToDescription
onVideoEventSelfAcknowledgment that your own video was muted or unmuted.
onRemoteStreamVideoMuteEveryone in roomNotification when any user mutes their video.
onRemoteStreamVideoUnMuteEveryone in roomNotification when any user unmutes their video.
localStream.muteSelfVideo(true);  // Mute video
localStream.muteSelfVideo(false); // Unmute video

// To self — video muted or unmuted
@Override
public void onVideoEvent(JSONObject json) {
    // json: { "result": 0, "msg": "Video Off" }
    // json: { "result": 0, "msg": "Video On" }
}

// To all — a remote user muted their video
@Override
public void onRemoteStreamVideoMute(JSONObject json) {
    // json: { "result": 0, "msg": "User muted video", "clientId": "XXX" }
}

// To all — a remote user unmuted their video
@Override
public void onRemoteStreamVideoUnMute(JSONObject json) {
    // json: { "result": 0, "msg": "User unmuted video", "clientId": "XXX" }
}
Error CodeDescription
5020Unable to process muteSelfVideo() — camera permission denied.
5063Called to mute video that is already muted.
5064Called to unmute video that is already unmuted.
5065Trying to unmute video without muting it first.
5066Unable to unmute — video has been hard-muted by the moderator.
5070Unable to unmute video in audio-only call mode.
5071Repeated muteSelfVideo() while a previous request is in process.
Active Talkers

EnableX delivers a maximum of 12 actively talking users to each client endpoint to prevent excessive resource consumption. Screen sharing (Stream ID 101) and canvas streams (Stream ID 102) are included only when the application supports those features. The Active Talker list is ordered by recency — the latest speaker moves to the top and updates with every change in activity.

Note: The Active Talker list contains remote streams only. Your own local stream is never included, so the list varies per participant.

Modes of Active Talker Usage

When calling joinRoom(), set the activeviews field in roomInfo to choose how Active Talkers are delivered:

List Mode — setActiveTalkerListObserver

Use this observer when activeviews is set to "list". The SDK calls onActiveTalkerList() each time the Active Talker list changes, passing the current list of streams. Attach each stream's player view to your own UI layout.

// Called after connecting to the room
enxRoom.setActiveTalkerListObserver(this);

@Override
public void onActiveTalkerList(List<EnxStream> enxStreamList) {
    yourView.removeAllViews();
    for (int i = 0; i < enxStreamList.size(); i++) {
        EnxPlayerView enxPlayerView = enxStreamList.get(i).mEnxPlayerView;
        yourView.addView(enxPlayerView);
    }
}

View Mode — setActiveTalkerViewObserver

Use this observer when activeviews is set to "view". The SDK delivers a pre-built RecyclerView grid that handles all stream rendering automatically. Call adjustLayout() whenever the screen rotates or the view needs to be reflowed.

Note: The local stream is not included in the RecyclerView even if the local user is currently talking, because the local stream is not part of the Active Talker list.
// Called after connecting to the room
enxRoom.setActiveTalkerViewObserver(this);

@Override
public void onActiveTalkerView(RecyclerView recyclerView) {
    yourRemoteView.addView(recyclerView);
}

// Call when the screen orientation changes or view needs to reflow
room.adjustLayout();

Get Maximum Permissible Talker Count

EnxRoom.getMaxTalkers() returns the maximum number of Active Talkers allowed for this room, as configured by the max_active_talkers setting when the room was created. The default cap is 12.

// Set the observer once (covers getMaxTalkers, setTalkerCount, getTalkerCount)
room.setTalkerObserver(this);

room.getMaxTalkers();

@Override
public void onMaxTalkerCount(JSONObject jsonobject) {
    // jsonobject: { "result": 0, "maxTalkers": 4 }
}

Set the Talker Count

EnxRoom.setTalkerCount() limits how many Active Talker streams your endpoint receives, up to the room's maximum. Set it to 0 to receive 3 audio-only streams and no video streams.

room.setTalkerObserver(this);

room.setTalkerCount(5);

@Override
public void onSetTalkerCount(JSONObject jsonobject) {
    // jsonobject: { "result": 0, "maxTalkers": 4 }
}
Error CodeDescription
5055Repeated setTalkerCount() called while a previous request is in process.

Get the Current Talker Count

EnxRoom.getTalkerCount() returns how many Active Talker streams are currently being received, taking into account the room maximum and any value set via setTalkerCount().

room.setTalkerObserver(this);

room.getTalkerCount();

@Override
public void onGetTalkerCount(JSONObject jsonobject) {
    // jsonobject: { "result": 0, "numTalkers": 4 }
}
Tip: Call setTalkerObserver(this) only once — it covers all three talker methods: getMaxTalkers(), setTalkerCount(), and getTalkerCount().

Switch Active Talker View Layout

EnxRoom.switchATView() switches between leader view (one prominent stream) and gallery view (grid of equal-sized streams). Gallery view is the default. Available in Android SDK v2.1.2 and later.

ObserverDescription
setActiveTalkerLeaderObserverRequired when switching to leader view.
setActiveTalkerViewObserverRequired when switching to gallery view.
// Register observers before switching
EnxRoom.setActiveTalkerLeaderObserver(this);
EnxRoom.setActiveTalkerViewObserver(this);

// Switch to leader view
EnxRoom.switchATView("leader");

// Callback when leader view is ready
@Override
public void onActiveTalkerList(RelativeLayout view) {
    yourContainer.addView(view);
}

// Callback when gallery view is ready
@Override
public void onActiveTalkerView(RecyclerView recyclerView) {
    yourContainer.addView(recyclerView);
}
Player View Customization

These methods let you customize the Active Talker player view when using the custom (activeviews: "list") mode. Available in Android SDK v2.1.3 and later.

Get a Player View

EnxRoom.getPlayer() returns the EnxPlayerView associated with a specific participant, identified by their client ID.

EnxPlayerView playerView = enxRoom.getPlayer(clientId);

Highlight Player Border

EnxRoom.highlightBorderForClient() highlights the border of the player views for the specified client IDs. Useful for visually indicating active speakers or selected participants.

ArrayList<String> ids = new ArrayList<>();
ids.add(clientId1);
ids.add(clientId2);

EnxRoom.highlightBorderForClient(ids);

Change Player Background Color

EnxRoom.changeBgColorForClients() sets a custom background color on the player views for the specified participants.

ParameterTypeDescription
clientIdsArrayAn array of client IDs whose player backgrounds should change.
colorStringHex color code of the background color (e.g. "#ff669900").
ArrayList<String> ids = new ArrayList<>();
ids.add(clientId1);
ids.add(clientId2);

EnxRoom.changeBgColorForClients(ids, "#ff669900");

Force Reload Active Talker View

EnxRoom.forceUpdateATList() forces a reload of the Active Talker view after any programmatic manipulation of the layout, ensuring the display is consistent with the current state.

EnxRoom.forceUpdateATList();
Receive Video Quality

EnxRoom.setReceiveVideoQuality() sets the desired video quality for incoming remote streams at your endpoint. Use this to let users control quality based on their network conditions or device capabilities.

ParameterTypeDescription
videoQualityStringEnumerated: Auto, HD, SD, LD. Auto lets EnableX select the optimum quality based on available bandwidth.
streamTypeStringEnumerated: talker (participant streams) or canvas (canvas streams).
JSONObject quality = new JSONObject();
quality.put("videoQuality", "HD");
quality.put("streamType", "talker");

room.setReceiveVideoQuality(quality);
Error CodeDescription
5057Stream already set with the desired quality.
Stream Information

The EnxStream class exposes a set of read-only methods to inspect the properties, state, and media tracks of any stream — local or remote — including screen sharing (Stream ID 101) and canvas (Stream ID 102).

Get Stream ID

EnxStream.getId() returns the unique identifier of a stream. Stream ID 101 identifies a screen share stream; Stream ID 102 identifies a canvas stream.

String streamId = stream.getId();
// "101" = screen share stream
// "102" = canvas stream

Get Stream Attributes

EnxStream.getAttributes() returns the custom attributes defined in the stream options during initialization.

JSONObject attributes = stream.getAttributes();
// e.g. { "name": "Stream Name", "custom_key": "value" }

Get Media Object

EnxStream.getMedia() returns the underlying Android MediaStream object for advanced use cases such as capturing raw audio/video frames.

MediaStream mStream = stream.getMedia();

Get Stream State

EnxStream.getState() returns the current lifecycle state of the stream as a string constant.

String currentState = stream.getState();

Verify Media Track Presence

Use the following methods to check whether a particular media track is present in the stream.

MethodDescription
public boolean hasAudio()Returns true if the stream has an audio track.
public boolean hasVideo()Returns true if the stream has a video track.
public boolean hasData()Returns true if the stream has a data track.
public boolean hasScreen()Returns true if the stream is a screen share.
if (stream.hasVideo()) {
    // Stream contains a video track
}

if (stream.hasAudio()) {
    // Stream contains an audio track
}

Check Audio / Video Track Status

These methods verify whether the audio or video track in a stream is currently active (not muted).

MethodDescription
public boolean isAudioActive()Returns true if the audio track is currently active (not muted).
public boolean isVideoActive()Returns true if the video track is currently active (not muted).
if (stream.isAudioActive()) {
    // Audio track is active in this stream
}

if (stream.isVideoActive()) {
    // Video track is active in this stream
}

Check If Stream Is Local

EnxStream.ifLocal() returns true for the local stream and false for any remote stream.

if (stream.ifLocal()) {
    // This is the local stream
} else {
    // This is a remote stream
}

Play a Stream (attachRenderer / detachRenderer)

To play any stream — local, remote, screen share, or canvas — create an EnxPlayerView instance and attach the stream to it using EnxStream.attachRenderer(). To stop playing, call EnxStream.detachRenderer().

// Create a player view
EnxPlayerView playerView = new EnxPlayerView(
    CurrentClassContext, ScalingType, mediaOverlay);

// Attach stream to the player view and add to your layout
stream.attachRenderer(playerView);
yourCustomView.addView(playerView);

// Stop playing the stream
stream.detachRenderer();