123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- using System;
- using System.Globalization;
- using Meta.Voice;
- using Meta.WitAi;
- using Meta.WitAi.Configuration;
- using Meta.WitAi.Data;
- using Meta.WitAi.Data.Configuration;
- using Meta.WitAi.Interfaces;
- using Meta.WitAi.Json;
- using Meta.WitAi.Requests;
- using Oculus.Voice.Bindings.Android;
- using Oculus.Voice.Core.Bindings.Android.PlatformLogger;
- using Oculus.Voice.Core.Bindings.Interfaces;
- using Oculus.Voice.Interfaces;
- using Oculus.VoiceSDK.Utilities;
- using UnityEngine;
- namespace Oculus.Voice
- {
- [HelpURL("https://developer.oculus.com/experimental/voice-sdk/tutorial-overview/")]
- public class AppVoiceExperience : VoiceService, IWitRuntimeConfigProvider, IWitConfigurationProvider
- {
- [SerializeField] private WitRuntimeConfiguration witRuntimeConfiguration;
- [Tooltip("Uses platform services to access wit.ai instead of accessing wit directly from within the application.")]
- [SerializeField] private bool usePlatformServices;
- [Tooltip("Enables logs related to the interaction to be displayed on console")]
- [SerializeField] private bool enableConsoleLogging;
- public WitRuntimeConfiguration RuntimeConfiguration
- {
- get => witRuntimeConfiguration;
- set => witRuntimeConfiguration = value;
- }
- public WitConfiguration Configuration => witRuntimeConfiguration?.witConfiguration;
- private IPlatformVoiceService platformService;
- private IVoiceService voiceServiceImpl;
- private IVoiceSDKLogger voiceSDKLoggerImpl;
- #if UNITY_ANDROID && !UNITY_EDITOR
-
- private readonly string PACKAGE_VERSION = "54.0.0.135.284";
- #endif
- private bool Initialized => null != voiceServiceImpl;
- public event Action OnInitialized;
- #region Voice Service Properties
- public override bool Active => base.Active || (null != voiceServiceImpl && voiceServiceImpl.Active);
- public override bool IsRequestActive => base.IsRequestActive || (null != voiceServiceImpl && voiceServiceImpl.IsRequestActive);
- public override ITranscriptionProvider TranscriptionProvider
- {
- get => voiceServiceImpl?.TranscriptionProvider;
- set
- {
- if (voiceServiceImpl != null)
- {
- voiceServiceImpl.TranscriptionProvider = value;
- }
- }
- }
- public override bool MicActive => null != voiceServiceImpl && voiceServiceImpl.MicActive;
- protected override bool ShouldSendMicData => witRuntimeConfiguration.sendAudioToWit ||
- null == TranscriptionProvider;
- #endregion
- #if UNITY_ANDROID && !UNITY_EDITOR
- public bool HasPlatformIntegrations => usePlatformServices && voiceServiceImpl is VoiceSDKImpl;
- #else
- public bool HasPlatformIntegrations => false;
- #endif
- public bool EnableConsoleLogging => enableConsoleLogging;
- public bool UsePlatformIntegrations
- {
- get => usePlatformServices;
- set
- {
-
-
- if (usePlatformServices != value || HasPlatformIntegrations != value)
- {
- usePlatformServices = value;
- #if UNITY_ANDROID && !UNITY_EDITOR
- Debug.Log($"{(usePlatformServices ? "Enabling" : "Disabling")} platform integration.");
- InitVoiceSDK();
- #endif
- }
- }
- }
- #region Voice Service Text Methods
- public override bool CanSend()
- {
- return base.CanSend() && voiceServiceImpl.CanSend();
- }
- public override VoiceServiceRequest Activate(string text, WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
- {
- if (CanSend())
- {
- voiceSDKLoggerImpl.LogInteractionStart(requestOptions.RequestId, "message");
- LogRequestConfig();
- return voiceServiceImpl.Activate(text, requestOptions, requestEvents);
- }
- return null;
- }
- #endregion
- #region Voice Service Audio Methods
- public override bool CanActivateAudio()
- {
- return base.CanActivateAudio() && voiceServiceImpl.CanActivateAudio();
- }
- protected override string GetActivateAudioError()
- {
- if (!HasPlatformIntegrations && !AudioBuffer.Instance.IsInputAvailable)
- {
- return "No Microphone(s)/recording devices found. You will be unable to capture audio on this device.";
- }
- return string.Empty;
- }
- public override VoiceServiceRequest Activate(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
- {
- if (CanActivateAudio() && CanSend())
- {
- voiceSDKLoggerImpl.LogInteractionStart(requestOptions.RequestId, "speech");
- LogRequestConfig();
- return voiceServiceImpl.Activate(requestOptions, requestEvents);
- }
- return null;
- }
- public override VoiceServiceRequest ActivateImmediately(WitRequestOptions requestOptions, VoiceServiceRequestEvents requestEvents)
- {
- if (CanActivateAudio() && CanSend())
- {
- voiceSDKLoggerImpl.LogInteractionStart(requestOptions.RequestId, "speech");
- LogRequestConfig();
- return voiceServiceImpl.ActivateImmediately(requestOptions, requestEvents);
- }
- return null;
- }
- public override void Deactivate()
- {
- voiceServiceImpl.Deactivate();
- }
- public override void DeactivateAndAbortRequest()
- {
- voiceServiceImpl.DeactivateAndAbortRequest();
- }
- #endregion
- private void InitVoiceSDK()
- {
-
- if (!UsePlatformIntegrations)
- {
- if (voiceServiceImpl is VoiceSDKImpl)
- {
- ((VoiceSDKImpl) voiceServiceImpl).Disconnect();
- }
- if (voiceSDKLoggerImpl is VoiceSDKPlatformLoggerImpl)
- {
- try
- {
- ((VoiceSDKPlatformLoggerImpl)voiceSDKLoggerImpl).Disconnect();
- }
- catch (Exception e)
- {
- VLog.E($"Disconnection error: {e.Message}");
- }
- }
- }
- #if UNITY_ANDROID && !UNITY_EDITOR
- var loggerImpl = new VoiceSDKPlatformLoggerImpl();
- loggerImpl.Connect(PACKAGE_VERSION);
- voiceSDKLoggerImpl = loggerImpl;
- if (UsePlatformIntegrations)
- {
- Debug.Log("Checking platform capabilities...");
- var platformImpl = new VoiceSDKImpl(this);
- platformImpl.OnServiceNotAvailableEvent += () => RevertToWitUnity();
- platformImpl.Connect(PACKAGE_VERSION);
- platformImpl.SetRuntimeConfiguration(RuntimeConfiguration);
- if (platformImpl.PlatformSupportsWit)
- {
- voiceServiceImpl = platformImpl;
- if (voiceServiceImpl is Wit wit)
- {
- wit.RuntimeConfiguration = witRuntimeConfiguration;
- }
- voiceServiceImpl.VoiceEvents = VoiceEvents;
- voiceServiceImpl.TelemetryEvents = TelemetryEvents;
- voiceSDKLoggerImpl.IsUsingPlatformIntegration = true;
- }
- else
- {
- Debug.Log("Platform registration indicated platform support is not currently available.");
- RevertToWitUnity();
- }
- }
- else
- {
- RevertToWitUnity();
- }
- #else
- voiceSDKLoggerImpl = new VoiceSDKConsoleLoggerImpl();
- RevertToWitUnity();
- #endif
- voiceSDKLoggerImpl.WitApplication = RuntimeConfiguration?.witConfiguration?.GetLoggerAppId();
- voiceSDKLoggerImpl.ShouldLogToConsole = EnableConsoleLogging;
- OnInitialized?.Invoke();
- }
- private void RevertToWitUnity()
- {
- Wit w = GetComponent<Wit>();
- if (null == w)
- {
- w = gameObject.AddComponent<Wit>();
- w.hideFlags = HideFlags.HideInInspector;
- }
- voiceServiceImpl = w;
- if (voiceServiceImpl is Wit wit)
- {
- wit.RuntimeConfiguration = witRuntimeConfiguration;
- }
- voiceServiceImpl.VoiceEvents = VoiceEvents;
- voiceServiceImpl.TelemetryEvents = TelemetryEvents;
- voiceSDKLoggerImpl.IsUsingPlatformIntegration = false;
- }
- protected override void OnEnable()
- {
- base.OnEnable();
- if (MicPermissionsManager.HasMicPermission())
- {
- InitVoiceSDK();
- }
- else
- {
- MicPermissionsManager.RequestMicPermission();
- }
- #if UNITY_ANDROID && !UNITY_EDITOR
- platformService?.SetRuntimeConfiguration(witRuntimeConfiguration);
- #endif
-
- VoiceEvents.OnResponse?.AddListener(OnWitResponseListener);
- VoiceEvents.OnStartListening?.AddListener(OnStartedListening);
- VoiceEvents.OnMinimumWakeThresholdHit?.AddListener(OnMinimumWakeThresholdHit);
- VoiceEvents.OnStoppedListening?.AddListener(OnStoppedListening);
- VoiceEvents.OnMicDataSent?.AddListener(OnMicDataSent);
- VoiceEvents.OnSend?.AddListener(OnSend);
- VoiceEvents.OnPartialTranscription?.AddListener(OnPartialTranscription);
- VoiceEvents.OnFullTranscription?.AddListener(OnFullTranscription);
- VoiceEvents.OnStoppedListeningDueToTimeout?.AddListener(OnStoppedListeningDueToTimeout);
- VoiceEvents.OnStoppedListeningDueToInactivity?.AddListener(OnStoppedListeningDueToInactivity);
- VoiceEvents.OnStoppedListeningDueToDeactivation?.AddListener(OnStoppedListeningDueToDeactivation);
- VoiceEvents.OnComplete?.AddListener(OnRequestComplete);
- TelemetryEvents.OnAudioTrackerFinished?.AddListener(OnAudioDurationTrackerFinished);
- }
- protected override void OnDisable()
- {
- base.OnDisable();
- #if UNITY_ANDROID
- if (voiceServiceImpl is VoiceSDKImpl platformImpl)
- {
- platformImpl.Disconnect();
- }
- if (voiceSDKLoggerImpl is VoiceSDKPlatformLoggerImpl loggerImpl)
- {
- loggerImpl.Disconnect();
- }
- #endif
- voiceServiceImpl = null;
- voiceSDKLoggerImpl = null;
-
- VoiceEvents.OnResponse?.RemoveListener(OnWitResponseListener);
- VoiceEvents.OnStartListening?.RemoveListener(OnStartedListening);
- VoiceEvents.OnMinimumWakeThresholdHit?.RemoveListener(OnMinimumWakeThresholdHit);
- VoiceEvents.OnStoppedListening?.RemoveListener(OnStoppedListening);
- VoiceEvents.OnMicDataSent?.RemoveListener(OnMicDataSent);
- VoiceEvents.OnSend?.RemoveListener(OnSend);
- VoiceEvents.OnPartialTranscription?.RemoveListener(OnPartialTranscription);
- VoiceEvents.OnFullTranscription?.RemoveListener(OnFullTranscription);
- VoiceEvents.OnStoppedListeningDueToTimeout?.RemoveListener(OnStoppedListeningDueToTimeout);
- VoiceEvents.OnStoppedListeningDueToInactivity?.RemoveListener(OnStoppedListeningDueToInactivity);
- VoiceEvents.OnStoppedListeningDueToDeactivation?.RemoveListener(OnStoppedListeningDueToDeactivation);
- VoiceEvents.OnComplete?.RemoveListener(OnRequestComplete);
- TelemetryEvents.OnAudioTrackerFinished?.RemoveListener(OnAudioDurationTrackerFinished);
- }
- private void OnApplicationFocus(bool hasFocus)
- {
- if (enabled && hasFocus && !Initialized)
- {
- if (MicPermissionsManager.HasMicPermission())
- {
- InitVoiceSDK();
- }
- }
- }
- #region Event listeners for logging
- void OnWitResponseListener(WitResponseNode witResponseNode)
- {
- var tokens = witResponseNode?["speech"]?["tokens"];
- if (tokens != null)
- {
- int speechTokensLength = tokens.Count;
- string speechLength = witResponseNode["speech"]["tokens"][speechTokensLength - 1]?["end"]?.Value;
- voiceSDKLoggerImpl.LogAnnotation("audioLength", speechLength);
- }
- }
- void OnStartedListening()
- {
- voiceSDKLoggerImpl.LogInteractionPoint("startedListening");
- }
- void OnMinimumWakeThresholdHit()
- {
- voiceSDKLoggerImpl.LogInteractionPoint("minWakeThresholdHit");
- }
- void OnStoppedListening()
- {
- voiceSDKLoggerImpl.LogInteractionPoint("stoppedListening");
- }
- void OnStoppedListeningDueToTimeout()
- {
- voiceSDKLoggerImpl.LogInteractionPoint("stoppedListeningTimeout");
- }
- void OnStoppedListeningDueToInactivity()
- {
- voiceSDKLoggerImpl.LogInteractionPoint("stoppedListeningInactivity");
- }
- void OnStoppedListeningDueToDeactivation()
- {
- voiceSDKLoggerImpl.LogInteractionPoint("stoppedListeningDeactivate");
- }
- void OnMicDataSent()
- {
- voiceSDKLoggerImpl.LogInteractionPoint("micDataSent");
- }
- void OnSend(VoiceServiceRequest request)
- {
- voiceSDKLoggerImpl.LogInteractionPoint("witRequestCreated");
- if (request != null)
- {
- voiceSDKLoggerImpl.LogAnnotation("requestIdOverride", request.Options?.RequestId);
- }
- }
- void OnAudioDurationTrackerFinished(long timestamp, double audioDuration)
- {
- voiceSDKLoggerImpl.LogAnnotation("adt_duration", audioDuration.ToString(CultureInfo.InvariantCulture));
- voiceSDKLoggerImpl.LogAnnotation("adt_finished", timestamp.ToString());
- }
- void OnPartialTranscription(string text)
- {
- voiceSDKLoggerImpl.LogFirstTranscriptionTime();
- }
- void OnFullTranscription(string text)
- {
- voiceSDKLoggerImpl.LogInteractionPoint("fullTranscriptionTime");
- }
- void OnRequestComplete(VoiceServiceRequest request)
- {
- if (request.State == VoiceRequestState.Failed)
- {
- VLog.E($"Request Failed\nError: {request.Results.Message}");
- voiceSDKLoggerImpl.LogInteractionEndFailure(request.Results.Message);
- }
- else if (request.State == VoiceRequestState.Canceled)
- {
- VLog.W($"Request Canceled\nMessage: {request.Results.Message}");
- voiceSDKLoggerImpl.LogInteractionEndFailure("aborted");
- }
- else
- {
- VLog.D($"Request Success");
- voiceSDKLoggerImpl.LogInteractionEndSuccess();
- }
- }
- void LogRequestConfig()
- {
- #if UNITY_ANDROID && !UNITY_EDITOR
- voiceSDKLoggerImpl.LogAnnotation("clientSDKVersion", PACKAGE_VERSION);
- #endif
- voiceSDKLoggerImpl.LogAnnotation("minWakeThreshold",
- RuntimeConfiguration?.soundWakeThreshold.ToString(CultureInfo.InvariantCulture));
- voiceSDKLoggerImpl.LogAnnotation("minKeepAliveTimeSec",
- RuntimeConfiguration?.minKeepAliveTimeInSeconds.ToString(CultureInfo.InvariantCulture));
- voiceSDKLoggerImpl.LogAnnotation("minTranscriptionKeepAliveTimeSec",
- RuntimeConfiguration?.minTranscriptionKeepAliveTimeInSeconds.ToString(CultureInfo.InvariantCulture));
- voiceSDKLoggerImpl.LogAnnotation("maxRecordingTime",
- RuntimeConfiguration?.maxRecordingTime.ToString(CultureInfo.InvariantCulture));
- }
- #endregion
- }
- }
|