# MRPS v5 phone-depth compatibility fix

## Why v4 could remain at “Waiting for depth”

The previous build started the rear-facing `getUserMedia()` stream and the
`immersive-ar` session at the same time. On an Android phone, WebXR/ARCore also
owns the rear camera. The working Babylon testbed does not open a MediaStream;
it requests CPU depth with only `luminance-alpha` and reads
`XRFrame.getDepthInformation(view)`.

## v5 startup contract

The encoder now requests WebXR first with this compatibility profile:

```js
requiredFeatures: ['depth-sensing']
optionalFeatures: ['dom-overlay', 'camera-access']
depthSensing: {
  usagePreference: ['cpu-optimized'],
  dataFormatPreference: ['luminance-alpha']
}
```

It deliberately omits `depthTypeRequest` and `matchDepthView` from the
compatibility request. `luminance-alpha` is the mandatory baseline depth format
for a user agent that implements WebXR Depth Sensing.

## RGB behavior

### Mono handheld/phone XR

1. No `getUserMedia()` stream is opened during WebXR depth startup.
2. If the runtime grants `camera-access`, RGB is read with
   `XRWebGLBinding.getCameraImage()` from the same `XRFrame` and `XRView` as the
   copied depth data.
3. The camera texture's bottom-left origin is flipped into the PNG's top-left
   image convention.
4. If raw camera access is not granted, the encoder keeps depth working and
   enables a sequential fallback. On snapshot it freezes the latest depth,
   ends the XR session, then opens `getUserMedia()` for RGB. The metadata marks
   this path as unsynchronized and records the measured time gap.

### Stereo headset XR

1. The encoder first waits for a complete left/right depth set.
2. Only after depth is active does it open the headset's `getUserMedia()` RGB
   stream.
3. Snapshot capture then follows the existing RGB-next-frame/depth-next-set
   path.

## Raw camera ordering

The phone raw-camera path mirrors Chromium's working barebones sample:

1. Create a WebGL 1 context.
2. Construct `XRWebGLBinding`.
3. Construct and install `XRWebGLLayer`.
4. Call `getCameraImage()` only inside the XR animation-frame callback.
5. Attach the opaque camera texture to a framebuffer and use `readPixels()`.

## Diagnostics

While depth is unavailable, the status line reports:

- XR view mode and missing eye/slot
- `session.depthActive`, when exposed
- selected depth usage and format
- active `getUserMedia()` track count

On the phone compatibility path, the track count must stay at zero while the
encoder waits for its first depth frame.

## Output compatibility

The native `MRD1` depth payload, matrices, camera-local coordinate system,
phase atlas, invalid/clipped masks, and player reconstruction rules are
unchanged. Metadata schema identification is now
`mr-phase-shift-snapshot/v5`; the v5 decoder remains backward-compatible with
v4 payloads.

## Sequential fallback limitation

The sequential fallback avoids the camera resource conflict but is not
hardware synchronized. Hold the phone still between the visible depth frame
and the RGB capture. For exact per-frame registration, use the granted WebXR
Raw Camera Access path.
