DataChannelSample.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. using System.Collections;
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. using Unity.WebRTC;
  5. using System;
  6. using Unity.WebRTC.Samples;
  7. class DataChannelSample : MonoBehaviour
  8. {
  9. #pragma warning disable 0649
  10. [SerializeField] private Button callButton;
  11. [SerializeField] private Button hangupButton;
  12. [SerializeField] private Button sendButton;
  13. [SerializeField] private InputField textSend;
  14. [SerializeField] private InputField textReceive;
  15. #pragma warning restore 0649
  16. private RTCPeerConnection pc1, pc2;
  17. private RTCDataChannel dataChannel, remoteDataChannel;
  18. private DelegateOnIceConnectionChange pc1OnIceConnectionChange;
  19. private DelegateOnIceConnectionChange pc2OnIceConnectionChange;
  20. private DelegateOnIceCandidate pc1OnIceCandidate;
  21. private DelegateOnIceCandidate pc2OnIceCandidate;
  22. private DelegateOnMessage onDataChannelMessage;
  23. private DelegateOnOpen onDataChannelOpen;
  24. private DelegateOnClose onDataChannelClose;
  25. private DelegateOnDataChannel onDataChannel;
  26. private void Awake()
  27. {
  28. WebRTC.Initialize(WebRTCSettings.LimitTextureSize);
  29. callButton.onClick.AddListener(() => { StartCoroutine(Call()); });
  30. hangupButton.onClick.AddListener(() => { Hangup(); });
  31. }
  32. private void OnDestroy()
  33. {
  34. WebRTC.Dispose();
  35. }
  36. private void Start()
  37. {
  38. callButton.interactable = true;
  39. hangupButton.interactable = false;
  40. pc1OnIceConnectionChange = state => { OnIceConnectionChange(pc1, state); };
  41. pc2OnIceConnectionChange = state => { OnIceConnectionChange(pc2, state); };
  42. pc1OnIceCandidate = candidate => { OnIceCandidate(pc1, candidate); };
  43. pc2OnIceCandidate = candidate => { OnIceCandidate(pc2, candidate); };
  44. onDataChannel = channel =>
  45. {
  46. remoteDataChannel = channel;
  47. remoteDataChannel.OnMessage = onDataChannelMessage;
  48. };
  49. onDataChannelMessage = bytes => { textReceive.text = System.Text.Encoding.UTF8.GetString(bytes); };
  50. onDataChannelOpen = () =>
  51. {
  52. sendButton.interactable = true;
  53. hangupButton.interactable = true;
  54. };
  55. onDataChannelClose = () =>
  56. {
  57. sendButton.interactable = false;
  58. hangupButton.interactable = false;
  59. };
  60. }
  61. RTCConfiguration GetSelectedSdpSemantics()
  62. {
  63. RTCConfiguration config = default;
  64. config.iceServers = new RTCIceServer[]
  65. {
  66. new RTCIceServer { urls = new string[] { "stun:stun.l.google.com:19302" } }
  67. };
  68. return config;
  69. }
  70. void OnIceConnectionChange(RTCPeerConnection pc, RTCIceConnectionState state)
  71. {
  72. switch (state)
  73. {
  74. case RTCIceConnectionState.New:
  75. Debug.Log($"{GetName(pc)} IceConnectionState: New");
  76. break;
  77. case RTCIceConnectionState.Checking:
  78. Debug.Log($"{GetName(pc)} IceConnectionState: Checking");
  79. break;
  80. case RTCIceConnectionState.Closed:
  81. Debug.Log($"{GetName(pc)} IceConnectionState: Closed");
  82. break;
  83. case RTCIceConnectionState.Completed:
  84. Debug.Log($"{GetName(pc)} IceConnectionState: Completed");
  85. break;
  86. case RTCIceConnectionState.Connected:
  87. Debug.Log($"{GetName(pc)} IceConnectionState: Connected");
  88. break;
  89. case RTCIceConnectionState.Disconnected:
  90. Debug.Log($"{GetName(pc)} IceConnectionState: Disconnected");
  91. break;
  92. case RTCIceConnectionState.Failed:
  93. Debug.Log($"{GetName(pc)} IceConnectionState: Failed");
  94. break;
  95. case RTCIceConnectionState.Max:
  96. Debug.Log($"{GetName(pc)} IceConnectionState: Max");
  97. break;
  98. default:
  99. break;
  100. }
  101. }
  102. void Pc1OnIceConnectinChange(RTCIceConnectionState state)
  103. {
  104. OnIceConnectionChange(pc1, state);
  105. }
  106. void Pc2OnIceConnectionChange(RTCIceConnectionState state)
  107. {
  108. OnIceConnectionChange(pc2, state);
  109. }
  110. void Pc1OnIceCandidate(RTCIceCandidate candidate)
  111. {
  112. OnIceCandidate(pc1, candidate);
  113. }
  114. void Pc2OnIceCandidate(RTCIceCandidate candidate)
  115. {
  116. OnIceCandidate(pc2, candidate);
  117. }
  118. IEnumerator Call()
  119. {
  120. callButton.interactable = false;
  121. Debug.Log("GetSelectedSdpSemantics");
  122. var configuration = GetSelectedSdpSemantics();
  123. pc1 = new RTCPeerConnection(ref configuration);
  124. Debug.Log("Created local peer connection object pc1");
  125. pc1.OnIceCandidate = pc1OnIceCandidate;
  126. pc1.OnIceConnectionChange = pc1OnIceConnectionChange;
  127. pc2 = new RTCPeerConnection(ref configuration);
  128. Debug.Log("Created remote peer connection object pc2");
  129. pc2.OnIceCandidate = pc2OnIceCandidate;
  130. pc2.OnIceConnectionChange = pc2OnIceConnectionChange;
  131. pc2.OnDataChannel = onDataChannel;
  132. RTCDataChannelInit conf = new RTCDataChannelInit();
  133. dataChannel = pc1.CreateDataChannel("data", conf);
  134. dataChannel.OnOpen = onDataChannelOpen;
  135. Debug.Log("pc1 createOffer start");
  136. var op = pc1.CreateOffer();
  137. yield return op;
  138. if (!op.IsError)
  139. {
  140. yield return StartCoroutine(OnCreateOfferSuccess(op.Desc));
  141. }
  142. else
  143. {
  144. OnCreateSessionDescriptionError(op.Error);
  145. }
  146. }
  147. void Hangup()
  148. {
  149. pc1.Close();
  150. pc2.Close();
  151. pc1 = null;
  152. pc2 = null;
  153. textSend.text = string.Empty;
  154. textReceive.text = string.Empty;
  155. hangupButton.interactable = false;
  156. sendButton.interactable = false;
  157. callButton.interactable = true;
  158. }
  159. /// <summary>
  160. ///
  161. /// </summary>
  162. /// <param name="pc"></param>
  163. /// <param name="streamEvent"></param>
  164. void OnIceCandidate(RTCPeerConnection pc, RTCIceCandidate candidate)
  165. {
  166. GetOtherPc(pc).AddIceCandidate(candidate);
  167. Debug.Log($"{GetName(pc)} ICE candidate:\n {candidate.Candidate}");
  168. }
  169. public void SendMsg()
  170. {
  171. dataChannel.Send(textSend.text);
  172. }
  173. string GetName(RTCPeerConnection pc)
  174. {
  175. return (pc == pc1) ? "pc1" : "pc2";
  176. }
  177. RTCPeerConnection GetOtherPc(RTCPeerConnection pc)
  178. {
  179. return (pc == pc1) ? pc2 : pc1;
  180. }
  181. IEnumerator OnCreateOfferSuccess(RTCSessionDescription desc)
  182. {
  183. Debug.Log($"Offer from pc1\n{desc.sdp}");
  184. Debug.Log("pc1 setLocalDescription start");
  185. var op = pc1.SetLocalDescription(ref desc);
  186. yield return op;
  187. if (!op.IsError)
  188. {
  189. OnSetLocalSuccess(pc1);
  190. }
  191. else
  192. {
  193. var error = op.Error;
  194. OnSetSessionDescriptionError(ref error);
  195. }
  196. Debug.Log("pc2 setRemoteDescription start");
  197. var op2 = pc2.SetRemoteDescription(ref desc);
  198. yield return op2;
  199. if (!op2.IsError)
  200. {
  201. OnSetRemoteSuccess(pc2);
  202. }
  203. else
  204. {
  205. var error = op2.Error;
  206. OnSetSessionDescriptionError(ref error);
  207. }
  208. Debug.Log("pc2 createAnswer start");
  209. // Since the 'remote' side has no media stream we need
  210. // to pass in the right constraints in order for it to
  211. // accept the incoming offer of audio and video.
  212. var op3 = pc2.CreateAnswer();
  213. yield return op3;
  214. if (!op3.IsError)
  215. {
  216. yield return OnCreateAnswerSuccess(op3.Desc);
  217. }
  218. else
  219. {
  220. OnCreateSessionDescriptionError(op3.Error);
  221. }
  222. }
  223. void OnSetLocalSuccess(RTCPeerConnection pc)
  224. {
  225. Debug.Log($"{GetName(pc)} SetLocalDescription complete");
  226. }
  227. void OnSetSessionDescriptionError(ref RTCError error) { }
  228. void OnSetRemoteSuccess(RTCPeerConnection pc)
  229. {
  230. Debug.Log($"{GetName(pc)} SetRemoteDescription complete");
  231. }
  232. IEnumerator OnCreateAnswerSuccess(RTCSessionDescription desc)
  233. {
  234. Debug.Log($"Answer from pc2:\n{desc.sdp}");
  235. Debug.Log("pc2 setLocalDescription start");
  236. var op = pc2.SetLocalDescription(ref desc);
  237. yield return op;
  238. if (!op.IsError)
  239. {
  240. OnSetLocalSuccess(pc2);
  241. }
  242. else
  243. {
  244. var error = op.Error;
  245. OnSetSessionDescriptionError(ref error);
  246. }
  247. Debug.Log("pc1 setRemoteDescription start");
  248. var op2 = pc1.SetRemoteDescription(ref desc);
  249. yield return op2;
  250. if (!op2.IsError)
  251. {
  252. OnSetRemoteSuccess(pc1);
  253. }
  254. else
  255. {
  256. var error = op2.Error;
  257. OnSetSessionDescriptionError(ref error);
  258. }
  259. }
  260. IEnumerator LoopGetStats()
  261. {
  262. while (true)
  263. {
  264. yield return new WaitForSeconds(1f);
  265. if (!sendButton.interactable)
  266. continue;
  267. var op1 = pc1.GetStats();
  268. var op2 = pc2.GetStats();
  269. yield return op1;
  270. yield return op2;
  271. Debug.Log("pc1");
  272. foreach (var stat in op1.Value.Stats.Values)
  273. {
  274. Debug.Log(stat.Type.ToString());
  275. }
  276. Debug.Log("pc2");
  277. foreach (var stat in op2.Value.Stats.Values)
  278. {
  279. Debug.Log(stat.Type.ToString());
  280. }
  281. }
  282. }
  283. void OnAddIceCandidateSuccess(RTCPeerConnection pc)
  284. {
  285. Debug.Log($"{GetName(pc)} addIceCandidate success");
  286. }
  287. void OnAddIceCandidateError(RTCPeerConnection pc, RTCError error)
  288. {
  289. Debug.Log($"{GetName(pc)} failed to add ICE Candidate: ${error}");
  290. }
  291. void OnCreateSessionDescriptionError(RTCError e)
  292. {
  293. }
  294. }