private void StartInternal()
        {
            MLPluginLog.Debug($"Initializing {typeof(T).Name} API...");

            if (DidNativeCallSucceed(StartAPI(), $"{typeof(T).Name} Start"))
            {
                IsStarted = true;
                MLDevice.RegisterUpdate(instance.Update);
                MLDevice.RegisterApplicationPause(instance.OnApplicationPause);
                MLDevice.RegisterDestroy(instance.StopInternal);

                instance.perceptionHandle = PerceptionHandle.Acquire();
                MLPluginLog.Debug($"{typeof(T).Name} API initialized.");
            }
        }
        private void StopInternal()
        {
            if (IsStarted)
            {
                MLDevice.UnregisterUpdate(this.Update);
                MLDevice.UnregisterApplicationPause(this.OnApplicationPause);
                MLDevice.UnregisterDestroy(instance.StopInternal);

                MLResult.Code resultCode = instance.StopAPI();

                if (DidNativeCallSucceed(resultCode, $"{typeof(T).Name} Stop"))
                {
                    MLPluginLog.Debug($"{typeof(T).Name} API stopped successfully");
                }

                if (perceptionHandle.active)
                {
                    perceptionHandle.Dispose();
                }

                IsStarted = false;
            }
        }
        /// <summary>
        ///     Poll the native API for barcode scanner results.
        /// </summary>
        /// <returns>
        ///     An array of BarcodeData that contains the results
        ///     that the scanner has collected since the last call to this function. This array
        ///     may be empty if there are no new results.
        /// </returns>
        private static List <BarcodeData> MLBarcodeScannerGetResults()
        {
            try
            {
                // get results from native api
                MLResult.Code resultCode = NativeBindings.MLBarcodeScannerGetResult(Instance.Handle, out NativeBindings.MLBarcodeScannerResultArray scannerResults);

                if (MLResult.IsOK(resultCode))
                {
                    var managedResults = new List <BarcodeData>((int)scannerResults.Count);

                    for (int i = 0; i < scannerResults.Count; i++)
                    {
                        // marshal native array into native structs
                        long address = scannerResults.Detections.ToInt64() + (Marshal.SizeOf <IntPtr>() * i);
                        NativeBindings.MLBarcodeScannerResult detectedResult = Marshal.PtrToStructure <NativeBindings.MLBarcodeScannerResult>(Marshal.ReadIntPtr(new IntPtr(address)));
                        MLPluginLog.Debug($"MLBarcodeScanner results found: {detectedResult}");

                        // create managed version of data
                        UnityEngine.Pose pose;
                        if (((BarcodeType)detectedResult.Type) == BarcodeType.QR)
                        {
                            if (!MagicLeapNativeBindings.UnityMagicLeap_TryGetPose(detectedResult.CoordinateFrameUID, out pose))
                            {
                                MLPluginLog.Error($"Barcode Scanner could not get pose data for coordinate frame id '{detectedResult.CoordinateFrameUID}'");
                                pose = Pose.identity;
                            }
                        }
                        else
                        {
                            pose = Pose.identity;
                        }

                        managedResults.Add
                        (
                            BarcodeData.Create
                            (
                                (BarcodeType)detectedResult.Type,
                                pose,
                                detectedResult.DecodedData.Data,
                                detectedResult.DecodedData.Size,
                                detectedResult.ReprojectionError
                            )
                        );
                    }

                    // release native memory so results can be polled again
                    if (MLResult.IsOK(NativeBindings.MLBarcodeScannerReleaseResult(scannerResults)))
                    {
                        return(managedResults);
                    }
                    else
                    {
                        MLPluginLog.Error($"MLBarcodeScanner.NativeBindings.MLBarcodeScannerReleaseResult failed when trying to release the results' memory. Reason: {MLResult.CodeToString(resultCode)}");
                        return(managedResults);
                    }
                }
                else
                {
                    MLPluginLog.Error($"MLBarcodeScanner.MLBarcodeScannerGetResult failed to obtain a result. Reason: {resultCode}");
                    return(default);