Migrating from CloudXR 5.0 to 6.0#

Overview#

CloudXR 6.0 introduces MessageChannels for client-server communication. Messages are no longer sent directly through Session; instead, you obtain a MessageChannel from the session and send messages through the channel.

Applications that use OmniverseStateManager do not require migration as the underlying API has been updated. Direct session.sendServerMessage() calls must be updated.

Migration time: ~15-30 minutes for typical applications.

API Changes#

Sending Messages#

CloudXR 5.0:

// Direct session messaging
session.sendServerMessage(messageData)

CloudXR 6.0 - Recommended Pattern:

// Use ServerMessageDispatcher (handles channels automatically)
ConfiguratorAppModel.omniverseMessageDispatcher.sendMessage(messageData)

// Or through OmniverseStateManager
asset.stateManager.send(message)

CloudXR 6.0 - Direct Channel Access (advanced):

// For applications needing fine control over channels
guard let channelInfo = session.availableMessageChannels.first,
      let channel = session.getMessageChannel(channelInfo) else {
    return
}
channel.sendServerMessage(messageData)

Receiving Messages#

CloudXR 5.0:

// ServerMessageDispatcher listened to session.serverMessageStream
for await message in session.serverMessageStream {
    listeners.forEach({ $0.onMessageReceived(message: message) })
}

CloudXR 6.0:

// ServerMessageDispatcher manages multiple channels
// Listens to each channel's receivedMessageStream separately
for await message in channel.receivedMessageStream {
    listeners.forEach({ $0.onMessageReceived(message: message) })
}

Updated ServerMessageDispatcher#

The ServerMessageDispatcher in CloudXR 6.0 now:

  • Manages multiple MessageChannels with UUIDs.

  • Automatically queues messages when channels aren’t ready.

  • Observes session.availableMessageChannels for lifecycle management.

  • Provides thread-safe operations.

Key change in ConfiguratorAppModel:

public class ConfiguratorAppModel {
    public static var omniverseMessageDispatcher = ServerMessageDispatcher()

    public var session: Session? {
        get { asset.stateManager.session }
        set {
            asset.stateManager.session = newValue
            Self.omniverseMessageDispatcher.session = newValue
            Self.omniverseMessageDispatcher.attach(asset.stateManager)
        }
    }
}

OmniverseStateManager send() method:

// CloudXR 5.0
public func send(_ message: any MessageProtocol) {
    guard let session = self.session else { return }
    session.sendServerMessage(encodeJSON(message.encodable))
}

// CloudXR 6.0
public func send(_ message: any MessageProtocol) {
    guard session != nil else { return }
    let messageData = encodeJSON(message.encodable)
    if !ConfiguratorAppModel.omniverseMessageDispatcher.sendMessage(messageData) {
        Self.logger.error("Failed to send message")
    }
}

Migration Checklist#

  1. Update ServerMessageDispatcher

    • Copy the updated ServerMessageDispatcher.swift from the CloudXR 6.0 sample.

    • Or implement channel management logic in your existing dispatcher.

  2. Update OmniverseStateManager (if customized)

    • Replace session.sendServerMessage() with messageDispatcher.sendMessage().

    • Add error handling for failed sends.

  3. Update ConfiguratorAppModel (if customized)

    • Add static omniverseMessageDispatcher instance.

    • Update session setter to configure the dispatcher.

  4. Search and replace direct session calls

    • Replace with asset.stateManager.send() or messageDispatcher.sendMessage().

  5. Remove MessageProtocol from AssetCamera (if implemented)

    • AssetCamera no longer needs MessageProtocol conformance.

    • Remove isEqualTo() method if present.

  6. Test messaging functionality

    • Verify variant changes work.

    • Test camera switching.

    • Confirm custom messages send/receive correctly.

    • Check that UI properly waits for server acknowledgments.

Common Issues#

“Channel not ready” warnings

  • Messages are automatically queued when channels aren’t available.

  • Ensure ServerMessageDispatcher is properly initialized with the session.

Multiple channel confusion

  • Most applications only need one channel (the first available).

  • messageDispatcher.sendMessage(data, channelUUID: nil) automatically uses first channel.

  • Only specify channelUUID if you need to target a specific channel.

Messages not being received

  • Verify ServerMessageDispatcher is attached as a listener.

  • Check that session.availableMessageChannels is not empty.

  • Ensure server-side channel creation is working.