/* 版权所有 (C) 2014 DaikonForge */ namespace DaikonForge.VoIP { using UnityEngine; using System.Collections; // 将该脚本添加到Unity的组件菜单中 [AddComponentMenu("DFVoice/Microphone Input Device")] public class MicrophoneInputDevice : AudioInputDeviceBase { // 默认麦克风设备名称 public static string DefaultMicrophone = null; /// /// 获取当前正在用于录制音频的设备 /// public string ActiveDevice { get { return device; } } // 每次读取的音频数据块大小 public int ChunkSize = 320; // 音频频率模式 public FrequencyMode Mode = FrequencyMode.Wide; // 按下通话的按键 //public KeyCode PushToTalk = KeyCode.None; // 音量阈值,用于判断是否有声音输入 public float AmplitudeThreshold = 0; // 录制的音频剪辑 public AudioClip recordedAudio; // 最大录制时间(秒) public int maxRecordTime = 15; // 上一次读取音频数据的位置 private int prevReadPosition = 0; // 重采样缓冲区 private BigArray resampleBuffer; // 当前使用的麦克风设备名称 private string device = null; // 录制音频的频率 private int recordingFrequency; // 按下通话的计时器(已注释,未使用) //private float pushToTalkTimer = 0f; // 录音状态标志 bool recording = false; #if UNITY_4_7 || UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 || UNITY_4_2 // 麦克风授权状态标志 bool hasAuthorization = false; #endif // 启动时的协程,用于请求麦克风授权 IEnumerator Start() { #if UNITY_4_7 || UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 || UNITY_4_2 // 请求用户授权使用麦克风 yield return Application.RequestUserAuthorization(UserAuthorization.Microphone); //Debug.LogWarning("[StartRecording]" + (Application.HasUserAuthorization(UserAuthorization.Microphone))); // 检查是否有可用的麦克风设备且已获得授权 if (Microphone.devices.Length > 0 && Application.HasUserAuthorization(UserAuthorization.Microphone)) { hasAuthorization = true; Debug.LogWarning("StartRecording(): 没有可用的设备!"); } #else yield return null; #endif } /// /// 开始录音 /// public override void StartRecording() { //Debug.LogWarning("[StartRecording]" + (hasAuthorization)); // 检查是否有可用的麦克风设备 if (Microphone.devices.Length <= 0) { Debug.LogWarning("StartRecording(): 没有可用的设备!"); // 没有录音权限的处理 NoRecordingPerimissions(); return; } // 使用默认麦克风设备 device = DefaultMicrophone; // 重置上一次读取位置 prevReadPosition = 0; // 获取指定模式下的音频频率 this.recordingFrequency = AudioUtils.GetFrequency(Mode); //this.recordingFrequency = 8000; int min, max; // 获取麦克风设备的频率范围 Microphone.GetDeviceCaps(device, out min, out max); min = 0; if (max == 0) max = 48000; // 确保录制频率在设备支持的范围内 int frequency = Mathf.Clamp(this.recordingFrequency, min, max); // 初始化重采样缓冲区 resampleBuffer = new BigArray(ChunkSize, 0); // 停止所有正在进行的录音 Microphone.End(null); // 开始录制音频 recordedAudio = Microphone.Start(null, false, maxRecordTime, frequency); // 触发录音开始事件 RecordingStart(); // 设置录音状态为正在录音 recording = true; } /// /// 停止录音 /// public override void StopRecording() { // 检查是否正在录音 if (recording) { int audioLength; // 录音的长度,单位为秒,UI上可能需要显示 // 获取当前录音的位置 int lastPos = Microphone.GetPosition(null); // 计算录音时长 audioLength = (int)(System.Math.Round((float)lastPos / this.recordingFrequency)); Debug.Log("StopRecording 录音时长= " + audioLength); // 触发录音结束事件 RecordingFinish(audioLength); // 停止录音 Microphone.End(null); // 清空录制的音频剪辑 recordedAudio = null; // 设置录音状态为停止录音 recording = false; } else { Debug.Log("[StopRecording] 没有正在进行的录音!"); } } /// /// 切换到新的麦克风设备 /// public void ChangeMicrophoneDevice(string newDevice) { // 停止当前录音 StopRecording(); // 设置新的默认麦克风设备 DefaultMicrophone = newDevice; // 开始新的录音 StartRecording(); } // 每帧更新方法 void Update() { // 检查是否正在录音,以及录音剪辑是否存在且正在录制 if (!recording && (recordedAudio == null || !Microphone.IsRecording(device))) { //Debug.LogWarning(string.Format("IsRecording = {0} , recordedAudion = {1}", !Microphone.IsRecording(device), (recordedAudio == null))); return; } // 从对象池中获取临时数组 float[] tempArray = TempArray.Obtain(ChunkSize); // 处理脚本重新编译的情况 if (resampleBuffer == null) { resampleBuffer = new BigArray(ChunkSize, 0); } // 获取当前录音的位置 int readPosition = Microphone.GetPosition(device); // 检查是否有足够的数据可供读取 if (readPosition >= (prevReadPosition + ChunkSize)) { while (readPosition >= (prevReadPosition + ChunkSize)) { //if (canTalk()) //{ // 从录音剪辑中读取数据 recordedAudio.GetData(tempArray, prevReadPosition); // 检查音量是否超过阈值 if (exceedsVolumeThreshold(tempArray)) { // 对数据进行重采样 resample(tempArray); // 触发缓冲区准备好事件 bufferReady(resampleBuffer, this.recordingFrequency); } //} // 更新上一次读取位置 prevReadPosition += ChunkSize; } } else if (prevReadPosition > readPosition) { var endReadPos = readPosition + recordedAudio.samples; var diff = endReadPos - prevReadPosition; while (diff >= ChunkSize) { //if (canTalk()) //{ // 从录音剪辑中读取数据 recordedAudio.GetData(tempArray, prevReadPosition); // 检查音量是否超过阈值 if (exceedsVolumeThreshold(tempArray)) { // 对数据进行重采样 resample(tempArray); // 触发缓冲区准备好事件 bufferReady(resampleBuffer, this.recordingFrequency); } //} // 更新上一次读取位置 prevReadPosition += ChunkSize; if (prevReadPosition >= recordedAudio.samples) { prevReadPosition -= recordedAudio.samples; break; } endReadPos = readPosition + recordedAudio.samples; diff = endReadPos - prevReadPosition; } } // 将临时数组释放回对象池 TempArray.Release(tempArray); } // 检查音频数据的音量是否超过阈值 bool exceedsVolumeThreshold(float[] data) { // 如果阈值为0,则认为始终超过阈值 if (AmplitudeThreshold == 0f) return true; // 获取音频数据中的最大值 var max = Mathf.Max(data); // 判断最大值是否超过阈值 return max >= AmplitudeThreshold; } // 对音频数据进行重采样 void resample(float[] tempArray) { // 初始化重采样缓冲区 resampleBuffer = new BigArray(tempArray.Length, tempArray.Length); // 调整重采样缓冲区的大小 resampleBuffer.Resize(tempArray.Length); // 将临时数组的数据复制到重采样缓冲区 resampleBuffer.CopyFrom(tempArray, 0, 0, tempArray.Length * 4); //Debug.Log( "Resampling from: " + recordedAudio.frequency + ", to: " + this.recordingFrequency ); // 调用音频工具类进行重采样 AudioUtils.Resample(resampleBuffer, recordedAudio.frequency, this.recordingFrequency); } // 能否通话的标志 bool _cantTalk = false; // 设置能否通话的状态 void SetCanTalk() { _cantTalk = !_cantTalk; } // 判断是否可以通话 bool canTalk() { return true; //if( PushToTalk == KeyCode.None ) return true; //if( Input.GetKey( PushToTalk ) ) pushToTalkTimer = 0.2f; //pushToTalkTimer -= Time.deltaTime; //return pushToTalkTimer > 0f; } } }