using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.WebRTC;
using UnityEngine;
namespace Unity.RenderStreaming
{
///
///
///
public abstract class StreamSenderBase : MonoBehaviour, IStreamSender
{
internal class WaitForCreateTrack : CustomYieldInstruction
{
public MediaStreamTrack Track { get { return m_track; } }
MediaStreamTrack m_track;
bool m_keepWaiting = true;
public override bool keepWaiting { get { return m_keepWaiting; } }
public WaitForCreateTrack() { }
public void Done(MediaStreamTrack track)
{
m_track = track;
m_keepWaiting = false;
}
}
internal Coroutine StartCoroutineWithCallback(T coroutine, Action callback) where T : IEnumerator
{
if (coroutine == null)
throw new ArgumentNullException("coroutine");
if (callback == null)
throw new ArgumentNullException("callback");
return StartCoroutine(_Coroutine(coroutine, callback));
}
internal IEnumerator _Coroutine(T coroutine, Action callback) where T : IEnumerator
{
yield return StartCoroutine(coroutine);
callback(coroutine);
}
///
///
///
public IReadOnlyDictionary Transceivers => m_transceivers;
///
///
///
public OnStartedStreamHandler OnStartedStream { get; set; }
///
///
///
public OnStoppedStreamHandler OnStoppedStream { get; set; }
///
///
///
///
internal abstract WaitForCreateTrack CreateTrack();
internal virtual void ReplaceTrack(MediaStreamTrack newTrack)
{
if (newTrack == null)
throw new ArgumentNullException("track", "This argument must be not null.");
if (m_track == newTrack)
throw new ArgumentException("track", "The value of this argument has already been set.");
/// todo:: If not disposing the old track here, the app will crash.
/// This problem is caused by the MediaStreamTrack when it is destroyed on the thread other than the main thread.
m_track?.Dispose();
m_track = newTrack;
foreach (var transceiver in Transceivers.Values)
{
transceiver.Sender.ReplaceTrack(m_track);
}
}
internal void SetTrack(MediaStreamTrack newTrack)
{
if (newTrack == null)
throw new ArgumentNullException("track", "This argument must be not null.");
if (m_track != null)
throw new InvalidOperationException("Track is not null. Use ReplaceTrack method.");
m_track = newTrack;
}
private MediaStreamTrack m_track;
private Dictionary m_transceivers =
new Dictionary();
///
///
///
public MediaStreamTrack Track => m_track;
///
///
///
public bool isPlaying
{
get
{
foreach (var transceiver in Transceivers.Values)
{
if (string.IsNullOrEmpty(transceiver.Mid))
continue;
if (transceiver.Sender.Track.ReadyState == TrackState.Ended)
continue;
return true;
}
return false;
}
}
private protected virtual void OnDestroy()
{
m_track?.Dispose();
m_track = null;
}
private protected virtual void OnEnable()
{
if (m_track?.ReadyState == TrackState.Live)
{
m_track.Enabled = true;
}
}
private protected virtual void OnDisable()
{
if (m_track?.ReadyState == TrackState.Live)
{
m_track.Enabled = false;
}
}
///
///
///
///
///
public virtual void SetTransceiver(string connectionId, RTCRtpTransceiver transceiver)
{
if (connectionId == null)
throw new ArgumentNullException("connectionId is null");
if (transceiver == null)
{
m_transceivers.Remove(connectionId);
OnStoppedStream?.Invoke(connectionId);
if (!m_transceivers.Any())
{
m_track.Dispose();
m_track = null;
}
}
else
{
m_transceivers.Add(connectionId, transceiver);
OnStartedStream?.Invoke(connectionId);
}
}
}
}