PrivateSignalingTest.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. using System;
  2. using System.Collections;
  3. using System.Threading;
  4. using System.Diagnostics;
  5. using NUnit.Framework;
  6. using Unity.RenderStreaming.RuntimeTest.Signaling;
  7. using Unity.RenderStreaming.Signaling;
  8. using Unity.WebRTC;
  9. using UnityEngine;
  10. using UnityEngine.TestTools;
  11. using Debug = UnityEngine.Debug;
  12. namespace Unity.RenderStreaming.RuntimeTest
  13. {
  14. [TestFixture(typeof(WebSocketSignaling))]
  15. [TestFixture(typeof(HttpSignaling))]
  16. [TestFixture(typeof(MockSignaling))]
  17. [UnityPlatform(exclude = new[] {RuntimePlatform.IPhonePlayer})]
  18. [ConditionalIgnore(ConditionalIgnore.IL2CPP, "Process.Start does not implement in IL2CPP.")]
  19. class PrivateSignalingTest : IPrebuildSetup
  20. {
  21. private readonly Type m_SignalingType;
  22. private Process m_ServerProcess;
  23. private RTCSessionDescription m_DescOffer;
  24. private RTCSessionDescription m_DescAnswer;
  25. private RTCIceCandidate m_candidate;
  26. private SynchronizationContext m_Context;
  27. private ISignaling signaling1;
  28. private ISignaling signaling2;
  29. public PrivateSignalingTest()
  30. {
  31. }
  32. public PrivateSignalingTest(Type type)
  33. {
  34. m_SignalingType = type;
  35. }
  36. public void Setup()
  37. {
  38. if (m_SignalingType == typeof(MockSignaling))
  39. {
  40. return;
  41. }
  42. #if UNITY_EDITOR
  43. string dir = System.IO.Directory.GetCurrentDirectory();
  44. string fileName = System.IO.Path.Combine(dir, Editor.WebAppDownloader.GetFileName());
  45. if (System.IO.File.Exists(fileName) || System.IO.File.Exists(TestUtility.GetWebAppLocationFromEnv()))
  46. {
  47. // already exists.
  48. return;
  49. }
  50. bool downloadRaised = false;
  51. Editor.WebAppDownloader.DownloadCurrentVersionWebApp(dir, success => { downloadRaised = true; });
  52. TestUtility.Wait(() => downloadRaised, 10000);
  53. #endif
  54. }
  55. [OneTimeSetUp]
  56. public void OneTimeSetUp()
  57. {
  58. if (m_SignalingType == typeof(MockSignaling))
  59. {
  60. MockSignaling.Reset(true);
  61. return;
  62. }
  63. m_ServerProcess = new Process();
  64. string fileName = TestUtility.GetWebAppLocationFromEnv();
  65. if (string.IsNullOrEmpty(fileName))
  66. {
  67. Debug.Log($"webapp file not found in {fileName}");
  68. string dir = System.IO.Directory.GetCurrentDirectory();
  69. fileName = System.IO.Path.Combine(dir, TestUtility.GetFileName());
  70. }
  71. Assert.IsTrue(System.IO.File.Exists(fileName), $"webapp file not found in {fileName}");
  72. ProcessStartInfo startInfo = new ProcessStartInfo
  73. {
  74. WindowStyle = ProcessWindowStyle.Hidden,
  75. FileName = fileName,
  76. UseShellExecute = false,
  77. RedirectStandardOutput = true,
  78. RedirectStandardError = true
  79. };
  80. string arguments = $"-m private -p {TestUtility.PortNumber}";
  81. if (m_SignalingType == typeof(HttpSignaling))
  82. {
  83. arguments += " -t http";
  84. }
  85. startInfo.Arguments = arguments;
  86. m_ServerProcess.StartInfo = startInfo;
  87. m_ServerProcess.OutputDataReceived += (sender, e) =>
  88. {
  89. Debug.Log(e.Data);
  90. };
  91. m_ServerProcess.ErrorDataReceived += (sender, e) =>
  92. {
  93. Debug.Log(e.Data);
  94. };
  95. bool success = m_ServerProcess.Start();
  96. m_ServerProcess.BeginErrorReadLine();
  97. m_ServerProcess.BeginOutputReadLine();
  98. Assert.True(success);
  99. Thread.Sleep(1000);
  100. }
  101. [OneTimeTearDown]
  102. public void OneTimeTearDown()
  103. {
  104. if (m_SignalingType == typeof(MockSignaling))
  105. {
  106. return;
  107. }
  108. m_ServerProcess?.Kill();
  109. m_ServerProcess?.WaitForExit();
  110. m_ServerProcess?.Dispose();
  111. m_ServerProcess = null;
  112. }
  113. ISignaling CreateSignaling(Type type, SynchronizationContext mainThread)
  114. {
  115. if (type == typeof(WebSocketSignaling))
  116. {
  117. var settings = new WebSocketSignalingSettings
  118. (
  119. url: $"ws://localhost:{TestUtility.PortNumber}"
  120. );
  121. return new WebSocketSignaling(settings, mainThread);
  122. }
  123. if (type == typeof(HttpSignaling))
  124. {
  125. var settings = new HttpSignalingSettings
  126. (
  127. url: $"http://localhost:{TestUtility.PortNumber}",
  128. interval: 100
  129. );
  130. return new HttpSignaling(settings, mainThread);
  131. }
  132. if (type == typeof(MockSignaling))
  133. {
  134. return new MockSignaling();
  135. }
  136. throw new ArgumentException();
  137. }
  138. [UnitySetUp, Timeout(1000)]
  139. public IEnumerator UnitySetUp()
  140. {
  141. RTCConfiguration config = default;
  142. RTCIceCandidate candidate_ = null;
  143. config.iceServers = new[] {new RTCIceServer {urls = new[] {"stun:stun.l.google.com:19302"}}};
  144. var peer1 = new RTCPeerConnection(ref config);
  145. var peer2 = new RTCPeerConnection(ref config);
  146. peer1.OnIceCandidate = candidate => { candidate_ = candidate; };
  147. AudioStreamTrack track = new AudioStreamTrack();
  148. peer1.AddTrack(track);
  149. var op1 = peer1.CreateOffer();
  150. yield return op1;
  151. m_DescOffer = op1.Desc;
  152. var op2 = peer1.SetLocalDescription(ref m_DescOffer);
  153. yield return op2;
  154. var op3 = peer2.SetRemoteDescription(ref m_DescOffer);
  155. yield return op3;
  156. var op4 = peer2.CreateAnswer();
  157. yield return op4;
  158. m_DescAnswer = op4.Desc;
  159. var op5 = peer2.SetLocalDescription(ref m_DescAnswer);
  160. yield return op5;
  161. var op6 = peer1.SetRemoteDescription(ref m_DescAnswer);
  162. yield return op6;
  163. yield return new WaitUntil(() => candidate_ != null);
  164. m_candidate = candidate_;
  165. track.Dispose();
  166. peer1.Close();
  167. peer2.Close();
  168. m_Context = SynchronizationContext.Current;
  169. signaling1 = CreateSignaling(m_SignalingType, m_Context);
  170. signaling2 = CreateSignaling(m_SignalingType, m_Context);
  171. }
  172. [TearDown]
  173. public void TearDown()
  174. {
  175. signaling1.Stop();
  176. signaling2.Stop();
  177. m_Context = null;
  178. }
  179. [UnityTest, Timeout(10000)]
  180. public IEnumerator OnConnect()
  181. {
  182. bool startRaised1 = false;
  183. bool startRaised2 = false;
  184. signaling1.OnStart += s => { startRaised1 = true; };
  185. signaling1.Start();
  186. signaling2.OnStart += s => { startRaised2 = true; };
  187. signaling2.Start();
  188. yield return new WaitUntil(() => startRaised1 && startRaised2);
  189. const string connectionId = "12345";
  190. string receiveConnectionId1 = null;
  191. string receiveConnectionId2 = null;
  192. bool receivePolite1 = false;
  193. bool receivePolite2 = false;
  194. bool raiseOnDestroy1 = false;
  195. bool raiseOnDestroy2 = false;
  196. signaling1.OnCreateConnection += (s, id, polite) =>
  197. {
  198. receiveConnectionId1 = id;
  199. receivePolite1 = polite;
  200. };
  201. signaling1.OnDestroyConnection += (signaling, id) =>
  202. {
  203. raiseOnDestroy1 = id == receiveConnectionId1;
  204. };
  205. signaling1.OpenConnection(connectionId);
  206. yield return new WaitUntil(() => !string.IsNullOrEmpty(receiveConnectionId1));
  207. signaling2.OnCreateConnection += (s, id, polite) =>
  208. {
  209. receiveConnectionId2 = id;
  210. receivePolite2 = polite;
  211. };
  212. signaling2.OnDestroyConnection += (signaling, id) =>
  213. {
  214. raiseOnDestroy2 = id == receiveConnectionId2;
  215. };
  216. signaling2.OpenConnection(connectionId);
  217. yield return new WaitUntil(() => !string.IsNullOrEmpty(receiveConnectionId2));
  218. Assert.That(receiveConnectionId1, Is.EqualTo(connectionId));
  219. Assert.That(receiveConnectionId2, Is.EqualTo(connectionId));
  220. Assert.That(receivePolite1, Is.False);
  221. Assert.That(receivePolite2, Is.True);
  222. signaling1.CloseConnection(receiveConnectionId1);
  223. yield return new WaitUntil(() => raiseOnDestroy1 && raiseOnDestroy2);
  224. Assert.That(raiseOnDestroy1, Is.True);
  225. Assert.That(raiseOnDestroy2, Is.True);
  226. signaling2.CloseConnection(receiveConnectionId2);
  227. signaling1.Stop();
  228. signaling2.Stop();
  229. }
  230. [UnityTest, Timeout(10000)]
  231. public IEnumerator OnOffer()
  232. {
  233. bool startRaised1 = false;
  234. bool startRaised2 = false;
  235. bool offerRaised2 = false;
  236. const string connectionId = "12345";
  237. bool raiseOnDestroy1 = false;
  238. bool raiseOnDestroy2 = false;
  239. string connectionId1 = null;
  240. string connectionId2 = null;
  241. signaling1.OnStart += s => { startRaised1 = true; };
  242. signaling2.OnStart += s => { startRaised2 = true; };
  243. signaling1.Start();
  244. signaling2.Start();
  245. yield return new WaitUntil(() => startRaised1 && startRaised2);
  246. signaling1.OnCreateConnection += (s, id, polite) =>
  247. {
  248. connectionId1 = id;
  249. };
  250. signaling1.OnDestroyConnection += (signaling, id) =>
  251. {
  252. raiseOnDestroy1 = id == connectionId1;
  253. };
  254. signaling1.OpenConnection(connectionId);
  255. yield return new WaitUntil(() => !string.IsNullOrEmpty(connectionId1));
  256. signaling2.OnOffer += (s, e) => { offerRaised2 = true; };
  257. signaling1.SendOffer(connectionId, m_DescOffer);
  258. // Do not receive offer other signaling if not connected same sendoffer connectionId in private mode
  259. Assert.IsFalse(offerRaised2);
  260. signaling2.OnCreateConnection += (s, id, polite) =>
  261. {
  262. connectionId2 = id;
  263. };
  264. signaling2.OnDestroyConnection += (signaling, id) =>
  265. {
  266. raiseOnDestroy2 = id == connectionId2;
  267. };
  268. signaling2.OpenConnection(connectionId);
  269. yield return new WaitUntil(() => !string.IsNullOrEmpty(connectionId2));
  270. Assert.That(connectionId1, Is.EqualTo(connectionId));
  271. Assert.That(connectionId2, Is.EqualTo(connectionId));
  272. signaling1.SendOffer(connectionId, m_DescOffer);
  273. yield return new WaitUntil(() => offerRaised2);
  274. signaling1.CloseConnection(connectionId1);
  275. yield return new WaitUntil(() => raiseOnDestroy1 && raiseOnDestroy2);
  276. Assert.That(raiseOnDestroy1, Is.True);
  277. Assert.That(raiseOnDestroy2, Is.True);
  278. signaling2.CloseConnection(connectionId2);
  279. signaling1.Stop();
  280. signaling2.Stop();
  281. }
  282. [UnityTest, Timeout(10000)]
  283. public IEnumerator OnAnswer()
  284. {
  285. bool startRaised1 = false;
  286. bool startRaised2 = false;
  287. bool offerRaised = false;
  288. bool answerRaised = false;
  289. const string connectionId = "12345";
  290. bool raiseOnDestroy1 = false;
  291. bool raiseOnDestroy2 = false;
  292. string connectionId1 = null;
  293. string connectionId2 = null;
  294. signaling1.OnStart += s => { startRaised1 = true; };
  295. signaling2.OnStart += s => { startRaised2 = true; };
  296. signaling1.Start();
  297. signaling2.Start();
  298. yield return new WaitUntil(() => startRaised1 && startRaised2);
  299. signaling1.OnCreateConnection += (s, id, polite) =>
  300. {
  301. connectionId1 = id;
  302. };
  303. signaling1.OnDestroyConnection += (signaling, id) =>
  304. {
  305. raiseOnDestroy1 = id == connectionId1;
  306. };
  307. signaling1.OpenConnection(connectionId);
  308. signaling2.OnCreateConnection += (s, id, polite) =>
  309. {
  310. connectionId2 = id;
  311. };
  312. signaling2.OnDestroyConnection += (signaling, id) =>
  313. {
  314. raiseOnDestroy2 = id == connectionId2;
  315. };
  316. signaling2.OpenConnection(connectionId);
  317. yield return new WaitUntil(() =>
  318. !string.IsNullOrEmpty(connectionId1) && !string.IsNullOrEmpty(connectionId2));
  319. Assert.That(connectionId1, Is.EqualTo(connectionId));
  320. Assert.That(connectionId2, Is.EqualTo(connectionId));
  321. signaling2.OnOffer += (s, e) => { offerRaised = true; };
  322. signaling1.SendOffer(connectionId1, m_DescOffer);
  323. yield return new WaitUntil(() => offerRaised);
  324. signaling1.OnAnswer += (s, e) => { answerRaised = true; };
  325. signaling2.SendAnswer(connectionId1, m_DescAnswer);
  326. yield return new WaitUntil(() => answerRaised);
  327. signaling1.CloseConnection(connectionId1);
  328. yield return new WaitUntil(() => raiseOnDestroy1 && raiseOnDestroy2);
  329. Assert.That(raiseOnDestroy1, Is.True);
  330. Assert.That(raiseOnDestroy2, Is.True);
  331. signaling2.CloseConnection(connectionId2);
  332. signaling1.Stop();
  333. signaling2.Stop();
  334. }
  335. [UnityTest, Timeout(10000)]
  336. public IEnumerator OnCandidate()
  337. {
  338. bool startRaised1 = false;
  339. bool startRaised2 = false;
  340. bool offerRaised = false;
  341. bool answerRaised = false;
  342. bool candidateRaised1 = false;
  343. bool candidateRaised2 = false;
  344. const string connectionId = "12345";
  345. bool raiseOnDestroy1 = false;
  346. bool raiseOnDestroy2 = false;
  347. string connectionId1 = null;
  348. string connectionId2 = null;
  349. signaling1.OnStart += s => { startRaised1 = true; };
  350. signaling2.OnStart += s => { startRaised2 = true; };
  351. signaling1.Start();
  352. signaling2.Start();
  353. yield return new WaitUntil(() => startRaised1 && startRaised2);
  354. signaling1.OnCreateConnection += (s, id, polite) =>
  355. {
  356. connectionId1 = id;
  357. };
  358. signaling1.OnDestroyConnection += (signaling, id) =>
  359. {
  360. raiseOnDestroy1 = id == connectionId1;
  361. };
  362. signaling1.OpenConnection(connectionId);
  363. signaling2.OnCreateConnection += (s, id, polite) =>
  364. {
  365. connectionId2 = id;
  366. };
  367. signaling2.OnDestroyConnection += (signaling, id) =>
  368. {
  369. raiseOnDestroy2 = id == connectionId2;
  370. };
  371. signaling2.OpenConnection(connectionId);
  372. yield return new WaitUntil(() =>
  373. !string.IsNullOrEmpty(connectionId1) && !string.IsNullOrEmpty(connectionId2));
  374. Assert.That(connectionId1, Is.EqualTo(connectionId));
  375. Assert.That(connectionId2, Is.EqualTo(connectionId));
  376. signaling2.OnOffer += (s, e) => { offerRaised = true; };
  377. signaling1.SendOffer(connectionId1, m_DescOffer);
  378. yield return new WaitUntil(() => offerRaised);
  379. signaling1.OnAnswer += (s, e) => { answerRaised = true; };
  380. signaling2.SendAnswer(connectionId1, m_DescAnswer);
  381. yield return new WaitUntil(() => answerRaised);
  382. signaling2.OnIceCandidate += (s, e) => { candidateRaised1 = true; };
  383. signaling1.SendCandidate(connectionId1, m_candidate);
  384. yield return new WaitUntil(() => candidateRaised1);
  385. signaling1.OnIceCandidate += (s, e) => { candidateRaised2 = true; };
  386. signaling2.SendCandidate(connectionId1, m_candidate);
  387. yield return new WaitUntil(() => candidateRaised2);
  388. signaling1.CloseConnection(connectionId1);
  389. yield return new WaitUntil(() => raiseOnDestroy1 && raiseOnDestroy2);
  390. Assert.That(raiseOnDestroy1, Is.True);
  391. Assert.That(raiseOnDestroy2, Is.True);
  392. signaling2.CloseConnection(connectionId2);
  393. signaling1.Stop();
  394. signaling2.Stop();
  395. }
  396. [UnityTest, Timeout(10000), LongRunning]
  397. public IEnumerator NotReceiveOwnOfferAnswer()
  398. {
  399. bool startRaised1 = false;
  400. bool startRaised2 = false;
  401. bool offerRaised1 = false;
  402. bool offerRaised2 = false;
  403. bool answerRaised1 = false;
  404. bool answerRaised2 = false;
  405. bool candidateRaised1 = false;
  406. bool candidateRaised2 = false;
  407. const string connectionId = "12345";
  408. bool raiseOnDestroy1 = false;
  409. bool raiseOnDestroy2 = false;
  410. string connectionId1 = null;
  411. string connectionId2 = null;
  412. signaling1.OnStart += s => { startRaised1 = true; };
  413. signaling2.OnStart += s => { startRaised2 = true; };
  414. signaling1.Start();
  415. signaling2.Start();
  416. yield return new WaitUntil(() => startRaised1 && startRaised2);
  417. signaling1.OnCreateConnection += (s, id, polite) =>
  418. {
  419. connectionId1 = id;
  420. };
  421. signaling1.OnDestroyConnection += (signaling, id) =>
  422. {
  423. raiseOnDestroy1 = id == connectionId1;
  424. };
  425. signaling1.OpenConnection(connectionId);
  426. signaling2.OnCreateConnection += (s, id, polite) =>
  427. {
  428. connectionId2 = id;
  429. };
  430. signaling2.OnDestroyConnection += (signaling, id) =>
  431. {
  432. raiseOnDestroy2 = id == connectionId2;
  433. };
  434. signaling2.OpenConnection(connectionId);
  435. yield return new WaitUntil(() =>
  436. !string.IsNullOrEmpty(connectionId1) && !string.IsNullOrEmpty(connectionId2));
  437. Assert.That(connectionId1, Is.EqualTo(connectionId));
  438. Assert.That(connectionId2, Is.EqualTo(connectionId));
  439. const float resendInterval = 0.1f;
  440. signaling1.OnOffer += (s, e) => { offerRaised1 = true; };
  441. signaling2.OnOffer += (s, e) => { offerRaised2 = true; };
  442. signaling1.SendOffer(connectionId1, m_DescOffer);
  443. // check each signaling invoke onOffer
  444. yield return new WaitForSeconds(resendInterval * 5);
  445. Assert.That(offerRaised1, Is.False, () => "Receive own offer on private mode");
  446. Assert.That(offerRaised2, Is.True);
  447. signaling1.OnAnswer += (s, e) => { answerRaised1 = true; };
  448. signaling2.OnAnswer += (s, e) => { answerRaised2 = true; };
  449. signaling2.SendAnswer(connectionId1, m_DescAnswer);
  450. // check each signaling invoke onAnswer
  451. yield return new WaitForSeconds(resendInterval * 5);
  452. Assert.That(answerRaised1, Is.True);
  453. Assert.That(answerRaised2, Is.False, () => "Receive own answer on private mode");
  454. signaling2.OnIceCandidate += (s, e) => { candidateRaised1 = true; };
  455. signaling1.SendCandidate(connectionId1, m_candidate);
  456. yield return new WaitUntil(() => candidateRaised1);
  457. signaling1.OnIceCandidate += (s, e) => { candidateRaised2 = true; };
  458. signaling2.SendCandidate(connectionId1, m_candidate);
  459. yield return new WaitUntil(() => candidateRaised2);
  460. signaling1.CloseConnection(connectionId1);
  461. yield return new WaitUntil(() => raiseOnDestroy1 && raiseOnDestroy2);
  462. Assert.That(raiseOnDestroy1, Is.True);
  463. Assert.That(raiseOnDestroy2, Is.True);
  464. signaling2.CloseConnection(connectionId2);
  465. signaling1.Stop();
  466. signaling2.Stop();
  467. }
  468. }
  469. }