Network Test and Session Quality#
CloudXR Framework provides two quality tools for Apple native clients:
Config.networkTestruns a short pre-session network test at the start of a connection.Session.sessionQualityandSession.liveNetworkStatsmonitor quality during an active streaming session.
Use the network test when your app needs an early pass, warning, or diagnostic report before continuing with a stream. Use the session quality monitor when your app needs live status in the UI, adaptive behavior, or diagnostic logging after streaming begins. For HUD charts and raw time-series metrics, refer to HUD and Streaming Metrics.
Pre-Session Network Test#
Configure the network test before you connect. The test starts after
CloudXRSession.connect() connects to the server and the server is ready.
CloudXR Framework waits for renderable frames, collects pose-to-frame-received
timing samples for the configured duration, and then publishes a
NetworkTestReport through Session.networkTestState.
import CloudXRKit
var config = CloudXRKit.Config()
config.networkTest = .enabled(duration: 5)
let cxrSession = CloudXRSession(config: config)
try await cxrSession.connect()
The NetworkTest modes control what happens after the test completes:
Mode |
Behavior |
|---|---|
|
Does not run the pre-session network test. |
|
Runs the test as a gate. If |
|
Runs the test and leaves the session connected even if |
|
Runs the test and disconnects when the report is complete, regardless of the result. Use this mode for diagnostics and automated checks. |
Use a duration long enough to collect representative startup samples.
Reading Test State#
Read Session.networkTestState to show progress and retrieve the report:
import QuartzCore
switch cxrSession.networkTestState {
case .notStarted:
break
case .waitingForApp(let testDuration):
print("Waiting for renderable frames:", testDuration, "seconds")
case .running(let endTime):
let secondsRemaining = max(0, endTime - CACurrentMediaTime())
print("Network test running:", Int(secondsRemaining), "seconds remaining")
case .stopped(let report):
if let report {
print(report.description)
} else {
print("Network test stopped before a report was available")
}
}
If a session disconnects before the test completes, the state can become
.stopped(report: nil). Treat a missing report as an incomplete test rather
than a failed network result.
Understanding the Report#
NetworkTestReport includes a pass flag, four scored dimensions, packet
loss, round-trip delay, server frame rate, and a diagnostic message.
NetworkScore values are ordered from noData to excellent.
networkIsUsable is true only when the latency, jitter, bandwidth, and
device-performance scores are all poor or better.
Field |
Meaning |
|---|---|
|
Indicates whether all required scores meet the minimum usable threshold. |
|
Scores pose-to-frame-received latency. |
|
Scores variation in pose-to-frame-received latency. |
|
Scores stable available network bandwidth during the test. |
|
Scores client tick consistency. A low score can indicate client device load or scheduling issues. |
|
Reports the latest lost video-packet count when the stream statistics provide it. |
|
Reports a conservative round-trip delay value in milliseconds when the stream statistics provide it. |
|
Reports the average server frame rate and a low-percentile frame-rate value. |
|
Provides a short pass or failure summary. |
Note
latencyScore and jitterScore use pose-to-frame-received timing: from
the client pose update to client receipt of the rendered frame. They do not
include frame dequeue, frame submission, reprojection, or display time. For
pose-to-display timing, refer to HUD and Streaming Metrics.
In-Session Quality Monitor#
During an active stream, CloudXR Framework updates Session.sessionQuality
and Session.liveNetworkStats approximately every 5 seconds. Session is
observable, so SwiftUI views can bind to these properties directly.
import CloudXRKit
import SwiftUI
struct QualityView: View {
@Environment(CloudXRSession.self) private var cxrSession
var body: some View {
VStack(alignment: .leading) {
Text("Quality: " + cxrSession.sessionQuality.description)
if let latency = cxrSession.liveNetworkStats.latencyMilliseconds {
Text("Pose to frame received: " + String(latency) + " msec")
}
if let bandwidth = cxrSession.liveNetworkStats.bandwidthMbps {
Text("Available bandwidth: " + String(bandwidth) + " Mbps")
}
}
}
}
Prefer the observable sessionQuality and liveNetworkStats properties
for new apps. setNetworkQualityListener(listener:) remains available for
older integrations, but it is deprecated.
Session Quality States#
Session.SessionQuality is ordered from lowest to highest quality:
The latency and jitter thresholds in these states refer to pose-to-frame-received timing.
State |
Meaning |
|---|---|
|
CloudXR Framework has not collected enough live samples to report quality. |
|
The stream is unlikely to remain usable. This can occur when pose-to-frame-received latency exceeds 200 msec, pose-to-frame-received jitter exceeds 150 msec, or bandwidth is below 50 Mbps. |
|
The stream is usable but visibly impaired. This can occur when pose-to-frame-received latency exceeds 120 msec, pose-to-frame-received jitter exceeds 60 msec, or bandwidth is below 75 Mbps. |
|
The stream has acceptable quality. |
|
The stream has the best reported quality. This requires pose-to-frame-received latency of 50 msec or less, pose-to-frame-received jitter of 15 msec or less, and bandwidth of at least 150 Mbps. |
.noData is expected at the start of a session. The live quality window must
collect enough pose-to-frame-received samples before it can report a quality
state.
Live Network Stats#
Session.liveNetworkStats provides the current values behind the quality
monitor:
Field |
Meaning |
|---|---|
|
Pose-to-frame-received latency in milliseconds. |
|
Jitter in pose-to-frame-received latency in milliseconds. |
|
Stable available bandwidth in Mbps. |
|
Lost video-packet count reported for the current streaming stats window. |
|
Estimated network round-trip delay between the server and client in milliseconds. |
Packet loss and round-trip delay are diagnostic values. The current
sessionQuality state is computed from pose-to-frame-received latency,
pose-to-frame-received jitter, and bandwidth.
Interpreting Results#
Use the pre-session network test to decide whether to continue, warn, or stop
early. Use the in-session quality monitor to react to changes while streaming.
For example, you can show a compact quality indicator, log transitions to
.degraded or .unsustainable, or adjust app-specific behavior when live
stats indicate sustained pressure.
If quality is poor, compare the scored fields before assuming the network is the only cause. Low bandwidth, packet loss, or high round-trip delay usually points to the network path. High pose-to-frame-received latency or jitter can also point to server load, server application frame pacing, or client device performance. For network requirements and topology guidance, refer to Network Setup.