// %BANNER_BEGIN% // --------------------------------------------------------------------- // %COPYRIGHT_BEGIN% // Copyright (c) (2018-2022) Magic Leap, Inc. All Rights Reserved. // Use of this file is governed by the Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2 // Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein. // %COPYRIGHT_END% // --------------------------------------------------------------------- // %BANNER_END% // Disabling deprecated warning for the internal project #pragma warning disable 618 namespace UnityEngine.XR.MagicLeap { using UnityEngine; using System.Collections.Generic; /// /// APIs for the voice service system. /// /// To use the voice feature (with a specific application's intent list), the application should send /// a Scriptable Object called MLVoiceIntentsConfiguration, Located under Assets/Magic Leap/Voice Intents Configuration, /// with the application's voice intents data to MLVoice.SetupVoiceIntents(). /// /// Name, id, and value should be unique. Value is the phrase needed to be spoken out loud after "Hey Magic Leap" /// " | " may be used in the configuration file's value field to indicate multiple values tied to the same name and id. /// public partial class MLVoice : MLAutoAPISingleton { /// /// Voice state in voice event. /// public enum State { /// /// Intent hotword detected, Automatic Speech Recognition (ASR) session is going to start. /// HotwordDetected, /// /// Voice UI is stopped, ASR session is going to stop. /// SessionEnded, /// /// ASR session is stopped due to abort. /// ISessionEndedAborted, /// /// ASR session is stopped without detecting an intent. /// SessionEndedNoIntent, /// /// ASR session is stopped due to timeout. /// SessionEndedTimeout, /// /// ASR session is stopped due to error. /// SessionEndedError, /// /// Intent mode is started and ready. /// Ready, /// /// Intent mode is stopped and not available. /// NotAvailable }; /// /// No intent reason code in voice event. /// public enum NoIntentReason { /// /// In case of success /// NoReason, /// /// When the State in IntentEvent is either MLVoice.State.SessionEndedTimeout or MLVoice.State.SessionEndedError. /// Silence, /// /// When the State in IntentEvent is MLVoice.State.SessionEndedNoIntent. /// NoMatch }; /// /// Slot Data in voice event. /// public struct EventSlot { /// /// Name of slot used. /// public string SlotName; /// /// Value of the specific slot used. /// public string SlotValue; public EventSlot(string name, string value) { this.SlotName = name; this.SlotValue = value; } } /// /// A structure containing voice intent event information. /// public struct IntentEvent { /// /// Voice state when generating the voice intent event. /// public State State; /// /// If intent is not detected, it contains the reason, /// otherwise the value is MLVoiceIntentNoIntentReason.NoReason. /// public NoIntentReason NoIntentReason; /// /// The Event Name /// public string EventName; /// /// User defined intent index which is detected. /// public uint EventID; // /// List of Slot Data used in this specific event. /// public List EventSlotsUsed; }; /// /// This callback will be invoked whenever a voice intent event is detected. /// /// /// Voice event handling result. In case of false, voiceEvent member variables should be ignored. (voiceEvent.EventName will be NULL) /// Voice intent event. public delegate void OnVoiceEventDelegate(in bool wasSuccessful, in IntentEvent voiceEvent); /// /// Event invoked for when a data channel opens. /// public static event OnVoiceEventDelegate OnVoiceEvent { add { OnVoiceEventInternal += value; } remove { OnVoiceEventInternal -= value; } } private static event OnVoiceEventDelegate OnVoiceEventInternal = delegate { }; /// /// Checks voice intent feature is enabled in the system. /// public static bool VoiceEnabled => Instance.isEnabled(); protected override MLResult.Code StartAPI() { if (!MLResult.DidNativeCallSucceed(MLPermissions.CheckPermission(MLPermission.VoiceInput).Result, nameof(StartAPI))) { MLPluginLog.Error($"{nameof(MLVoice)} requires missing permission {MLPermission.VoiceInput}"); return MLResult.Code.PermissionDenied; } var resultCode = MLVoice.NativeBindings.MLVoiceIntentCreate(out this.Handle); MLResult.DidNativeCallSucceed(resultCode, nameof(MLVoice.NativeBindings.MLVoiceIntentCreate)); return resultCode; } protected override MLResult.Code StopAPI() { Stop(); var result = MLVoice.NativeBindings.MLVoiceIntentDestroy(this.Handle); if (MLResult.IsOK(result)) { this.Handle = Native.MagicLeapNativeBindings.InvalidHandle; } return result; } /// /// Configures Settings sent, Sets the callbacks for voice intent events, and starts processing. /// /// Max Voice Intents Supported: 100 /// /// MLVoiceIntentsConfiguration scriptable object that contains the App Intents data. /// Memory of this variable is managed by user. /// /// /// MLResult.Result will be MLResult.Code.InvalidParam if failed due to an invalid param. /// MLResult.Result will be MLResult.Code.Ok if Successfully set settings, callbacks, and starts processing. /// MLResult.Result will be MLResult.Code.MLVoiceResult_IntentDisabled if failed to set the callbacks or settings because required voice intent feature is disabled in system settings. /// MLResult.Result will be MLResult.Code.UnspecifiedFailure if the operation failed with an unspecified error. /// public static MLResult SetupVoiceIntents(MLVoiceIntentsConfiguration voiceConfiguration) { string JSONString = voiceConfiguration.GetJSONString(); MLResult result = MLResult.Create(Instance.ConfigureSettings(JSONString)); if (!result.IsOk) { MLPluginLog.Error("MLVoice failed to ConfigureSettings: " + result); return result; } result = MLResult.Create(Instance.SetCallbacks(false)); if (!result.IsOk) { MLPluginLog.Error("MLVoice failed to SetCallbacks: " + result); return result; } var resultCode = NativeBindings.MLVoiceIntentStartProcessing(Instance.Handle); if (!MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLVoiceIntentStartProcessing))) { MLPluginLog.Error("MLVoice failed to StartProcessing: " + result); } return result; } /// /// Configures Settings sent, Sets the callbacks for voice intent events, and starts processing. /// /// When providing a string instead of the MLVoiceIntentsConfiguration Scriptable Object no /// validation is done to confirm proper format. /// /// Max Voice Intents Supported: 100 /// /// The JSON file with the voice intents data in the proper format. /// /// /// MLResult.Result will be MLResult.Code.InvalidParam if failed due to an invalid param. /// MLResult.Result will be MLResult.Code.Ok if Successfully set settings, callbacks, and starts processing. /// MLResult.Result will be MLResult.Code.MLVoiceResult_IntentDisabled if failed to set the callbacks or settings because required voice intent feature is disabled in system settings. /// MLResult.Result will be MLResult.Code.UnspecifiedFailure if the operation failed with an unspecified error. /// public static MLResult SetupVoiceIntents(string JSONString) { MLResult result = MLResult.Create(Instance.ConfigureSettings(JSONString)); if (!result.IsOk) { MLPluginLog.Error("MLVoice failed to ConfigureSettings: " + result); return result; } result = MLResult.Create(Instance.SetCallbacks(false)); if (!result.IsOk) { MLPluginLog.Error("MLVoice failed to SetCallbacks: " + result); return result; } var resultCode = NativeBindings.MLVoiceIntentStartProcessing(Instance.Handle); if (!MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLVoiceIntentStartProcessing))) { MLPluginLog.Error("MLVoice failed to StartProcessing: " + result); } return result; } /// /// Stop unsets callbacks and stops processing. This is not necessary for shutdown. /// This is only needed if a user wants to stop processing at runtime after call MLVoice.SetupVoiceIntents. /// MLVoice can be restarted by calling MLVoice.SetupVoiceIntents. /// /// /// MLResult.Result will be MLResult.Code.InvalidParam if failed due to an invalid param. /// MLResult.Result will be MLResult.Code.Ok if Successfully unset callbacks and stops processing. /// MLResult.Result will be MLResult.Code.MLVoiceResult_IntentDisabled if failed because required voice intent feature is disabled in system settings. /// MLResult.Result will be MLResult.Code.UnspecifiedFailure if the operation failed with an unspecified error. /// public static MLResult Stop() { MLResult.Code resultCode = MLResult.Code.Ok; if (Instance.Handle != Native.MagicLeapNativeBindings.InvalidHandle) { MLResult result = MLResult.Create(Instance.SetCallbacks(true)); if (!MLResult.IsOK(result.Result)) { MLPluginLog.Error("MLVoice.Stop failed to unregister MLVoiceIntentSetCallbacks: " + result); } resultCode = NativeBindings.MLVoiceIntentStopProcessing(Instance.Handle); if (!MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLVoiceIntentStopProcessing))) { MLPluginLog.Error("MLVoice.Stop failed to MLVoiceIntentStopProcessing: " + result); } } return MLResult.Create(resultCode); } } }