Skip to main content
Version: 21 Aug 2024

Initialize Sensor with Default Settings

If your application needs access to one of Magic Leap's pixel sensors, and you do not plan to use a custom configuration, you can initialize the sensor with it's generic configuration.

caution

This features requires either Depth Camera , Eye Camera , Depth Camera permissions to be requested at runtime and enabled in your project's Manifest Settings (Edit > Project Settings > Magic Leap > Manifest Settings) depending on the selected sensor.

Example

The following script initializes a given sensor using the default configuration values. Note, the Pixel Sensor Visualizer has been commented out. See the Visualizing Pixel Sensor Data to see the example script.

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using MagicLeap.Android;
using Unity.Collections;
using UnityEngine;
using UnityEngine.XR.MagicLeap;
using UnityEngine.XR.OpenXR;
using MagicLeap.OpenXR.Features.PixelSensors;

/// <summary>
/// Example script to show how to obtain data from a sensor after configuring the sensor using the default configuration.
/// </summary>
public class EyeCameraPixelExample : MonoBehaviour
{
[SerializeField]
private SensorNameUtility.PixelSensorType sensorType = SensorNameUtility.PixelSensorType.EyeNasalLeft;

//public SimplePixelVisualizer streamVisualizer;

// This example assumes you need all of the permissions enabled
private readonly string[] requiredPermissions =
{
MLPermission.Camera,
MLPermission.DepthCamera,
MLPermission.EyeCamera
};

// True if all of the permissions were granted
private bool AreAllPermissionsGranted => requiredPermissions.All(Permissions.CheckPermission);

private MagicLeapPixelSensorFeature pixelSensorFeature;
private PixelSensorId? sensorId;
private List<uint> configuredStreams = new List<uint>();

void Start()
{
pixelSensorFeature = OpenXRSettings.Instance.GetFeature<MagicLeapPixelSensorFeature>();
if (pixelSensorFeature == null || !pixelSensorFeature.enabled)
{
Debug.LogError("Pixel Sensor Feature not found or not enabled!");
enabled = false;
return;
}
Permissions.RequestPermissions(requiredPermissions, OnPermissionGranted, OnPermissionDenied,
OnPermissionDenied);
}

private void OnPermissionGranted(string permission)
{
if(AreAllPermissionsGranted)
FindAndInitializeSensor();

}

private void OnPermissionDenied(string permission)
{
Debug.LogError($"Permission { permission} not granted. Example script will not work.");
enabled = false;
}

private void FindAndInitializeSensor()
{
List<PixelSensorId> sensors = pixelSensorFeature.GetSupportedSensors();
int index = sensors.FindIndex(x => x.SensorName.Contains(SensorNameUtility.GetName(sensorType)));

if (index <= 0)
{
Debug.LogError($"{SensorNameUtility.GetName(sensorType)} sensor not found.");
return;
}

sensorId = sensors[index];

// Subscribe to the Availability changed callback if the sensor becomes available.
pixelSensorFeature.OnSensorAvailabilityChanged += OnSensorAvailabilityChanged;
TryInitializeSensor();
}

private void OnSensorAvailabilityChanged(PixelSensorId id, bool available)
{
if (id == sensorId && available)
{
Debug.Log("Sensor became available.");
TryInitializeSensor();
}
}

private void TryInitializeSensor()
{
if (sensorId.HasValue && pixelSensorFeature.GetSensorStatus(sensorId.Value) ==
PixelSensorStatus.Undefined && pixelSensorFeature.CreatePixelSensor(sensorId.Value))
{
Debug.Log("Sensor created successfully.");
ConfigureSensorStreams();
}
else
{
Debug.LogWarning("Failed to create sensor. Will retry when it becomes available.");
}
}

private void ConfigureSensorStreams()
{
if (!sensorId.HasValue)
{
Debug.LogError("Sensor ID not set.");
return;
}

uint streamCount = pixelSensorFeature.GetStreamCount(sensorId.Value);
if (streamCount < 1)
{
Debug.LogError("Expected at least one stream from the sensor.");
return;
}

// Only add the first stream
configuredStreams.Add(0);

StartCoroutine(ConfigureStreamsAndStartSensor());
}

private IEnumerator ConfigureStreamsAndStartSensor()
{

PixelSensorAsyncOperationResult configureOperation =
pixelSensorFeature.ConfigureSensorWithDefaultCapabilities(sensorId.Value, configuredStreams.ToArray());

yield return configureOperation;

if (configureOperation.DidOperationSucceed)
{
Debug.Log("Sensor configured with defaults successfully.");
}
else
{
Debug.LogError("Failed to configure sensor.");
yield break;
}


Dictionary<uint, PixelSensorMetaDataType[]> supportedMetadataTypes =
new Dictionary<uint, PixelSensorMetaDataType[]>();

foreach (uint stream in configuredStreams)
{
if (pixelSensorFeature.EnumeratePixelSensorMetaDataTypes(sensorId.Value, stream, out var metaDataTypes))
{
supportedMetadataTypes[stream] = metaDataTypes;
}
}

// Assuming that `configuredStreams` is correctly populated with the intended stream indices
PixelSensorAsyncOperationResult startOperation = pixelSensorFeature.StartSensor(sensorId.Value, configuredStreams, supportedMetadataTypes);

yield return startOperation;

if (startOperation.DidOperationSucceed)
{
Debug.Log("Sensor started successfully. Monitoring data...");
StartCoroutine(MonitorSensorData());
}
else
{
Debug.LogError("Failed to start sensor.");
}
}

private IEnumerator MonitorSensorData()
{
while (pixelSensorFeature.GetSensorStatus(sensorId.Value) ==
PixelSensorStatus.Started)
{
foreach (uint stream in configuredStreams)
{
if (pixelSensorFeature.GetSensorData(sensorId.Value, stream, out var frame, out var metaData, Allocator.Temp, shouldFlipTexture: true))
{
// TODO: streamVisualizer.ProcessFrame(frame, stream);

// You can also obtain the capture time as well. Note it is returned as a long and needs to be converted.
// ie : DateTimeOffset.FromUnixTimeMilliseconds(frame.CaptureTime / 1000);

Debug.Log($"Obtained Pixel Sensor Data.");
}
}
yield return null;
}
}

public void OnDisable()
{
//We start the Coroutine on another MonoBehaviour since it can only run while the object is enabled.
MonoBehaviour camMono = Camera.main.GetComponent<MonoBehaviour>();
camMono.StartCoroutine(StopSensorCoroutine());
}

private IEnumerator StopSensorCoroutine()
{
if (sensorId.HasValue)
{
PixelSensorAsyncOperationResult stopSensorAsyncResult =
pixelSensorFeature.StopSensor(sensorId.Value, configuredStreams);

yield return stopSensorAsyncResult;

if (stopSensorAsyncResult.DidOperationSucceed)
{
Debug.Log("Sensor stopped successfully.");
pixelSensorFeature.ClearAllAppliedConfigs(sensorId.Value);
// Free the sensor so it can be marked available and used in other scripts.
pixelSensorFeature.DestroyPixelSensor(sensorId.Value);
}
else
{
Debug.LogError("Failed to stop the sensor.");
}
}
}
}

/// <summary>
/// Simple class to make it easier to get the Sensor Name based on the type of sensor.
/// </summary>
public static class SensorNameUtility
{
public enum PixelSensorType {PictureCenter, WorldLeft, WorldRight, DepthCenter, EyeTempleLeft, EyeNasalLeft, EyeNasalRight, EyeTempleRight };

/// <summary>
/// Get the Pixel Sensor Name based on the Sensor Type
/// </summary>
/// <param name="sensor">The Sensor your wish to get the name for.</param>
/// <returns>The name of the sensor as listed by the Pixel Sensor Feature.</returns>
public static string GetName(PixelSensorType sensor)
{
// Convert the enum to a string
string sensorName = sensor.ToString();
// Use regular expression to insert a space before each uppercase letter, except for the first one
string spacedName = Regex.Replace(sensorName, "(\\B[A-Z])", " $1");
return spacedName;
}
}