/* Copyright (c) 2019-present Evereal. All rights reserved. */ using System; using System.Collections.Generic; using UnityEngine; namespace Evereal.VideoCapture { /// /// This script will record target audio listener sample and encode to audio file, or mux audio into video file if required. /// [Serializable] public class AudioCapture : MonoBehaviour, ICapture { #region Properties // Start capture on awake if set to true. [SerializeField] public bool startOnAwake = false; // Quit process after capture finish. [SerializeField] public bool quitAfterCapture = false; // The capture duration if start capture on awake. [SerializeField] public float captureTime = 30f; [Tooltip("Save folder for recorded audio")] // Save path for recorded video including file name (c://xxx.wav) [SerializeField] public string saveFolder = ""; // Capture microphone settings [SerializeField] public bool captureMicrophone = false; // Microphone device index [SerializeField] public int deviceIndex = 0; // The audio recorder private IRecorder audioRecorder; // Get or set the current status. public CaptureStatus status { get { if (audioRecorder != null && audioRecorder.RecordStarted()) return CaptureStatus.STARTED; return CaptureStatus.READY; } } private string saveFolderFullPath = ""; // Log message format template private string LOG_FORMAT = "[AudioCapture] {0}"; #endregion #region Events protected Queue completeEventQueue = new Queue(); protected Queue errorEventQueue = new Queue(); public event EventHandler OnComplete; protected void OnCaptureComplete(CaptureCompleteEventArgs args) { EventHandler handler = OnComplete; if (handler != null) { handler(this, args); } } public event EventHandler OnError; protected void OnCaptureError(CaptureErrorEventArgs args) { EventHandler handler = OnError; if (handler != null) { handler(this, args); } } #endregion #region Methods // Start capture audio session public bool StartCapture() { // Check if we can start capture session if (status != CaptureStatus.READY) { OnCaptureError(new CaptureErrorEventArgs(CaptureErrorCode.CAPTURE_ALREADY_IN_PROGRESS)); return false; } saveFolderFullPath = Utils.CreateFolder(saveFolder); // Init audio recorder if (captureMicrophone) { if (MicrophoneRecorder.singleton == null) { gameObject.AddComponent(); } MicrophoneRecorder.singleton.saveFolderFullPath = saveFolderFullPath; MicrophoneRecorder.singleton.captureType = CaptureType.VOD; audioRecorder = MicrophoneRecorder.singleton; } else { if (AudioRecorder.singleton == null) { if (GetComponent() != null) { // Reset AudioListener AudioListener listener = FindObjectOfType(); if (listener) { Destroy(listener); Debug.LogFormat(LOG_FORMAT, "AudioListener found, reset in game scene."); } gameObject.AddComponent(); gameObject.AddComponent(); } else { // Keep AudioListener AudioListener listener = FindObjectOfType(); if (!listener) { listener = gameObject.AddComponent(); Debug.LogFormat(LOG_FORMAT, "AudioListener not found, add a new AudioListener."); } listener.gameObject.AddComponent(); } } AudioRecorder.singleton.saveFolderFullPath = saveFolderFullPath; AudioRecorder.singleton.captureType = CaptureType.VOD; audioRecorder = AudioRecorder.singleton; } if (audioRecorder == null) { OnCaptureError(new CaptureErrorEventArgs(CaptureErrorCode.AUDIO_CAPTURE_START_FAILED)); return false; } audioRecorder.StartRecord(); Debug.LogFormat(LOG_FORMAT, "Audio capture session started."); return true; } // Stop capture audio session public bool StopCapture() { if (status != CaptureStatus.STARTED) { Debug.LogFormat(LOG_FORMAT, "Audio capture session not start yet!"); return false; } audioRecorder.StopRecord(); OnCaptureComplete(new CaptureCompleteEventArgs(audioRecorder.GetRecordedAudio())); Debug.LogFormat(LOG_FORMAT, "Audio capture session success!"); return true; } // Cancel capture audio session public bool CancelCapture() { if (status != CaptureStatus.STARTED) { Debug.LogFormat(LOG_FORMAT, "Audio capture session not start yet!"); return false; } audioRecorder.CancelRecord(); Debug.LogFormat(LOG_FORMAT, "Audio capture session canceled!"); return true; } #endregion #region Unity Lifecycle private void Awake() { if (startOnAwake) { StartCapture(); } } private void Update() { if (startOnAwake) { if (Time.time >= captureTime && status == CaptureStatus.STARTED) { StopCapture(); } if (quitAfterCapture && status != CaptureStatus.STARTED) { #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #else Application.Quit(); #endif } } } private void OnDestroy() { // Check if still processing on destroy if (status == CaptureStatus.STARTED) { StopCapture(); } } #endregion } }