NativeAPITest.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. using System;
  2. using System.Collections;
  3. using System.Runtime.InteropServices;
  4. using NUnit.Framework;
  5. using UnityEditor;
  6. using UnityEngine;
  7. using UnityEngine.TestTools;
  8. namespace Unity.WebRTC.RuntimeTest
  9. {
  10. class NativeAPITest
  11. {
  12. private static RenderTexture CreateRenderTexture(int width, int height)
  13. {
  14. var format = WebRTC.GetSupportedRenderTextureFormat(SystemInfo.graphicsDeviceType);
  15. var renderTexture = new RenderTexture(width, height, 0, format);
  16. renderTexture.Create();
  17. return renderTexture;
  18. }
  19. [AOT.MonoPInvokeCallback(typeof(DelegateDebugLog))]
  20. protected static void DebugLog(string str)
  21. {
  22. Debug.Log(str);
  23. }
  24. [SetUp]
  25. public void Init()
  26. {
  27. #if UNITY_IOS && !UNITY_EDITOR
  28. NativeMethods.RegisterRenderingWebRTCPlugin();
  29. #endif
  30. }
  31. [Test]
  32. public void NothingToDo()
  33. {
  34. }
  35. [Test]
  36. public void CreateAndDestroyContext()
  37. {
  38. var context = NativeMethods.ContextCreate(0);
  39. NativeMethods.ContextDestroy(0);
  40. }
  41. [Test]
  42. public void CreateAndDeletePeerConnection()
  43. {
  44. var context = NativeMethods.ContextCreate(0);
  45. var peer = NativeMethods.ContextCreatePeerConnection(context);
  46. NativeMethods.ContextDeletePeerConnection(context, peer);
  47. NativeMethods.ContextDestroy(0);
  48. }
  49. [Test]
  50. public void RestartIcePeerConnection()
  51. {
  52. var context = NativeMethods.ContextCreate(0);
  53. var peer = NativeMethods.ContextCreatePeerConnection(context);
  54. NativeMethods.PeerConnectionRestartIce(peer);
  55. NativeMethods.ContextDeletePeerConnection(context, peer);
  56. NativeMethods.ContextDestroy(0);
  57. }
  58. // todo(kazuki):: crash on iOS device
  59. [Test]
  60. [UnityPlatform(exclude = new[] { RuntimePlatform.IPhonePlayer })]
  61. public void PeerConnectionGetReceivers()
  62. {
  63. var context = NativeMethods.ContextCreate(0);
  64. var connection = NativeMethods.ContextCreatePeerConnection(context);
  65. IntPtr buf = NativeMethods.PeerConnectionGetReceivers(context, connection, out ulong length);
  66. Assert.AreEqual(0, length);
  67. NativeMethods.ContextDeletePeerConnection(context, connection);
  68. NativeMethods.ContextDestroy(0);
  69. }
  70. [Test]
  71. public void CreateAndDeleteDataChannel()
  72. {
  73. var context = NativeMethods.ContextCreate(0);
  74. var peer = NativeMethods.ContextCreatePeerConnection(context);
  75. var init = (RTCDataChannelInitInternal)new RTCDataChannelInit();
  76. var channel = NativeMethods.ContextCreateDataChannel(context, peer, "test", ref init);
  77. NativeMethods.ContextDeleteDataChannel(context, channel);
  78. NativeMethods.ContextDeletePeerConnection(context, peer);
  79. NativeMethods.ContextDestroy(0);
  80. }
  81. [Test]
  82. public void CreateAndDeleteMediaStream()
  83. {
  84. var context = NativeMethods.ContextCreate(0);
  85. var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream");
  86. NativeMethods.ContextDeleteRefPtr(context, stream);
  87. NativeMethods.ContextDestroy(0);
  88. }
  89. [AOT.MonoPInvokeCallback(typeof(DelegateNativeMediaStreamOnAddTrack))]
  90. static void MediaStreamOnAddTrack(IntPtr ptr, IntPtr track) { }
  91. [AOT.MonoPInvokeCallback(typeof(DelegateNativeMediaStreamOnRemoveTrack))]
  92. static void MediaStreamOnRemoveTrack(IntPtr ptr, IntPtr track) { }
  93. [Test]
  94. public void RegisterDelegateToMediaStream()
  95. {
  96. var context = NativeMethods.ContextCreate(0);
  97. var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream");
  98. NativeMethods.ContextRegisterMediaStreamObserver(context, stream);
  99. NativeMethods.MediaStreamRegisterOnAddTrack(context, stream, MediaStreamOnAddTrack);
  100. NativeMethods.MediaStreamRegisterOnRemoveTrack(context, stream, MediaStreamOnRemoveTrack);
  101. NativeMethods.ContextUnRegisterMediaStreamObserver(context, stream);
  102. NativeMethods.ContextDeleteRefPtr(context, stream);
  103. NativeMethods.ContextDestroy(0);
  104. }
  105. [Test]
  106. [ConditionalIgnore(ConditionalIgnore.UnsupportedPlatformOpenGL,
  107. "Not support VideoStreamTrack for OpenGL")]
  108. public void AddAndRemoveVideoTrack()
  109. {
  110. var context = NativeMethods.ContextCreate(0);
  111. const int width = 1280;
  112. const int height = 720;
  113. var renderTexture = CreateRenderTexture(width, height);
  114. var source = NativeMethods.ContextCreateVideoTrackSource(context);
  115. var track = NativeMethods.ContextCreateVideoTrack(context, "video", source);
  116. NativeMethods.ContextDeleteRefPtr(context, track);
  117. NativeMethods.ContextDeleteRefPtr(context, source);
  118. NativeMethods.ContextDestroy(0);
  119. UnityEngine.Object.DestroyImmediate(renderTexture);
  120. }
  121. [Test]
  122. [ConditionalIgnore(ConditionalIgnore.UnsupportedPlatformOpenGL,
  123. "Not support VideoStreamTrack for OpenGL")]
  124. public void AddAndRemoveVideoTrackToPeerConnection()
  125. {
  126. var context = NativeMethods.ContextCreate(0);
  127. var peer = NativeMethods.ContextCreatePeerConnection(context);
  128. var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream");
  129. string streamId = NativeMethods.MediaStreamGetID(stream).AsAnsiStringWithFreeMem();
  130. Assert.IsNotEmpty(streamId);
  131. const int width = 1280;
  132. const int height = 720;
  133. var renderTexture = CreateRenderTexture(width, height);
  134. var source = NativeMethods.ContextCreateVideoTrackSource(context);
  135. var track = NativeMethods.ContextCreateVideoTrack(context, "video", source);
  136. var error = NativeMethods.PeerConnectionAddTrack(peer, track, streamId, out var sender);
  137. Assert.That(error, Is.EqualTo(RTCErrorType.None));
  138. var track2 = NativeMethods.SenderGetTrack(sender);
  139. Assert.AreEqual(track, track2);
  140. Assert.That(NativeMethods.PeerConnectionRemoveTrack(peer, sender), Is.EqualTo(RTCErrorType.None));
  141. NativeMethods.ContextDeleteRefPtr(context, track);
  142. NativeMethods.ContextDeleteRefPtr(context, stream);
  143. NativeMethods.ContextDeleteRefPtr(context, source);
  144. NativeMethods.ContextDeletePeerConnection(context, peer);
  145. NativeMethods.ContextDestroy(0);
  146. UnityEngine.Object.DestroyImmediate(renderTexture);
  147. }
  148. [Test]
  149. [ConditionalIgnore(ConditionalIgnore.UnsupportedPlatformOpenGL,
  150. "Not support VideoStreamTrack for OpenGL")]
  151. public void SenderGetParameter()
  152. {
  153. var context = NativeMethods.ContextCreate(0);
  154. var peer = NativeMethods.ContextCreatePeerConnection(context);
  155. var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream");
  156. string streamId = NativeMethods.MediaStreamGetID(stream).AsAnsiStringWithFreeMem();
  157. Assert.IsNotEmpty(streamId);
  158. var source = NativeMethods.ContextCreateVideoTrackSource(context);
  159. var track = NativeMethods.ContextCreateVideoTrack(context, "video", source);
  160. var error = NativeMethods.PeerConnectionAddTrack(peer, track, streamId, out var sender);
  161. Assert.That(error, Is.EqualTo(RTCErrorType.None));
  162. NativeMethods.SenderGetParameters(sender, out var ptr);
  163. var parameters = Marshal.PtrToStructure<RTCRtpSendParametersInternal>(ptr);
  164. Marshal.FreeHGlobal(ptr);
  165. Assert.AreNotEqual(IntPtr.Zero, parameters.encodings);
  166. Assert.AreNotEqual(IntPtr.Zero, parameters.transactionId);
  167. Assert.That(NativeMethods.PeerConnectionRemoveTrack(peer, sender), Is.EqualTo(RTCErrorType.None));
  168. NativeMethods.ContextDeleteRefPtr(context, track);
  169. NativeMethods.ContextDeleteRefPtr(context, stream);
  170. NativeMethods.ContextDeleteRefPtr(context, source);
  171. NativeMethods.ContextDeletePeerConnection(context, peer);
  172. NativeMethods.ContextDestroy(0);
  173. }
  174. // todo(kazuki): Crash occurs when calling NativeMethods.MediaStreamRemoveTrack method on iOS device
  175. [Test]
  176. [UnityPlatform(exclude = new[] { RuntimePlatform.IPhonePlayer })]
  177. [ConditionalIgnore(ConditionalIgnore.UnsupportedPlatformOpenGL,
  178. "Not support VideoStreamTrack for OpenGL")]
  179. public void AddAndRemoveVideoTrackToMediaStream()
  180. {
  181. var context = NativeMethods.ContextCreate(0);
  182. var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream");
  183. const int width = 1280;
  184. const int height = 720;
  185. var renderTexture = CreateRenderTexture(width, height);
  186. var source = NativeMethods.ContextCreateVideoTrackSource(context);
  187. var track = NativeMethods.ContextCreateVideoTrack(context, "video", source);
  188. NativeMethods.MediaStreamAddTrack(stream, track);
  189. IntPtr buf = NativeMethods.MediaStreamGetVideoTracks(stream, out ulong length);
  190. Assert.AreNotEqual(buf, IntPtr.Zero);
  191. Assert.Greater(length, 0);
  192. // todo(kazuki):: Copying native buffer to managed array occurs crash
  193. // on linux with il2cpp
  194. #if !(UNITY_STANDALONE_LINUX && ENABLE_IL2CPP)
  195. IntPtr[] array = new IntPtr[length];
  196. Marshal.Copy(buf, array, 0, (int)length);
  197. Marshal.FreeCoTaskMem(buf);
  198. #endif
  199. NativeMethods.MediaStreamRemoveTrack(stream, track);
  200. NativeMethods.ContextDeleteRefPtr(context, track);
  201. NativeMethods.ContextDeleteRefPtr(context, stream);
  202. NativeMethods.ContextDeleteRefPtr(context, source);
  203. NativeMethods.ContextDestroy(0);
  204. UnityEngine.Object.DestroyImmediate(renderTexture);
  205. }
  206. // todo(kazuki): Crash occurs when calling NativeMethods.MediaStreamRemoveTrack method on iOS device
  207. [Test]
  208. [UnityPlatform(exclude = new[] { RuntimePlatform.IPhonePlayer })]
  209. public void AddAndRemoveAudioTrackToMediaStream()
  210. {
  211. var context = NativeMethods.ContextCreate(0);
  212. var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream");
  213. var source = NativeMethods.ContextCreateAudioTrackSource(context);
  214. var track = NativeMethods.ContextCreateAudioTrack(context, "audio", source);
  215. NativeMethods.MediaStreamAddTrack(stream, track);
  216. var trackNativePtr = NativeMethods.MediaStreamGetAudioTracks(stream, out ulong trackSize);
  217. Assert.AreNotEqual(trackNativePtr, IntPtr.Zero);
  218. Assert.Greater(trackSize, 0);
  219. IntPtr buf = NativeMethods.MediaStreamGetAudioTracks(stream, out ulong length);
  220. Assert.AreNotEqual(buf, IntPtr.Zero);
  221. Assert.Greater(length, 0);
  222. // todo(kazuki):: Copying native buffer to managed array occurs crash
  223. // on linux with il2cpp
  224. #if !(UNITY_STANDALONE_LINUX && ENABLE_IL2CPP)
  225. IntPtr[] array = new IntPtr[length];
  226. Marshal.Copy(buf, array, 0, (int)length);
  227. Marshal.FreeCoTaskMem(buf);
  228. #endif
  229. NativeMethods.MediaStreamRemoveTrack(stream, track);
  230. NativeMethods.ContextDeleteRefPtr(context, track);
  231. NativeMethods.ContextDeleteRefPtr(context, stream);
  232. NativeMethods.ContextDeleteRefPtr(context, source);
  233. NativeMethods.ContextDestroy(0);
  234. }
  235. [Test]
  236. public void AddAndRemoveAudioTrack()
  237. {
  238. var context = NativeMethods.ContextCreate(0);
  239. var peer = NativeMethods.ContextCreatePeerConnection(context);
  240. var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream");
  241. var streamId = NativeMethods.MediaStreamGetID(stream).AsAnsiStringWithFreeMem();
  242. Assert.IsNotEmpty(streamId);
  243. var source = NativeMethods.ContextCreateAudioTrackSource(context);
  244. var track = NativeMethods.ContextCreateAudioTrack(context, "audio", source);
  245. var error = NativeMethods.PeerConnectionAddTrack(peer, track, streamId, out var sender);
  246. Assert.That(error, Is.EqualTo(RTCErrorType.None));
  247. NativeMethods.ContextDeleteRefPtr(context, track);
  248. NativeMethods.ContextDeleteRefPtr(context, source);
  249. Assert.That(NativeMethods.PeerConnectionRemoveTrack(peer, sender), Is.EqualTo(RTCErrorType.None));
  250. NativeMethods.ContextDeleteRefPtr(context, stream);
  251. NativeMethods.ContextDeletePeerConnection(context, peer);
  252. NativeMethods.ContextDestroy(0);
  253. }
  254. [AOT.MonoPInvokeCallback(typeof(DelegateVideoFrameResize))]
  255. static void OnVideoFrameResize(IntPtr ptrRenderer, int width, int height) { }
  256. [Test]
  257. public void CreateAndDeleteVideoRenderer()
  258. {
  259. var context = NativeMethods.ContextCreate(0);
  260. var renderer = NativeMethods.CreateVideoRenderer(context, OnVideoFrameResize, true);
  261. NativeMethods.DeleteVideoRenderer(context, renderer);
  262. NativeMethods.ContextDestroy(0);
  263. }
  264. [Test]
  265. [ConditionalIgnore(ConditionalIgnore.UnsupportedPlatformOpenGL,
  266. "Not support VideoStreamTrack for OpenGL")]
  267. public void AddAndRemoveVideoRendererToVideoTrack()
  268. {
  269. var context = NativeMethods.ContextCreate(0);
  270. const int width = 1280;
  271. const int height = 720;
  272. var renderTexture = CreateRenderTexture(width, height);
  273. var source = NativeMethods.ContextCreateVideoTrackSource(context);
  274. var track = NativeMethods.ContextCreateVideoTrack(context, "video", source);
  275. var renderer = NativeMethods.CreateVideoRenderer(context, OnVideoFrameResize, true);
  276. NativeMethods.VideoTrackAddOrUpdateSink(track, renderer);
  277. NativeMethods.VideoTrackRemoveSink(track, renderer);
  278. NativeMethods.DeleteVideoRenderer(context, renderer);
  279. NativeMethods.ContextDeleteRefPtr(context, track);
  280. NativeMethods.ContextDeleteRefPtr(context, source);
  281. NativeMethods.ContextDestroy(0);
  282. UnityEngine.Object.DestroyImmediate(renderTexture);
  283. }
  284. [Test]
  285. public void CallGetRenderEventFunc()
  286. {
  287. var context = NativeMethods.ContextCreate(0);
  288. var callback = NativeMethods.GetRenderEventFunc(context);
  289. Assert.AreNotEqual(callback, IntPtr.Zero);
  290. NativeMethods.ContextDestroy(0);
  291. NativeMethods.GetRenderEventFunc(IntPtr.Zero);
  292. }
  293. [Test]
  294. public void RTCRtpSendParametersCreateAndDeletePtr()
  295. {
  296. RTCRtpSendParametersInternal parametersInternal = default;
  297. int encodingsLength = 2;
  298. RTCRtpEncodingParametersInternal[] encodings = new RTCRtpEncodingParametersInternal[encodingsLength];
  299. for (int i = 0; i < encodingsLength; i++)
  300. {
  301. encodings[i].active = true;
  302. encodings[i].maxBitrate = 10000000;
  303. encodings[i].minBitrate = 10000000;
  304. encodings[i].maxFramerate = 30;
  305. encodings[i].scaleResolutionDownBy = 1.0;
  306. encodings[i].rid = Marshal.StringToCoTaskMemAnsi(string.Empty);
  307. }
  308. parametersInternal.transactionId = Marshal.StringToCoTaskMemAnsi(string.Empty);
  309. parametersInternal.encodings = encodings;
  310. RTCRtpSendParameters parameter = new RTCRtpSendParameters(ref parametersInternal);
  311. parameter.CreateInstance(out var instance);
  312. instance.Dispose();
  313. }
  314. [UnityTest, LongRunning]
  315. [ConditionalIgnore(ConditionalIgnore.UnsupportedPlatformOpenGL,
  316. "Not support VideoStreamTrack for OpenGL")]
  317. public IEnumerator CallVideoEncoderMethods()
  318. {
  319. var context = NativeMethods.ContextCreate(0);
  320. var peer = NativeMethods.ContextCreatePeerConnection(context);
  321. var stream = NativeMethods.ContextCreateMediaStream(context, "MediaStream");
  322. var streamId = NativeMethods.MediaStreamGetID(stream).AsAnsiStringWithFreeMem();
  323. Assert.IsNotEmpty(streamId);
  324. const int width = 1280;
  325. const int height = 720;
  326. var renderTexture = CreateRenderTexture(width, height);
  327. var source = NativeMethods.ContextCreateVideoTrackSource(context);
  328. var track = NativeMethods.ContextCreateVideoTrack(context, "video", source);
  329. var error = NativeMethods.PeerConnectionAddTrack(peer, track, streamId, out var sender);
  330. Assert.That(error, Is.EqualTo(RTCErrorType.None));
  331. var callback = NativeMethods.GetRenderEventFunc(context);
  332. yield return new WaitForSeconds(1.0f);
  333. VideoTrackSource.EncodeData data = new VideoTrackSource.EncodeData(renderTexture, source);
  334. IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VideoTrackSource.EncodeData)));
  335. Marshal.StructureToPtr(data, ptr, true);
  336. VideoEncoderMethods.Encode(callback, ptr);
  337. yield return new WaitForSeconds(1.0f);
  338. Marshal.FreeHGlobal(ptr);
  339. Assert.That(NativeMethods.PeerConnectionRemoveTrack(peer, sender), Is.EqualTo(RTCErrorType.None));
  340. NativeMethods.ContextDeleteRefPtr(context, track);
  341. NativeMethods.ContextDeleteRefPtr(context, stream);
  342. NativeMethods.ContextDeleteRefPtr(context, source);
  343. NativeMethods.ContextDeletePeerConnection(context, peer);
  344. NativeMethods.ContextDestroy(0);
  345. UnityEngine.Object.DestroyImmediate(renderTexture);
  346. }
  347. [Test]
  348. public void CallGetUpdateTextureFunc()
  349. {
  350. var context = NativeMethods.ContextCreate(0);
  351. var callback = NativeMethods.GetUpdateTextureFunc(context);
  352. Assert.AreNotEqual(callback, IntPtr.Zero);
  353. NativeMethods.ContextDestroy(0);
  354. NativeMethods.GetUpdateTextureFunc(IntPtr.Zero);
  355. }
  356. [UnityTest, LongRunning]
  357. [ConditionalIgnoreMultiple(ConditionalIgnore.UnsupportedPlatformVideoDecoder,
  358. "VideoDecoderMethods.UpdateRendererTexture is not supported on Direct3D12.")]
  359. [ConditionalIgnoreMultiple(ConditionalIgnore.UnsupportedPlatformOpenGL,
  360. "Not support VideoStreamTrack for OpenGL")]
  361. public IEnumerator CallVideoDecoderMethods()
  362. {
  363. var context = NativeMethods.ContextCreate(0);
  364. const int width = 1280;
  365. const int height = 720;
  366. var renderTexture = CreateRenderTexture(width, height);
  367. var receiveTexture = CreateRenderTexture(width, height);
  368. var source = NativeMethods.ContextCreateVideoTrackSource(context);
  369. var track = NativeMethods.ContextCreateVideoTrack(context, "video", source);
  370. var renderer = NativeMethods.CreateVideoRenderer(context, OnVideoFrameResize, true);
  371. var rendererId = NativeMethods.GetVideoRendererId(renderer);
  372. NativeMethods.VideoTrackAddOrUpdateSink(track, renderer);
  373. var renderEvent = NativeMethods.GetRenderEventFunc(context);
  374. var updateTextureEvent = NativeMethods.GetUpdateTextureFunc(context);
  375. yield return new WaitForSeconds(1.0f);
  376. VideoTrackSource.EncodeData data = new VideoTrackSource.EncodeData(renderTexture, source);
  377. IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(VideoTrackSource.EncodeData)));
  378. Marshal.StructureToPtr(data, ptr, true);
  379. VideoEncoderMethods.Encode(renderEvent, ptr);
  380. yield return new WaitForSeconds(1.0f);
  381. // this method is not supported on Direct3D12
  382. VideoDecoderMethods.UpdateRendererTexture(updateTextureEvent, receiveTexture, rendererId);
  383. yield return new WaitForSeconds(1.0f);
  384. yield return new WaitForSeconds(1.0f);
  385. Marshal.FreeHGlobal(ptr);
  386. NativeMethods.VideoTrackRemoveSink(track, renderer);
  387. NativeMethods.DeleteVideoRenderer(context, renderer);
  388. NativeMethods.ContextDeleteRefPtr(context, track);
  389. NativeMethods.ContextDeleteRefPtr(context, source);
  390. NativeMethods.ContextDestroy(0);
  391. UnityEngine.Object.DestroyImmediate(renderTexture);
  392. UnityEngine.Object.DestroyImmediate(receiveTexture);
  393. }
  394. }
  395. [UnityPlatform(RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor)]
  396. class NativeAPITestAndEnterPlayModeOptionsEnabled : NativeAPITest, IPrebuildSetup
  397. {
  398. public void Setup()
  399. {
  400. #if UNITY_EDITOR
  401. EditorSettings.enterPlayModeOptionsEnabled = true;
  402. EditorSettings.enterPlayModeOptions =
  403. EnterPlayModeOptions.DisableDomainReload | EnterPlayModeOptions.DisableSceneReload;
  404. #endif
  405. }
  406. }
  407. }