@@ -58,6 +58,12 @@ interface CloudXRComponentProps {
5858 /** Callback fired when an error occurs. Receives error message string. */
5959 onError ?: ( error : string ) => void ;
6060
61+ /**
62+ * Called when CloudXR fails to connect or streaming stops with an error.
63+ * Use this to end the immersive WebXR session (same as the user pressing Disconnect).
64+ */
65+ onExitImmersiveXR ?: ( ) => void ;
66+
6167 /** Callback fired when CloudXR session is created or destroyed. Receives session instance or null. */
6268 onSessionReady ?: ( session : CloudXR . Session | null ) => void ;
6369
@@ -91,6 +97,7 @@ export default function CloudXRComponent({
9197 applicationName,
9298 onStatusChange,
9399 onError,
100+ onExitImmersiveXR,
94101 onSessionReady,
95102 onServerAddress,
96103 onRenderPerformanceMetrics,
@@ -101,6 +108,8 @@ export default function CloudXRComponent({
101108 const { session } = useXR ( ) ;
102109 // React reference to the CloudXR session that persists across re-renders.
103110 const cxrSessionRef = useRef < CloudXR . Session | null > ( null ) ;
111+ const onExitImmersiveXRRef = useRef ( onExitImmersiveXR ) ;
112+ onExitImmersiveXRRef . current = onExitImmersiveXR ;
104113
105114 // Metrics trackers for averaging performance metrics
106115 // Use prop values if provided, otherwise use defaults
@@ -192,6 +201,7 @@ export default function CloudXRComponent({
192201 } catch ( error ) {
193202 onStatusChange ?.( false , 'Configuration Error' ) ;
194203 onError ?.( `Proxy configuration failed: ${ error } ` ) ;
204+ onExitImmersiveXRRef . current ?.( ) ;
195205 return ;
196206 }
197207
@@ -267,6 +277,7 @@ export default function CloudXRComponent({
267277 if ( error . reasonCode !== undefined ) {
268278 console . debug ( 'Stop reason code:' , error . reasonCode ) ;
269279 }
280+ onExitImmersiveXRRef . current ?.( ) ;
270281 } else {
271282 console . debug ( 'CloudXR session stopped' ) ;
272283 onStatusChange ?.( false , 'Disconnected' ) ;
@@ -304,6 +315,7 @@ export default function CloudXRComponent({
304315 } catch ( error ) {
305316 onStatusChange ?.( false , 'Session Creation Failed' ) ;
306317 onError ?.( `Failed to create CloudXR session: ${ error } ` ) ;
318+ onExitImmersiveXRRef . current ?.( ) ;
307319 return ;
308320 }
309321
@@ -323,9 +335,20 @@ export default function CloudXRComponent({
323335 onStatusChange ?.( false , 'Connection Failed' ) ;
324336 // Report error via callback
325337 onError ?.( 'Failed to connect CloudXR session' ) ;
326- // Clean up the failed session
338+ // Best-effort: release SDK resources if connect() threw after createSession(); ignore disconnect failures.
339+ try {
340+ cxrSession . disconnect ( ) ;
341+ } catch {
342+ // Ignore errors from disconnect().
343+ }
327344 cxrSessionRef . current = null ;
345+ onSessionReady ?.( null ) ;
346+ onExitImmersiveXRRef . current ?.( ) ;
328347 }
348+ } else {
349+ onStatusChange ?.( false , 'Reference Space Unavailable' ) ;
350+ onError ?.( 'Could not obtain an XR reference space for CloudXR' ) ;
351+ onExitImmersiveXRRef . current ?.( ) ;
329352 }
330353 } ;
331354
0 commit comments