Skip to main content
Version: 14 Oct 2024

User Calibration

This document demonstrates how to use the User Calibration OpenXR Feature to determine if the user has calibrated the device to fit and track their eyes properly. This feature can be used in conjunction with Android Intents to:

  1. Determine if the user has calibrated their device.
  2. Use Android Intents to launch the Custom Fit app to complete fit or eye tracking calibration.
caution

This feature requires the Magic Leap 2 User Calibration OpenXR Feature to be enabled in your project's OpenXR Settings (Window > XR Plugin Manager > OpenXR Settings).

info

Magic Leap 2's Eye Calibration API and HeadsetFit API have been combined into a single User Calibration OpenXR Feature.

Example

The following example logs the user's fit status time and eye calibration status every frame when the component is enabled.

using UnityEngine;
using UnityEngine.XR.OpenXR;
using MagicLeap.OpenXR.Features.UserCalibration;

public class UserCalibrationTest : MonoBehaviour
{
private MagicLeapUserCalibrationFeature _userCalibrationFeature;

void OnEnable()
{
_userCalibrationFeature = OpenXRSettings.Instance.GetFeature<MagicLeapUserCalibrationFeature>();
if (_userCalibrationFeature == null || !_userCalibrationFeature.enabled)
{
Debug.LogError("Magic Leap User Calibration Feature does not exists or is disabled.");
return;
}

_userCalibrationFeature.EnableUserCalibrationEvents(true);
}

private void Update()
{
_userCalibrationFeature.GetLastHeadsetFit(out MagicLeapUserCalibrationFeature.HeadsetFitData headsetFitData);

// Status can return HeadsetFitStatus.Unknown, HeadsetFitStatus.NotWorn, HeadsetFitStatus.GoodFit or HeadsetFitStatus.BadFit.
Debug.Log($"Last Headset fit status: { headsetFitData.Status} at time { headsetFitData.Time}");

_userCalibrationFeature.GetLastEyeCalibration(out MagicLeapUserCalibrationFeature.EyeCalibrationData eyeCalibrationData);

// Status can return EyeCalibrationStatus.Unknown, EyeCalibrationStatus.None, EyeCalibrationStatus.Coarse or EyeCalibrationStatus.Fine.
Debug.Log($"Last Eye calibration status: {eyeCalibrationData.Status}");
}

private void OnDisable()
{
if (_userCalibrationFeature != null && _userCalibrationFeature.enabled)
_userCalibrationFeature.EnableUserCalibrationEvents(false);
}
}

Convert HeadsetFitData.Time into a user readable value

The MagicLeapUserCalibrationFeature.HeadsetFitData.Time is provided as a Unix timestamp which is used to store/transmit date and time information in a compact way. However, to display the date and time in a human-readable, you need to convert it to a a .NET object such as DateTimeOffset or DateTime that supports different formats and time zones.

// Get the time from the headset fit data
MagicLeapUserCalibrationFeature _userCalibrationFeature; = OpenXRSettings.Instance.GetFeature<MagicLeapUserCalibrationFeature>();
_userCalibrationFeature.GetLastHeadsetFit(out MagicLeapUserCalibrationFeature.HeadsetFitData headsetFitData);

// Convert the time from microseconds to DateTime and format it
string formattedTime = DateTimeOffset.FromUnixTimeMilliseconds(headsetFitData.Time / 1000).ToString("d/M/y HH:mm");

Debug.Log($"Last Headset fit at time {formattedTime}");

Headset Status

The User Calibration API can help determine if the headset is being worn and if it fits properly. The example below demonstrates how to query the MagicLeapUserCalibrationFeature.HeadsetFitStatus.

caution

When Standby is enabled on the Magic Leap 2, your application will receive the OnPause callback when the Magic Leap detects that the user has removed the headset. This can result in your application being paused before the GetLastHeadsetFit() query returns the HeadsetFitStatus.NotWorn status.

using UnityEngine;
using UnityEngine.XR.OpenXR;
using MagicLeap.OpenXR.Features.UserCalibration;

public class UserCalibrationTest : MonoBehaviour
{
private MagicLeapUserCalibrationFeature _userCalibrationFeature;

void OnEnable()
{
_userCalibrationFeature = OpenXRSettings.Instance.GetFeature<MagicLeapUserCalibrationFeature>();
if (_userCalibrationFeature == null || !_userCalibrationFeature.enabled)
{
Debug.LogError("Magic Leap User Calibration Feature does not exists or is disabled.");
return;
}

_userCalibrationFeature.EnableUserCalibrationEvents(true);
}


private void Update()
{
if (_userCalibrationFeature.GetLastHeadsetFit(out MagicLeapUserCalibrationFeature.HeadsetFitData headsetFitData))
{
switch (headsetFitData.Status)
{
case MagicLeapUserCalibrationFeature.HeadsetFitStatus.Unknown:
// (Optional) Implement logic when the headset status is unknown.
break;
case MagicLeapUserCalibrationFeature.HeadsetFitStatus.NotWorn:
// (Optional) Implement logic when the headset is not worn.
break;
case MagicLeapUserCalibrationFeature.HeadsetFitStatus.GoodFit:
// (Optional) Implement logic when the headset has a good fit.
break;
case MagicLeapUserCalibrationFeature.HeadsetFitStatus.BadFit:
// (Optional) Implement logic when the headset has a bad fit.
break;
}
}
}

private void OnDisable()
{
if (_userCalibrationFeature != null && _userCalibrationFeature.enabled)
_userCalibrationFeature.EnableUserCalibrationEvents(false);
}
}