338 lines
8.8 KiB
C#
338 lines
8.8 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using System.IO;
|
||
using UnityEngine.Networking;
|
||
using System.Text;
|
||
using System.Security.Cryptography;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using UnityEngine.UI;
|
||
|
||
public class MicrophoneInput : MonoBehaviour
|
||
{
|
||
public static MicrophoneInput instance;
|
||
public AudioSource audioSource;
|
||
/// <summary>
|
||
/// 最大录音时长
|
||
/// </summary>
|
||
public int lengthSec = 30;
|
||
/// <summary>
|
||
/// 采样频率
|
||
/// </summary>
|
||
private int frequency = 16000;
|
||
private string savePath;
|
||
/// <summary>
|
||
/// 录音时长
|
||
/// </summary>
|
||
public float recordTime;
|
||
|
||
|
||
private void Awake()
|
||
{
|
||
instance = this;
|
||
savePath = Application.persistentDataPath + "/audios/micro.wav";
|
||
audioSource = gameObject.AddComponent<AudioSource>();
|
||
audioSource.playOnAwake = false;
|
||
if (!Directory.Exists(Path.GetDirectoryName(savePath)))
|
||
{
|
||
Directory.CreateDirectory(Path.GetDirectoryName(savePath));
|
||
}
|
||
|
||
if (!File.Exists(savePath))
|
||
{
|
||
File.Create(savePath);
|
||
}
|
||
|
||
}
|
||
private void Update()
|
||
{
|
||
if (Microphone.IsRecording(null))
|
||
{
|
||
recordTime += Time.deltaTime;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查录音权限,并开始录制
|
||
/// </summary>
|
||
[ContextMenu("开始录音")]
|
||
public void OnStartClick()
|
||
{
|
||
Debug.Log("OnStartClick");
|
||
|
||
|
||
if (!CheckMicrophone())
|
||
{
|
||
Debug.LogError("无录音权限,获取中,请重新说话");
|
||
MyDebugger.Log("无录音权限,获取中,请重新说话");
|
||
StartCoroutine(RequestMicrophoneAuth());
|
||
return;
|
||
}
|
||
|
||
StartRecord();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测麦克风
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public bool CheckMicrophone()
|
||
{
|
||
return Application.HasUserAuthorization(UserAuthorization.Microphone);
|
||
}
|
||
|
||
|
||
[ContextMenu("结束录音,开始识别")]
|
||
public void MyStop()
|
||
{
|
||
OnStopClick(str =>
|
||
{
|
||
Debug.Log("识别完成: "+str);
|
||
});
|
||
}
|
||
/// <summary>
|
||
/// 停止录制,并转文字
|
||
/// </summary>
|
||
public void OnStopClick(Action<string> callback)
|
||
{
|
||
Debug.Log("OnStopClick");
|
||
|
||
int length = StopRecord();
|
||
Debug.Log("录音返回长度:" + length);
|
||
if (length > 0)
|
||
{
|
||
TransToText(callback);
|
||
}
|
||
else
|
||
{
|
||
MyDebugger.Log("没录音数据");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播放录音
|
||
/// </summary>
|
||
public void PlayAudio()
|
||
{
|
||
|
||
//读取本地文件播放
|
||
ReadAudioFile(savePath);
|
||
}
|
||
|
||
|
||
public IEnumerator RequestMicrophoneAuth()
|
||
{
|
||
yield return Application.RequestUserAuthorization(UserAuthorization.Microphone);
|
||
}
|
||
|
||
|
||
private void StartRecord()
|
||
{
|
||
if (Microphone.devices.Length > 0)
|
||
{
|
||
if (!Microphone.IsRecording(null))
|
||
{
|
||
Debug.Log("开始录音");
|
||
|
||
audioSource.Stop();
|
||
audioSource.loop = false;
|
||
audioSource.mute = true;
|
||
audioSource.clip = Microphone.Start(null, false, lengthSec, frequency);
|
||
MyDebugger.Log("录音中");
|
||
recordTime = 0;
|
||
}
|
||
else
|
||
{
|
||
Debug.Log("当前正在录音,请先停止录音");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.Log("无麦克风");
|
||
MyDebugger.Log("无麦克风");
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 单纯停止录音
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public int StopRecord()
|
||
{
|
||
int length = Microphone.GetPosition(null);
|
||
Microphone.End(null);
|
||
|
||
return length;
|
||
}
|
||
|
||
public void TransToText(Action<string> callback)
|
||
{
|
||
if (audioSource.clip != null && audioSource.clip.length > 0)
|
||
{
|
||
byte[] file = WavUtility.FromAudioClip(audioSource.clip, savePath, true);
|
||
Debug.Log("TransToText长度:" + file.Length); ;
|
||
IFlytekManager.instance.AudioToText(file, str =>
|
||
{
|
||
callback(str);
|
||
});
|
||
}
|
||
}
|
||
|
||
public bool SaveAudioFile(string filePath, int length)
|
||
{
|
||
if (Microphone.IsRecording(null))
|
||
return false;
|
||
|
||
|
||
|
||
byte[] data = GetClipData(audioSource, length);
|
||
if (data == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
File.WriteAllBytes(filePath, data);
|
||
string infoLog = "total length:" + data.Length + " time:" + audioSource.time+" path:"+ filePath;
|
||
Debug.Log(infoLog);
|
||
|
||
return true;
|
||
}
|
||
|
||
public void ReadAudioFile(string filePath)
|
||
{
|
||
byte[] bytes = File.ReadAllBytes(filePath);
|
||
float[] samples = byte2float(bytes);
|
||
|
||
var clip = audioSource.clip;
|
||
audioSource.Stop();
|
||
audioSource.clip = AudioClip.Create(clip.name, samples.Length, clip.channels, clip.frequency, false);
|
||
audioSource.clip.SetData(samples, 0);
|
||
audioSource.mute = false;
|
||
audioSource.Play();
|
||
}
|
||
|
||
byte[] GetClipData(AudioSource source, int length)
|
||
{
|
||
if (length < 10)
|
||
{
|
||
Debug.Log("录音文件太短");
|
||
return null;
|
||
}
|
||
|
||
float[] samples = new float[length];
|
||
source.clip.GetData(samples, 0);
|
||
|
||
byte[] outData = float2byte(samples);
|
||
return outData;
|
||
}
|
||
byte[] float2byte(float[] floats)
|
||
{
|
||
byte[] outData = new byte[floats.Length * 2];
|
||
int reScaleFactor = 32767;
|
||
|
||
for (int i = 0; i < floats.Length; i++)
|
||
{
|
||
short tempShort = (short)(floats[i] * reScaleFactor);
|
||
byte[] tempData = BitConverter.GetBytes(tempShort);
|
||
|
||
outData[i * 2] = tempData[0];
|
||
outData[i * 2 + 1] = tempData[1];
|
||
}
|
||
|
||
return outData;
|
||
}
|
||
|
||
float[] byte2float(byte[] bytes)
|
||
{
|
||
float reScaleFactor = 32768.0f;
|
||
float[] data = new float[bytes.Length / 2];
|
||
for (int i = 0; i < bytes.Length; i += 2)
|
||
{
|
||
short s;
|
||
if (BitConverter.IsLittleEndian) //小端和大端顺序要调整
|
||
s = (short)((bytes[i + 1] << 8) | bytes[i]);
|
||
else
|
||
s = (short)((bytes[i] << 8) | bytes[i + 1]);
|
||
// convert to range from -1 to (just below) 1
|
||
data[i / 2] = s / reScaleFactor;
|
||
}
|
||
|
||
return data;
|
||
}
|
||
|
||
//private IEnumerator CallAudioToString(string fileName,long fileSize)
|
||
//{
|
||
// string ts = GetTimeStampSecond().ToString();
|
||
// var a = new { duration = 200, fileName = fileName, fileSize = fileSize, signa = GetSigna(ts), ts = ts, appId = APPID };
|
||
|
||
// UnityWebRequest request = UnityWebRequest.Post("https://raasr.xfyun.cn/v2/api/upload", JsonConvert.SerializeObject(a));
|
||
// request.uploadHandler.contentType = "application/json";
|
||
|
||
// yield return request.SendWebRequest();
|
||
|
||
// if(!request.isNetworkError && !request.isHttpError)
|
||
// {
|
||
// Debug.Log(request.downloadHandler.text);
|
||
// audioText.text = request.downloadHandler.text;
|
||
// }
|
||
// else
|
||
// {
|
||
// audioText.text = request.downloadHandler.error;
|
||
// }
|
||
//}
|
||
|
||
//private string GetSigna(string ts)
|
||
//{
|
||
// string md5str = MD5(APPID + ts);
|
||
// string hmacStr= HMACSHA1Text(md5str, SecretKey);
|
||
// return hmacStr;
|
||
//}
|
||
/// <summary>
|
||
/// 获取时间戳-单位秒
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private int GetTimeStampSecond()
|
||
{
|
||
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
|
||
return Convert.ToInt32(ts.TotalSeconds);
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 字符串MD5加密
|
||
/// </summary>
|
||
/// <param name="Text">要加密的字符串</param>
|
||
/// <returns>密文</returns>
|
||
private string MD5(string Text)
|
||
{
|
||
byte[] buffer = Encoding.UTF8.GetBytes(Text);
|
||
System.Security.Cryptography.MD5CryptoServiceProvider check;
|
||
check = new System.Security.Cryptography.MD5CryptoServiceProvider();
|
||
byte[] somme = check.ComputeHash(buffer);
|
||
string ret = "";
|
||
foreach (byte a in somme)
|
||
{
|
||
if (a < 16)
|
||
ret += "0" + a.ToString("X");
|
||
else
|
||
ret += a.ToString("X");
|
||
}
|
||
return ret.ToLower();
|
||
}
|
||
|
||
private string HMACSHA1Text(string text, string key)
|
||
{
|
||
//HMACSHA1加密
|
||
HMACSHA1 hmacsha1 = new HMACSHA1();
|
||
hmacsha1.Key = Encoding.UTF8.GetBytes(key);
|
||
|
||
byte[] dataBuffer =Encoding.UTF8.GetBytes(text);
|
||
byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
|
||
|
||
return Convert.ToBase64String(hashBytes);
|
||
}
|
||
}
|