Unity5.3 API 之 Microphone(游戏语音SDK )
发表于2017-08-10
好久不见,最近手机游戏内置语音越来越普遍,这样的需求也难免多了起来。对就是像微信/阴阳师那样。
下面介绍两种实现方法:
1.unity内置API - Microphone
2.第三方包SDK
3.- API - sealed class Microphine
优点:unity爸爸自己内置的,以后功能应该会更强大,避免接SDK,和第三方包的不稳定因素。
缺点:提供的方法太少,编码和解码需要自己搞定,优化不够到位,没有语音识别功能。
我推荐第二种方法,具体还是看需求!
第一种:unityAPI
API - sealed class Microphone
namespace UnityEngine { // // 摘要: // /// // Use this class to record to an AudioClip using a connected microphone. // /// public sealed class Microphone { public Microphone(); // // 摘要: // /// // A list of available microphone devices, identified by name. // /// public static string[] devices { get; } // // 摘要: // /// // Stops recording. // /// // // 参数: // deviceName: // The name of the device. [WrapperlessIcall] public static void End(string deviceName); [WrapperlessIcall] public static void GetDeviceCaps(string deviceName, out int minFreq, out int maxFreq); // // 摘要: // /// // Get the position in samples of the recording. // /// // // 参数: // deviceName: // The name of the device. [WrapperlessIcall] public static int GetPosition(string deviceName); // // 摘要: // /// // Query if a device is currently recording. // /// // // 参数: // deviceName: // The name of the device. [WrapperlessIcall] public static bool IsRecording(string deviceName); // // 摘要: // /// // Start Recording with device. // /// // // 参数: // deviceName: // The name of the device. // // loop: // Indicates whether the recording should continue recording if lengthSec is reached, // and wrap around and record from the beginning of the AudioClip. // // lengthSec: // Is the length of the AudioClip produced by the recording. // // frequency: // The sample rate of the AudioClip produced by the recording. // // 返回结果: // /// // The function returns null if the recording fails to start. // /// [WrapperlessIcall] public static AudioClip Start(string deviceName, bool loop, int lengthSec, int frequency); } }
开关录音
/// <summary> /// 开关录音 /// </summary> /// <param name="isFlag"></param> public void StartMicro(bool isFlag) { if (Microphone.devices.Length < 0) return; if (isFlag) { Microphone.End(null); m_CurrentClip = Microphone.Start(null, false, m_SamplingMaxTime, m_SamplingRate); if (m_CurrentClip) return; } else { int length; int lastPos = Microphone.GetPosition(null); Debug.Log(lastPos "..........." Microphone.IsRecording(null)); if (Microphone.IsRecording(null)) { length = lastPos / m_SamplingRate; Debug.Log(length); } else { length = m_SamplingMaxTime; } Microphone.End(null); //if (length < m_SamplingMinTime) //{ // Debug.Log("长度小于两秒"); // return; //} byte[] wav = m_CurrentClip.EncodeToWAV(m_SamplingRate * length); int lengthSamples; int frequency; float[] pcm = AudioClipCompress.WavToPCM(wav, out lengthSamples, out frequency); labelText = "pcm" pcm.Length; AudioClip mClip = AudioClip.Create("", lengthSamples, 1, frequency, false); mClip.SetData(pcm, 0); AudioSource source = gameObject.GetComponent<AudioSource>(); if (source == null) source = gameObject.AddComponent<AudioSource>(); source.clip = mClip; source.Play(); } }
其实Microphone.Start的返回值就是AuidoClip,拿过来就可以播了。
但是语音聊天涉及到网络通信,所以需要进行一下数据转换。
EncodeToWAV - audioclip 转 byte
WavToPCM - byte 转 float
最后mClip.SetData(pcm, 0);
OK!
第二种:sdk(呀呀云SDK 和 亲加SDK)
1.呀呀云Dome 和 说明书文档 在附件里!
特别注意的是 播放语音的时候有两种方式 本地 和 下载。
根据项目需求选择吧。
using UnityEngine; using System.Collections; using System; using YunvaIM; public class Demo : MonoBehaviour { private string sUserId="123"; private string labelText = "ssss"; string filePath = ""; private string recordPath=string.Empty;//返回录音地址 private string recordUrlPath=string.Empty;//返回录音url地址 public GUISkin guiSkin; void Start () { EventListenerManager.AddListener(ProtocolEnum.IM_RECORD_VOLUME_NOTIFY, ImRecordVolume);//录音音量大小回调监听 #region 初始化注册 int init = YunVaImSDK.instance.YunVa_Init(0, 300000, Application.persistentDataPath, true); #endregion if (init == 0) { Debug.Log("初始化成功..."); labelText="初始化成功..."; } else { Debug.Log("初始化失败..."); labelText="初始化失败..."; } } void OnGUI() { if (guiSkin != null) { GUI.skin=guiSkin; } GUI.Box(new Rect(10f, 10f, 340, 900f), "菜单"); sUserId = GUI.TextField(new Rect(20f, 50f, 150f, 100f), sUserId); if(GUI.Button(new Rect(20f,150f,150f,100f),"登录")) { #region 登录 string ttFormat = "{{\"nickname\":\"{0}\",\"uid\":\"{1}\"}}"; string tt = string.Format(ttFormat, sUserId, sUserId); string[] wildcard = new string[2]; wildcard[0] = "0x001"; wildcard[1] = "0x002"; YunVaImSDK.instance.YunVaOnLogin(tt, "1111", wildcard, 0, (data) => { if (data.result == 0) { labelText = string.Format("登录成功,昵称:{0},用户ID:{1}", data.nickName, data.userId); YunVaImSDK.instance.RecordSetInfoReq(true);//开启录音的音量大小回调 } else { labelText = string.Format("登录失败,错误消息:{0}", data.msg); } }); #endregion } if (GUI.Button(new Rect(20f, 250f, 150f, 100f), "开始录音")) { labelText = "正在录音中。。。。。。"; #region 开始录音 filePath = string.Format("{0}/{1}.amr", Application.persistentDataPath, DateTime.Now.ToFileTime()); Debug.Log("FilePath:" filePath); YunVaImSDK.instance.RecordStartRequest(filePath); #endregion } if (GUI.Button(new Rect(20f,350f, 150f, 100f),"停止录音")) { labelText = "停止录音........."; #region 停止录音 YunVaImSDK.instance.RecordStopRequest(StopRecordResponse); #endregion } if (GUI.Button(new Rect(20f, 450f, 150f, 100f), "播放语音")) { labelText = "播放语音........."; #region 播放语音 string ext = DateTime.Now.ToFileTime().ToString(); YunVaImSDK.instance.RecordStartPlayRequest(filePath, "", ext, (data2) => //YunVaImSDK.instance.RecordStartPlayRequest("", recordUrlPath, ext, (data2) => { if (data2.result == 0) { Debug.Log("播放成功"); labelText = "播放成功"; } else { Debug.Log("播放失败"); labelText = "播放失败"; } }); #endregion } if (GUI.Button(new Rect(190f,50f, 150f, 100f),"停止播放")) { labelText = "停止播放........."; Debug.Log("停止播放"); #region 停止播放 YunVaImSDK.instance.RecordStopPlayRequest(); #endregion } if (GUI.Button(new Rect(190f,150f, 150f, 100f),"语音识别")) { labelText = "语音识别........."; Debug.Log("语音识别"); string ext = DateTime.Now.ToFileTime().ToString(); YunVaImSDK.instance.SpeechStartRequest(recordPath, ext, (data3) => { if(data3.result==0) { labelText = "识别成功,识别内容:" data3.text; } else { labelText = "识别失败,原因:" data3.msg; } }); } if(GUI.Button(new Rect(190f,250f, 150f, 100f),"上传语音")) { Debug.Log("准备上传:" recordPath); labelText = "准备上传:" recordPath; string fileId = DateTime.Now.ToFileTime().ToString(); YunVaImSDK.instance.UploadFileRequest(recordPath, fileId, (data1) => { if(data1.result==0) { recordUrlPath=data1.fileurl; Debug.Log("上传成功:" recordUrlPath); labelText = "上传成功:" recordUrlPath; } else { labelText ="上传失败:" data1.msg; Debug.Log("上传失败:" data1.msg); } }); } if(GUI.Button(new Rect(190f,350f, 150f, 100f),"下载语音")) { labelText = "下载语音......"; string DownLoadfilePath = string.Format("{0}/{1}.amr", Application.persistentDataPath, DateTime.Now.ToFileTime()); Debug.Log("下载语音:" DownLoadfilePath); string fileid = DateTime.Now.ToFileTime().ToString(); YunVaImSDK.instance.DownLoadFileRequest(recordUrlPath, DownLoadfilePath, fileid, (data4) => { if(data4.result==0) { Debug.Log("下载成功:" data4.filename); labelText = "下载成功:" data4.filename; } else { Debug.Log("下载失败:" data4.msg); labelText = "下载失败:" data4.msg; } }); } if (GUI.Button(new Rect(190f, 450f, 150f, 100f), "登出")) { #region 登出 YunVaImSDK.instance.YunVaLogOut(); #endregion } GUI.Label(new Rect(400f, 10f, 500f, 30f), "返回提示"); GUI.Label(new Rect(400f, 30f, 500f, 50f), labelText); } /// <summary> /// 停止录音 /// </summary> /// <param name="data"></param> private void StopRecordResponse(ImRecordStopResp data) { if(!string.IsNullOrEmpty(data.strfilepath)) { recordPath=data.strfilepath; labelText = "停止录音返回:" recordPath; Debug.Log("停止录音返回:" recordPath); } } public void ImRecordVolume(object data) { ImRecordVolumeNotify RecordVolumeNotify = data as ImRecordVolumeNotify; Debug.Log("ImRecordVolumeNotify:v_volume=" RecordVolumeNotify.v_volume); } }
2.亲加 主要是各种事件回调和接口
使用操作起来有点复杂,但是功能全面。
(慎重选择)
亲加说明文档连接
http://www.gotye.com.cn/docs/ime/unity3d.html
Dome
using UnityEngine; using System.Collections; using gotye; public class MainManager : MonoBehaviour { public GotyeAPI api; string appKey = "xxxxxxxxxxxxxxxx"; string packageName = "com.gotye.api"; ListenerLogin listenerLogin; ListenerChat listenerChat; ListenerRoom listenerRoom; string resurt = ""; string text = ""; static MainManager _instance; public static MainManager Instance { get { return _instance; } } void Awake() { InvokeRepeating("mainLoop", 0.0f, 0.050f);//初始化 _instance = this; } // Use this for initialization void Start() { //初始化 api = GotyeAPI.GetInstance(); api.Init(appKey, packageName); //添加事件回调 listenerLogin = new ListenerLogin(); listenerChat = new ListenerChat(); listenerRoom = new ListenerRoom(); api.AddListener(listenerLogin); api.AddListener(listenerChat); api.AddListener(listenerRoom); } void OnGUI() { GUI.Label(new Rect(200, 0, 200, 200), text); GUI.Label(new Rect(200, 200, 200, 200), resurt); if (GUI.Button(new Rect(0, 0, 200, 100), "sq123登录")) { text = "sq123登录"; api.Login("sq123", null); } if (GUI.Button(new Rect(0, 100, 200, 100), "sq222登录")) { text = "sq222登录"; api.Login("sq222", null); } if (GUI.Button(new Rect(0, 200, 200, 100), "进入聊天室")) { //298926 text = "进入聊天室"; GotyeRoom room = new GotyeRoom(298926); api.EnterRoom(room); } if (GUI.Button(new Rect(0, 300, 200, 100), "开始说话")) { text = "开始说话"; GotyeRoom room = new GotyeRoom(298926); //api.SendMessage(GotyeMessage.CreateTextMessage(room, "111")); api.StartTalk(room,0,false,20000); } if (GUI.Button(new Rect(0, 400, 200, 100), "停止说话")) { text = "停止说话"; api.StopTalk(); } if (GUI.Button(new Rect(0, 500, 200, 100), "退出聊天室")) { text = "退出聊天室"; GotyeRoom room = new GotyeRoom(298926); api.LeaveRoom(room); } if (GUI.Button(new Rect(0, 600, 200, 100), "退出登录")) { text = "退出登录"; api.Logout(); } } void mainLoop()//初始化 { GotyeAPI.GetInstance().MainLoop(); } //显示Gui信息 public void ShowAnimate(string log) { text = log; } public void ShowResurt(string log) { resurt = log; } }