// %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);
}
}
}