SignalingHandlerTest.cs 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. using System;
  2. using System.Collections;
  3. using System.Linq;
  4. using System.Reflection;
  5. using NUnit.Framework;
  6. using Unity.RenderStreaming.RuntimeTest.Signaling;
  7. using Unity.WebRTC;
  8. using UnityEngine;
  9. using UnityEngine.TestTools;
  10. namespace Unity.RenderStreaming.RuntimeTest
  11. {
  12. class SingleConnectionBehaviourTest : SingleConnection, IMonoBehaviourTest
  13. {
  14. public bool IsTestFinished
  15. {
  16. get { return true; }
  17. }
  18. }
  19. class BroadcastBehaviourTest : Broadcast, IMonoBehaviourTest
  20. {
  21. public bool IsTestFinished
  22. {
  23. get { return true; }
  24. }
  25. }
  26. class VideoStreamSenderTester : VideoStreamSender
  27. {
  28. private Camera m_camera;
  29. internal override WaitForCreateTrack CreateTrack()
  30. {
  31. m_camera = gameObject.AddComponent<Camera>();
  32. var instruction = new WaitForCreateTrack();
  33. instruction.Done(m_camera.CaptureStreamTrack(256, 256));
  34. return instruction;
  35. }
  36. }
  37. class VideoStreamReceiverTester : VideoStreamReceiver
  38. {
  39. }
  40. class AudioStreamSenderTester : AudioStreamSender
  41. {
  42. private AudioSource m_audioSource;
  43. internal override WaitForCreateTrack CreateTrack()
  44. {
  45. m_audioSource = gameObject.AddComponent<AudioSource>();
  46. m_audioSource.clip = AudioClip.Create("test", 48000, 2, 48000, false);
  47. var instruction = new WaitForCreateTrack();
  48. instruction.Done(new AudioStreamTrack(m_audioSource));
  49. return instruction;
  50. }
  51. }
  52. class AudioStreamReceiverTester : AudioStreamReceiver
  53. {
  54. }
  55. class DataChannelTest : DataChannelBase
  56. {
  57. public Action<string> OnReceiveMessage;
  58. public void SetLocal(bool isLocal)
  59. {
  60. Type myClass = typeof(DataChannelBase);
  61. FieldInfo fieldLocal = myClass.GetField("local",
  62. BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
  63. fieldLocal.SetValue(this, true);
  64. }
  65. public void SetLabel(string label)
  66. {
  67. Type myClass = typeof(DataChannelBase);
  68. FieldInfo fieldLabel = myClass.GetField("label",
  69. BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
  70. fieldLabel.SetValue(this, label);
  71. }
  72. protected override void OnMessage(byte[] bytes)
  73. {
  74. OnReceiveMessage(System.Text.Encoding.UTF8.GetString(bytes));
  75. }
  76. }
  77. class TestContainer<T> : IDisposable where T : SignalingHandlerBase, IMonoBehaviourTest
  78. {
  79. const float ResendOfferInterval = 3.0f;
  80. public MonoBehaviourTest<T> test;
  81. public SignalingManagerInternal instance;
  82. public SignalingEventProvider provider;
  83. private static RenderStreamingDependencies CreateDependencies(MonoBehaviour behaviour)
  84. {
  85. return new RenderStreamingDependencies
  86. {
  87. signaling = new MockSignaling(),
  88. config = new RTCConfiguration
  89. {
  90. iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } },
  91. },
  92. startCoroutine = behaviour.StartCoroutine,
  93. stopCoroutine = behaviour.StopCoroutine,
  94. resentOfferInterval = ResendOfferInterval,
  95. };
  96. }
  97. public static TestContainer<T> Create(string name)
  98. {
  99. var test = new MonoBehaviourTest<T>();
  100. var dependencies = CreateDependencies(test.component);
  101. var instance = new SignalingManagerInternal(ref dependencies);
  102. var provider = new SignalingEventProvider(instance);
  103. var container = new TestContainer<T> { test = test, instance = instance, provider = provider };
  104. test.component.SetHandler(instance);
  105. test.gameObject.name = name;
  106. provider.Subscribe(test.component);
  107. return container;
  108. }
  109. public void Dispose()
  110. {
  111. test.component.StopAllCoroutines();
  112. instance.Dispose();
  113. UnityEngine.Object.DestroyImmediate(test.gameObject);
  114. }
  115. }
  116. class BroadcastTest
  117. {
  118. [SetUp]
  119. public void SetUp()
  120. {
  121. MockSignaling.Reset(false);
  122. }
  123. //todo:: crash in dispose process on standalone linux
  124. [Test]
  125. [UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer })]
  126. public void AddStreamSource()
  127. {
  128. var container = TestContainer<BroadcastBehaviourTest>.Create("test");
  129. var streamer = container.test.gameObject.AddComponent<VideoStreamSenderTester>();
  130. Assert.That(streamer.Track, Is.Null);
  131. Assert.That(streamer.Transceivers, Is.Empty);
  132. container.test.component.AddComponent(streamer);
  133. container.Dispose();
  134. }
  135. [Test]
  136. public void AddDataChannel()
  137. {
  138. var container = TestContainer<BroadcastBehaviourTest>.Create("test");
  139. var channel = container.test.gameObject.AddComponent<DataChannelTest>();
  140. channel.SetLabel("test");
  141. channel.SetLocal(true);
  142. Assert.That(channel.IsLocal, Is.True);
  143. Assert.That(channel.Label, Is.EqualTo("test"));
  144. Assert.That(channel.IsConnected, Is.False);
  145. container.test.component.AddComponent(channel);
  146. container.Dispose();
  147. }
  148. //todo:: crash in dispose process on standalone linux
  149. [UnityTest, Timeout(10000)]
  150. [UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
  151. public IEnumerator ReceiveStream()
  152. {
  153. string connectionId = "12345";
  154. var container1 = TestContainer<BroadcastBehaviourTest>.Create("test1");
  155. var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
  156. var streamer = container1.test.gameObject.AddComponent<AudioStreamSenderTester>();
  157. bool isStartedStream1 = false;
  158. bool isStoppedStream1 = false;
  159. streamer.OnStartedStream += _ => isStartedStream1 = true;
  160. streamer.OnStoppedStream += _ => isStoppedStream1 = true;
  161. container1.test.component.AddComponent(streamer);
  162. var receiver = container2.test.gameObject.AddComponent<AudioStreamReceiverTester>();
  163. bool isStartedStream2 = false;
  164. bool isStoppedStream2 = false;
  165. receiver.OnStartedStream += _ => isStartedStream2 = true;
  166. receiver.OnStoppedStream += _ => isStoppedStream2 = true;
  167. container2.test.component.AddComponent(receiver);
  168. container2.test.component.CreateConnection(connectionId);
  169. yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
  170. container2.test.component.SendOffer(connectionId);
  171. yield return new WaitUntil(() => isStartedStream2 && isStartedStream1);
  172. Assert.That(isStartedStream1, Is.True);
  173. Assert.That(isStartedStream2, Is.True);
  174. Assert.That(receiver.Track, Is.Not.Null);
  175. Assert.That(receiver.Transceiver, Is.Not.Null);
  176. yield return new WaitUntil(() => container1.test.component.IsConnected(connectionId));
  177. yield return new WaitUntil(() => container2.test.component.IsConnected(connectionId));
  178. container2.test.component.DeleteConnection(connectionId);
  179. yield return new WaitUntil(() => isStoppedStream1 && isStoppedStream2);
  180. Assert.That(isStoppedStream1, Is.True);
  181. Assert.That(isStoppedStream2, Is.True);
  182. Assert.That(container1.test.component.ExistConnection(connectionId), Is.False);
  183. Assert.That(container2.test.component.ExistConnection(connectionId), Is.False);
  184. container1.Dispose();
  185. container2.Dispose();
  186. }
  187. // todo:: Crash in dispose process on Linux standalone.
  188. // todo:: Timeout error on iPhonePlayer.
  189. [UnityTest, Timeout(10000)]
  190. [UnityPlatform(exclude = new[]
  191. {
  192. RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor,
  193. RuntimePlatform.LinuxPlayer, RuntimePlatform.IPhonePlayer, RuntimePlatform.Android
  194. })]
  195. public IEnumerator SetCodec()
  196. {
  197. string connectionId = "12345";
  198. var container1 = TestContainer<BroadcastBehaviourTest>.Create("test1");
  199. var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
  200. var streamer = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
  201. bool isStartedStream1 = false;
  202. bool isStoppedStream1 = false;
  203. streamer.OnStartedStream += _ => isStartedStream1 = true;
  204. streamer.OnStoppedStream += _ => isStoppedStream1 = true;
  205. var codec = VideoStreamSender.GetAvailableCodecs().FirstOrDefault(x => x.mimeType.Contains("VP9"));
  206. Assert.That(codec, Is.Not.Null);
  207. streamer.SetCodec(codec);
  208. container1.test.component.AddComponent(streamer);
  209. var receiver = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
  210. bool isStartedStream2 = false;
  211. bool isStoppedStream2 = false;
  212. receiver.OnStartedStream += _ => isStartedStream2 = true;
  213. receiver.OnStoppedStream += _ => isStoppedStream2 = true;
  214. container2.test.component.AddComponent(receiver);
  215. container2.test.component.CreateConnection(connectionId);
  216. yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
  217. container2.test.component.SendOffer(connectionId);
  218. yield return new WaitUntil(() => isStartedStream2 && isStartedStream1);
  219. Assert.That(isStartedStream1, Is.True);
  220. Assert.That(isStartedStream2, Is.True);
  221. Assert.That(receiver.Track, Is.Not.Null);
  222. Assert.That(receiver.Transceiver, Is.Not.Null);
  223. yield return new WaitUntil(() => container1.test.component.IsConnected(connectionId));
  224. yield return new WaitUntil(() => container2.test.component.IsConnected(connectionId));
  225. RTCCodecStats senderCodecStats = null;
  226. while (senderCodecStats == null)
  227. {
  228. var statsOp = streamer.Transceivers[connectionId].Sender.GetStats();
  229. yield return statsOp;
  230. Assert.That(statsOp.IsError, Is.False);
  231. var outboundStats =
  232. statsOp.Value.Stats.Values.FirstOrDefault(x =>
  233. x is RTCOutboundRTPStreamStats stats && stats.kind == "video") as RTCOutboundRTPStreamStats;
  234. if (outboundStats == null || string.IsNullOrEmpty(outboundStats.codecId))
  235. {
  236. yield return new WaitForSeconds(0.1f);
  237. continue;
  238. }
  239. senderCodecStats =
  240. statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == outboundStats.codecId) as RTCCodecStats;
  241. }
  242. Assert.That(senderCodecStats.mimeType, Is.EqualTo(codec.mimeType));
  243. Assert.That(senderCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
  244. container2.test.component.DeleteConnection(connectionId);
  245. yield return new WaitUntil(() => isStoppedStream1 && isStoppedStream2);
  246. Assert.That(isStoppedStream1, Is.True);
  247. Assert.That(isStoppedStream2, Is.True);
  248. Assert.That(container1.test.component.ExistConnection(connectionId), Is.False);
  249. Assert.That(container2.test.component.ExistConnection(connectionId), Is.False);
  250. container1.Dispose();
  251. container2.Dispose();
  252. }
  253. }
  254. class SingleConnectionTest
  255. {
  256. [SetUp]
  257. public void SetUp()
  258. {
  259. MockSignaling.Reset(true);
  260. }
  261. //todo:: crash in dispose process on standalone Linux and Android
  262. [UnityTest, Timeout(10000)]
  263. [UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
  264. public IEnumerator AddAudioStreamSource()
  265. {
  266. string connectionId = "12345";
  267. var container = TestContainer<SingleConnectionBehaviourTest>.Create("test");
  268. var streamer = container.test.gameObject.AddComponent<AudioStreamSenderTester>();
  269. Assert.That(streamer.Track, Is.Null);
  270. Assert.That(streamer.Transceivers, Is.Empty);
  271. container.test.component.AddComponent(streamer);
  272. container.test.component.CreateConnection(connectionId);
  273. yield return new WaitUntil(() => container.test.component.ExistConnection(connectionId));
  274. Assert.That(streamer.Track, Is.Not.Null);
  275. Assert.That(streamer.Transceivers, Is.Not.Empty);
  276. // SetCodec
  277. streamer.SetCodec(null);
  278. // SetBitrate
  279. var maxBitrate = streamer.maxBitrate;
  280. var minBitrate = streamer.maxBitrate;
  281. streamer.SetBitrate(minBitrate, maxBitrate);
  282. container.test.component.DeleteConnection(connectionId);
  283. yield return new WaitUntil(() => !container.test.component.ExistConnection(connectionId));
  284. container.Dispose();
  285. }
  286. //todo:: crash in dispose process on standalone Linux and Android
  287. [UnityTest, Timeout(10000)]
  288. [UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
  289. public IEnumerator AddVideoStreamSource()
  290. {
  291. string connectionId = "12345";
  292. var container = TestContainer<SingleConnectionBehaviourTest>.Create("test");
  293. var streamer = container.test.gameObject.AddComponent<VideoStreamSenderTester>();
  294. Assert.That(streamer.Track, Is.Null);
  295. Assert.That(streamer.Transceivers, Is.Empty);
  296. container.test.component.AddComponent(streamer);
  297. container.test.component.CreateConnection(connectionId);
  298. yield return new WaitUntil(() => container.test.component.ExistConnection(connectionId));
  299. Assert.That(streamer.Track, Is.Not.Null);
  300. Assert.That(streamer.Transceivers, Is.Not.Empty);
  301. // SetCodec
  302. streamer.SetCodec(null);
  303. // SetFramerate
  304. var frameRate = streamer.frameRate;
  305. streamer.SetFrameRate(frameRate);
  306. // SetBitrate
  307. var maxBitrate = streamer.maxBitrate;
  308. var minBitrate = streamer.maxBitrate;
  309. streamer.SetBitrate(minBitrate, maxBitrate);
  310. // SetScaleResolutionDown
  311. var scaleFactor = streamer.scaleResolutionDown;
  312. streamer.SetScaleResolutionDown(scaleFactor);
  313. // SetTextureSize
  314. var width = streamer.width;
  315. var height = streamer.height;
  316. streamer.SetTextureSize(new Vector2Int((int)width, (int)height));
  317. container.test.component.DeleteConnection(connectionId);
  318. yield return new WaitUntil(() => !container.test.component.ExistConnection(connectionId));
  319. container.Dispose();
  320. }
  321. [UnityTest, Timeout(10000)]
  322. public IEnumerator AddDataChannel()
  323. {
  324. string connectionId = "12345";
  325. var container = TestContainer<SingleConnectionBehaviourTest>.Create("test");
  326. var handler = container.test.component;
  327. var channel = container.test.gameObject.AddComponent<DataChannelTest>();
  328. channel.SetLocal(true);
  329. channel.SetLabel("test");
  330. handler.AddComponent(channel);
  331. handler.CreateConnection(connectionId);
  332. yield return new WaitUntil(() => container.test.component.ExistConnection(connectionId));
  333. Assert.That(channel.IsLocal, Is.True);
  334. Assert.That(channel.Label, Is.EqualTo("test"));
  335. container.test.component.DeleteConnection(connectionId);
  336. yield return new WaitUntil(() => !container.test.component.ExistConnection(connectionId));
  337. container.Dispose();
  338. }
  339. [UnityTest, Timeout(10000)]
  340. public IEnumerator AddSource()
  341. {
  342. string connectionId = "12345";
  343. var container = TestContainer<SingleConnectionBehaviourTest>.Create("test");
  344. var channel = container.test.gameObject.AddComponent<DataChannelTest>();
  345. channel.SetLocal(true);
  346. channel.SetLabel("test");
  347. Assert.That(channel.IsLocal, Is.True);
  348. Assert.That(channel.IsConnected, Is.False);
  349. Assert.That(channel.Label, Is.EqualTo("test"));
  350. container.test.component.AddComponent(channel);
  351. container.test.component.CreateConnection(connectionId);
  352. yield return new WaitUntil(() => container.test.component.ExistConnection(connectionId));
  353. Assert.That(channel.IsLocal, Is.True);
  354. Assert.That(channel.IsConnected, Is.False);
  355. Assert.That(channel.Label, Is.EqualTo("test"));
  356. container.test.component.DeleteConnection(connectionId);
  357. yield return new WaitUntil(() => !container.test.component.ExistConnection(connectionId));
  358. container.Dispose();
  359. }
  360. // todo:: Crash in dispose process on Linux standalone
  361. // todo:: Timeout error on iPhonePlayer
  362. [UnityTest, Timeout(10000)]
  363. [UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.IPhonePlayer, RuntimePlatform.Android })]
  364. public IEnumerator ReceiveStream()
  365. {
  366. string connectionId = "12345";
  367. var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
  368. var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
  369. var streamer = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
  370. bool isStartedStream0 = false;
  371. bool isStoppedStream0 = false;
  372. streamer.OnStartedStream += _ => isStartedStream0 = true;
  373. streamer.OnStoppedStream += _ => isStoppedStream0 = true;
  374. container1.test.component.AddComponent(streamer);
  375. container1.test.component.CreateConnection(connectionId);
  376. yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
  377. yield return new WaitUntil(() => isStartedStream0);
  378. Assert.That(isStartedStream0, Is.True);
  379. var receiver = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
  380. bool isStartedStream1 = false;
  381. bool isStoppedStream1 = false;
  382. receiver.OnStartedStream += _ => isStartedStream1 = true;
  383. receiver.OnStoppedStream += _ => isStoppedStream1 = true;
  384. Assert.That(receiver.Track, Is.Null);
  385. Assert.That(receiver.Transceiver, Is.Null);
  386. container2.test.component.AddComponent(receiver);
  387. container2.test.component.CreateConnection(connectionId);
  388. yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
  389. yield return new WaitUntil(() => isStartedStream1);
  390. Assert.That(isStartedStream1, Is.True);
  391. Assert.That(receiver.Track, Is.Not.Null);
  392. Assert.That(receiver.Transceiver, Is.Not.Null);
  393. container1.test.component.DeleteConnection(connectionId);
  394. container2.test.component.DeleteConnection(connectionId);
  395. yield return new WaitUntil(() => isStoppedStream0 && isStoppedStream1);
  396. Assert.That(isStoppedStream0, Is.True);
  397. Assert.That(isStoppedStream1, Is.True);
  398. container1.Dispose();
  399. container2.Dispose();
  400. }
  401. //todo(kazuki):: Unknown error is occurred on Android
  402. [UnityTest, Timeout(10000)]
  403. [UnityPlatform(exclude = new[] { RuntimePlatform.Android })]
  404. public IEnumerator ReceiveDataChannel()
  405. {
  406. string connectionId = "12345";
  407. var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
  408. var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
  409. var channel1 = container1.test.gameObject.AddComponent<DataChannelTest>();
  410. bool isStartedChannel1 = false;
  411. bool isStoppedChannel1 = false;
  412. channel1.OnStartedChannel += _ => isStartedChannel1 = true;
  413. channel1.OnStoppedChannel += _ => isStoppedChannel1 = true;
  414. container1.test.component.AddComponent(channel1);
  415. container1.test.component.CreateConnection(connectionId);
  416. yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
  417. var channel2 = container2.test.gameObject.AddComponent<DataChannelTest>();
  418. bool isStartedChannel2 = false;
  419. bool isStoppedChannel2 = false;
  420. channel2.OnStartedChannel += _ => isStartedChannel2 = true;
  421. channel2.OnStoppedChannel += _ => isStoppedChannel2 = true;
  422. channel2.SetLocal(true);
  423. channel2.SetLabel("test");
  424. Assert.That(channel2.IsConnected, Is.False);
  425. Assert.That(channel2.IsLocal, Is.True);
  426. Assert.That(channel2.Label, Is.EqualTo("test"));
  427. container2.test.component.AddComponent(channel2);
  428. container2.test.component.CreateConnection(connectionId);
  429. yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
  430. yield return new WaitUntil(() => isStartedChannel1 && isStartedChannel2);
  431. Assert.That(isStartedChannel1, Is.True);
  432. Assert.That(isStartedChannel2, Is.True);
  433. Assert.That(channel1.IsLocal, Is.False);
  434. Assert.That(channel1.Label, Is.EqualTo("test"));
  435. Assert.That(channel1.IsConnected, Is.True);
  436. Assert.That(channel2.IsConnected, Is.True);
  437. // send message from channel1 to channel2
  438. string sendMessage = "hello";
  439. string receivedMessage = null;
  440. channel2.OnReceiveMessage = message => { receivedMessage = message; };
  441. channel1.Send(sendMessage);
  442. yield return new WaitUntil(() => !string.IsNullOrEmpty(receivedMessage));
  443. Assert.That(receivedMessage, Is.EqualTo(sendMessage));
  444. // send message from channel2 to channel1
  445. receivedMessage = null;
  446. channel1.OnReceiveMessage = message => { receivedMessage = message; };
  447. channel2.Send(sendMessage);
  448. yield return new WaitUntil(() => !string.IsNullOrEmpty(receivedMessage));
  449. Assert.That(receivedMessage, Is.EqualTo(sendMessage));
  450. container1.test.component.DeleteConnection(connectionId);
  451. container2.test.component.DeleteConnection(connectionId);
  452. yield return new WaitUntil(() => isStoppedChannel1 && isStoppedChannel2);
  453. Assert.That(isStoppedChannel1, Is.True);
  454. Assert.That(isStoppedChannel2, Is.True);
  455. container1.Dispose();
  456. container2.Dispose();
  457. }
  458. [UnityTest, Timeout(10000)]
  459. [UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
  460. public IEnumerator AssignTransceivers()
  461. {
  462. string connectionId = "12345";
  463. var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
  464. var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
  465. // prepare caller
  466. var videoStreamer1 = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
  467. bool isStartedVideoSourceStream1 = false;
  468. bool isStoppedVideoSourceStream1 = false;
  469. videoStreamer1.OnStartedStream += _ => isStartedVideoSourceStream1 = true;
  470. videoStreamer1.OnStoppedStream += _ => isStoppedVideoSourceStream1 = true;
  471. var audioStreamer1 = container1.test.gameObject.AddComponent<AudioStreamSenderTester>();
  472. bool isStartedAudioSourceStream1 = false;
  473. bool isStoppedAudioSourceStream1 = false;
  474. audioStreamer1.OnStartedStream += _ => isStartedAudioSourceStream1 = true;
  475. audioStreamer1.OnStoppedStream += _ => isStoppedAudioSourceStream1 = true;
  476. var videoReceiver1 = container1.test.gameObject.AddComponent<VideoStreamReceiverTester>();
  477. bool isStartedVideoReceiveStream1 = false;
  478. bool isStoppedVideoReceiveStream1 = false;
  479. videoReceiver1.OnStartedStream += _ => isStartedVideoReceiveStream1 = true;
  480. videoReceiver1.OnStoppedStream += _ => isStoppedVideoReceiveStream1 = true;
  481. var audioReceiver1 = container1.test.gameObject.AddComponent<AudioStreamReceiverTester>();
  482. bool isStartedAudioReceiveStream1 = false;
  483. bool isStoppedAudioReceiveStream1 = false;
  484. audioReceiver1.OnStartedStream += _ => isStartedAudioReceiveStream1 = true;
  485. audioReceiver1.OnStoppedStream += _ => isStoppedAudioReceiveStream1 = true;
  486. container1.test.component.AddComponent(videoStreamer1);
  487. container1.test.component.AddComponent(videoReceiver1);
  488. container1.test.component.AddComponent(audioStreamer1);
  489. container1.test.component.AddComponent(audioReceiver1);
  490. // prepare callee
  491. var videoStreamer2 = container2.test.gameObject.AddComponent<VideoStreamSenderTester>();
  492. bool isStartedVideoSourceStream2 = false;
  493. bool isStoppedVideoSourceStream2 = false;
  494. videoStreamer2.OnStartedStream += _ => isStartedVideoSourceStream2 = true;
  495. videoStreamer2.OnStoppedStream += _ => isStoppedVideoSourceStream2 = true;
  496. var audioStreamer2 = container2.test.gameObject.AddComponent<AudioStreamSenderTester>();
  497. bool isStartedAudioSourceStream2 = false;
  498. bool isStoppedAudioSourceStream2 = false;
  499. audioStreamer2.OnStartedStream += _ => isStartedAudioSourceStream2 = true;
  500. audioStreamer2.OnStoppedStream += _ => isStoppedAudioSourceStream2 = true;
  501. var videoReceiver2 = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
  502. bool isStartedVideoReceiveStream2 = false;
  503. bool isStoppedVideoReceiveStream2 = false;
  504. videoReceiver2.OnStartedStream += _ => isStartedVideoReceiveStream2 = true;
  505. videoReceiver2.OnStoppedStream += _ => isStoppedVideoReceiveStream2 = true;
  506. var audioReceiver2 = container2.test.gameObject.AddComponent<AudioStreamReceiverTester>();
  507. bool isStartedAudioReceiveStream2 = false;
  508. bool isStoppedAudioReceiveStream2 = false;
  509. audioReceiver2.OnStartedStream += _ => isStartedAudioReceiveStream2 = true;
  510. audioReceiver2.OnStoppedStream += _ => isStoppedAudioReceiveStream2 = true;
  511. container2.test.component.AddComponent(videoStreamer2);
  512. container2.test.component.AddComponent(videoReceiver2);
  513. container2.test.component.AddComponent(audioStreamer2);
  514. container2.test.component.AddComponent(audioReceiver2);
  515. // start signaling
  516. container1.test.component.CreateConnection(connectionId);
  517. container2.test.component.CreateConnection(connectionId);
  518. yield return new WaitUntil(() =>
  519. container1.test.component.ExistConnection(connectionId) &&
  520. container2.test.component.ExistConnection(connectionId));
  521. yield return new WaitUntil(() => isStartedVideoSourceStream1 && isStartedAudioSourceStream1 && isStartedVideoSourceStream2 && isStartedAudioSourceStream2);
  522. yield return new WaitUntil(() => isStartedVideoReceiveStream1 && isStartedAudioReceiveStream1 && isStartedVideoReceiveStream2 && isStartedAudioReceiveStream2);
  523. yield return new WaitUntil(() =>
  524. container1.test.component.IsStable(connectionId) && container2.test.component.IsStable(connectionId));
  525. var transceivers1 = container1.instance.GetTransceivers(connectionId).ToList();
  526. var count1 = transceivers1.Count;
  527. Assert.That(count1, Is.EqualTo(4), $"{nameof(transceivers1)} count is {count1}");
  528. Assert.That(transceivers1.Select(x => x.Direction),
  529. Is.EquivalentTo(new[]
  530. {
  531. RTCRtpTransceiverDirection.SendOnly, RTCRtpTransceiverDirection.SendOnly,
  532. RTCRtpTransceiverDirection.RecvOnly, RTCRtpTransceiverDirection.RecvOnly,
  533. }));
  534. var transceivers2 = container2.instance.GetTransceivers(connectionId).ToList();
  535. var count2 = transceivers2.Count;
  536. Assert.That(count2, Is.EqualTo(4), $"{nameof(transceivers2)} count is {count2}");
  537. Assert.That(transceivers2.Select(x => x.Direction),
  538. Is.EquivalentTo(new[]
  539. {
  540. RTCRtpTransceiverDirection.SendOnly, RTCRtpTransceiverDirection.SendOnly,
  541. RTCRtpTransceiverDirection.RecvOnly, RTCRtpTransceiverDirection.RecvOnly,
  542. }));
  543. container1.test.component.DeleteConnection(connectionId);
  544. container2.test.component.DeleteConnection(connectionId);
  545. yield return new WaitUntil(() => isStoppedVideoSourceStream1 && isStoppedAudioSourceStream1 && isStoppedVideoSourceStream2 && isStoppedAudioSourceStream2);
  546. yield return new WaitUntil(() => isStoppedVideoReceiveStream1 && isStoppedAudioReceiveStream1 && isStoppedVideoReceiveStream2 && isStoppedAudioReceiveStream2);
  547. yield return new WaitUntil(() =>
  548. !container1.test.component.ExistConnection(connectionId) &&
  549. !container2.test.component.ExistConnection(connectionId));
  550. container1.Dispose();
  551. container2.Dispose();
  552. }
  553. //todo:: crash in dispose process on standalone linux
  554. [UnityTest, Timeout(10000)]
  555. [UnityPlatform(exclude = new[]
  556. {
  557. RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor,
  558. RuntimePlatform.LinuxPlayer, RuntimePlatform.Android
  559. })]
  560. public IEnumerator SetCodecOnSender()
  561. {
  562. string connectionId = "12345";
  563. var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
  564. var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
  565. var streamer = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
  566. bool isStartedStream0 = false;
  567. bool isStoppedStream0 = false;
  568. streamer.OnStartedStream += _ => isStartedStream0 = true;
  569. streamer.OnStoppedStream += _ => isStoppedStream0 = true;
  570. var codec = VideoStreamSender.GetAvailableCodecs().FirstOrDefault(x => x.mimeType.Contains("VP9"));
  571. Assert.That(codec, Is.Not.Null);
  572. streamer.SetCodec(codec);
  573. container1.test.component.AddComponent(streamer);
  574. container1.test.component.CreateConnection(connectionId);
  575. yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
  576. yield return new WaitUntil(() => isStartedStream0);
  577. Assert.That(isStartedStream0, Is.True);
  578. var receiver = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
  579. bool isStartedStream1 = false;
  580. bool isStoppedStream1 = false;
  581. receiver.OnStartedStream += _ => isStartedStream1 = true;
  582. receiver.OnStoppedStream += _ => isStoppedStream1 = true;
  583. Assert.That(receiver.Track, Is.Null);
  584. Assert.That(receiver.Transceiver, Is.Null);
  585. container2.test.component.AddComponent(receiver);
  586. container2.test.component.CreateConnection(connectionId);
  587. yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
  588. yield return new WaitUntil(() => isStartedStream1);
  589. Assert.That(isStartedStream1, Is.True);
  590. Assert.That(receiver.Track, Is.Not.Null);
  591. Assert.That(receiver.Transceiver, Is.Not.Null);
  592. RTCCodecStats senderCodecStats = null;
  593. while (senderCodecStats == null)
  594. {
  595. var statsOp = streamer.Transceivers[connectionId].Sender.GetStats();
  596. yield return statsOp;
  597. Assert.That(statsOp.IsError, Is.False);
  598. var outboundStats =
  599. statsOp.Value.Stats.Values.FirstOrDefault(x =>
  600. x is RTCOutboundRTPStreamStats stats && stats.kind == "video") as RTCOutboundRTPStreamStats;
  601. if (outboundStats == null || string.IsNullOrEmpty(outboundStats.codecId))
  602. {
  603. yield return new WaitForSeconds(0.1f);
  604. continue;
  605. }
  606. senderCodecStats =
  607. statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == outboundStats.codecId) as RTCCodecStats;
  608. }
  609. Assert.That(senderCodecStats.mimeType, Is.EqualTo(codec.mimeType));
  610. Assert.That(senderCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
  611. RTCCodecStats receiverCodecStats = null;
  612. while (receiverCodecStats == null)
  613. {
  614. var statsOp = receiver.Transceiver.Receiver.GetStats();
  615. yield return statsOp;
  616. Assert.That(statsOp.IsError, Is.False);
  617. var inboundStats =
  618. statsOp.Value.Stats.Values.FirstOrDefault(x =>
  619. x is RTCInboundRTPStreamStats stats && stats.kind == "video") as RTCInboundRTPStreamStats;
  620. if (inboundStats == null || string.IsNullOrEmpty(inboundStats.codecId))
  621. {
  622. yield return new WaitForSeconds(0.1f);
  623. continue;
  624. }
  625. receiverCodecStats =
  626. statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == inboundStats.codecId) as RTCCodecStats;
  627. }
  628. Assert.That(receiverCodecStats.mimeType, Is.EqualTo(codec.mimeType));
  629. Assert.That(receiverCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
  630. container1.test.component.DeleteConnection(connectionId);
  631. container2.test.component.DeleteConnection(connectionId);
  632. yield return new WaitUntil(() => isStoppedStream0 && isStoppedStream1);
  633. Assert.That(isStoppedStream0, Is.True);
  634. Assert.That(isStoppedStream1, Is.True);
  635. container1.Dispose();
  636. container2.Dispose();
  637. }
  638. //todo:: crash in dispose process on standalone linux
  639. [UnityTest, Timeout(10000)]
  640. [UnityPlatform(exclude = new[]
  641. {
  642. RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor,
  643. RuntimePlatform.LinuxPlayer, RuntimePlatform.Android
  644. })]
  645. public IEnumerator SetCodecOnReceiver()
  646. {
  647. string connectionId = "12345";
  648. var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
  649. var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
  650. var streamer = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
  651. bool isStartedStream0 = false;
  652. bool isStoppedStream0 = false;
  653. streamer.OnStartedStream += _ => isStartedStream0 = true;
  654. streamer.OnStoppedStream += _ => isStoppedStream0 = true;
  655. container1.test.component.AddComponent(streamer);
  656. container1.test.component.CreateConnection(connectionId);
  657. yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
  658. yield return new WaitUntil(() => isStartedStream0);
  659. Assert.That(isStartedStream0, Is.True);
  660. var receiver = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
  661. bool isStartedStream1 = false;
  662. bool isStoppedStream1 = false;
  663. receiver.OnStartedStream += _ => isStartedStream1 = true;
  664. receiver.OnStoppedStream += _ => isStoppedStream1 = true;
  665. var codec = VideoStreamSender.GetAvailableCodecs().FirstOrDefault(x => x.mimeType.Contains("VP9"));
  666. Assert.That(codec, Is.Not.Null);
  667. streamer.SetCodec(codec);
  668. Assert.That(receiver.Track, Is.Null);
  669. Assert.That(receiver.Transceiver, Is.Null);
  670. container2.test.component.AddComponent(receiver);
  671. container2.test.component.CreateConnection(connectionId);
  672. yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
  673. yield return new WaitUntil(() => isStartedStream1);
  674. Assert.That(isStartedStream1, Is.True);
  675. Assert.That(receiver.Track, Is.Not.Null);
  676. Assert.That(receiver.Transceiver, Is.Not.Null);
  677. RTCCodecStats senderCodecStats = null;
  678. while (senderCodecStats == null)
  679. {
  680. var statsOp = streamer.Transceivers[connectionId].Sender.GetStats();
  681. yield return statsOp;
  682. Assert.That(statsOp.IsError, Is.False);
  683. var outboundStats =
  684. statsOp.Value.Stats.Values.FirstOrDefault(x =>
  685. x is RTCOutboundRTPStreamStats stats && stats.kind == "video") as RTCOutboundRTPStreamStats;
  686. if (outboundStats == null || string.IsNullOrEmpty(outboundStats.codecId))
  687. {
  688. yield return new WaitForSeconds(0.1f);
  689. continue;
  690. }
  691. senderCodecStats =
  692. statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == outboundStats.codecId) as RTCCodecStats;
  693. }
  694. Assert.That(senderCodecStats.mimeType, Is.EqualTo(codec.mimeType));
  695. Assert.That(senderCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
  696. RTCCodecStats receiverCodecStats = null;
  697. while (receiverCodecStats == null)
  698. {
  699. var statsOp = receiver.Transceiver.Receiver.GetStats();
  700. yield return statsOp;
  701. Assert.That(statsOp.IsError, Is.False);
  702. var inboundStats =
  703. statsOp.Value.Stats.Values.FirstOrDefault(x =>
  704. x is RTCInboundRTPStreamStats stats && stats.kind == "video") as RTCInboundRTPStreamStats;
  705. if (inboundStats == null || string.IsNullOrEmpty(inboundStats.codecId))
  706. {
  707. yield return new WaitForSeconds(0.1f);
  708. continue;
  709. }
  710. receiverCodecStats =
  711. statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == inboundStats.codecId) as RTCCodecStats;
  712. }
  713. Assert.That(receiverCodecStats.mimeType, Is.EqualTo(codec.mimeType));
  714. Assert.That(receiverCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
  715. container1.test.component.DeleteConnection(connectionId);
  716. container2.test.component.DeleteConnection(connectionId);
  717. yield return new WaitUntil(() => isStoppedStream0 && isStoppedStream1);
  718. Assert.That(isStoppedStream0, Is.True);
  719. Assert.That(isStoppedStream1, Is.True);
  720. container1.Dispose();
  721. container2.Dispose();
  722. }
  723. }
  724. }