SignalingManager.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. using System;
  2. using System.Linq;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Threading;
  6. using UnityEngine;
  7. using Unity.WebRTC;
  8. using Unity.RenderStreaming.Signaling;
  9. #if UNITY_EDITOR
  10. using UnityEditor;
  11. #endif
  12. namespace Unity.RenderStreaming
  13. {
  14. [AddComponentMenu("Render Streaming/Signaling Manager")]
  15. public sealed class SignalingManager : MonoBehaviour
  16. {
  17. #pragma warning disable 0649
  18. [SerializeField]
  19. private bool m_useDefault = true;
  20. [SerializeField]
  21. internal SignalingSettingsObject signalingSettingsObject;
  22. [SerializeReference, SignalingSettings]
  23. private SignalingSettings signalingSettings = new WebSocketSignalingSettings();
  24. [SerializeField, Tooltip("List of handlers of signaling process.")]
  25. private List<SignalingHandlerBase> handlers = new List<SignalingHandlerBase>();
  26. /// <summary>
  27. ///
  28. /// </summary>
  29. [SerializeField, Tooltip("Automatically started when called Awake method.")]
  30. public bool runOnAwake = true;
  31. /// <summary>
  32. ///
  33. /// </summary>
  34. [SerializeField, Tooltip("Evaluate commandline arguments if launching runtime on the command line.")]
  35. public bool evaluateCommandlineArguments = true;
  36. #pragma warning restore 0649
  37. private SignalingManagerInternal m_instance;
  38. private SignalingEventProvider m_provider;
  39. private bool m_running;
  40. public bool Running => m_running;
  41. static ISignaling CreateSignaling(SignalingSettings settings, SynchronizationContext context)
  42. {
  43. if (settings.signalingClass == null)
  44. {
  45. throw new ArgumentException($"Signaling type is undefined. {settings.signalingClass}");
  46. }
  47. object[] args = { settings, context };
  48. return (ISignaling)Activator.CreateInstance(settings.signalingClass, args);
  49. }
  50. /// <summary>
  51. /// Use settings in Project Settings.
  52. /// </summary>
  53. public bool useDefaultSettings
  54. {
  55. get { return m_useDefault; }
  56. set { m_useDefault = value; }
  57. }
  58. /// <summary>
  59. ///
  60. /// </summary>
  61. /// <param name="settings"></param>
  62. /// <exception cref="InvalidOperationException"></exception>
  63. public void SetSignalingSettings(SignalingSettings settings)
  64. {
  65. if (m_running)
  66. throw new InvalidOperationException("The Signaling process has already started.");
  67. if (settings == null)
  68. throw new ArgumentNullException("settings");
  69. signalingSettings = settings;
  70. }
  71. /// <summary>
  72. ///
  73. /// </summary>
  74. /// <returns></returns>
  75. public SignalingSettings GetSignalingSettings()
  76. {
  77. return signalingSettings;
  78. }
  79. /// <summary>
  80. ///
  81. /// </summary>
  82. /// <param name="handlerBase"></param>
  83. public void AddSignalingHandler(SignalingHandlerBase handlerBase)
  84. {
  85. if (handlers.Contains(handlerBase))
  86. {
  87. return;
  88. }
  89. handlers.Add(handlerBase);
  90. if (!m_running)
  91. {
  92. return;
  93. }
  94. handlerBase.SetHandler(m_instance);
  95. m_provider.Subscribe(handlerBase);
  96. }
  97. /// <summary>
  98. ///
  99. /// </summary>
  100. /// <param name="handlerBase"></param>
  101. public void RemoveSignalingHandler(SignalingHandlerBase handlerBase)
  102. {
  103. handlers.Remove(handlerBase);
  104. if (!m_running)
  105. {
  106. return;
  107. }
  108. handlerBase.SetHandler(null);
  109. m_provider.Unsubscribe(handlerBase);
  110. }
  111. /// <summary>
  112. ///
  113. /// </summary>
  114. /// <param name="signaling"></param>
  115. /// <param name="handlers"></param>
  116. public void Run(
  117. ISignaling signaling = null,
  118. SignalingHandlerBase[] handlers = null)
  119. {
  120. Debug.Log("RunRunRunRunRunRunRunRunRunRun");
  121. _Run(null, signaling, handlers);
  122. }
  123. /// <summary>
  124. ///
  125. /// </summary>
  126. /// <param name="conf"></param>
  127. /// <param name="signaling"></param>
  128. /// <param name="handlers"></param>
  129. /// <remarks> To use this method, Need to depend WebRTC package </remarks>
  130. public void Run(
  131. RTCConfiguration conf,
  132. ISignaling signaling = null,
  133. SignalingHandlerBase[] handlers = null
  134. )
  135. {
  136. _Run(conf, signaling, handlers);
  137. }
  138. #if UNITY_EDITOR
  139. bool IsValidSignalingSettingsObject(SignalingSettingsObject asset)
  140. {
  141. if (asset == null)
  142. return false;
  143. if (AssetDatabase.GetAssetPath(asset).IndexOf("Assets", StringComparison.Ordinal) != 0)
  144. return false;
  145. return true;
  146. }
  147. #endif
  148. /// <summary>
  149. ///
  150. /// </summary>
  151. /// <param name="conf"></param>
  152. /// <param name="signaling"></param>
  153. /// <param name="handlers"></param>
  154. private void _Run(
  155. RTCConfiguration? conf = null,
  156. ISignaling signaling = null,
  157. SignalingHandlerBase[] handlers = null
  158. )
  159. {
  160. var settings = m_useDefault ? RenderStreaming.GetSignalingSettings<SignalingSettings>() : signalingSettings;
  161. #if !UNITY_EDITOR
  162. var arguments = Environment.GetCommandLineArgs();
  163. if (evaluateCommandlineArguments && arguments.Length > 1)
  164. {
  165. if (!EvaluateCommandlineArguments(ref settings, arguments))
  166. {
  167. Debug.LogError("Command line arguments are invalid.");
  168. }
  169. }
  170. #endif
  171. RTCIceServer[] iceServers = settings.iceServers.OfType<RTCIceServer>().ToArray();
  172. RTCConfiguration _conf =
  173. conf.GetValueOrDefault(new RTCConfiguration { iceServers = iceServers });
  174. ISignaling _signaling = signaling ?? CreateSignaling(settings, SynchronizationContext.Current);
  175. RenderStreamingDependencies dependencies = new RenderStreamingDependencies
  176. {
  177. config = _conf,
  178. signaling = _signaling,
  179. startCoroutine = StartCoroutine,
  180. stopCoroutine = StopCoroutine,
  181. resentOfferInterval = 5.0f,
  182. };
  183. var _handlers = (handlers ?? this.handlers.AsEnumerable()).Where(_ => _ != null);
  184. if (_handlers.Count() == 0)
  185. throw new InvalidOperationException("Handler list is empty.");
  186. m_instance = new SignalingManagerInternal(ref dependencies);
  187. m_provider = new SignalingEventProvider(m_instance);
  188. foreach (var handler in _handlers)
  189. {
  190. handler.SetHandler(m_instance);
  191. m_provider.Subscribe(handler);
  192. }
  193. m_running = true;
  194. }
  195. internal static bool EvaluateCommandlineArguments(ref SignalingSettings settings, string[] arguments)
  196. {
  197. if (!CommandLineParser.TryParse(arguments))
  198. return false;
  199. string signalingTypeName = null;
  200. if (CommandLineParser.SignalingType.Value != null)
  201. {
  202. signalingTypeName = CommandLineParser.SignalingType;
  203. }
  204. else if (CommandLineParser.ImportJson.Value != null)
  205. {
  206. signalingTypeName = CommandLineParser.ImportJson.Value.Value.signalingType;
  207. }
  208. if (signalingTypeName != null)
  209. {
  210. Type[] types = RuntimeTypeCache<SignalingSettings>.GetTypesDerivedFrom();
  211. Dictionary<string, Type> map =
  212. types.Where(type => type.GetCustomAttribute<SignalingTypeAttribute>() != null)
  213. .ToDictionary(type => type.GetCustomAttribute<SignalingTypeAttribute>().typename, type => type);
  214. if (map.ContainsKey(signalingTypeName))
  215. {
  216. var type = map[signalingTypeName];
  217. settings = (SignalingSettings)Activator.CreateInstance(type);
  218. }
  219. }
  220. return settings.ParseArguments(arguments);
  221. }
  222. /// <summary>
  223. ///
  224. /// </summary>
  225. public void Stop()
  226. {
  227. m_instance?.Dispose();
  228. m_instance = null;
  229. m_running = false;
  230. }
  231. void Awake()
  232. {
  233. if (!runOnAwake || m_running || handlers.Count == 0)
  234. return;
  235. var settings = m_useDefault ? RenderStreaming.GetSignalingSettings<SignalingSettings>() : signalingSettings;
  236. RTCIceServer[] iceServers = settings.iceServers.OfType<RTCIceServer>().ToArray();
  237. RTCConfiguration conf = new RTCConfiguration { iceServers = iceServers };
  238. ISignaling signaling = CreateSignaling(settings, SynchronizationContext.Current);
  239. _Run(conf, signaling, handlers.ToArray());
  240. }
  241. void OnDestroy()
  242. {
  243. Stop();
  244. }
  245. }
  246. }