Developer Tools
The iOS SDK includes tools for monitoring session quality, running pre-call diagnostics, making
outbound calls, controlling session behaviour, and sharing logs with EnableX engineering. Use
these tools to build production-grade apps and diagnose issues quickly.
Live Media Statistics
During a live session, you often need visibility into how your streams are actually performing
— not just whether they are connected, but what resolution they are publishing at, how much
bandwidth they are consuming, and how much bandwidth is available. The
enableStats: method on EnxRoom gives you exactly this: a real-time,
periodic feed of statistics for every stream in the room.
Once you call enableStats:YES, the SDK begins collecting metrics for all published
and subscribed streams and delivers them to your delegate at regular intervals. The data includes
publishing resolution, publisher bandwidth, receiver resolution, receiver bandwidth consumed,
and available bandwidth. Call enableStats:NO to stop receiving updates.
| Detail |
Value |
| Class |
EnxRoom |
| Method |
-(void)enableStats:(BOOL)isEnabled |
Delegate Methods
| Delegate |
Description |
didAcknowledgeStats: |
ACK when stats subscription is enabled or disabled. |
didReceiveStats: |
Fires periodically with an array of stats for all streams. |
Per-Player Stats
In addition to room-level stats, you can receive statistics scoped to a single stream's player
view. This is useful when you want to display per-tile quality indicators in your UI rather than
processing the full room-level array. You must enable room-level stats first — per-player stats
layer on top of them, they do not work independently.
Call enablePlayerStats: on the EnxPlayerView instance for the stream
you want to monitor. The didPlayerStats: delegate fires with stats specific to that
player.
| Detail |
Value |
| Class |
EnxPlayerView |
| Method |
-(void)enablePlayerStats:(BOOL)isEnabled |
| Prerequisite |
Room-level stats must be enabled first via enableStats:YES |
| Delegate |
didPlayerStats: — stats for that specific player |
Error Codes
| Code |
Description |
| 5075 |
Repeated subscription while previous request is in process. |
| 5076 |
Repeated unsubscription while previous request is in process. |
| 5077 |
Already subscribed to stats. |
| 5078 |
Unsubscribing without having subscribed first. |
| 5079 |
Cannot unsubscribe while subscription is in process. |
| 5080 |
Unsubscription already in process. |
// Enable room-level stats
[enxRoom enableStats:YES];
-(void)didAcknowledgeStats:(NSArray *)data {
// Stats subscription toggled successfully
}
-(void)didReceiveStats:(NSArray *)data {
// data: array of stream stats objects
// Each object includes resolution, bandwidth, available bandwidth
}
// Enable per-player stats (room-level must be enabled first)
[enxPlayer enablePlayerStats:YES];
-(void)didPlayerStats:(NSArray *)data {
// Stats for this specific stream player
}
Talker and Noise Notification
Note. Available from iOS SDK v1.9.5 and later.
When you need to know in real time who is speaking and who is generating background noise,
subscribe to talker notifications. The SDK analyses audio levels continuously and fires delegate
events whenever the set of speaking or noisy participants changes.
The talker list produced by this subscription can be longer than the Active Talker list shown in
the video grid, because it is not capped by the room's max_active_talkers setting.
This makes it well-suited for building speaker-highlight UIs — for example, putting a coloured
border around anyone who is currently speaking — and for debugging audio issues in a session.
| Detail |
Value |
| Class |
EnxRoom |
| Method |
-(void)subscribeForTalkerNotification:(BOOL)enabled |
Delegate Methods
| Delegate |
Description |
room:didAckSubscribeTalkerNotification: |
ACK when successfully subscribed. |
room:didAckUnsubscribeTalkerNotification: |
ACK when successfully unsubscribed. |
room:didTalkerNotification: |
Notification with speech and noise data. |
Notification Payload
Each didTalkerNotification: callback carries two arrays inside the data object.
The speech array lists users who are currently speaking — each entry includes a
clientId and a speechType indicating intensity
(high, medium, or low). The noise array
lists users generating background noise, identified by clientId only.
Error Codes
| Code |
Description |
| 5128 |
Repeated subscription while previous request is in process. |
| 5129 |
Repeated unsubscription while previous request is in process. |
| 5130 |
Already subscribed to talker notifications. |
| 5131 |
Unsubscribing without having subscribed first. |
[room subscribeForTalkerNotification:YES]; // Subscribe
[room subscribeForTalkerNotification:NO]; // Unsubscribe
-(void)room:(EnxRoom *)room didAckSubscribeTalkerNotification:(NSArray *)data {
// Subscribed successfully
}
-(void)room:(EnxRoom *)room didTalkerNotification:(NSArray *)data {
// data payload example:
// {
// "type": "talker-notification",
// "data": [
// {
// "speech": true,
// "users": [
// { "speechType": "high", "clientId": "xxxxx" },
// { "speechType": "medium", "clientId": "yyyyy" },
// { "speechType": "low", "clientId": "zzz" }
// ]
// },
// {
// "noise": true,
// "users": [
// { "clientId": "sssss" },
// { "clientId": "uuuuu" }
// ]
// }
// ]
// }
}
Voice Activity Detection
Voice Activity Detection (VAD) analyses your local audio track in real time and fires delegate
callbacks the moment speech or noise is detected. Unlike talker notifications — which are
server-side and cover all participants — VAD runs locally and reports on the device's own
microphone input only.
Use VAD to build microphone level indicators that animate in response to actual audio activity,
or to implement auto-mute and auto-unmute triggers that react to the user starting or stopping
speech. Call enableVAD:YES to start detection and enableVAD:NO to
stop.
| Detail |
Value |
| Class |
EnxRoom |
| Method |
-(void)enableVAD:(BOOL)isEnabled |
Delegate Methods
| Delegate |
Description |
vadDidDetectSpeech: |
Fires when speech is detected. Returns a confidence score from 0.0 to 1.0 — higher values indicate greater confidence. |
vadDidDetectNoise: |
Fires when noise is detected. Returns an enumerated noise type string. |
Possible noise type values reported by vadDidDetectNoise:: Background Noise,
Static Noise, Music, Audio Noise, Traffic Noise.
[enxRoom enableVAD:YES];
-(void)vadDidDetectSpeech:(Float32)confidence {
// confidence: 0.0 to 1.0
// Use to drive a mic-level indicator
}
-(void)vadDidDetectNoise:(NSString *)noiseType {
// noiseType examples: "Background Noise", "Traffic Noise"
}
Pre-Call Diagnostics
Note. Available from iOS SDK v1.9.6 and later. Requires iOS 13 or higher.
Camera, Microphone, and Bandwidth test groups are not available in SDK v1.9.6.
Rather than discovering connectivity or hardware issues during a live session, you can run a
full suite of pre-call tests before the session begins. Pre-call diagnostics probe your
microphone, camera, network connectivity, throughput, bandwidth, and signalling layer — giving
you a complete picture of whether the device and network are ready for a call.
Tests are grouped by category and execute asynchronously. The SDK fires
didClientDiagnosisStatus: after each individual test case completes, giving you
intermediate results as they arrive. When every test in the suite is finished,
didClientDiagnosisFinished: fires with the complete report. You can also stop
tests mid-run by passing stop: YES in a second call to
clientDiagnostics:.
Test Groups
| Group |
Tests |
| Microphone |
Audio capture |
| Camera |
Resolution 320×240, 640×480, 1280×720, supported resolutions |
| Network |
UDP/TCP/IPv6 via TURN and STUN |
| Connectivity |
Relay, reflexive, host connectivity via TURN and STUN |
| Throughput |
Data throughput via TURN |
| Bandwidth |
Video bandwidth, audio bandwidth via TURN |
| Signaling |
Signaling connectivity |
| Detail |
Value |
| Class |
EnxRtc |
| Method |
-(void)clientDiagnostics:(NSDictionary *)Options |
Options Parameters
| Key |
Type |
Description |
testNames |
Array |
Test group names to run, e.g. ["microphone","camera"] or ["all"]. |
audioDeviceId |
String |
Optional. Audio input device ID to test. |
videoDeviceId |
String |
Optional. Video input device ID to test. |
regionId |
Array |
Optional. ICE server regions to test against, e.g. ["IN","US"]. |
testDurationDataThroughput |
String |
Optional. Duration in seconds for the data throughput test (1–30). Default: 2. |
testDurationVideoBandwidth |
String |
Optional. Duration in seconds for the video bandwidth test (1–30). Default: 10. |
testDurationAudioBandwidth |
String |
Optional. Duration in seconds for the audio bandwidth test (1–30). Default: 10. |
stop |
Boolean |
Optional. Set true to stop any currently running tests. |
Delegate Methods
| Delegate |
Description |
didClientDiagnosisStatus: |
Fires after each individual test case with an intermediate result JSON object. |
didClientDiagnosisFinished: |
All tests complete — the full diagnostic report JSON is returned. |
didClientDiagnosisFailed: |
Fired when options are invalid or a duplicate call is made while tests are running. |
didClientDiagnosisStopped: |
Fired when tests are explicitly stopped via the stop option. |
NSDictionary *options = @{
@"testNames": @[@"microphone", @"camera", @"network"],
@"regionId": @[@"IN"],
@"testDurationDataThroughput": @"2"
};
[enxRtc clientDiagnostics:options];
[enxRtc setDelegate:self];
// Each test case result
-(void)didClientDiagnosisStatus:(NSArray *)data {
// {
// "test_group": "microphone",
// "test_case": "audio_capture",
// "status": "finished",
// "output": { ... }
// }
}
// All tests done
-(void)didClientDiagnosisFinished:(NSArray *)data {
// Full report: grouped by test_group → test_case → result/execution_time/success/error
}
// Stop tests mid-run
NSDictionary *stopOptions = @{@"testNames": @[@"all"], @"stop": @YES};
[enxRtc clientDiagnostics:stopOptions];
-(void)didClientDiagnosisStopped:(NSArray *)data { }
Outbound Calling
Outbound calling lets you dial a PSTN phone number or SIP URI from within a live session.
The called party receives a regular phone call on their device; once they answer, they are
bridged directly into the video session. This is useful for inviting external participants who
do not have the app, or for integrating with legacy telephony systems via SIP.
You can dial a single number or up to five numbers simultaneously. Each outgoing call fires
repeated dial state events — initiated, calling,
connecting, connected, terminated — so you can track the
call lifecycle and update your UI accordingly.
Make a Single Outbound Call
| Detail |
Value |
| Class |
EnxRoom |
| Method |
-(void)makeOutboundCall:(NSString *)number callerId:(NSString *)callerId withDialOptions:(NSDictionary *)dialOptions |
Make Multiple Outbound Calls (max 5)
| Detail |
Value |
| Class |
EnxRoom |
| Method |
-(void)makeOutboundCalls:(NSArray *)numberList callerId:(NSString *)callerId withDialOptions:(NSDictionary *)dialOptions |
Parameters
| Parameter |
Type |
Description |
number / numberList |
String / Array |
PSTN number or SIP URI to dial. |
callerId |
String |
Your CLI (Calling Line ID). Must match your purchased or shared number in the EnableX portal. |
dialOptions.name |
String |
Display name shown to the called party. |
dialOptions.early_media |
Boolean |
When true, plays a ringer inside the room while the call is dialling. Default: false. |
dialOptions.silent_join |
Boolean |
When true, holds the caller outside the room until they answer. Default: true. |
Note. The dialOptions parameters (early_media and
silent_join) are available from iOS SDK 2.1.3 and later.
early_media and silent_join cannot be used together.
Important. The callerId must exactly match the PSTN number
purchased or configured as a shared number in the EnableX portal. A mismatch causes error
1142 (CLI mismatch) and the call will not be placed.
Delegate Methods
| Delegate |
Description |
room:didOutBoundCallInitiated: |
Fires for the call initiator to confirm the call has started dialling. |
room:didDialStateEvents: |
Fires repeatedly with state updates: initiated → calling → connecting → connected → terminated. |
Error Codes
| Code |
Description |
| 1141 |
Outbound call already in process. |
| 1142 |
CLI mismatch — callerId does not match a configured number. |
| 5095 |
Invalid phone number format. |
Cancel an Outbound Call
Available from iOS SDK 2.1.3 and later. Call cancelOutboundCall: to cancel a
dialling or ringing outbound call before it is answered. The
room:didOutBoundCallCancel: delegate fires on success.
| Detail |
Value |
| Method |
-(void)cancelOutboundCall:(NSString *)number |
| Delegate |
room:didOutBoundCallCancel: |
Send DTMF
Available from iOS SDK v2.3.16 and later. After a PSTN call connects and the called party's
system presents an IVR, use sendDTMF:digits: to send digit presses into the call.
This is necessary when the connected party is an automated system that expects keypad input —
for example, navigating a menu or entering a conference PIN.
| Detail |
Value |
| Method |
-(void)sendDTMF:(NSString *)number digits:(NSString *)digits |
| Delegate |
room:didOutBoundCallSendDtmf: |
| Error Code |
Description |
| 1155 |
Invalid parameters. |
| 1201 |
Invalid dial state — call is not connected. |
| 1202 |
Dial request not found. |
NSDictionary *dialOptions = @{
@"name": @"John",
@"early_media": @NO,
@"silent_join": @YES
};
// Make a call
[enxRoom makeOutboundCall:@"919999999999"
callerId:@"918888888888"
withDialOptions:dialOptions];
-(void)room:(EnxRoom *)room didOutBoundCallInitiated:(NSArray *)data {
// Call is dialling
}
-(void)room:(EnxRoom *)room didDialStateEvents:(EnxOutBoundCallState)state {
// Track: initiated → calling → connecting → connected → terminated
}
// Cancel
[enxRoom cancelOutboundCall:@"919999999999"];
// Send DTMF after call answers
[enxRoom sendDTMF:@"919999999999" digits:@"1"];
-(void)room:(EnxRoom *)room didOutBoundCallSendDtmf:(NSArray *)data {
// DTMF sent successfully
}
Session Utilities
Audio-Only Mode
Use setAudioOnlyMode: to toggle between audio-only and full audio+video within a
live session. When audio-only mode is active, you neither send nor receive video. Your audio
stream continues uninterrupted, and other participants in the room are not affected. This is
useful on poor network connections where video cannot be sustained, or when the user explicitly
opts out of video.
| Detail |
Value |
| Class |
EnxRoom |
| Method |
-(void)setAudioOnlyMode:(BOOL)check |
| Error Code |
Description |
| 5051 |
Previous audio-only request is still in process. |
| 5052 |
Already in audio-only mode. |
| 5053 |
Already in audio+video mode. |
| 5054 |
Previous audio-video request is still in process. |
Adjust Layout
When you use activeviews: "view" in connect(), the SDK manages a
UIView grid internally. If the parent container changes size — due to device
rotation or a dynamic layout change — the grid does not automatically refit. Call
adjustLayout to tell the SDK to recalculate and reposition all player tiles to
match the current container dimensions.
| Detail |
Value |
| Class |
EnxRoom |
| Method |
-(void)adjustLayout |
[enxRoom adjustLayout];
Background and Foreground Handling
iOS suspends camera capture when an app moves to the background. If you do not handle this
explicitly, your published video track will freeze on other participants' screens until the app
returns to the foreground. Use the two lifecycle methods below to stop and resume local video
in sync with the app lifecycle.
Call stopVideoTracksOnApplicationBackground: in your
applicationDidEnterBackground: handler to stop publishing local video. Call
startVideoTracksOnApplicationForeground: in
applicationWillEnterForeground: to resume it. Pass YES to each.
| Method |
Description |
-(void)stopVideoTracksOnApplicationBackground:(BOOL)flag |
Stop publishing local video when the app enters the background. |
-(void)startVideoTracksOnApplicationForeground:(BOOL)flag |
Resume publishing local video when the app returns to the foreground. |
// In applicationDidEnterBackground:
[room stopVideoTracksOnApplicationBackground:YES];
// In applicationWillEnterForeground:
[room startVideoTracksOnApplicationForeground:YES];
Update Stream Configuration
Available from iOS SDK 1.5.6 and later. You can reconfigure the bandwidth limits on an active
local or remote stream without disconnecting or republishing. This is useful when network
conditions change mid-session and you want to throttle the stream to prevent dropped frames or
buffering without ending the call.
| Detail |
Value |
| Class |
EnxStream |
| Method |
-(void)updateConfiguration:(NSDictionary *)data |
The data dictionary accepts the following bandwidth keys (all values as strings,
in kbps): maxVideoBW, minVideoBW, maxAudioBW,
minAudioBW.
| Error Code |
Description |
| 5113 |
Invalid JSON — the data dictionary is malformed. |
| 5114 |
Canvas streaming is active — configuration cannot be updated. |
NSDictionary *config = @{
@"maxVideoBW": @"900",
@"minVideoBW": @"150",
@"maxAudioBW": @"150",
@"minAudioBW": @"150"
};
[stream updateConfiguration:config];
Capture Screenshot
You can take a snapshot of the current video frame from any EnxPlayerView —
whether it is displaying your own local stream or a remote participant's stream. The snapshot
is returned as a UIImage, which you can display in your UI, save to the photo
library, or upload to a server.
Set the delegate on the EnxPlayerView instance, then call
captureScreenShot. The didCapturedView: delegate fires with the
captured image.
| Detail |
Value |
| Class |
EnxPlayerView |
| Method |
captureScreenShot |
| Delegate |
didCapturedView: — receives a UIImage of the current frame |
// Set delegate and capture
enxPlayer.delegate = self;
[enxPlayer captureScreenShot];
-(void)didCapturedView:(UIImage *)snapShot {
// snapShot is the captured UIImage frame
UIImageWriteToSavedPhotosAlbum(snapShot, nil, nil, nil);
}
Logging
When investigating a connection problem or an intermittent failure, raw console output is often
not enough — you need the SDK's internal log stream, which captures ICE negotiation steps,
connection events, and error details that are not surfaced through delegates. The
EnxLogger class lets you start capturing this log data, and
postClientLogs uploads the most recent 200 KB directly to EnableX engineering for
diagnosis.
Start logging early in your app lifecycle — ideally in application:didFinishLaunchingWithOptions:
— so that the log buffer captures the full connection sequence from the moment the SDK
initialises. Once you have reproduced the issue, call postClientLogs on the room
to upload.
| Detail |
Value |
| Class |
EnxRoom |
| Method |
-(void)postClientLogs |
Error Codes
| Code |
Description |
| 5056 |
Log upload already in process. |
| 5083 |
Cannot upload — log file is empty. |
// Start logging early in your app lifecycle
EnxLogger *logger = [EnxLogger sharedInstance];
[logger startLog];
// When you need to report an issue, post logs to EnableX
[room postClientLogs];
Tip. Enable logging at app launch during development. Logs capture connection
events, ICE negotiation, and error details that are essential for diagnosing intermittent
issues.