原文:http://www.cnblogs.com/saucerman/p/5555793.html
因为项目要加语音。语音数据都非常大。所以顺带就把之前写的网络模块一起测试了。
然后发现了一些bug,逐修。本来想在原文上面直接修改掉。但是恐怕已经看到的人拿去用了之后,再回头看也不一定能看明白,索性再写一文,将新文件直接放上来。
错误修改:
- 网络接收数据后,有一种情况没有处理完整,导致接收数据之后数据池的计数器没有向后偏移
- 网络数据处理后,当当前包仅剩1字节,下一个次数据进来的时候,需要2字节才能确认当前消息长度。增加了消息补齐机制。
- 增加了当网络数据拥堵的时候,直接断开当前链接。
- MsgUnPack的GetHead函数获取消息id的时候使用了错误的函数,导致数据偏移不正确
- MsgUnPack的UnPack(byte[] mBuff, ushort offset, ushort len),由于总buff扩大,导致offset参数超过上限,改为int
- 消息事件增加了错误消息ID过滤
由于语音的需求,将原本的服务器段接受buff容量扩大一倍。增加了语音模块。
特别说下语音模块。
http://blog.csdn.net/huutu/article/details/20216613
这是原文。
稍做修改。特别说一下这个语音模块在使用中容易遇到的问题。
- 如果声音太小,可能是你录音设备的侦听开得不够。
- 本地测试还好,放到网络上之后,因为代码里有处理,如果没有对象会创建对象并且添加必要组件。原文在创建的时候比特率是手动填写的。导致我客户端一个比特率,服务器一个比特率。然后客户端听着一切正常,传给服务器就错了。后来查了一天,排查各个代码段之后才找到这个原因。
以下是代码:
新增语音模块:
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Text; 6 using UnityEngine; 7 using System.Collections; 8 9 [RequireComponent(typeof(AudioSource))] 10 public class MicroPhoneInput : MonoBehaviour 11 { 12 13 private static MicroPhoneInput m_instance; 14 15 public float sensitivity = 100; 16 public float loudness = 0; 17 18 private static string[] micArray = null; 19 20 const int HEADER_SIZE = 44; 21 22 const int RECORD_TIME = 5; 23 const int RECORD_frequency = 8000; 24 25 // Use this for initialization 26 void Start() 27 { 28 } 29 30 public static MicroPhoneInput getInstance() 31 { 32 if (m_instance == null) 33 { 34 micArray = Microphone.devices; 35 if (micArray.Length == 0) 36 { 37 Debug.LogError("Microphone.devices is null"); 38 } 39 foreach (string deviceStr in Microphone.devices) 40 { 41 Debug.Log("device name = " + deviceStr); 42 } 43 if (micArray.Length == 0) 44 { 45 Debug.LogError("no mic device"); 46 } 47 48 GameObject MicObj = new GameObject("MicObj"); 49 m_instance = MicObj.AddComponent<MicroPhoneInput>(); 50 } 51 return m_instance; 52 } 53 54 public void StartRecord() 55 { 56 audio.Stop(); 57 if (micArray.Length == 0) 58 { 59 Debug.Log("No Record Device!"); 60 return; 61 } 62 audio.loop = false; 63 audio.mute = true; 64 audio.clip = Microphone.Start(null, false, RECORD_TIME, RECORD_frequency); //22050 65 while (!(Microphone.GetPosition(null) > 0)) 66 { 67 } 68 audio.Play(); 69 Debug.Log("StartRecord"); 70 //倒计时 71 StartCoroutine(TimeDown()); 72 73 } 74 75 public void StopRecord() 76 { 77 if (micArray.Length == 0) 78 { 79 Debug.Log("No Record Device!"); 80 return; 81 } 82 if (!Microphone.IsRecording(null)) 83 { 84 return; 85 } 86 Microphone.End(null); 87 audio.Stop(); 88 89 Debug.Log("StopRecord"); 90 91 } 92 93 public Byte[] GetClipData() 94 { 95 if (audio.clip == null) 96 { 97 Debug.Log("GetClipData audio.clip is null"); 98 return null; 99 } 100 101 float[] samples = new float[audio.clip.samples]; 102 103 audio.clip.GetData(samples, 0); 104 105 106 Byte[] outData = new byte[samples.Length * 2]; 107 //Int16[] intData = new Int16[samples.Length]; 108 //converting in 2 float[] steps to Int16[], //then Int16[] to Byte[] 109 110 int rescaleFactor = 32767; //to convert float to Int16 111 112 for (int i = 0; i < samples.Length; i++) 113 { 114 short temshort = (short)(samples[i] * rescaleFactor); 115 116 Byte[] temdata = System.BitConverter.GetBytes(temshort); 117 118 outData[i * 2] = temdata[0]; 119 outData[i * 2 + 1] = temdata[1]; 120 121 122 } 123 if (outData == null || outData.Length <= 0) 124 { 125 Debug.Log("GetClipData intData is null"); 126 return null; 127 } 128 //return intData; 129 return outData; 130 } 131 public void PlayClipData(Int16[] intArr) 132 { 133 if (intArr.Length == 0) 134 { 135 Debug.Log("get intarr clipdata is null"); 136 return; 137 } 138 //从Int16[]到float[] 139 float[] samples = new float[intArr.Length]; 140 int rescaleFactor = 32767; 141 for (int i = 0; i < intArr.Length; i++) 142 { 143 samples[i] = (float)intArr[i] / rescaleFactor; 144 } 145 146 //从float[]到Clip 147 AudioSource audioSource = this.GetComponent<AudioSource>(); 148 if (audioSource.clip == null) 149 { 150 audioSource.clip = AudioClip.Create("playRecordClip", intArr.Length, 1, RECORD_frequency, false, false); 151 } 152 audioSource.clip.SetData(samples, 0); 153 audioSource.mute = false; 154 audioSource.Play(); 155 } 156 public void PlayRecord() 157 { 158 if (audio.clip == null) 159 { 160 Debug.Log("audio.clip=null"); 161 return; 162 } 163 audio.mute = false; 164 audio.loop = false; 165 audio.Play(); 166 Debug.Log("PlayRecord"); 167 168 } 169 170 171 172 public float GetAveragedVolume() 173 { 174 float[] data = new float[256]; 175 float a = 0; 176 audio.GetOutputData(data, 0); 177 foreach (float s in data) 178 { 179 a += Mathf.Abs(s); 180 } 181 return a / 256; 182 } 183 184 // Update is called once per frame 185 void Update() 186 { 187 // loudness = GetAveragedVolume() * sensitivity; 188 // if (loudness > 1) 189 // { 190 // Debug.Log("loudness = " + loudness); 191 // } 192 } 193 194 private IEnumerator TimeDown() 195 { 196 Debug.Log(" IEnumerator TimeDown()"); 197 198 int time = 0; 199 while (time < RECORD_TIME) 200 { 201 if (!Microphone.IsRecording(null)) 202 { //如果没有录制 203 Debug.Log("IsRecording false"); 204 yield break; 205 } 206 Debug.Log("yield return new WaitForSeconds " + time); 207 yield return new WaitForSeconds(1); 208 time++; 209 } 210 if (time >= 10) 211 { 212 Debug.Log("RECORD_TIME is out! stop record!"); 213 StopRecord(); 214 } 215 yield return 0; 216 } 217 }