QuickAudioVideoManager.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. using CScript.Net;
  2. using CScript.Utilities;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Runtime.InteropServices;
  8. using System.Threading;
  9. using UnityEngine;
  10. namespace CScript.Quick
  11. {
  12. public class QuickAudioVideoManager : MonoSingleton<QuickAudioVideoManager>
  13. {
  14. public PackageHandler packageHandler = new PackageHandler(null);
  15. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  16. public delegate int OnVideoFrameCallBackDelegate(IntPtr frame, int frameLen, int timestamp);
  17. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  18. public delegate int OnAudioFrameCallBackDelegate(IntPtr frame, int frameLen, int timestamp);
  19. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  20. public delegate int OnLogCallBackDelegate(int state, string msg);
  21. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  22. public delegate IntPtr OnWriteCallBackDelegete();
  23. [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  24. public delegate int OnCloseCallBackDelegate();
  25. /**
  26. *
  27. * @param channel 传输方式 支持tcp或quic
  28. * @param ip 服务端 IP
  29. * @param port 服务端 Port
  30. * @param isW 是否开启 socket写入回调 1:开启写入 0:不开启写入
  31. * @param wInter 开启socket写入回调的循环间隔,单位毫秒 1-30000
  32. * @param retryCount 重连服务器的次数 0:一直重连 ,1:重连一次 2:重连2次,以此类推
  33. * @param retryInter 重连服务器的间隔,单位毫秒 1-30000
  34. * @param onVideoFrameCb 视频帧回调
  35. * @param onAudioFrameCb 音频帧回调
  36. * @param onLogCb 日志回调
  37. * @param onWriteCb socket写入数据回调
  38. * @param onCloseCb 是否关闭连接回调
  39. * @return
  40. */
  41. [DllImport("AvClient")]
  42. public static extern IntPtr AvClientConnect(string channel, string ip, int port, int isW, int wInter, int retryCount, int retryInter,
  43. OnVideoFrameCallBackDelegate onVideoFrameCb, OnAudioFrameCallBackDelegate onAudioFrameCb,
  44. OnLogCallBackDelegate onLogCb, OnWriteCallBackDelegete onWriteCb, OnCloseCallBackDelegate onCloseCb
  45. );
  46. private string _quickServerIP;
  47. private int _quickServerPort;
  48. public AudioSource audio;
  49. private int buffPosAudio = 0;
  50. int positionAudio = 0;
  51. private byte[] databuff;
  52. private MemoryStream _receiveAudioBuffer = new MemoryStream(44100 * 12);
  53. private Thread _quickThread;
  54. bool isPlay = false;
  55. private MemoryStream _audioBuffer = new MemoryStream(4096);
  56. public readonly int sampleLength = 44100 * 12;
  57. private int closeSign = 0;
  58. const int DEF_RECV_BUFFER_SIZE = 409600 * 4;
  59. private MemoryStream _receiveVideoBuffer = new MemoryStream(DEF_RECV_BUFFER_SIZE);
  60. private string serverType = "tcp";
  61. public void Init(string ip, int port)
  62. {
  63. _quickServerIP = ip;
  64. _quickServerPort = port;
  65. positionAudio = 0;
  66. closeSign = 0;
  67. switch (App.AppManager.Instance.connectType)
  68. {
  69. case App.ConnectType.None:
  70. break;
  71. case App.ConnectType.TCPServer:
  72. serverType = "tcp";
  73. break;
  74. case App.ConnectType.Quic:
  75. serverType = "quic";
  76. break;
  77. default:
  78. break;
  79. }
  80. Debug.Log("serverType:"+serverType);
  81. if (_quickThread == null || !_quickThread.IsAlive)
  82. {
  83. _quickThread = new Thread(StartQuick);
  84. _quickThread.Start();
  85. }
  86. NetDistribute.Instance.OnConnect(true, "success");
  87. }
  88. void StartQuick()
  89. {
  90. //AvClientConnect(serverType, _quickServerIP, _quickServerPort,
  91. // OnNewConnCallBack, OnConnClosedCallBack,
  92. // OnVideoFrameCallBack, OnAudioFrameCallBack,
  93. // OnLogCallBack
  94. // );
  95. int isW = 0;
  96. int wInter = 1000;
  97. int retryCount = 0;
  98. int retryInter = 1000;
  99. AvClientConnect(serverType, _quickServerIP, _quickServerPort, isW, wInter, retryCount, retryInter,
  100. OnVideoFrameCallBack, OnAudioFrameCallBack,
  101. OnLogCallBack, OnWriteCallBack, OnCloseCallBack);
  102. }
  103. private int OnCloseCallBack()
  104. {
  105. //检测应用层是否关闭连接
  106. /**
  107. * 返回值说明:
  108. * 返回值类型为 c#的Int
  109. * 返回 0 表示继续保持当前连接
  110. * 返回 100 表示关闭当前连接
  111. */
  112. return closeSign;
  113. }
  114. private IntPtr OnWriteCallBack()
  115. {
  116. //动态库回调应用层写入数据
  117. /**
  118. * 返回值说明:
  119. * 返回值类型为 c#的IntPtr
  120. * 返回值的前4个字节表示(发送字节流的长度)
  121. * 返回值从第4个字节之后的所有字节表示发送的内容字节流
  122. * 如果当前无数据,请确保前4个字节表示的值的长度为0
  123. */
  124. //int writeBufLen = 1003;// 发送字节流的长度
  125. //byte[] writeBufLenBytes = BitConverter.GetBytes(writeBufLen);// 内容长度转为4个字节
  126. byte[] writeBuf = new byte[4 + 1003];
  127. //for (int i = 0; i < 4; i++)
  128. //{
  129. // writeBuf[i] = writeBufLenBytes[i];
  130. //}
  131. //int size = writeBuf.Length;
  132. IntPtr p = Marshal.AllocHGlobal(0);
  133. Marshal.Copy(writeBuf, 0, p, 0);
  134. return p;
  135. }
  136. private int OnLogCallBack(int state, string msg)
  137. {
  138. //日志回调
  139. Console.WriteLine("c# OnLogCallBack state=" + state.ToString() + ",msg=" + msg);
  140. if (state == 100)
  141. {
  142. NetDistribute.Instance.OnConnect(true, "success");
  143. }
  144. /**
  145. * state=99 :开始连接
  146. * state=100 :连接成功
  147. * state=101 :连接已经断开
  148. */
  149. return 0;
  150. }
  151. private int OnVideoFrameCallBack(IntPtr frame, int frameLen, int timestamp)
  152. {
  153. Debug.Log("c# OnVideoFrameCallBack frameLen=" + frameLen.ToString() + ",timestamp=" + timestamp.ToString());
  154. Marshal.Copy(frame, this._receiveVideoBuffer.GetBuffer(), 0, frameLen);
  155. this.packageHandler.ReceiveQuicData(this._receiveVideoBuffer.GetBuffer(), 0, frameLen);
  156. return 0;
  157. }
  158. private int OnAudioFrameCallBack(IntPtr frame, int frameLen, int timestamp)
  159. {
  160. byte[] buf = new byte[frameLen];
  161. Marshal.Copy(frame, _audioBuffer.GetBuffer(), 0, frameLen);
  162. _receiveAudioBuffer.Write(_audioBuffer.GetBuffer(), 0, frameLen);
  163. if (!isPlay)
  164. {
  165. if (_receiveAudioBuffer.Length > 4096 * 4)
  166. {
  167. isPlay = true;
  168. positionAudio = 0;
  169. AudioClip clip = AudioClip.Create("MySinusoid1", sampleLength, 1, 44100, true, OnAudioRead);//307200/2(audioBuffer.GetBuffer().Length - buffPos) / 4
  170. audio.clip = clip;
  171. audio.Play();
  172. }
  173. }
  174. Debug.Log("c# OnAudioFrameCallBack frameLen=" + frameLen.ToString() + ",timestamp=" + timestamp.ToString() + "$$$ " + _receiveAudioBuffer.Length);
  175. return 0;
  176. }
  177. void OnAudioRead(float[] data)
  178. {
  179. int count = 0;
  180. float[] floatValue = null;
  181. // Debug.Log("开始 isPlay:" + isPlay + "buffPos:" + buffPos + " position :"+ position + " sampleLength:"+ sampleLength);
  182. if (!isPlay)
  183. {
  184. if (positionAudio < sampleLength)
  185. {
  186. isPlay = true;
  187. }
  188. }
  189. if (isPlay)
  190. {
  191. if (buffPosAudio < _receiveAudioBuffer.Length)
  192. {
  193. // Debug.LogWarning("播放中 buffPos:"+ buffPos + " data.Length: "+ data.Length);
  194. floatValue = GetByte2Float(_receiveAudioBuffer.GetBuffer(), buffPosAudio, data.Length * 4);
  195. buffPosAudio += data.Length * 4;
  196. }
  197. }
  198. while (count < data.Length)
  199. {
  200. // data[count] = floatValue[count];//11
  201. data[count] = floatValue == null ? 0 : floatValue[count]*3;
  202. count++;
  203. }
  204. positionAudio += data.Length;
  205. if (positionAudio >= sampleLength)
  206. {
  207. isPlay = false;
  208. long size = _receiveAudioBuffer.Position - buffPosAudio;
  209. if (buffPosAudio < _receiveAudioBuffer.Position)
  210. {
  211. Array.Copy(_receiveAudioBuffer.GetBuffer(), this.buffPosAudio, _receiveAudioBuffer.GetBuffer(), 0, _receiveAudioBuffer.Position - this.buffPosAudio);
  212. }
  213. _receiveAudioBuffer.Position = size;
  214. _receiveAudioBuffer.SetLength(size);
  215. buffPosAudio = 0;
  216. }
  217. //Debug.LogWarning("播放结束:"+ position + " ^^^ " + buffPos + " () " + isPlay + " " + sampleLength);
  218. }
  219. public void Close()
  220. {
  221. closeSign = 100;
  222. }
  223. private float[] GetByte2Float(byte[] rawData)
  224. {
  225. float[] samples = new float[rawData.Length / 4];
  226. float rescaleFactor = 32767;
  227. short st = 0;
  228. float ft = 0;
  229. for (int i = 0; i < rawData.Length; i += 4)
  230. {
  231. st = BitConverter.ToInt16(rawData, i);
  232. ft = st / rescaleFactor;
  233. samples[i / 4] = ft;
  234. }
  235. return samples;
  236. }
  237. private float[] GetByte2Float(byte[] buffer, int start, int count)
  238. {
  239. byte[] realBuffer = new byte[count];
  240. Array.Copy(buffer, start, realBuffer, 0, count);
  241. return GetByte2Float(realBuffer);
  242. }
  243. }
  244. }