2025-09-24 19:24:19 +08:00

121 lines
4.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Concurrent;
using UnityEngine;
public class OnlineAudio : MonoBehaviour
{
private AudioClip recording; // 用于存储录音的 AudioClip 对象
private int lastSample = 0; // 上一次处理的音频样本位置,用于追踪录音的当前位置
public static int wave_buffer_collectfrequency = 16000; // 采样率,定义为 16000 Hz
public static readonly ConcurrentQueue<byte[]> voicebuff = new ConcurrentQueue<byte[]>(); // 使用 ConcurrentQueue 存储 byte[] 数据,确保多线程安全
private int bufferLengthSeconds = 10; // 定义缓冲区的时长为 10 秒
public bool hasAudio;
public void StartRec()
{
Debug.Log("开始录音"); // 输出调试信息,表示开始录音
// 清空缓存数据,避免旧数据残留
int buffnum = voicebuff.Count; // 获取当前队列中的数据数量
for (int i = 0; i < buffnum; i++)
voicebuff.TryDequeue(out byte[] buff); // 从队列中逐个移除数据
// 获取麦克风设备并开始录音
string microphoneName = Microphone.devices[0]; // 获取第一个麦克风设备的名称
Debug.Log("麦克风设备"+microphoneName);
recording = Microphone.Start(microphoneName, true, bufferLengthSeconds, wave_buffer_collectfrequency);
// 使用麦克风开始录音设置循环录音true时长为 bufferLengthSeconds1秒采样率为 wave_buffer_collectfrequency16000Hz
// 检查麦克风是否成功启动
if (Microphone.IsRecording(microphoneName))
{
Debug.Log("录音已启动"); // 如果录音成功,输出调试信息
}
else
{
Debug.LogError("无法启动录音"); // 如果录音失败,输出错误信息
}
}
public void StopRec()
{
// 停止录音并结束当前录音会话
if (Microphone.IsRecording(null)) // 如果当前麦克风正在录音
{
Microphone.End(null); // 停止录音
}
Debug.Log("录音结束"); // 输出调试信息,表示录音结束
}
private void Update()
{
// 如果当前麦克风正在录音,处理录音数据
if (Microphone.IsRecording(null) && recording != null)
{
int currentSample = Microphone.GetPosition(null); // 获取当前麦克风的录音位置(样本位置)
// 处理录音数据(检查缓冲区环绕情况,即缓冲区重新开始的情况)
if (currentSample > lastSample || currentSample < lastSample)
{
// 计算需要处理的样本数
int samplesToProcess = (currentSample > lastSample) ? currentSample - lastSample : (recording.samples - lastSample + currentSample);
// 创建一个新的数组来存储从录音中提取的浮点型样本数据
float[] data = new float[samplesToProcess];
// 从录音数据中提取样本,从上一次的位置开始
recording.GetData(data, lastSample);
// 将提取的 float[] 数据转换为 16-bit PCM 格式的 byte[] 数据
byte[] byteData = ConvertFloatTo16BitPCM(data);
// 将转换后的 byte[] 数据存入队列
voicebuff.Enqueue(byteData);
// 更新 lastSample准备处理下一部分数据
lastSample = currentSample;
}
// 检测是否有音频输入(示例:检查是否超过阈值)
//float[] samples = new float[recording.samples]; // 创建一个数组来存储PCM数据
//recording.GetData(samples, 0); // 从音频剪辑中获取PCM数据
//hasAudio = false;
//foreach (float sample in samples)
//{
// if (Mathf.Abs(sample) > 0.01f) // 设置一个阈值来检测是否有音频输入
// {
// hasAudio = true;
// break;
// }
//}
//Debug.Log(hasAudio ? "检测到音频输入" : "没有检测到音频输入");
}
}
// 将 float[] 数据转换为 16-bit PCM 格式的 byte[] 数据
public static byte[] ConvertFloatTo16BitPCM(float[] samples)
{
// 创建 byte[] 数组,大小为 float 数组大小的两倍,因为每个 float 需要 2 个字节来表示
byte[] byteData = new byte[samples.Length * 2];
int byteIndex = 0; // 用于追踪 byte[] 数组中的位置
// 遍历所有的 float 样本数据
foreach (float sample in samples)
{
// 将 float 样本限制在 -1.0f 和 1.0f 之间,并映射到 16-bit 整数 (-32768 到 32767)
short intSample = (short)(Mathf.Clamp(sample, -1.0f, 1.0f) * short.MaxValue);
// 将 16-bit 整数拆分为两个字节,并存储在 byte[] 中
byteData[byteIndex++] = (byte)(intSample & 0xFF); // 存储低字节
byteData[byteIndex++] = (byte)((intSample >> 8) & 0xFF); // 存储高字节
}
return byteData; // 返回转换后的 byte[] 数据
}
// 从队列中取出录音数据
public static byte[] Wavedata_Dequeue()
{
byte[] datas;
voicebuff.TryDequeue(out datas); // 尝试从队列中取出 byte[] 数据
return datas; // 返回取出的数据
}
}