Stream Management
This page covers everything you need to manage audio and video streams in an active session — from publishing and muting your own stream, to switching devices on the fly, to receiving and controlling remote participant streams.
Publish a Local Stream
After connecting to a room, call room.publish() to make your audio and video available to all other participants. You can publish and unpublish multiple times within the same session. The stream-added event is broadcast to everyone — including yourself — when publishing succeeds.
- Method:
EnxRoom.publish(LocalStream, PublishOpt, Callback) - Event:
stream-added— fired to everyone when a stream is published - Event:
stream-failed— fired to the publisher if publishing fails
var publishOpt = {
minVideoBW: 150, // Minimum video bitrate in kbps
maxVideoBW: 1200 // Maximum video bitrate in kbps
};
room.publish(localStream, publishOpt, function(streamId) {
console.log("Published with stream ID:", streamId);
});
room.addEventListener("stream-added", function(event) {
if (localStream.getID() === event.stream.getID()) {
// Your own stream confirmed published — update UI
} else {
// Someone else published — subscribe to their stream
room.subscribe(event.stream, { audio: true, video: true, data: true });
}
});
room.addEventListener("stream-failed", function(event) {
console.error("Publishing failed");
});
| Error Code | Description |
|---|---|
| 1170 | Feature not enabled — check room configuration or service subscription |
Unpublish a Local Stream
room.unpublish() removes your stream from the room without releasing camera/microphone access. You can republish later without having to re-request device permissions.
- Method:
EnxRoom.unpublish(LocalStream, Callback) - Event:
stream-removed— fired to everyone when a stream is removed
room.unpublish(localStream, function(result, error) {
if (result === undefined) {
console.error("Unpublish failed:", error);
} else {
console.log("Stream unpublished");
}
});
room.addEventListener("stream-removed", function(event) {
if (localStream.getID() === event.stream.getID()) {
// Your stream was removed — hide your video tile
} else {
// Another participant's stream was removed
}
});
Close a Local Stream
stream.close() is a stronger action than unpublish. It stops capturing media from the camera and microphone, unpublishes the stream if it is published, and stops playback if it is being played. Use it to fully release device resources.
- Method:
EnxStream.close()
localStream.close(); // Stops capture, unpublishes, releases device
Mute / Unmute Audio
Use these methods to control the audio track of your own published stream. When you mute, all other participants are notified via the user-audio-muted event so they can update their UI (e.g., show a muted microphone icon).
- Mute:
EnxStream.muteAudio(Callback)— Event:user-audio-muted - Unmute:
EnxStream.unmuteAudio(Callback)— Event:user-audio-unmuted
// Mute your microphone
localStream.muteAudio(function(res) {
if (res.result === 0) {
showMutedIcon();
}
});
// Others are notified
room.addEventListener("user-audio-muted", function(event) {
// event.streamId — who muted. Update their participant tile.
});
// Unmute your microphone
localStream.unmuteAudio(function(res) {
if (res.result === 0) {
hideMutedIcon();
}
});
room.addEventListener("user-audio-unmuted", function(event) {
// Update UI for the participant who unmuted
});
| Error Code | Description |
|---|---|
| 1140 | Previous mute request still in progress — wait before sending another |
| 1176 | Moderator controls media devices — self-unmute not permitted |
| 1191 | Stream track has ended — user must rejoin to restore audio |
Mute / Unmute Video
Controls the video track of your own published stream. Muting video turns off the camera but keeps the audio stream active. Others are notified so they can show a video-off placeholder.
- Mute:
EnxStream.muteVideo(Callback)— Event:user-video-muted - Unmute:
EnxStream.unmuteVideo(Callback)— Event:user-video-unmuted
// Turn off camera
localStream.muteVideo(function(res) {
if (res.result === 0) { showCameraOffPlaceholder(); }
});
room.addEventListener("user-video-muted", function(event) {
// Show camera-off placeholder for the affected participant
});
// Turn camera back on
localStream.unmuteVideo(function(res) {
if (res.result === 0) { hideCameraOffPlaceholder(); }
});
room.addEventListener("user-video-unmuted", function(event) {
// Remove camera-off placeholder
});
Switch Camera & Microphone Simultaneously
EnxRtc.switchMediaDevice() swaps both the camera and microphone of a published stream at once. The stream remains published — participants experience a seamless transition to the new devices without a gap in audio/video.
- Method:
EnxRtc.switchMediaDevice(LocalStream, micDeviceId, camDeviceId, Callback)
// Switch both camera and mic using device IDs from getDevices()
EnxRtc.switchMediaDevice(
localStream,
newMicDeviceId,
newCamDeviceId,
function(stream) {
if (stream && stream.getID) {
localStream = stream; // Update local reference
console.log("Devices switched");
} else {
console.error("Switch failed");
}
}
);
// For mobile: switch to front camera using facingMode
EnxRtc.switchMediaDevice(
localStream,
micDeviceId,
{ facingMode: "user" }, // "user" = front, "environment" = rear
function(stream) {
if (stream && stream.getID) {
localStream = stream;
}
}
);
| Error Code | Description |
|---|---|
| 1140 | Previous switch request still in progress |
| 1155 | Invalid parameter passed |
| 1159 | Audio or video stream not available |
| 1189 | Device switching not allowed while stream is muted |
Switch Camera Only
- Method:
EnxRtc.switchCamera(LocalStream, camDeviceId, Callback)
EnxRtc.switchCamera(localStream, newCamDeviceId, function(stream) {
if (stream && stream.getID) {
localStream = stream;
}
});
Switch Microphone Only
- Method:
EnxStream.switchMicrophone(LocalStream, micDeviceId, Callback)
localStream.switchMicrophone(localStream, newMicDeviceId, function(stream) {
if (stream && stream.getID) {
localStream = stream;
}
});
Switch Speaker
Switch to a different audio output device (speaker/headset) to play remote audio. Use the deviceId from getDevices().
- Method:
EnxRoom.switchSpeaker(speakerId, Callback)
room.switchSpeaker(newSpeakerId, function(res) {
if (res.result === 0) {
console.log("Speaker switched");
}
});
Subscribe to Remote Streams
To receive audio and video from another participant, call room.subscribe() on their stream object. You must subscribe individually to each stream you want to receive. After a successful subscription, you can play the stream in a DOM element.
- Method:
EnxRoom.subscribe(RemoteStream, SubsOptions, Callback) - Event:
stream-subscribed— acknowledgment to you when subscription succeeds
var subsOptions = {
audio: true,
video: true,
data: true
};
room.subscribe(remoteStream, subsOptions, function(err) {
if (err) console.error("Subscribe failed:", err);
});
room.addEventListener("stream-subscribed", function(event) {
// Now safe to play the stream
event.stream.play("video-container-" + event.stream.getID(), {
player: { width: "100%", height: "150px" },
toolbar: { displayMode: false }
});
});
Screen share is always available as Stream ID 101. Canvas streaming is Stream ID 102. Subscribe to these stream IDs from room.remoteStreams if your app supports those features.
Active Talker List
EnableX limits the active stream set to the most recently speaking participants (up to 12 by default). The active-talkers-updated event fires every time the active list changes — a new speaker joins, someone goes silent, or a pinned user is added. Rebuild your video grid on each event.
room.addEventListener("active-talkers-updated", function(event) {
var talkers = event.message.activeList;
// Each entry: { clientId, name, streamId, mediatype, videomuted, pinned }
talkers.forEach(function(talker) {
if (!talker.streamId) return;
var stream = room.remoteStreams.get(talker.streamId);
if (stream) {
// Show/refresh this tile in your grid
stream.play("slot-" + talker.streamId, { player: { width: "100%", height: "150px" } });
}
});
});
Control the Talker Count
By default, up to 12 remote streams are delivered. You can reduce this to save bandwidth, or query the current limit programmatically.
Get Current Talker Count
- Method:
EnxRoom.getTalkerCount(Callback)
room.getTalkerCount(function(response) {
// response: { result: 0, maxTalkers: 4 }
console.log("Currently receiving up to", response.maxTalkers, "streams");
});
Set Talker Count
- Method:
EnxRoom.setTalkerCount(numTalkers, Callback)
// Limit to 4 remote streams (saves bandwidth on slow connections)
room.setTalkerCount(4, function(response) {
// response: { result: 0, maxTalkers: 4 }
});
// Setting to 0 delivers 3 audio-only streams, no video
The maximum value is capped by max_active_talkers set during room creation (default: 12). Passing a value above this cap is rejected with error code 4106.
Get Maximum Permissible Talker Count
- Method:
EnxRoom.getMaxTalkers(Callback)
room.getMaxTalkers(function(response) {
// response: { result: 0, maxTalkers: 6 }
console.log("Room allows up to", response.maxTalkers, "active talkers");
});
Set Receive Video Quality
When the publisher sends multiple video layers (maxVideoLayers: 3), each subscriber can independently choose which quality tier to receive. Use this to let users trade bandwidth for quality.
- Method:
EnxRoom.setReceiveVideoQuality(QualityOpt, Callback) - videoQuality values:
"Auto","HD","SD","LD" - streamType values:
"talker","canvas"
var qualityOpt = {
videoQuality: "SD", // Receive SD to save bandwidth
streamType: "talker" // Apply to active talker streams
};
room.setReceiveVideoQuality(qualityOpt, function(result) {
if (result.result === 0) {
console.log("Quality set to SD");
}
});
Stream Information Methods
These methods work on any EnxStream object — local or remote. Use them to inspect or update stream metadata.
Get Stream ID
var streamId = localStream.getID(); // Returns the unique stream ID string
Get Stream Attributes
Returns the custom attributes set during stream initialization or via setAttributes().
var attrs = stream.getAttributes();
// Returns: { name: "Alice", custom_key: "value", ... }
Update Stream Attributes
Update custom attributes on your local stream at any time during the session. All subscribers of your stream are notified via the stream-attributes-updated event.
- Method:
EnxStream.setAttributes(attributes) - Event:
stream-attributes-updated
localStream.setAttributes({
name: "Alice (presenting)",
role: "presenter",
slide_no: 3
});
room.addEventListener("stream-attributes-updated", function(event) {
// event.attributes — updated attributes. Refresh participant name label, etc.
});
Update Stream Bandwidth Configuration
Dynamically change the max audio/video bitrate of a stream without republishing it.
- Method:
EnxStream.updateConfiguration(ConfigSpecs, Callback)
localStream.updateConfiguration({
maxVideoBW: 400, // kbps
maxAudioBW: 64
}, function(result) {
console.log("Bandwidth reconfigured");
});
Check Available Media Tracks
if (stream.ifVideo()) { /* has video track */ }
if (stream.ifAudio()) { /* has audio track */ }
if (stream.ifData()) { /* has data channel */ }
if (stream.ifScreen()) { /* is screen share */ }
Play a Stream
stream.play() renders the stream inside a DOM element. The SDK creates an <audio> or <video> element inside the target div and begins playback. Call this after successfully subscribing to a remote stream, or after publishing your local stream to show a self-preview.
- Method:
EnxStream.play(DOMElementID, PlayerOpt)
var playerOpt = {
player: {
width: "100%",
height: "150px",
minHeight: "inherit",
minWidth: "inherit"
},
toolbar: {
displayMode: false, // Hide SDK toolbar overlay
branding: { display: false }
}
};
stream.play("video-slot-42", playerOpt);
Stop Playing a Stream
Stops the audio/video playback in the HTML player without removing the subscription or closing the stream.
- Method:
EnxStream.stop()
stream.stop(); // Stops rendering; stream remains subscribed