예제 #1
0
        /// <summary>
        /// Register a unique schema for <c>OAuth</c> redirect handler. The caller needs to ensure that the schema is unique.
        /// If the schema is already registered the function will return an error. The handler
        /// will be called once the authorization procedure has been completed.
        /// The caller should register two schema callbacks. The first will be for
        /// authorization redirect and the second schema will in case the user cancels
        /// the authentication.
        /// </summary>
        /// <param name="schema">A unique string that will match the redirect uri schema</param>
        /// <param name="callback">MLDispatch <c>OAuth</c> callback function</param>
        /// <returns>
        /// MLResult.Result will be <c>MLResult.Code.Ok</c> if the new schema has been registered correctly.
        /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if SecureBrowserWindow privilege is denied.
        /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if the operation failed with an unspecified error.
        /// MLResult.Result will be <c>MLResult.Code.SchemaAlreadyRegistered</c> if the schema already is registered.
        /// MLResult.Result will be <c>MLResult.Code.Dispatch*</c> if a dispatch specific error occurred.
        /// </returns>
        public static MLResult OAuthRegisterSchema(string schema, ref OAuthHandler callback)
        {
            try
            {
                NativeBindings.OAuthCallbacksNative newSchema = NativeBindings.OAuthCallbacksNative.Create();
                newSchema.OnReplyComplete = OAuthOnReplyNative;

                int newID = uniqueID + 1;

                MLResult.Code resultCode = NativeBindings.MLDispatchOAuthRegisterSchemaEx(schema, ref newSchema, new IntPtr(newID));

                if (MLResult.IsOK(resultCode))
                {
                    OAuthPair newEntry = new OAuthPair(schema, callback);
                    oAuthCallbacks.Add(newID, newEntry);
                    uniqueID = newID;
                }

                return(MLResult.Create(resultCode));
            }
            catch (System.DllNotFoundException)
            {
                MLPluginLog.Error(DllNotFoundExceptionError);
                return(MLResult.Create(MLResult.Code.UnspecifiedFailure, DllNotFoundExceptionError));
            }
            catch (System.EntryPointNotFoundException)
            {
                MLPluginLog.Error("MLDispatch API symbols not found");
                return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLDispatch API symbols not found"));
            }
        }
        /// <summary>
        /// Gets the offset position/rotation values and the PCF of the current Perception root.
        /// </summary>
        /// <param name="offsetPosition">Stores the value of the current offset from the root's position.</param>
        /// <param name="offsetRotation">Stores the value of the current offset from the root's rotation.</param>
        /// <param name="pcf">Stores the reference to the current root PCF.</param>
        /// <returns>
        /// MLResult.Result will be <c>MLResult.Code.Ok</c> if operation completed successfully.
        /// MLResult.Result will be <c>MLResult.Code.MLPerceptionNotStarted</c> if unable to retrieve the Perception System.
        /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to other internal error.
        /// </returns>
        public static MLResult GetPerceptionRoot(out Vector3 offsetPosition, out Quaternion offsetRotation, out PCF pcf)
        {
            offsetPosition = Vector3.zero;
            offsetRotation = Quaternion.identity;
            pcf            = new PCF(new MagicLeapNativeBindings.MLCoordinateFrameUID());

            if (MLPersistentCoordinateFrames.IsValidInstance())
            {
                try
                {
                    MLResult.Code resultCode = NativeBindings.MLPerceptionGetRootCoordinateFrame(out MagicLeapNativeBindings.MLCoordinateFrameUID cfuid, out MagicLeapNativeBindings.MLTransform mlTransform);
                    if (MLResult.IsOK(resultCode))
                    {
                        offsetPosition = MLConvert.ToUnity(mlTransform.Position);
                        offsetRotation = MLConvert.ToUnity(mlTransform.Rotation);
                        return(MLResult.Create(MLResult.Code.Ok));
                    }
                    else
                    {
                        MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.GetPerceptionRoot failed. Reason: {0}", MLResult.CodeToString(resultCode));
                        return(MLResult.Create(resultCode));
                    }
                }
                catch (EntryPointNotFoundException)
                {
                    MLPluginLog.Error("MLPersistentCoordinateFrames.GetPerceptionRoot failed. Reason: API symbols not found.");
                    return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLPersistentCoordinateFrames.GetPerceptionRoot failed. Reason: API symbols not found."));
                }
            }
            else
            {
                MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.GetPerceptionRoot failed. Reason: No Instance for MLPersistentCoordinateFrames.");
                return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLPersistentCoordinateFrames.GetPerceptionRoot failed. Reason: No Instance for MLPersistentCoordinateFrames."));
            }
        }
            /// <summary>
            /// GetClientCredentials is a blocking function that accesses the cloud and
            /// returns a MLTokenAgentClientCredentials structure containing the users credentials and
            /// tokens for a particular service (Audience).
            /// The library deduces the Audience being requested from the name of the calling service.
            /// </summary>
            /// <param name="clientCredentials">Reference to the clientCredentials object.</param>
            /// <param name="credentials">Reference to the credentials struct of the clientCredentials object.</param>
            /// <param name="tokens">Reference to the tokens struct of the clientCredentials object.</param>
            /// <returns>
            /// MLResult.Result will be <c>MLResult.Code.Ok</c> if successful.
            /// MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if failed due to internal invalid input parameter.
            /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error.
            /// MLResult.Result will be <c>MLResult.Code.AllocFailed</c> if failed to allocate memory.
            /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if necessary privilege is missing.
            /// MLResult.Result will be <c>MLResult.Code.TokenAgent*</c> if a token specific failure occurred during the operation.
            /// </returns>
            public static MLResult.Code GetClientCredentials(MLTokenAgent.ClientCredentials clientCredentials, ref MLTokenAgent.Credentials credentials, ref MLTokenAgent.Tokens tokens)
            {
                try
                {
                    IntPtr        clientCredentialsPtr = clientCredentialsPtrMap.ContainsKey(clientCredentials) ? clientCredentialsPtrMap[clientCredentials] : IntPtr.Zero;
                    MLResult.Code resultCode           = MLTokenAgent.NativeBindings.MLTokenAgentGetClientCredentials(ref clientCredentialsPtr);
                    if (MLResult.IsOK(resultCode))
                    {
                        clientCredentialsPtrMap.Remove(clientCredentials);
                        clientCredentialsPtrMap.Add(clientCredentials, clientCredentialsPtr);

                        MLTokenAgent.NativeBindings.ClientCredentialsNative clientCredentialsNative = (MLTokenAgent.NativeBindings.ClientCredentialsNative)Marshal.PtrToStructure(clientCredentialsPtr, typeof(MLTokenAgent.NativeBindings.ClientCredentialsNative));
                        credentials = clientCredentialsNative.Credentials;
                        tokens      = clientCredentials.Tokens;
                    }
                    else
                    {
                        credentials = new Credentials();
                        tokens      = new Tokens();
                    }

                    return(resultCode);
                }
                catch (EntryPointNotFoundException)
                {
                    MLPluginLog.Error("MLTokenAgent.NativeBindings.GetClientCredentials failed. Reason: API symbols not found.");
                    return(MLResult.Code.UnspecifiedFailure);
                }
            }
            /// <summary>
            /// Invokes the MLTokenAgentGetClientCredentials() function asynchronously (in a different thread).
            /// </summary>
            /// <param name="clientCredentials">Reference to the clientCredentials object.</param>
            /// <returns>
            /// MLResult.Result will be <c>MLResult.Code.Ok</c> if the operation completed successfully.
            /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if the operation failed with an unspecified error.
            /// MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if the profile or out_future were 0 (null).
            /// MLResult.Result will be <c>MLResult.Code.AllocFailed</c> if the operation failed to allocate memory.
            /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if the caller does not have the ClientCredentialsRead privilege.
            /// MLResult.Result will be <c>MLResult.Code.TokenAgent*</c> if a token specific failure occurred during the operation.
            /// </returns>
            public static MLResult.Code RequestClientCredentialsAsync(MLTokenAgent.ClientCredentials clientCredentials)
            {
                IntPtr clientCredentialsFuturePtr = clientCredentialsFuturePtrMap.ContainsKey(clientCredentials) ? clientCredentialsFuturePtrMap[clientCredentials] : IntPtr.Zero;

                try
                {
                    MLResult.Code resultCode = MLTokenAgent.NativeBindings.MLTokenAgentGetClientCredentialsAsync(ref clientCredentialsFuturePtr);

                    if (MLResult.IsOK(resultCode))
                    {
                        clientCredentialsFuturePtrMap.Remove(clientCredentials);
                        clientCredentialsFuturePtrMap.Add(clientCredentials, clientCredentialsFuturePtr);
                    }
                    else if (resultCode == MLResult.Code.PrivilegeDenied)
                    {
                        MLPluginLog.Warning("MLTokenAgent.NativeBindings.RequestClientCredentialsAsync failed. Reason: Caller does not have IdentityRead Privilege.");
                    }
                    else
                    {
                        MLPluginLog.ErrorFormat("MLTokenAgent.NativeBindings.RequestClientCredentialsAsync failed. Reason: {0}", resultCode);
                    }

                    return(resultCode);
                }
                catch (EntryPointNotFoundException)
                {
                    MLPluginLog.Error("MLTokenAgent.NativeBindings.RequestClientCredentialsAsync failed. Reason: API symbols not found.");
                    return(MLResult.Code.UnspecifiedFailure);
                }
            }
예제 #5
0
            /// <summary>
            /// Handles when a request queries client credentials.
            /// </summary>
            public void ProcessRequest()
            {
                if (this.request == null)
                {
                    return;
                }

                switch (this.request.RequestState)
                {
                case Request.State.REQUEST_CREDENTIALS:
                    this.RequestClientCredentialsAsync();
                    break;

                case Request.State.LISTENING_CREDENTIALS:
                    this.ListenClientCredentialsResponse();
                    break;

                case Request.State.DONE:
                    this.request?.Callback?.Invoke(MLResult.Create(this.request.ResultCode));

                    // Removes the clientCredentials object if something when wrong with the request.
                    if (!MLResult.IsOK(this.request.ResultCode))
                    {
                        this.request = null;
                        MLTokenAgent.RemoveClientCredentials(this);
                    }

                    this.request = null;
                    break;

                default:
                    break;
                }
            }
예제 #6
0
        /// <summary>
        /// Used to safely make native calls.
        /// </summary>
        /// <param name="resultCode">MLResult.Code enum that the wrappedPlatformCall should set.</param>
        /// <param name="platformFunctionName">Name of the function for the log to print on failure.</param>
        /// <param name="wrappedPlatformCall">Anonymous function for making your native call that you should set resultCode with.</param>
        /// <param name="successCase">Predicate delegate for determining when a call was successful.</param>
        /// <param name="checkInstance">Determines if this call should check for a valid instance before running.</param>
        protected static void PlatformInvoke(out MLResult.Code resultCode, string platformFunctionName, Action wrappedPlatformCall, Predicate <MLResult.Code> successCase = null, bool checkInstance = true)
        {
            resultCode = MLResult.Code.UnspecifiedFailure;

            if (checkInstance && !IsValidInstance())
            {
                MLPluginLog.ErrorFormat("{0} failed. Reason: {1} API has no valid instance.", platformFunctionName, typeof(T).Name);
                return;
            }

            try
            {
                wrappedPlatformCall?.Invoke();
                bool success = successCase != null?successCase(resultCode) : MLResult.IsOK(resultCode);

                if (!success)
                {
                    MLPluginLog.ErrorFormat("{0} failed. Reason: {1}", platformFunctionName, MLResult.CodeToString(resultCode));
                }
            }
            catch (DllNotFoundException)
            {
                MLPluginLog.ErrorFormat("{0} failed. Reason: {1} API is currently available only on device.", platformFunctionName, typeof(T).Name);
                resultCode = MLResult.Code.APIDLLNotFound;
            }
            catch (EntryPointNotFoundException)
            {
                MLPluginLog.ErrorFormat("{0} failed. Reason: {1} API symbols not found.", platformFunctionName, typeof(T).Name);
                resultCode = MLResult.Code.APISymbolsNotFound;
            }
        }
예제 #7
0
            /// <summary>
            /// Updates the state of the PCF.
            /// </summary>
            /// <returns>
            /// MLResult.Result will be <c>MLResult.Code.Ok</c> if operation completed successfully.
            /// MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if failed due to an invalid input parameter.
            /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if there was a lack of privileges.
            /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to other internal error.
            /// MLResult.Result will be <c>MLResult.Code.PassableWorldLowMapQuality</c> if map quality is too low for content persistence. Continue building the map.
            /// MLResult.Result will be <c>MLResult.Code.PassableWorldNotFound</c> if the passed CFUID is not available.
            /// MLResult.Result will be <c>MLResult.Code.PassableWorldUnableToLocalize</c> if currently unable to localize into any map. Continue building the map.
            /// </returns>
            private MLResult UpdateState()
            {
                if (MLPersistentCoordinateFrames.IsValidInstance())
                {
                    try
                    {
                        NativeBindings.FrameStateNative nativeState = NativeBindings.FrameStateNative.Create();
                        MLResult.Code resultCode = NativeBindings.MLPersistentCoordinateFramesGetFrameState(MLPersistentCoordinateFrames._instance.nativeTracker, in this.cfuid, ref nativeState);
                        if (!MLResult.IsOK(resultCode))
                        {
                            MLPluginLog.ErrorFormat("PCF.UpdateState failed to get frame state. Reason: {0}", MLResult.CodeToString(resultCode));
                            return(MLResult.Create(resultCode, string.Format("PCF.UpdateState failed to get frame state. Reason: {0}", MLResult.CodeToString(resultCode))));
                        }

                        this.FrameState = nativeState.Data();

                        return(MLResult.Create(resultCode));
                    }
                    catch (EntryPointNotFoundException)
                    {
                        MLPluginLog.Error("PCF.UpdateState failed. Reason: API symbols not found.");
                        return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "PCF.UpdateState failed. Reason: API symbols not found."));
                    }
                }
                else
                {
                    MLPluginLog.ErrorFormat("PCF.UpdateState failed. Reason: No Instance for MLPersistentCoordinateFrames.");
                    return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "PCF.UpdateState failed. Reason: No Instance for MLPersistentCoordinateFrames."));
                }
            }
예제 #8
0
            /// <summary>
            /// Fetches client credentials, can be used with a callback or as a blocking call.
            /// </summary>
            /// <param name="callback">The callback to notify when the CurrentRequest is complete.</param>
            /// <returns>
            /// MLResult.Result will be <c>MLResult.Code.Ok</c> if the operation completed successfully.
            /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if the operation failed with an unspecified error.
            /// MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if the out_credentials was 0 (null).
            /// MLResult.Result will be <c>MLResult.Code.AllocFailed</c> if the operation failed to allocate memory.
            /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if the caller does not have the ClientCredentialsRead privilege.
            /// MLResult.Result will be <c>MLResult.Code.TokenAgent*</c> if a token specific failure occurred during the operation.
            /// </returns>
            public MLResult Fetch(MLTokenAgent.ClientCredentials.Request.RequestAttibutesDelegate callback = null)
            {
                if (callback == null)
                {
                    MLResult.Code resultCode = MLTokenAgent.NativeBindings.GetClientCredentials(this, ref this.credentials, ref this.tokens);
                    if (!MLResult.IsOK(resultCode))
                    {
                        MLPluginLog.ErrorFormat("MLTokenAgent.Fetch failed. Reason: {0}", MLResult.CodeToString(resultCode));
                    }

                    return(MLResult.Create(resultCode));
                }
                else
                {
                    this.CurrentRequest = new Request
                    {
                        Callback     = callback,
                        ResultCode   = MLResult.Code.Pending,
                        RequestState = Request.State.REQUEST_CREDENTIALS
                    };

                    MLTokenAgent.AddClientCredentials(this);

                    return(MLResult.Create(MLResult.Code.Ok));
                }
            }
            /// <summary>
            /// Apply any changes made to the MLCamera.GeneralSettings properties.
            /// </summary>
            /// <returns>
            /// MLResult.Result will be <c>MLResult.Code.Ok</c> if successful.
            /// MLResult.Result will be <c>MLResult.Code.MediaGenericUnexpectedNull</c> if failed to connect to camera characteristic due to null pointer.
            /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error.
            /// MLResult.Result will be <c>MLResult.Code.AllocFailed</c> if failed to allocate memory.
            /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if necessary privilege is missing.
            /// </returns>
            public MLResult Apply()
            {
                MLResult.Code resultCode;

                if (this.SensorInfoExposureTimeRange.IsDirty)
                {
                    ulong cameraCharacteristicsHandle = MagicLeapNativeBindings.InvalidHandle;
                    resultCode = MLCameraNativeBindings.MLCameraGetCameraCharacteristics(ref cameraCharacteristicsHandle);

                    if (!MLResult.IsOK(resultCode))
                    {
                        MLResult result = MLResult.Create(resultCode);
                        MLPluginLog.ErrorFormat("MLCamera.GeneralSettings.Apply failed to get camera characteristics for MLCamera while applying. Reason: {0}", result);
                        return(result);
                    }

                    long[] sensorExposureTimeRange = new long[2];
                    sensorExposureTimeRange[0] = this.SensorInfoExposureTimeRange.Minimum;
                    sensorExposureTimeRange[1] = this.SensorInfoExposureTimeRange.Maximum;

                    resultCode = MLCameraNativeBindings.MLCameraMetadataSetSensorInfoExposureTimeRange(cameraCharacteristicsHandle, sensorExposureTimeRange);

                    if (!MLResult.IsOK(resultCode))
                    {
                        MLResult result = MLResult.Create(resultCode);
                        MLPluginLog.ErrorFormat("MLCamera.GeneralSettings.Apply failed to set sensor exposure time range. Reason: {0}", result);
                        return(result);
                    }
                }

                return(MLResult.Create(MLResult.Code.Ok));
            }
예제 #10
0
        /// <summary>
        /// Called by MLAPISingleton on destruction
        /// </summary>
        /// <param name="isSafeToAccessManagedObjects">Used for cleanup</param>
        protected override void CleanupAPI(bool isSafeToAccessManagedObjects)
        {
            if (Native.MagicLeapNativeBindings.MLHandleIsValid(this.registerHandle))
            {
                MLResult.Code resultCode = NativeBindings.MLConnectionsRegistrationShutdown(this.registerHandle);

                if (!MLResult.IsOK(resultCode))
                {
                    MLPluginLog.ErrorFormat("MLConnections.Stop failed in CleapupAPI() to shutdown registration to receive invites. Reason: {0}", MLResult.CodeToString(resultCode));
                }
            }

            // Shutdown should only be called if Startup was successful.
            if (this.sendInviteHasStarted)
            {
                MLResult.Code shutdownResultCode = NativeBindings.MLConnectionsShutdown();

                if (!MLResult.IsOK(shutdownResultCode))
                {
                    MLPluginLog.ErrorFormat("MLConnections.Stop failed in CleapupAPI() to deinitialize all resources used for sending an invite. Reason: {0}", MLResult.CodeToString(shutdownResultCode));
                }
            }

            this.registerHandle       = Native.MagicLeapNativeBindings.InvalidHandle;
            this.activeRequest        = false;
            this.sendInviteHasStarted = false;
        }
예제 #11
0
                /// <summary>
                /// Initialized a given appDefinedVideoSource object and sets it's callbacks.
                /// </summary>
                /// <param name="appDefinedVideoSource">The AppDefinedVideoSource object to initialize.</param>
                /// <returns>
                /// MLResult.Result will be <c>MLResult.Code.Ok</c> if the connection was successfully created.
                /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if necessary privilege is missing.
                /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to other internal error.
                /// </returns>
                public static MLResult.Code InitializeAppDefinedVideoSource(MLWebRTC.AppDefinedVideoSource appDefinedVideoSource)
                {
#if PLATFORM_LUMIN
                    appDefinedVideoSource.TrackType = Type.Video;
                    appDefinedVideoSource.IsLocal   = true;
                    appDefinedVideoSource.gcHandle  = GCHandle.Alloc(appDefinedVideoSource);
                    IntPtr gcHandlePtr = GCHandle.ToIntPtr(appDefinedVideoSource.gcHandle);

                    ulong appDefinedVideoSourceHandle = MagicLeapNativeBindings.InvalidHandle;

                    NativeBindings.MLWebRTCAppDefinedSourceEventCallbacks callbacks = NativeBindings.MLWebRTCAppDefinedSourceEventCallbacks.Create(gcHandlePtr);
                    MLResult.Code resultCode = NativeBindings.MLWebRTCSourceCreateAppDefinedVideoSource(in callbacks, out appDefinedVideoSourceHandle);
                    appDefinedVideoSource.Handle = appDefinedVideoSourceHandle;

                    if (!MLResult.IsOK(resultCode))
                    {
                        appDefinedVideoSource.gcHandle.Free();
                    }

                    return(resultCode);
#else
                    appDefinedVideoSource = null;
                    return(MLResult.Code.Ok);
#endif
                }
                private static MLResult.Code CreateRemoteConnection(MLWebRTC.IceServer[] iceServers, IntPtr proxyConfig, out PeerConnection connection)
                {
#if PLATFORM_LUMIN
                    connection = new PeerConnection();

                    // Converts into native ice server structs
                    MLWebRTCConnectionIceServer[] nativeIceServers = new MLWebRTCConnectionIceServer[iceServers.Length];
                    for (int i = 0; i < iceServers.Length; ++i)
                    {
                        nativeIceServers[i].Data = iceServers[i];
                    }

                    IntPtr arrayPtr = Marshal.AllocHGlobal(Marshal.SizeOf <MLWebRTCConnectionIceServer>() * nativeIceServers.Length);
                    IntPtr walkPtr  = arrayPtr;

                    for (int i = 0; i < nativeIceServers.Length; ++i)
                    {
                        Marshal.StructureToPtr(nativeIceServers[i], walkPtr, false);
                        walkPtr = new IntPtr(walkPtr.ToInt64() + Marshal.SizeOf <MLWebRTCConnectionIceServer>());
                    }

                    NativeBindings.MLWebRTCConnectionConfig config = new NativeBindings.MLWebRTCConnectionConfig();
                    config.IceServers    = arrayPtr;
                    config.NumIceServers = (uint)nativeIceServers.Length;
                    config.ProxyConfig   = proxyConfig;

                    NativeBindings.MLWebRTCConnectionEventCallbacks callbacks = new NativeBindings.MLWebRTCConnectionEventCallbacks();
                    callbacks.OnError                  = NativeBindings.OnError;
                    callbacks.OnConnected              = NativeBindings.OnConnected;
                    callbacks.OnDisconnected           = NativeBindings.OnDisconnected;
                    callbacks.OnLocalOfferCreated      = NativeBindings.OnLocalOfferCreated;
                    callbacks.OnLocalAnswerCreated     = NativeBindings.OnLocalAnswerCreated;
                    callbacks.OnLocalIceCandidateFound = NativeBindings.OnLocalIceCandidateFound;
                    callbacks.OnIceGatheringCompleted  = NativeBindings.OnIceGatheringCompleted;
                    callbacks.OnTrackRemoved           = NativeBindings.OnTrackRemoved;
                    callbacks.OnTrackAdded             = NativeBindings.OnTrackAdded;
                    callbacks.OnDataChannelReceived    = NativeBindings.OnDataChannelReceived;

                    connection.gcHandle = GCHandle.Alloc(connection);
                    IntPtr gcHandlePtr = GCHandle.ToIntPtr(connection.gcHandle);
                    callbacks.Context = gcHandlePtr;

                    ulong connectionHandle = MagicLeapNativeBindings.InvalidHandle;

                    MLResult.Code resultCode = NativeBindings.MLWebRTCConnectionCreate(in config, in callbacks, out connectionHandle);
                    Marshal.FreeHGlobal(arrayPtr);

                    if (!MLResult.IsOK(resultCode))
                    {
                        connection.gcHandle.Free();
                        return(resultCode);
                    }

                    connection.Handle = connectionHandle;
                    return(resultCode);
#else
                    connection = null;
                    return(MLResult.Code.Ok);
#endif
                }
        /// <summary>
        /// Sets the localization status based on if PCFs can currently be found
        /// </summary>
        private void SetLocalizationStatus()
        {
            if (MLPersistentCoordinateFrames.IsValidInstance())
            {
                try
                {
                    MLResult      result     = MLResult.Create(MLResult.Code.Ok);
                    uint          numPCFs    = 0;
                    MLResult.Code resultCode = NativeBindings.MLPersistentCoordinateFrameGetCount(MLPersistentCoordinateFrames._instance.nativeTracker, ref numPCFs);

                    if (!MLResult.IsOK(resultCode))
                    {
                        if (resultCode == MLResult.Code.PassableWorldLowMapQuality || resultCode == MLResult.Code.PassableWorldUnableToLocalize)
                        {
                            MLPluginLog.WarningFormat("Map quality not sufficient enough for MLPersistentCoordinateFrames.SetLocalizationStatus. Reason: {0}", MLResult.CodeToString(resultCode));
                        }
                        else
                        {
                            MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.SetLocalizationStatus failed. Reason: {0}", MLResult.IsOK(resultCode) ? "No PCFs could be found." : MLResult.CodeToString(resultCode));
                        }

                        result = MLResult.Create(resultCode, string.Format("MLPersistentCoordinateFrames.SetLocalizationStatus failed. Reason: {0}", MLResult.IsOK(resultCode) ? "No PCFs could be found." : MLResult.CodeToString(resultCode)));
                    }

                    bool foundPCFs = result.IsOk && numPCFs > 0;
                    if (!MLPersistentCoordinateFrames.IsLocalized && foundPCFs)
                    {
                        MLPersistentCoordinateFrames.IsLocalized = true;
                        MLPersistentCoordinateFrames.OnLocalized?.Invoke(IsLocalized);
                    }
                    else if (MLPersistentCoordinateFrames.IsLocalized && !foundPCFs)
                    {
                        List <PCF> allPCFs = new List <PCF>(MLPersistentCoordinateFrames._instance.mapAllPCFs.Values);

                        MLPersistentCoordinateFrames._instance.mapTrackedPCFs.Clear();
                        MLPersistentCoordinateFrames._instance.mapAllPCFs.Clear();

                        MLPersistentCoordinateFrames.IsLocalized = false;

                        foreach (PCF pcf in allPCFs)
                        {
                            pcf.Update();
                        }

                        MLPersistentCoordinateFrames._instance.mapUpdatedPCFsThisFrame.Clear();
                        MLPersistentCoordinateFrames.OnLocalized?.Invoke(MLPersistentCoordinateFrames.IsLocalized);
                    }
                }
                catch (EntryPointNotFoundException)
                {
                    MLPluginLog.Error("MLPersistentCoordinateFrames.SetLocalizationStatus failed. Reason: API symbols not found.");
                }
            }
            else
            {
                MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.SetLocalizationStatus failed. Reason: No Instance for MLPersistentCoordinateFrames.");
            }
        }
        /// <summary>
        ///     Checks native code results for failure.
        /// </summary>
        /// <param name="resultCode"> The result of the native function call. </param>
        /// <param name="functionName"> The name of the native function. </param>
        /// <param name="successCase">
        ///     Predicate delegate for determining when a call was successful.
        ///     Defaults to a check against <c>MLResult.IsOK(resultCode)</c>.
        /// </param>
        /// <param name="showError">
        ///     Should the default error message be displayed
        ///     if the <c>resultCode</c> is not expected?
        /// </param>
        /// <returns>
        ///     <c>true</c> if the result of <c>successCase</c> matches <c>resultCode</c>.
        ///     <c>false</c> otherwise.
        ///  </returns>
        protected static bool DidNativeCallSucceed(MLResult.Code resultCode, string functionName = "A native function", Predicate <MLResult.Code> successCase = null, bool showError = true)
        {
            bool success = successCase != null?successCase(resultCode) : MLResult.IsOK(resultCode);

            if (!success && showError)
            {
                MLPluginLog.ErrorFormat($"{functionName} in the Magic Leap API failed. Reason: {MLResult.CodeToString(resultCode)} ");
            }

            return(success);
        }
예제 #15
0
        /// <summary>
        /// Request the list of detected found objects.
        /// Callback will never be called while request is still pending.
        /// </summary>
        /// <param name="callback">
        /// Callback used to report query results.
        /// Callback MLResult code will never be <c>MLResult.Code.Pending</c>.
        /// </param>
        /// <returns>
        /// MLResult.Result inside callback will be <c>MLResult.Code.Ok</c> if successful.
        /// MLResult.Result inside callback will be <c>MLResult.Code.InvalidParam</c> if failed due to invalid input parameter.
        /// MLResult.Result inside callback will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error.
        /// </returns>
        public static MLResult GetUniqueObjectLabelsAsync(OnGetUniqueObjectLabelsDelegate callback)
        {
            MLThreadDispatch.ScheduleWork(() =>
            {
                string[] labels;

                MLResult result = MLResult.Create(MLResult.Code.Ok);
                if (MLFoundObjects.IsValidInstance())
                {
                    MLResult.Code resultCode = NativeBindings.MLFoundObjectGetAvailableLabelsCount(_instance.handle, out uint labelCount);

                    result = MLResult.Create(resultCode);
                    labels = new string[labelCount];
                    if (MLResult.IsOK(resultCode))
                    {
                        for (uint i = 0; i < labelCount; ++i)
                        {
                            resultCode = NativeBindings.MLFoundObjectGetUniqueLabel(_instance.handle, i, 20, out string label);

                            if (MLResult.IsOK(resultCode))
                            {
                                labels[i] = label;
                            }
                            else
                            {
                                MLPluginLog.ErrorFormat("MLFoundObjects.GetUniqueObjectLabels failed getting a unique label. Reason: {0}", MLResult.CodeToString(resultCode));
                                result = MLResult.Create(MLResult.Code.UnspecifiedFailure, string.Format("MLFoundObjects.GetUniqueObjectLabels failed getting a unique label. Reason: {0}", MLResult.CodeToString(resultCode)));
                            }
                        }
                    }
                    else
                    {
                        MLPluginLog.ErrorFormat("MLFoundObjects.GetUniqueObjectLabels failed getting the unique label count. Reason: {0}", MLResult.CodeToString(resultCode));
                        result = MLResult.Create(MLResult.Code.UnspecifiedFailure, string.Format("MLFoundObjects.GetUniqueObjectLabels failed getting the unique label count. Reason: {0}", MLResult.CodeToString(resultCode)));
                    }
                }
                else
                {
                    labels = new string[0];
                    MLPluginLog.ErrorFormat("MLFoundObjects.GetUniqueObjectLabelsAsync failed. Reason: No Instance for MLFoundObjects.");
                    result = MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLFoundObjects.GetUniqueObjectLabelsAsync failed. Reason: No Instance for MLFoundObjects");
                }

                MLThreadDispatch.ScheduleMain(() =>
                {
                    callback?.Invoke(result, labels);
                });

                return(true);
            });

            return(MLResult.Create(MLResult.Code.Ok));
        }
            /// <summary>
            /// Queries a profile for a list of attribute values asynchronously.
            /// </summary>
            private void RequestAttributeValuesAsync()
            {
                MLResult.Code resultCode = MLIdentity.NativeBindings.RequestAttributeValuesAsync(this, ref this.attributes);

                if (MLResult.IsOK(resultCode))
                {
                    this.request.RequestState = Request.State.LISTENING_ATTRIB_VALUES;
                }
                else
                {
                    MLPluginLog.WarningFormat("MLIdentity.Profile.RequestAttributeValuesAsync failed request for attribute values async. Reason: {0}", MLResult.CodeToString(resultCode));
                    this.request.RequestState = Request.State.DONE;
                }
            }
예제 #17
0
        /// <summary>
        ///     Instance.settings setter.
        ///     If called with the same value while a settings update operation is in progress,
        ///     nothing will happen.
        /// </summary>
        public static async Task SetSettingsAsync(Settings value)
        {
            if (futureSettingsValue.Equals(value))
            {
                return;
            }

            futureSettingsValue = value;

            if (MLResult.IsOK((await MLBarcodeScannerSettingsUpdate(value)).Result))
            {
                Instance.settings = value;
            }
        }
예제 #18
0
        /// <summary>
        /// Called by MLAPISingleton to start the API
        /// </summary>
        /// <returns>
        /// <para>MLResult.Result will be <c>MLResult.Code.AllocFailed</c> if the registration resource allocation failed.</para>
        /// <para>MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if a given argument is invalid.</para>
        /// <para>MLResult.Result will be <c>MLResult.Code.Ok</c> if successfully initialized.</para>
        /// <para>MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if there was an unexpected failure.</para>
        /// <para>MLResult.Result will be <c>MLResult.Code.ConnectionsAlreadyRegistered</c> if this is a duplicate registration.</para>
        /// <para>MLResult.Result will be <c>MLResult.Code.ConnectionsNetworkFailure</c> if communication to the network failed.</para>
        /// <para>MLResult.Result will be <c>MLResult.Code.ConnectionsSystemFailure</c> if there was system failure.</para>
        /// </returns>
        protected override MLResult StartAPI()
        {
            MLResult.Code resultCode = NativeBindings.MLConnectionsRegistrationStartup(ref _instance.registerHandle);

            if (!MLResult.IsOK(resultCode) || !Native.MagicLeapNativeBindings.MLHandleIsValid(_instance.registerHandle))
            {
                MLResult resultError = MLResult.Create(resultCode);

                MLPluginLog.ErrorFormat("MLConnections.Start failed in StartAPI() to register to receive invites. Handle is invalid or Reason: {0}", resultError);

                return(resultError);
            }

            NativeBindings.InviteCallbacks connectionCallbacks = NativeBindings.InviteCallbacks.Create();

            resultCode = NativeBindings.MLConnectionsRegisterForInvite(_instance.registerHandle, connectionCallbacks, IntPtr.Zero);

            if (!MLResult.IsOK(resultCode))
            {
                MLResult resultError = MLResult.Create(resultCode);

                MLPluginLog.ErrorFormat("MLConnections.Start failed in StartAPI() to set callbacks. Reason: {0}", resultError);

                return(resultError);
            }
            else
            {
                if (_instance.activeRequest)
                {
                    // This check is just precautionary, but it should never happen.
                    MLPluginLog.WarningFormat("MLConnections.Start allowed multiple active registrations.");
                }

                Instance.activeRequest = true;
            }

            resultCode = NativeBindings.MLConnectionsStartup();

            if (!MLResult.IsOK(resultCode))
            {
                MLPluginLog.ErrorFormat("MLConnections.Start failed in StartAPI() to initialize resources for sending an invite. Reason: {0}", MLResult.CodeToString(resultCode));
            }
            else
            {
                _instance.sendInviteHasStarted = true;
            }

            return(MLResult.Create(resultCode));
        }
예제 #19
0
        /// <summary>
        /// Destroys the native Hand Meshing client.
        /// </summary>
        private void DestroyNativeTracker()
        {
            if (!MagicLeapNativeBindings.MLHandleIsValid(this.nativeTracker))
            {
                return;
            }

            MLResult.Code result = NativeBindings.MLHandMeshingDestroyClient(ref this.nativeTracker);
            if (!MLResult.IsOK(result))
            {
                MLPluginLog.ErrorFormat("MLHandMeshing.DestroyNativeTracker failed to destroy native hand tracker. Reason: {0}", result);
            }

            this.nativeTracker = MagicLeapNativeBindings.InvalidHandle;
        }
예제 #20
0
            /// <summary>
            /// Queries for the client credentials of this user.
            /// </summary>
            private void RequestClientCredentialsAsync()
            {
                MLResult.Code resultCode = MLTokenAgent.NativeBindings.RequestClientCredentialsAsync(this);

                if (MLResult.IsOK(resultCode))
                {
                    this.request.ResultCode   = MLResult.Code.Pending;
                    this.request.RequestState = MLTokenAgent.ClientCredentials.Request.State.LISTENING_CREDENTIALS;
                }
                else
                {
                    this.request.ResultCode   = resultCode;
                    this.request.RequestState = MLTokenAgent.ClientCredentials.Request.State.DONE;
                }
            }
            /// <summary>
            /// Listens for a list of attribute values previously requested by RequestAttributeValuesAsync.
            /// </summary>
            private void ListenAttributeValuesResponse()
            {
                MLResult.Code resultCode = MLIdentity.NativeBindings.ListenAttributeValuesResponse(this, ref this.attributes);
                if (MLResult.IsOK(resultCode))
                {
                    this.request.RequestState = Request.State.DONE;
                }
                else if (!MLResult.IsPending(resultCode))
                {
                    MLPluginLog.ErrorFormat("MLIdentity.Profile.ListenAttributeValuesResponse failed to retrieve attribute values. Reason: {0}", resultCode);
                    this.request.RequestState = Request.State.DONE;
                }

                this.request.ResultCode = resultCode;
            }
예제 #22
0
            /// <summary>
            /// Listens for client credentials previously requested by RequestClientCredentialsAsync.
            /// </summary>
            private void ListenClientCredentialsResponse()
            {
                MLResult.Code resultCode = MLTokenAgent.NativeBindings.ListenClientCredentialsResponse(this, ref this.credentials, ref this.tokens);

                if (MLResult.IsOK(resultCode))
                {
                    this.request.RequestState = Request.State.DONE;
                }
                else if (!MLResult.IsPending(resultCode))
                {
                    MLPluginLog.ErrorFormat("MLIdentity.clientCredentials.ListenAttributeNamesResponse failed to retrieve attribute names. Reason: {0}", resultCode);
                    this.request.RequestState = Request.State.DONE;
                }

                this.request.ResultCode = resultCode;
            }
예제 #23
0
        /// <summary>
        /// Updates the settings of the found objects tracker.
        /// </summary>
        /// <param name="newSettings">The new settings to update the found objects tracker with.</param>
        /// <param name="callback">The callback to invoke when the settings have been updated or failed doing so.</param>
        /// <returns>
        /// MLResult.Result inside callback will be <c>MLResult.Code.Ok</c> if successful.
        /// MLResult.Result inside callback will be <c>MLResult.Code.InvalidParam</c> if failed due to invalid input parameter.
        /// MLResult.Result inside callback will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error.
        /// </returns>
        public static MLResult UpdateSettingsAsync(Settings newSettings, OnUpdateSettingsDelegate callback = null)
        {
            MLResult result = MLResult.Create(MLResult.Code.Ok);

            MLThreadDispatch.ScheduleWork(() =>
            {
                if (MLFoundObjects.IsValidInstance())
                {
                    NativeBindings.Settings settingsNative = new NativeBindings.Settings();
                    settingsNative.Data = newSettings;

                    MLResult.Code resultCode = NativeBindings.MLFoundObjectTrackerUpdateSettings(_instance.handle, in settingsNative);

                    if (MLResult.IsOK(resultCode))
                    {
                        MLThreadDispatch.ScheduleMain(() =>
                        {
                            result             = MLResult.Create(resultCode);
                            _instance.settings = newSettings;
                            callback?.Invoke(result, _instance.settings);
                        });
                    }
                    else
                    {
                        MLPluginLog.ErrorFormat("MLFoundObjects.UpdateSettingsAsync failed to update settings. Reason: {0}", MLResult.CodeToString(resultCode));
                        result = MLResult.Create(MLResult.Code.UnspecifiedFailure, string.Format("MLFoundObjects.UpdateSettingsAsync failed to update settings. Reason: {0}", MLResult.CodeToString(resultCode)));
                        MLThreadDispatch.ScheduleMain(() =>
                        {
                            callback?.Invoke(result, _instance.settings);
                        });
                    }
                }
                else
                {
                    MLPluginLog.ErrorFormat("MLFoundObjects.GetObjects failed. Reason: No Instance for MLFoundObjects");
                    result = MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLFoundObjects.GetFoundObjects failed. Reason: No Instance for MLFoundObjects");
                    MLThreadDispatch.ScheduleMain(() =>
                    {
                        callback?.Invoke(result, _instance.settings);
                    });
                }

                return(true);
            });
            return(result);
        }
                /// <summary>
                /// Creates an initialized Track object.
                /// Recommended to use app defined video sources in production, with sample sources provided
                /// as MLCameraVideoSource and MLMRCameraVideoSource in the UnityEngine.XR.MagicLeap namespace
                /// since those sources provide more information about and control over various error cases and
                /// handle special cases like app pause/resume and device standby/reality/active.
                /// </summary>
                /// <param name="videoType">The type of video source to use.</param>
                /// <param name="result">The MLResult object of the inner platform call(s).</param>
                /// <param name="inputContext">The InputContext object to start the MLMRCamera API with.</param>
                /// <returns> An initialized Track object.</returns>
                public static Track CreateVideoTrack(VideoType videoType, out MLResult result, MLMRCamera.InputContext?inputContext = null, string trackId = "")
                {
                    Track track  = null;
                    ulong handle = MagicLeapNativeBindings.InvalidHandle;

                    MLResult.Code resultCode = MLResult.Code.Ok;

                    switch (videoType)
                    {
                    case VideoType.MLCamera:
                    {
                        resultCode = Source.NativeBindings.MLWebRTCSourceCreateLocalSourceForCamera(out handle);
                        DidNativeCallSucceed(resultCode, "MLWebRTCSourceCreateLocalSourceForCamera");
                        break;
                    }

                    case VideoType.MLMRCamera:
                    {
                        MLMRCamera.NativeBindings.InputContextNative inputContextNative = new MLMRCamera.NativeBindings.InputContextNative
                        {
                            Data = inputContext ?? MLMRCamera.InputContext.Create()
                        };
                        resultCode = Source.NativeBindings.MLWebRTCSourceCreateLocalSourceForMRCamera(in inputContextNative, out handle);
                        DidNativeCallSucceed(resultCode, "MLWebRTCSourceCreateLocalSourceForMRCamera");
                        break;
                    }
                    }

                    if (!MLResult.IsOK(resultCode))
                    {
                        result = MLResult.Create(resultCode);
                        return(track);
                    }

                    track = new Track(trackId)
                    {
                        Handle    = handle,
                        TrackType = Type.Video,
                        IsLocal   = true,
                    };

                    MLWebRTC.Instance.localTracks.Add(track);
                    result = MLResult.Create(resultCode);
                    return(track);
                }
예제 #25
0
        /// <summary>
        /// Create a new found object native tracker.
        /// </summary>
        /// <returns>
        /// MLResult.Result will be <c>MLResult.Code.Ok</c> if successful.
        /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to internal error.
        /// </returns>
        private MLResult CreateTracker()
        {
            try
            {
                MLResult.Code resultCode = NativeBindings.MLFoundObjectTrackerCreate(out _instance.handle);
                if (!MLResult.IsOK(resultCode))
                {
                    MLPluginLog.ErrorFormat("MLFoundObjects.CreateTracker failed to initialize native tracker. Reason: {0}", resultCode);
                }

                return(MLResult.Create(resultCode));
            }
            catch (System.EntryPointNotFoundException)
            {
                MLPluginLog.Error("MLFoundObjects.CreateTracker failed. Reason: API symbols not found");
                return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLFoundObjects.CreateTracker failed. Reason: API symbols not found"));
            }
        }
            /// <summary>
            /// Queries a profile for a list of attribute names asynchronously.
            /// </summary>
            private void RequestAttributeNamesAsync()
            {
                MLResult.Code resultCode = MLIdentity.NativeBindings.RequestAttributeNamesAsync(this, this.requestAttributes, ref this.attributes);

                if (MLResult.IsOK(resultCode))
                {
                    this.request.ResultCode   = MLResult.Code.Pending;
                    this.request.RequestState = (this.requestAttributes != null && this.requestAttributes.Length > 0) ?
                                                MLIdentity.Profile.Request.State.REQUEST_ATTRIB_VALUES :
                                                MLIdentity.Profile.Request.State.LISTENING_ATTRIB_NAMES;
                }
                else
                {
                    MLPluginLog.WarningFormat("MLIdentity.Profile.RequestAttributeNamesAsync failed request for attribute names async. Reason: {0}", MLResult.CodeToString(resultCode));
                    this.request.ResultCode   = resultCode;
                    this.request.RequestState = MLIdentity.Profile.Request.State.DONE;
                }
            }
예제 #27
0
            /// <summary>
            /// Updates the tracking status of the PCF based on the current and last MLResult
            /// received when querying for the PCF's pose.
            /// </summary>
            /// <param name="oldCode">The MLResult from the previous pose query.</param>
            /// <param name="newCode">The MLResult from the current pose query.</param>

            /* -----------------------------------------
             * OldCode                                   | NewCode | Event
             * ------------------------------------------|---------|---------------
             * Pending                                   | Ok      | Create
             * !Ok & !Pending                            | Ok      | Regain
             * Ok & (poseChanged || stateChanged)        | Ok      | Update
             * Ok & !(poseChanged || stateChanged)       | Ok      | Stable
             * Ok                                        | !Ok     | Lost
             * ----------------------------------------- */
            private void OnCurrentResultChanged(MLResult.Code oldCode, MLResult.Code newCode)
            {
                if (MLResult.IsOK(newCode))
                {
                    if (oldCode == MLResult.Code.Pending)
                    {
                        this.UpdateStatus(Status.Created);
                    }
                    else if (!MLResult.IsOK(oldCode))
                    {
                        foreach (IBinding binding in this.bindings)
                        {
                            binding.Regain();
                        }

                        this.UpdateStatus(Status.Regained);
                    }
                    else if (this.poseChanged || this.stateChanged)
                    {
                        foreach (IBinding binding in this.bindings)
                        {
                            binding.Update();
                        }

                        this.UpdateStatus(Status.Updated);

                        this.poseChanged  = false;
                        this.stateChanged = false;
                    }
                    else
                    {
                        this.UpdateStatus(Status.Stable);
                    }
                }
                else
                {
                    foreach (IBinding binding in this.bindings)
                    {
                        binding.Lost();
                    }

                    this.UpdateStatus(Status.Lost);
                }
            }
예제 #28
0
        /// <summary>
        /// Starts the Persistent Coordinate Frames API.
        /// Initializes the PCF tracker.
        /// </summary>
        /// <returns>
        /// MLResult.Result will be <c>MLResult.Code.Ok</c> if the PCF tracker could be created successfully.
        /// MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if the tracker to initialize was null.
        /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if there were any missing privileges.
        /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if failed due to an internal error.
        /// </returns>
        protected override MLResult StartAPI()
        {
            try
            {
                MLResult.Code resultCode = NativeBindings.MLPersistentCoordinateFrameTrackerCreate(ref _instance.nativeTracker);
                if (!MLResult.IsOK(resultCode))
                {
                    MLPluginLog.ErrorFormat("MLPersistentCoordinateFrames.StartAPI failed to create PCF tracker. Reason: {0}", MLResult.CodeToString(resultCode));
                    return(MLResult.Create(resultCode, "MLPersistentCoordinateFrames.StartAPI failed to create PCF tracker."));
                }

                return(MLResult.Create(resultCode));
            }
            catch (EntryPointNotFoundException)
            {
                MLPluginLog.Error("MLPersistentCoordinateFrames.StartAPI failed. Reason: API symbols not found.");
                return(MLResult.Create(MLResult.Code.UnspecifiedFailure, "MLPersistentCoordinateFrames.StartAPI failed. Reason: API symbols not found."));
            }
        }
            /// <summary>
            /// Having made a call to MLTokenAgentGetClientCredentialsAsync(), the user can call MLTokenAgentGetClientCredentialsWait()
            /// to detect whether the asynchronous call completed and if so, to retrieve the credentials in out_credentials.
            /// </summary>
            /// <param name="clientCredentials">Reference to the clientCredentials object.</param>
            /// <param name="credentials">Reference to the credentials struct of the clientCredentials object.</param>
            /// <param name="tokens">Reference to the tokens struct of the clientCredentials object.</param>
            /// <returns>
            /// MLResult.Result will be <c>MLResult.Code.Ok</c> if the operation completed successfully before the timeout elapsed.
            /// MLResult.Result will be <c>MLResult.Code.Pending</c> if the timeout elapsed before the asynchronous call completed.
            /// MLResult.Result will be <c>MLResult.Code.UnspecifiedFailure</c> if the operation failed with an unspecified error.
            /// MLResult.Result will be <c>MLResult.Code.InvalidParam</c> if the future or out_credentials were 0 (null).
            /// MLResult.Result will be <c>MLResult.Code.AllocFailed</c> if the operation failed to allocate memory.
            /// MLResult.Result will be <c>MLResult.Code.PrivilegeDenied</c> if the caller does not have the ClientCredentialsRead privilege.
            /// MLResult.Result will be <c>MLResult.Code.TokenAgent*</c> if a token specific failure occurred during the operation.
            /// </returns>
            public static MLResult.Code ListenClientCredentialsResponse(MLTokenAgent.ClientCredentials clientCredentials, ref MLTokenAgent.Credentials credentials, ref MLTokenAgent.Tokens tokens)
            {
                try
                {
                    IntPtr clientCredentialsPtr       = clientCredentialsPtrMap.ContainsKey(clientCredentials) ? clientCredentialsPtrMap[clientCredentials] : IntPtr.Zero;
                    IntPtr clientCredentialsFuturePtr = clientCredentialsFuturePtrMap.ContainsKey(clientCredentials) ? clientCredentialsFuturePtrMap[clientCredentials] : IntPtr.Zero;

                    if (clientCredentialsFuturePtr == IntPtr.Zero)
                    {
                        MLPluginLog.Warning("MLTokenAgent.NativeBindings.ListenClientCredentialsResponse failed because a valid future pointer could not be found with the passed request.");
                        return(MLResult.Code.UnspecifiedFailure);
                    }

                    //// Attempt to get data if available, 0 is passed as a timeout to immediately return and never wait for results.
                    MLResult.Code resultCode = MLTokenAgent.NativeBindings.MLTokenAgentGetClientCredentialsWait(clientCredentialsFuturePtr, 0, ref clientCredentialsPtr);

                    // If it succeeded, copy any modifications made to the profile in unmanaged memory by the Identity API to managed memory.
                    if (MLResult.IsOK(resultCode))
                    {
                        clientCredentialsFuturePtrMap.Remove(clientCredentials);

                        clientCredentialsPtrMap.Remove(clientCredentials);
                        clientCredentialsPtrMap.Add(clientCredentials, clientCredentialsPtr);

                        MLTokenAgent.NativeBindings.ClientCredentialsNative clientCredentialsNative = (MLTokenAgent.NativeBindings.ClientCredentialsNative)Marshal.PtrToStructure(clientCredentialsPtr, typeof(MLTokenAgent.NativeBindings.ClientCredentialsNative));
                        credentials = clientCredentialsNative.Credentials;
                        tokens      = clientCredentials.Tokens;
                    }
                    else
                    {
                        credentials = new Credentials();
                        tokens      = new Tokens();
                    }

                    return(resultCode);
                }
                catch (EntryPointNotFoundException)
                {
                    MLPluginLog.Error("MLTokenAgent.NativeBindings.ListenClientCredentialsResponse failed. Reason: API symbols not found.");
                    return(MLResult.Code.UnspecifiedFailure);
                }
            }
            /// <summary>
            /// Handles when a request queries the attribute names.
            /// </summary>
            public void ProcessRequest()
            {
                if (this.request == null)
                {
                    return;
                }

                switch (this.request.RequestState)
                {
                case Request.State.REQUEST_ATTRIB_NAMES:
                    this.RequestAttributeNamesAsync();
                    break;

                case Request.State.LISTENING_ATTRIB_NAMES:
                    this.ListenAttributeNamesResponse();
                    break;

                case Request.State.REQUEST_ATTRIB_VALUES:
                    this.RequestAttributeValuesAsync();
                    break;

                case Request.State.LISTENING_ATTRIB_VALUES:
                    this.ListenAttributeValuesResponse();
                    break;

                case Request.State.DONE:
                    this.request?.Callback?.Invoke(MLResult.Create(this.request.ResultCode));

                    //// Removes the profile if something when wrong with the request.
                    if (!MLResult.IsOK(this.request.ResultCode))
                    {
                        this.request = null;
                        MLIdentity.RemoveProfile(this);
                    }

                    this.request = null;
                    break;

                default:
                    break;
                }
            }