/************************************************************************************ Filename : OVRLipSyncMicInput.cs Content : Interface to microphone input Created : May 12, 2015 Copyright : Copyright Facebook Technologies, LLC and its affiliates. All rights reserved. Licensed under the Oculus Audio SDK License Version 3.3 (the "License"); you may not use the Oculus Audio SDK except in compliance with the License, which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. You may obtain a copy of the License at https://developer.oculus.com/licenses/audio-3.3/ Unless required by applicable law or agreed to in writing, the Oculus Audio SDK distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ************************************************************************************/ using System; using UnityEngine; using System.Diagnostics; using Debug = UnityEngine.Debug; using System.Threading; [RequireComponent(typeof(AudioSource))] public class OVRLipSyncMicInput : MonoBehaviour { public enum micActivation { HoldToSpeak, PushToSpeak, ConstantSpeak } // PUBLIC MEMBERS [Tooltip("Manual specification of Audio Source - " + "by default will use any attached to the same object.")] public AudioSource audioSource = null; [Tooltip("Enable a keypress to toggle the microphone device selection GUI.")] public bool enableMicSelectionGUI = false; [Tooltip("Key to toggle the microphone selection GUI if enabled.")] public KeyCode micSelectionGUIKey = KeyCode.M; [SerializeField] [Range(0.0f, 100.0f)] [Tooltip("Microphone input volume control.")] private float micInputVolume = 100; [SerializeField] [Tooltip("Requested microphone input frequency")] private int micFrequency = 48000; public float MicFrequency { get { return micFrequency; } set { micFrequency = (int)Mathf.Clamp((float)value, 0, 96000); } } [Tooltip("Microphone input control method. Hold To Speak and Push" + " To Speak are driven with the Mic Activation Key.")] public micActivation micControl = micActivation.ConstantSpeak; [Tooltip("Key used to drive Hold To Speak and Push To Speak methods" + " of microphone input control.")] public KeyCode micActivationKey = KeyCode.Space; [Tooltip("Will contain the string name of the selected microphone device - read only.")] public string selectedDevice; // PRIVATE MEMBERS private bool micSelected = false; private int minFreq, maxFreq; private bool focused = true; private bool initialized = false; //---------------------------------------------------- // MONOBEHAVIOUR OVERRIDE FUNCTIONS //---------------------------------------------------- /// /// Awake this instance. /// void Awake() { // First thing to do, cache the unity audio source (can be managed by the // user if audio source can change) if (!audioSource) audioSource = GetComponent(); if (!audioSource) return; // this should never happen } /// /// Start this instance. /// void Start() { audioSource.loop = true; // Set the AudioClip to loop audioSource.mute = false; InitializeMicrophone(); } /// /// Initializes the microphone. /// private void InitializeMicrophone() { if (initialized) { return; } if (Microphone.devices.Length == 0) { return; } selectedDevice = Microphone.devices[0].ToString(); micSelected = true; GetMicCaps(); initialized = true; } /// /// Update this instance. /// void Update() { if (!focused) { if (Microphone.IsRecording(selectedDevice)) { StopMicrophone(); } return; } if (!Application.isPlaying) { StopMicrophone(); return; } // Lazy Microphone initialization (needed on Android) if (!initialized) { InitializeMicrophone(); } audioSource.volume = (micInputVolume / 100); //Hold To Speak if (micControl == micActivation.HoldToSpeak) { if (Input.GetKey(micActivationKey)) { if (!Microphone.IsRecording(selectedDevice)) { StartMicrophone(); } } else { if (Microphone.IsRecording(selectedDevice)) { StopMicrophone(); } } } //Push To Talk if (micControl == micActivation.PushToSpeak) { if (Input.GetKeyDown(micActivationKey)) { if (Microphone.IsRecording(selectedDevice)) { StopMicrophone(); } else if (!Microphone.IsRecording(selectedDevice)) { StartMicrophone(); } } } //Constant Speak if (micControl == micActivation.ConstantSpeak) { if (!Microphone.IsRecording(selectedDevice)) { StartMicrophone(); } } //Mic Selected = False if (enableMicSelectionGUI) { if (Input.GetKeyDown(micSelectionGUIKey)) { micSelected = false; } } } /// /// Raises the application focus event. /// /// If set to true: focused. void OnApplicationFocus(bool focus) { focused = focus; if (!focused) StopMicrophone(); } /// /// Raises the application pause event. /// /// If set to true: paused. void OnApplicationPause(bool pauseStatus) { focused = !pauseStatus; if (!focused) StopMicrophone(); } void OnDisable() { StopMicrophone(); } /// /// Raises the GU event. /// void OnGUI() { MicDeviceGUI((Screen.width / 2) - 150, (Screen.height / 2) - 75, 300, 50, 10, -300); } //---------------------------------------------------- // PUBLIC FUNCTIONS //---------------------------------------------------- /// /// Mics the device GU. /// /// Left. /// Top. /// Width. /// Height. /// Button space top. /// Button space left. public void MicDeviceGUI( float left, float top, float width, float height, float buttonSpaceTop, float buttonSpaceLeft) { //If there is more than one device, choose one. if (Microphone.devices.Length >= 1 && enableMicSelectionGUI == true && micSelected == false) { for (int i = 0; i < Microphone.devices.Length; ++i) { if (GUI.Button(new Rect(left + ((width + buttonSpaceLeft) * i), top + ((height + buttonSpaceTop) * i), width, height), Microphone.devices[i].ToString())) { StopMicrophone(); selectedDevice = Microphone.devices[i].ToString(); micSelected = true; GetMicCaps(); StartMicrophone(); } } } } /// /// Gets the mic caps. /// public void GetMicCaps() { if (micSelected == false) return; //Gets the frequency of the device Microphone.GetDeviceCaps(selectedDevice, out minFreq, out maxFreq); if (minFreq == 0 && maxFreq == 0) { Debug.LogWarning("GetMicCaps warning:: min and max frequencies are 0"); minFreq = 44100; maxFreq = 44100; } if (micFrequency > maxFreq) micFrequency = maxFreq; } /// /// Starts the microphone. /// public void StartMicrophone() { if (micSelected == false) return; //Starts recording audioSource.clip = Microphone.Start(selectedDevice, true, 1, micFrequency); Stopwatch timer = Stopwatch.StartNew(); // Wait until the recording has started while (!(Microphone.GetPosition(selectedDevice) > 0) && timer.Elapsed.TotalMilliseconds < 1000) { Thread.Sleep(50); } if (Microphone.GetPosition(selectedDevice) <= 0) { throw new Exception("Timeout initializing microphone " + selectedDevice); } // Play the audio source audioSource.Play(); } /// /// Stops the microphone. /// public void StopMicrophone() { if (micSelected == false) return; // Overriden with a clip to play? Don't stop the audio source if ((audioSource != null) && (audioSource.clip != null) && (audioSource.clip.name == "Microphone")) { audioSource.Stop(); } // Reset to stop mouth movement OVRLipSyncContext context = GetComponent(); context.ResetContext(); Microphone.End(selectedDevice); } //---------------------------------------------------- // PRIVATE FUNCTIONS //---------------------------------------------------- /// /// Gets the averaged volume. /// /// The averaged volume. float GetAveragedVolume() { // We will use the SR to get average volume // return OVRSpeechRec.GetAverageVolume(); return 0.0f; } }