MultiplePeerConnectionsSample.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. namespace Unity.WebRTC.Samples
  6. {
  7. class MultiplePeerConnectionsSample : MonoBehaviour
  8. {
  9. #pragma warning disable 0649
  10. [SerializeField] private Button startButton;
  11. [SerializeField] private Button callButton;
  12. [SerializeField] private Button hangUpButton;
  13. [SerializeField] private Camera cam;
  14. [SerializeField] private RawImage sourceImage;
  15. [SerializeField] private RawImage receiveImage1;
  16. [SerializeField] private RawImage receiveImage2;
  17. [SerializeField] private AudioSource sourceAudio;
  18. [SerializeField] private AudioSource receiveAudio1;
  19. [SerializeField] private AudioSource receiveAudio2;
  20. [SerializeField] private Transform rotateObject;
  21. [SerializeField] private AudioClip audioclipStereoSample;
  22. #pragma warning restore 0649
  23. private static RTCConfiguration configuration = new RTCConfiguration
  24. {
  25. iceServers = new[] {new RTCIceServer {urls = new[] {"stun:stun.l.google.com:19302"}}}
  26. };
  27. private RTCPeerConnection pc1Local, pc1Remote, pc2Local, pc2Remote;
  28. private MediaStream sourceStream;
  29. private void Awake()
  30. {
  31. WebRTC.Initialize(WebRTCSettings.LimitTextureSize);
  32. }
  33. private void OnDestroy()
  34. {
  35. WebRTC.Dispose();
  36. }
  37. private void Start()
  38. {
  39. StartCoroutine(WebRTC.Update());
  40. startButton.onClick.AddListener(Setup);
  41. callButton.onClick.AddListener(Call);
  42. hangUpButton.onClick.AddListener(HangUp);
  43. startButton.interactable = true;
  44. callButton.interactable = false;
  45. hangUpButton.interactable = false;
  46. }
  47. private void Update()
  48. {
  49. if (rotateObject != null)
  50. {
  51. rotateObject.Rotate(1, 2, 3);
  52. }
  53. }
  54. private void Setup()
  55. {
  56. Debug.Log("Set up source/receive streams");
  57. sourceStream = new MediaStream();
  58. var videoTrack = cam.CaptureStreamTrack(WebRTCSettings.StreamSize.x, WebRTCSettings.StreamSize.y);
  59. sourceStream.AddTrack(videoTrack);
  60. sourceImage.texture = cam.targetTexture;
  61. sourceAudio.clip = audioclipStereoSample;
  62. sourceAudio.loop = true;
  63. sourceAudio.Play();
  64. var audioTrack = new AudioStreamTrack(sourceAudio);
  65. sourceStream.AddTrack(audioTrack);
  66. startButton.interactable = false;
  67. callButton.interactable = true;
  68. }
  69. private void Call()
  70. {
  71. Debug.Log("Starting calls");
  72. pc1Local = new RTCPeerConnection(ref configuration);
  73. pc1Remote = new RTCPeerConnection(ref configuration);
  74. pc1Remote.OnTrack = e =>
  75. {
  76. if (e.Track is VideoStreamTrack videoTrack)
  77. {
  78. videoTrack.OnVideoReceived += tex =>
  79. {
  80. receiveImage1.texture = tex;
  81. };
  82. }
  83. if (e.Track is AudioStreamTrack audioTrack)
  84. {
  85. receiveAudio1.SetTrack(audioTrack);
  86. receiveAudio1.loop = true;
  87. receiveAudio1.Play();
  88. }
  89. };
  90. pc1Local.OnIceCandidate = candidate => pc1Remote.AddIceCandidate(candidate);
  91. pc1Remote.OnIceCandidate = candidate => pc1Local.AddIceCandidate(candidate);
  92. Debug.Log("pc1: created local and remote peer connection object");
  93. pc2Local = new RTCPeerConnection(ref configuration);
  94. pc2Remote = new RTCPeerConnection(ref configuration);
  95. pc2Remote.OnTrack = e =>
  96. {
  97. if (e.Track is VideoStreamTrack videoTrack)
  98. {
  99. videoTrack.OnVideoReceived += tex =>
  100. {
  101. receiveImage2.texture = tex;
  102. };
  103. }
  104. if (e.Track is AudioStreamTrack audioTrack)
  105. {
  106. receiveAudio2.SetTrack(audioTrack);
  107. receiveAudio2.loop = true;
  108. receiveAudio2.Play();
  109. }
  110. };
  111. pc2Local.OnIceCandidate = candidate => pc2Remote.AddIceCandidate(candidate);
  112. pc2Remote.OnIceCandidate = candidate => pc2Local.AddIceCandidate(candidate);
  113. Debug.Log("pc2: created local and remote peer connection object");
  114. var pc1VideoSenders = new List<RTCRtpSender>();
  115. var pc2VideoSenders = new List<RTCRtpSender>();
  116. foreach (var track in sourceStream.GetTracks())
  117. {
  118. var pc1Sender = pc1Local.AddTrack(track, sourceStream);
  119. var pc2Sender = pc2Local.AddTrack(track, sourceStream);
  120. if (track.Kind == TrackKind.Video)
  121. {
  122. pc1VideoSenders.Add(pc1Sender);
  123. pc2VideoSenders.Add(pc2Sender);
  124. }
  125. }
  126. if (WebRTCSettings.UseVideoCodec != null)
  127. {
  128. var codecs = new[] {WebRTCSettings.UseVideoCodec};
  129. foreach (var transceiver in pc1Local.GetTransceivers())
  130. {
  131. if (pc1VideoSenders.Contains(transceiver.Sender))
  132. {
  133. transceiver.SetCodecPreferences(codecs);
  134. }
  135. }
  136. foreach (var transceiver in pc2Local.GetTransceivers())
  137. {
  138. if (pc2VideoSenders.Contains(transceiver.Sender))
  139. {
  140. transceiver.SetCodecPreferences(codecs);
  141. }
  142. }
  143. }
  144. Debug.Log("Adding local stream to pc1Local/pc2Local");
  145. StartCoroutine(NegotiationPeer(pc1Local, pc1Remote));
  146. StartCoroutine(NegotiationPeer(pc2Local, pc2Remote));
  147. callButton.interactable = false;
  148. hangUpButton.interactable = true;
  149. }
  150. private void HangUp()
  151. {
  152. foreach (var track in sourceStream.GetTracks())
  153. {
  154. track.Dispose();
  155. }
  156. sourceStream.Dispose();
  157. sourceStream = null;
  158. pc1Local.Close();
  159. pc1Remote.Close();
  160. pc2Local.Close();
  161. pc2Remote.Close();
  162. pc1Local.Dispose();
  163. pc1Remote.Dispose();
  164. pc2Local.Dispose();
  165. pc2Remote.Dispose();
  166. pc1Local = null;
  167. pc1Remote = null;
  168. pc2Local = null;
  169. pc2Remote = null;
  170. sourceImage.texture = null;
  171. sourceAudio.Stop();
  172. sourceAudio.clip = null;
  173. receiveImage1.texture = null;
  174. receiveAudio1.Stop();
  175. receiveAudio1.clip = null;
  176. receiveImage2.texture = null;
  177. receiveAudio2.Stop();
  178. receiveAudio2.clip = null;
  179. startButton.interactable = true;
  180. callButton.interactable = false;
  181. hangUpButton.interactable = false;
  182. }
  183. private static void OnCreateSessionDescriptionError(RTCError error)
  184. {
  185. Debug.LogError($"Failed to create session description: {error.message}");
  186. }
  187. private static IEnumerator NegotiationPeer(RTCPeerConnection localPeer, RTCPeerConnection remotePeer)
  188. {
  189. var opCreateOffer = localPeer.CreateOffer();
  190. yield return opCreateOffer;
  191. if (opCreateOffer.IsError)
  192. {
  193. OnCreateSessionDescriptionError(opCreateOffer.Error);
  194. yield break;
  195. }
  196. var offerDesc = opCreateOffer.Desc;
  197. yield return localPeer.SetLocalDescription(ref offerDesc);
  198. Debug.Log($"Offer from LocalPeer \n {offerDesc.sdp}");
  199. yield return remotePeer.SetRemoteDescription(ref offerDesc);
  200. var opCreateAnswer = remotePeer.CreateAnswer();
  201. yield return opCreateAnswer;
  202. if (opCreateAnswer.IsError)
  203. {
  204. OnCreateSessionDescriptionError(opCreateAnswer.Error);
  205. yield break;
  206. }
  207. var answerDesc = opCreateAnswer.Desc;
  208. yield return remotePeer.SetLocalDescription(ref answerDesc);
  209. Debug.Log($"Answer from RemotePeer \n {answerDesc.sdp}");
  210. yield return localPeer.SetRemoteDescription(ref answerDesc);
  211. }
  212. }
  213. }