OVRLipSyncMicInput.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /************************************************************************************
  2. Filename : OVRLipSyncMicInput.cs
  3. Content : Interface to microphone input
  4. Created : May 12, 2015
  5. Copyright : Copyright Facebook Technologies, LLC and its affiliates.
  6. All rights reserved.
  7. Licensed under the Oculus Audio SDK License Version 3.3 (the "License");
  8. you may not use the Oculus Audio SDK except in compliance with the License,
  9. which is provided at the time of installation or download, or which
  10. otherwise accompanies this software in either electronic or hard copy form.
  11. You may obtain a copy of the License at
  12. https://developer.oculus.com/licenses/audio-3.3/
  13. Unless required by applicable law or agreed to in writing, the Oculus Audio SDK
  14. distributed under the License is distributed on an "AS IS" BASIS,
  15. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. See the License for the specific language governing permissions and
  17. limitations under the License.
  18. ************************************************************************************/
  19. using System;
  20. using UnityEngine;
  21. using System.Diagnostics;
  22. using Debug = UnityEngine.Debug;
  23. using System.Threading;
  24. [RequireComponent(typeof(AudioSource))]
  25. public class OVRLipSyncMicInput : MonoBehaviour
  26. {
  27. public enum micActivation
  28. {
  29. HoldToSpeak,
  30. PushToSpeak,
  31. ConstantSpeak
  32. }
  33. // PUBLIC MEMBERS
  34. [Tooltip("Manual specification of Audio Source - " +
  35. "by default will use any attached to the same object.")]
  36. public AudioSource audioSource = null;
  37. [Tooltip("Enable a keypress to toggle the microphone device selection GUI.")]
  38. public bool enableMicSelectionGUI = false;
  39. [Tooltip("Key to toggle the microphone selection GUI if enabled.")]
  40. public KeyCode micSelectionGUIKey = KeyCode.M;
  41. [SerializeField]
  42. [Range(0.0f, 100.0f)]
  43. [Tooltip("Microphone input volume control.")]
  44. private float micInputVolume = 100;
  45. [SerializeField]
  46. [Tooltip("Requested microphone input frequency")]
  47. private int micFrequency = 48000;
  48. public float MicFrequency
  49. {
  50. get { return micFrequency; }
  51. set { micFrequency = (int)Mathf.Clamp((float)value, 0, 96000); }
  52. }
  53. [Tooltip("Microphone input control method. Hold To Speak and Push" +
  54. " To Speak are driven with the Mic Activation Key.")]
  55. public micActivation micControl = micActivation.ConstantSpeak;
  56. [Tooltip("Key used to drive Hold To Speak and Push To Speak methods" +
  57. " of microphone input control.")]
  58. public KeyCode micActivationKey = KeyCode.Space;
  59. [Tooltip("Will contain the string name of the selected microphone device - read only.")]
  60. public string selectedDevice;
  61. // PRIVATE MEMBERS
  62. private bool micSelected = false;
  63. private int minFreq, maxFreq;
  64. private bool focused = true;
  65. private bool initialized = false;
  66. //----------------------------------------------------
  67. // MONOBEHAVIOUR OVERRIDE FUNCTIONS
  68. //----------------------------------------------------
  69. /// <summary>
  70. /// Awake this instance.
  71. /// </summary>
  72. void Awake()
  73. {
  74. // First thing to do, cache the unity audio source (can be managed by the
  75. // user if audio source can change)
  76. if (!audioSource) audioSource = GetComponent<AudioSource>();
  77. if (!audioSource) return; // this should never happen
  78. }
  79. /// <summary>
  80. /// Start this instance.
  81. /// </summary>
  82. void Start()
  83. {
  84. audioSource.loop = true; // Set the AudioClip to loop
  85. audioSource.mute = false;
  86. InitializeMicrophone();
  87. }
  88. /// <summary>
  89. /// Initializes the microphone.
  90. /// </summary>
  91. ///
  92. private void InitializeMicrophone()
  93. {
  94. if (initialized)
  95. {
  96. return;
  97. }
  98. if (Microphone.devices.Length == 0)
  99. {
  100. return;
  101. }
  102. selectedDevice = Microphone.devices[0].ToString();
  103. micSelected = true;
  104. GetMicCaps();
  105. initialized = true;
  106. }
  107. /// <summary>
  108. /// Update this instance.
  109. /// </summary>
  110. void Update()
  111. {
  112. if (!focused)
  113. {
  114. if (Microphone.IsRecording(selectedDevice))
  115. {
  116. StopMicrophone();
  117. }
  118. return;
  119. }
  120. if (!Application.isPlaying)
  121. {
  122. StopMicrophone();
  123. return;
  124. }
  125. // Lazy Microphone initialization (needed on Android)
  126. if (!initialized)
  127. {
  128. InitializeMicrophone();
  129. }
  130. audioSource.volume = (micInputVolume / 100);
  131. //Hold To Speak
  132. if (micControl == micActivation.HoldToSpeak)
  133. {
  134. if (Input.GetKey(micActivationKey))
  135. {
  136. if (!Microphone.IsRecording(selectedDevice))
  137. {
  138. StartMicrophone();
  139. }
  140. }
  141. else
  142. {
  143. if (Microphone.IsRecording(selectedDevice))
  144. {
  145. StopMicrophone();
  146. }
  147. }
  148. }
  149. //Push To Talk
  150. if (micControl == micActivation.PushToSpeak)
  151. {
  152. if (Input.GetKeyDown(micActivationKey))
  153. {
  154. if (Microphone.IsRecording(selectedDevice))
  155. {
  156. StopMicrophone();
  157. }
  158. else if (!Microphone.IsRecording(selectedDevice))
  159. {
  160. StartMicrophone();
  161. }
  162. }
  163. }
  164. //Constant Speak
  165. if (micControl == micActivation.ConstantSpeak)
  166. {
  167. if (!Microphone.IsRecording(selectedDevice))
  168. {
  169. StartMicrophone();
  170. }
  171. }
  172. //Mic Selected = False
  173. if (enableMicSelectionGUI)
  174. {
  175. if (Input.GetKeyDown(micSelectionGUIKey))
  176. {
  177. micSelected = false;
  178. }
  179. }
  180. }
  181. /// <summary>
  182. /// Raises the application focus event.
  183. /// </summary>
  184. /// <param name="focus">If set to <c>true</c>: focused.</param>
  185. void OnApplicationFocus(bool focus)
  186. {
  187. focused = focus;
  188. if (!focused)
  189. StopMicrophone();
  190. }
  191. /// <summary>
  192. /// Raises the application pause event.
  193. /// </summary>
  194. /// <param name="pauseStatus">If set to <c>true</c>: paused.</param>
  195. void OnApplicationPause(bool pauseStatus)
  196. {
  197. focused = !pauseStatus;
  198. if (!focused)
  199. StopMicrophone();
  200. }
  201. void OnDisable()
  202. {
  203. StopMicrophone();
  204. }
  205. /// <summary>
  206. /// Raises the GU event.
  207. /// </summary>
  208. void OnGUI()
  209. {
  210. MicDeviceGUI((Screen.width / 2) - 150, (Screen.height / 2) - 75, 300, 50, 10, -300);
  211. }
  212. //----------------------------------------------------
  213. // PUBLIC FUNCTIONS
  214. //----------------------------------------------------
  215. /// <summary>
  216. /// Mics the device GU.
  217. /// </summary>
  218. /// <param name="left">Left.</param>
  219. /// <param name="top">Top.</param>
  220. /// <param name="width">Width.</param>
  221. /// <param name="height">Height.</param>
  222. /// <param name="buttonSpaceTop">Button space top.</param>
  223. /// <param name="buttonSpaceLeft">Button space left.</param>
  224. public void MicDeviceGUI(
  225. float left,
  226. float top,
  227. float width,
  228. float height,
  229. float buttonSpaceTop,
  230. float buttonSpaceLeft)
  231. {
  232. //If there is more than one device, choose one.
  233. if (Microphone.devices.Length >= 1 && enableMicSelectionGUI == true && micSelected == false)
  234. {
  235. for (int i = 0; i < Microphone.devices.Length; ++i)
  236. {
  237. if (GUI.Button(new Rect(left + ((width + buttonSpaceLeft) * i),
  238. top + ((height + buttonSpaceTop) * i), width, height),
  239. Microphone.devices[i].ToString()))
  240. {
  241. StopMicrophone();
  242. selectedDevice = Microphone.devices[i].ToString();
  243. micSelected = true;
  244. GetMicCaps();
  245. StartMicrophone();
  246. }
  247. }
  248. }
  249. }
  250. /// <summary>
  251. /// Gets the mic caps.
  252. /// </summary>
  253. public void GetMicCaps()
  254. {
  255. if (micSelected == false) return;
  256. //Gets the frequency of the device
  257. Microphone.GetDeviceCaps(selectedDevice, out minFreq, out maxFreq);
  258. if (minFreq == 0 && maxFreq == 0)
  259. {
  260. Debug.LogWarning("GetMicCaps warning:: min and max frequencies are 0");
  261. minFreq = 44100;
  262. maxFreq = 44100;
  263. }
  264. if (micFrequency > maxFreq)
  265. micFrequency = maxFreq;
  266. }
  267. /// <summary>
  268. /// Starts the microphone.
  269. /// </summary>
  270. public void StartMicrophone()
  271. {
  272. if (micSelected == false) return;
  273. //Starts recording
  274. audioSource.clip = Microphone.Start(selectedDevice, true, 1, micFrequency);
  275. Stopwatch timer = Stopwatch.StartNew();
  276. // Wait until the recording has started
  277. while (!(Microphone.GetPosition(selectedDevice) > 0) && timer.Elapsed.TotalMilliseconds < 1000) {
  278. Thread.Sleep(50);
  279. }
  280. if (Microphone.GetPosition(selectedDevice) <= 0)
  281. {
  282. throw new Exception("Timeout initializing microphone " + selectedDevice);
  283. }
  284. // Play the audio source
  285. audioSource.Play();
  286. }
  287. /// <summary>
  288. /// Stops the microphone.
  289. /// </summary>
  290. public void StopMicrophone()
  291. {
  292. if (micSelected == false) return;
  293. // Overriden with a clip to play? Don't stop the audio source
  294. if ((audioSource != null) &&
  295. (audioSource.clip != null) &&
  296. (audioSource.clip.name == "Microphone"))
  297. {
  298. audioSource.Stop();
  299. }
  300. // Reset to stop mouth movement
  301. OVRLipSyncContext context = GetComponent<OVRLipSyncContext>();
  302. context.ResetContext();
  303. Microphone.End(selectedDevice);
  304. }
  305. //----------------------------------------------------
  306. // PRIVATE FUNCTIONS
  307. //----------------------------------------------------
  308. /// <summary>
  309. /// Gets the averaged volume.
  310. /// </summary>
  311. /// <returns>The averaged volume.</returns>
  312. float GetAveragedVolume()
  313. {
  314. // We will use the SR to get average volume
  315. // return OVRSpeechRec.GetAverageVolume();
  316. return 0.0f;
  317. }
  318. }