Network Test and Session Quality#

CloudXR Framework provides two quality tools for Apple native clients:

  • Config.networkTest runs a short pre-session network test at the start of a connection.

  • Session.sessionQuality and Session.liveNetworkStats monitor 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 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

.disabled

Does not run the pre-session network test.

.enabled(duration:)

Runs the test as a gate. If networkIsUsable is false, CloudXR Framework disconnects and reports a network-test failure.

.warningOnly(duration:)

Runs the test and leaves the session connected even if networkIsUsable is false. Use this mode when your app presents its own warning.

.testOnly(duration:)

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. The CloudXR Developer Client exposes 5-second and 10-second options.

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

networkIsUsable

Indicates whether all required scores meet the minimum usable threshold.

latencyScore

Scores end-to-end pose-to-frame latency.

jitterScore

Scores end-to-end pose-to-frame latency jitter.

bandwidthScore

Scores stable available network bandwidth during the test.

devicePerformanceScore

Scores client tick consistency. A low score can indicate client device load or scheduling issues.

networkPacketLoss

Reports the latest lost video-packet count when the stream statistics provide it.

networkRoundTripDelayMilliseconds

Reports a conservative round-trip delay value in milliseconds when the stream statistics provide it.

serverFPS

Reports the average server frame rate and a low-percentile frame-rate value.

message

Provides a short pass or failure summary.

The latency and jitter scores are end-to-end measurements. They can be affected by network conditions, server performance, and server application frame production consistency.

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("E2E latency: " + 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:

State

Meaning

.noData

CloudXR Framework has not collected enough live samples to report quality.

.unsustainable

The stream is unlikely to remain usable. This can occur when latency exceeds 200 msec, jitter exceeds 150 msec, or bandwidth is below 50 Mbps.

.degraded

The stream is usable but visibly impaired. This can occur when latency exceeds 120 msec, jitter exceeds 60 msec, or bandwidth is below 75 Mbps.

.good

The stream has acceptable quality.

.excellent

The stream has the best reported quality. This requires latency of 50 msec or less, 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 end-to-end latency samples before it can report a quality state.

Live Network Stats#

Session.liveNetworkStats provides the current values behind the quality monitor:

Field

Meaning

latencyMilliseconds

End-to-end pose-to-frame latency in milliseconds.

jitterMilliseconds

End-to-end pose-to-frame latency jitter in milliseconds.

bandwidthMbps

Stable available bandwidth in Mbps.

networkPacketLoss

Lost video-packet count reported for the current streaming stats window.

networkRoundTripDelayMilliseconds

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 end-to-end latency, 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 end-to-end 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.