封装录音服务
封装类:
using System;
using UnityEngine;
public class MicrophoneWrapper : MonoSingleton<MicrophoneWrapper>
{
private string TAG = "MicrophoneWrapper: ";
//标记是否有麦克风
private bool isHaveMic = false;
//当前录音设备名称
string currentDeviceName = string.Empty;
//录音频率(音质)
int recordFrequency = 8000;
//上次按下时间戳
double lastPressTimestamp = 0;
//表示录音的最大时长
int recordMaxLength = 10;
//实际录音长度
int trueLength = 0;
//存储录音的片段
[HideInInspector]
public AudioClip saveAudioClip;
// Start is called before the first frame update
void Start()
{
}
public void Init()
{
//获取麦克风设备,判断是否有麦克风设备
if (Microphone.devices.Length > 0)
{
isHaveMic = true;
currentDeviceName = Microphone.devices[0];
}
else {
Debug.Log(TAG + " Microphone.devices is null(0) ");
}
}
/// 按下录音按钮
public void OnStartRecord()
{
StartRecording();
}
/// 放开录音按钮
public AudioClip OnStopRecord()
{
trueLength = EndRecording();
if (trueLength > 1)
{
Debug.Log(TAG+ " return AudioClip data ");
return saveAudioClip;
}
Debug.Log(TAG + " return AudioClip is null ");
return null;
}
/// 开始录音
private bool StartRecording(bool isLoop = false) //8000,16000
{
Debug.Log(TAG+"StartRecording ");
if (isHaveMic == false || Microphone.IsRecording(currentDeviceName))
{
return false;
}
lastPressTimestamp = GetTimestampOfNowWithMillisecond();
saveAudioClip = Microphone.Start(currentDeviceName, isLoop, recordMaxLength, recordFrequency);
return true;
}
/// 录音结束, 返回实际的录音时长
private int EndRecording()
{
Debug.Log(TAG+"EndRecording ");
if (isHaveMic == false || !Microphone.IsRecording(currentDeviceName))
{
Debug.Log(TAG + "EndRecording Failed ");
return 0;
}
//结束录音
Microphone.End(currentDeviceName);
//向上取整,避免遗漏录音末尾
return Mathf.CeilToInt((float)(GetTimestampOfNowWithMillisecond() - lastPressTimestamp) / 1000f);
}
/// 计算按下录音时长
private double GetTimestampOfNowWithMillisecond()
{
return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000;
}
}
调用示例:
public class Test : MonoBehaviour,IPointerDownHandler,IPointerUpHandler
{
private AudioSource mAudioSource;
private AudioClip mAudioClip;
void Start()
{
MicrophoneWrapper.Instance.Init();
mAudioSource = GetComponent<AudioSource>();
}
public void OnPointerDown(PointerEventData eventData)
{
this.transform.GetChild(0).GetComponent<Text>().text = "松开播放";
MicrophoneWrapper.Instance.OnStartRecord();
}
public void OnPointerUp(PointerEventData eventData)
{
this.transform.GetChild(0).GetComponent<Text>().text = "按下说话录音";
mAudioClip = MicrophoneWrapper.Instance.OnStopRecord();
if (mAudioSource != null && mAudioClip != null)
{
mAudioSource.PlayOneShot(mAudioClip);
}
else {
Debug.Log(" mAudioSource or mAudioClip is null ");
}
}
}
生成文件与上传
把AudioClip转换为wav文件并上传至服务器
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityEngine.Networking;
[RequireComponent(typeof(AudioSource))]
public class Speech2text : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
private AudioSource mAudioSource;
private AudioClip mAudioClip;
// 语音转换后的内容
public Text speechContent;
// 服务器地址
public string url = "http://***.***.210.247:8086/getText";
void Start()
{
// 这个路径在各平台有效
Debug.Log("Audio saved at: " + Application.persistentDataPath);
MicrophoneWrapper.Instance.Init();
mAudioSource = GetComponent<AudioSource>();
}
public void OnPointerDown(PointerEventData eventData)
{
this.transform.GetChild(0).GetComponent<Text>().text = "松开结束";
MicrophoneWrapper.Instance.OnStartRecord();
}
public void OnPointerUp(PointerEventData eventData)
{
this.transform.GetChild(0).GetComponent<Text>().text = "按下说话";
mAudioClip = MicrophoneWrapper.Instance.OnStopRecord();
if (mAudioSource != null && mAudioClip != null)
{
mAudioSource.PlayOneShot(mAudioClip);
// record
string fileName = DateTime.UtcNow.Ticks + ".wav";
string filePath = Path.Combine(Application.persistentDataPath, fileName);
WavFromClip(filePath, mAudioClip);
// upload
StartCoroutine(sendWav(filePath, fileName));
}
else
{
Debug.Log(" mAudioSource or mAudioClip is null ");
}
}
public void WavFromClip(string WavPosition, AudioClip clip)
{
if (Microphone.IsRecording(null))
return;
Microphone.End(null);
using (FileStream fs = CreateEmpty(WavPosition))
{
ConvertAndWrite(fs, clip);
WriteHeader(fs, clip); //wav文件头
}
}
private FileStream CreateEmpty(string filepath)
{
FileStream fileStream = new FileStream(filepath, FileMode.Create);
byte emptyByte = new byte();
for (int i = 0; i < 44; i++) //为wav文件头留出空间
{
fileStream.WriteByte(emptyByte);
}
return fileStream;
}
private void ConvertAndWrite(FileStream fileStream, AudioClip clip)
{
float[] samples = new float[clip.samples];
clip.GetData(samples, 0);
Int16[] intData = new Int16[samples.Length];
Byte[] bytesData = new Byte[samples.Length * 2];
int rescaleFactor = 32767; //to convert float to Int16
for (int i = 0; i < samples.Length; i++)
{
intData[i] = (short)(samples[i] * rescaleFactor);
Byte[] byteArr = new Byte[2];
byteArr = BitConverter.GetBytes(intData[i]);
byteArr.CopyTo(bytesData, i * 2);
}
fileStream.Write(bytesData, 0, bytesData.Length);
}
private void WriteHeader(FileStream stream, AudioClip clip)
{
int hz = clip.frequency;
int channels = clip.channels;
int samples = clip.samples;
stream.Seek(0, SeekOrigin.Begin);
Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");
stream.Write(riff, 0, 4);
Byte[] chunkSize = BitConverter.GetBytes(stream.Length - 8);
stream.Write(chunkSize, 0, 4);
Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");
stream.Write(wave, 0, 4);
Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");
stream.Write(fmt, 0, 4);
Byte[] subChunk1 = BitConverter.GetBytes(16);
stream.Write(subChunk1, 0, 4);
UInt16 two = 2;
UInt16 one = 1;
Byte[] audioFormat = BitConverter.GetBytes(one);
stream.Write(audioFormat, 0, 2);
Byte[] numChannels = BitConverter.GetBytes(channels);
stream.Write(numChannels, 0, 2);
Byte[] sampleRate = BitConverter.GetBytes(hz);
stream.Write(sampleRate, 0, 4);
Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2); // sampleRate * bytesPerSample*number of channels, here 44100*2*2
stream.Write(byteRate, 0, 4);
UInt16 blockAlign = (ushort)(channels * 2);
stream.Write(BitConverter.GetBytes(blockAlign), 0, 2);
UInt16 bps = 16;
Byte[] bitsPerSample = BitConverter.GetBytes(bps);
stream.Write(bitsPerSample, 0, 2);
Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data");
stream.Write(datastring, 0, 4);
Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2);
stream.Write(subChunk2, 0, 4);
}
IEnumerator sendWav(string filePath, string fileName)
{
byte[] wavFileBytes = File.ReadAllBytes(filePath);
WWWForm form = new WWWForm();
form.AddBinaryData("file", wavFileBytes, fileName);
using (UnityWebRequest www = UnityWebRequest.Post(url, form))
{
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
string text = www.downloadHandler.text;
Response res = JsonUtility.FromJson<Response>(text);
speechContent.text = res.content;
}
}
}
}
[Serializable]
class Response
{
public bool success;
public string content;
}