StreamSenderBase.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Unity.WebRTC;
  6. using UnityEngine;
  7. namespace Unity.RenderStreaming
  8. {
  9. /// <summary>
  10. ///
  11. /// </summary>
  12. public abstract class StreamSenderBase : MonoBehaviour, IStreamSender
  13. {
  14. internal class WaitForCreateTrack : CustomYieldInstruction
  15. {
  16. public MediaStreamTrack Track { get { return m_track; } }
  17. MediaStreamTrack m_track;
  18. bool m_keepWaiting = true;
  19. public override bool keepWaiting { get { return m_keepWaiting; } }
  20. public WaitForCreateTrack() { }
  21. public void Done(MediaStreamTrack track)
  22. {
  23. m_track = track;
  24. m_keepWaiting = false;
  25. }
  26. }
  27. internal Coroutine StartCoroutineWithCallback<T>(T coroutine, Action<T> callback) where T : IEnumerator
  28. {
  29. if (coroutine == null)
  30. throw new ArgumentNullException("coroutine");
  31. if (callback == null)
  32. throw new ArgumentNullException("callback");
  33. return StartCoroutine(_Coroutine(coroutine, callback));
  34. }
  35. internal IEnumerator _Coroutine<T>(T coroutine, Action<T> callback) where T : IEnumerator
  36. {
  37. yield return StartCoroutine(coroutine);
  38. callback(coroutine);
  39. }
  40. /// <summary>
  41. ///
  42. /// </summary>
  43. public IReadOnlyDictionary<string, RTCRtpTransceiver> Transceivers => m_transceivers;
  44. /// <summary>
  45. ///
  46. /// </summary>
  47. public OnStartedStreamHandler OnStartedStream { get; set; }
  48. /// <summary>
  49. ///
  50. /// </summary>
  51. public OnStoppedStreamHandler OnStoppedStream { get; set; }
  52. /// <summary>
  53. ///
  54. /// </summary>
  55. /// <returns></returns>
  56. internal abstract WaitForCreateTrack CreateTrack();
  57. internal virtual void ReplaceTrack(MediaStreamTrack newTrack)
  58. {
  59. if (newTrack == null)
  60. throw new ArgumentNullException("track", "This argument must be not null.");
  61. if (m_track == newTrack)
  62. throw new ArgumentException("track", "The value of this argument has already been set.");
  63. /// todo:: If not disposing the old track here, the app will crash.
  64. /// This problem is caused by the MediaStreamTrack when it is destroyed on the thread other than the main thread.
  65. m_track?.Dispose();
  66. m_track = newTrack;
  67. foreach (var transceiver in Transceivers.Values)
  68. {
  69. transceiver.Sender.ReplaceTrack(m_track);
  70. }
  71. }
  72. internal void SetTrack(MediaStreamTrack newTrack)
  73. {
  74. if (newTrack == null)
  75. throw new ArgumentNullException("track", "This argument must be not null.");
  76. if (m_track != null)
  77. throw new InvalidOperationException("Track is not null. Use ReplaceTrack method.");
  78. m_track = newTrack;
  79. }
  80. private MediaStreamTrack m_track;
  81. private Dictionary<string, RTCRtpTransceiver> m_transceivers =
  82. new Dictionary<string, RTCRtpTransceiver>();
  83. /// <summary>
  84. ///
  85. /// </summary>
  86. public MediaStreamTrack Track => m_track;
  87. /// <summary>
  88. ///
  89. /// </summary>
  90. public bool isPlaying
  91. {
  92. get
  93. {
  94. foreach (var transceiver in Transceivers.Values)
  95. {
  96. if (string.IsNullOrEmpty(transceiver.Mid))
  97. continue;
  98. if (transceiver.Sender.Track.ReadyState == TrackState.Ended)
  99. continue;
  100. return true;
  101. }
  102. return false;
  103. }
  104. }
  105. private protected virtual void OnDestroy()
  106. {
  107. m_track?.Dispose();
  108. m_track = null;
  109. }
  110. private protected virtual void OnEnable()
  111. {
  112. if (m_track?.ReadyState == TrackState.Live)
  113. {
  114. m_track.Enabled = true;
  115. }
  116. }
  117. private protected virtual void OnDisable()
  118. {
  119. if (m_track?.ReadyState == TrackState.Live)
  120. {
  121. m_track.Enabled = false;
  122. }
  123. }
  124. /// <summary>
  125. ///
  126. /// </summary>
  127. /// <param name="connectionId"></param>
  128. /// <param name="sender"></param>
  129. public virtual void SetTransceiver(string connectionId, RTCRtpTransceiver transceiver)
  130. {
  131. if (connectionId == null)
  132. throw new ArgumentNullException("connectionId is null");
  133. if (transceiver == null)
  134. {
  135. m_transceivers.Remove(connectionId);
  136. OnStoppedStream?.Invoke(connectionId);
  137. if (!m_transceivers.Any())
  138. {
  139. m_track.Dispose();
  140. m_track = null;
  141. }
  142. }
  143. else
  144. {
  145. m_transceivers.Add(connectionId, transceiver);
  146. OnStartedStream?.Invoke(connectionId);
  147. }
  148. }
  149. }
  150. }