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;
}
}