123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using Unity.RenderStreaming.Signaling;
- using Unity.WebRTC;
- namespace Unity.RenderStreaming
- {
- /// <summary>
- ///
- /// </summary>
- internal struct RenderStreamingDependencies
- {
- /// <summary>
- ///
- /// </summary>
- public ISignaling signaling;
- /// <summary>
- ///
- /// </summary>
- public RTCConfiguration config;
- /// <summary>
- ///
- /// </summary>
- public Func<IEnumerator, Coroutine> startCoroutine;
- /// <summary>
- ///
- /// </summary>
- public Action<Coroutine> stopCoroutine;
- /// <summary>
- /// unit is second;
- /// </summary>
- public float resentOfferInterval;
- }
- /// <summary>
- ///
- /// </summary>
- internal class SignalingManagerInternal : IDisposable,
- IRenderStreamingHandler, IRenderStreamingDelegate
- {
- /// <summary>
- ///
- /// </summary>
- public event Action onStart;
- /// <summary>
- ///
- /// </summary>
- public event Action<string> onCreatedConnection;
- /// <summary>
- ///
- /// </summary>
- public event Action<string> onDeletedConnection;
- /// <summary>
- ///
- /// </summary>
- public event Action<string, string> onGotOffer;
- /// <summary>
- ///
- /// </summary>
- public event Action<string, string> onGotAnswer;
- /// <summary>
- ///
- /// </summary>
- public event Action<string> onConnect;
- /// <summary>
- ///
- /// </summary>
- public event Action<string> onDisconnect;
- /// <summary>
- ///
- /// </summary>
- public event Action<string, RTCRtpTransceiver> onAddTransceiver;
- /// <summary>
- ///
- /// </summary>
- public event Action<string, RTCDataChannel> onAddChannel;
- private bool _disposed;
- private readonly ISignaling _signaling;
- private RTCConfiguration _config;
- private readonly Func<IEnumerator, Coroutine> _startCoroutine;
- private readonly Action<Coroutine> _stopCoroutine;
- private readonly Dictionary<string, PeerConnection> _mapConnectionIdAndPeer =
- new Dictionary<string, PeerConnection>();
- private bool _runningResendCoroutine;
- private float _resendInterval = 3.0f;
- /// <summary>
- ///
- /// </summary>
- /// <param name="dependencies"></param>
- public SignalingManagerInternal(ref RenderStreamingDependencies dependencies)
- {
- if (dependencies.signaling == null)
- throw new ArgumentException("Signaling instance is null.");
- if (dependencies.startCoroutine == null)
- throw new ArgumentException("Coroutine action instance is null.");
- _config = dependencies.config;
- _startCoroutine = dependencies.startCoroutine;
- _stopCoroutine = dependencies.stopCoroutine;
- _resendInterval = dependencies.resentOfferInterval;
- _signaling = dependencies.signaling;
- _signaling.OnStart += OnStart;
- _signaling.OnCreateConnection += OnCreateConnection;
- _signaling.OnDestroyConnection += OnDestroyConnection;
- _signaling.OnOffer += OnOffer;
- _signaling.OnAnswer += OnAnswer;
- _signaling.OnIceCandidate += OnIceCandidate;
- _signaling.Start();
- _startCoroutine(WebRTC.WebRTC.Update());
- }
- /// <summary>
- ///
- /// </summary>
- ~SignalingManagerInternal()
- {
- Dispose();
- }
- /// <summary>
- ///
- /// </summary>
- public void Dispose()
- {
- if (this._disposed)
- {
- return;
- }
- _runningResendCoroutine = false;
- _signaling.Stop();
- _signaling.OnStart -= OnStart;
- _signaling.OnCreateConnection -= OnCreateConnection;
- _signaling.OnDestroyConnection -= OnDestroyConnection;
- _signaling.OnOffer -= OnOffer;
- _signaling.OnAnswer -= OnAnswer;
- _signaling.OnIceCandidate -= OnIceCandidate;
- foreach(var pair in _mapConnectionIdAndPeer)
- pair.Value.Dispose();
- this._disposed = true;
- GC.SuppressFinalize(this);
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- public void CreateConnection(string connectionId)
- {
- _signaling.OpenConnection(connectionId);
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- public void DeleteConnection(string connectionId)
- {
- _signaling.CloseConnection(connectionId);
- }
- public bool ExistConnection(string connectionId)
- {
- return _mapConnectionIdAndPeer.ContainsKey(connectionId);
- }
- public bool IsConnected(string connectionId)
- {
- return _mapConnectionIdAndPeer.TryGetValue(connectionId, out var peer) && peer.IsConnected();
- }
- public bool IsStable(string connectionId)
- {
- return _mapConnectionIdAndPeer.TryGetValue(connectionId, out var peer) && peer.IsStable();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- /// <param name="track"></param>
- public void RemoveSenderTrack(string connectionId, MediaStreamTrack track)
- {
- var sender = GetSenders(connectionId).First(s => s.Track == track);
- _mapConnectionIdAndPeer[connectionId].peer.RemoveTrack(sender);
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- /// <param name="track"></param>
- /// <param name="direction"></param>
- /// <returns></returns>
- public RTCRtpTransceiver AddTransceiver(string connectionId, MediaStreamTrack track, RTCRtpTransceiverInit init = null)
- {
- var transceiver = _mapConnectionIdAndPeer[connectionId].peer.AddTransceiver(track, init);
- return transceiver;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- /// <param name="kind"></param>
- /// <param name="direction"></param>
- /// <returns></returns>
- public RTCRtpTransceiver AddTransceiver(string connectionId, TrackKind kind, RTCRtpTransceiverInit init = null)
- {
- var transceiver = _mapConnectionIdAndPeer[connectionId].peer.AddTransceiver(kind, init);
- return transceiver;
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- /// <param name="name"></param>
- /// <returns></returns>
- public RTCDataChannel CreateChannel(string connectionId, string name)
- {
- RTCDataChannelInit conf = new RTCDataChannelInit();
- if (string.IsNullOrEmpty(name))
- name = Guid.NewGuid().ToString();
- return _mapConnectionIdAndPeer[connectionId].peer.CreateDataChannel(name, conf);
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- /// <param name="track"></param>
- /// <returns></returns>
- public IEnumerable<RTCRtpSender> GetSenders(string connectionId)
- {
- return _mapConnectionIdAndPeer[connectionId].peer.GetSenders();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- /// <param name="track"></param>
- /// <returns></returns>
- public IEnumerable<RTCRtpReceiver> GetReceivers(string connectionId)
- {
- return _mapConnectionIdAndPeer[connectionId].peer.GetReceivers();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- /// <param name="track"></param>
- /// <returns></returns>
- public IEnumerable<RTCRtpTransceiver> GetTransceivers(string connectionId)
- {
- return _mapConnectionIdAndPeer[connectionId].peer.GetTransceivers();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- public void SendOffer(string connectionId)
- {
- if (!_mapConnectionIdAndPeer.TryGetValue(connectionId, out var pc))
- return;
- pc.SendOffer();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="connectionId"></param>
- public void SendAnswer(string connectionId)
- {
- if (!_mapConnectionIdAndPeer.TryGetValue(connectionId, out var pc))
- return;
- pc.SendAnswer();
- }
- IEnumerator ResendOfferCoroutine()
- {
- HashSet<string> failedConnections = new HashSet<string>();
- while (_runningResendCoroutine)
- {
- failedConnections.Clear();
- foreach (var peer in _mapConnectionIdAndPeer)
- {
- if (peer.Value.peer.ConnectionState == RTCPeerConnectionState.Failed)
- {
- failedConnections.Add(peer.Key);
- }
- else if(peer.Value.waitingAnswer)
- {
- peer.Value.SendOffer();
- }
- }
- foreach (var connectionId in failedConnections)
- {
- DestroyConnection(connectionId);
- }
- yield return 0;
- }
- }
- void OnStart(ISignaling signaling)
- {
- if (!_runningResendCoroutine)
- {
- _runningResendCoroutine = true;
- _startCoroutine(ResendOfferCoroutine());
- }
- onStart?.Invoke();
- }
- void OnCreateConnection(ISignaling signaling, string connectionId, bool polite)
- {
- CreatePeerConnection(connectionId, polite);
- onCreatedConnection?.Invoke(connectionId);
- }
- void OnDestroyConnection(ISignaling signaling, string connectionId)
- {
- DestroyConnection(connectionId);
- }
- void DestroyConnection(string connectionId)
- {
- DeletePeerConnection(connectionId);
- onDeletedConnection?.Invoke(connectionId);
- }
- PeerConnection CreatePeerConnection(string connectionId, bool polite)
- {
- if (_mapConnectionIdAndPeer.TryGetValue(connectionId, out var peer))
- {
- peer.Dispose();
- }
- peer = new PeerConnection(polite, _config, _resendInterval, _startCoroutine, _stopCoroutine);
- _mapConnectionIdAndPeer[connectionId] = peer;
- peer.OnConnectHandler += () => onConnect?.Invoke(connectionId);
- peer.OnDisconnectHandler += () => onDisconnect?.Invoke(connectionId);
- peer.OnDataChannelHandler += channel => onAddChannel?.Invoke(connectionId, channel);;
- peer.OnTrackEventHandler += e => onAddTransceiver?.Invoke(connectionId, e.Transceiver);
- peer.SendOfferHandler += desc => _signaling?.SendOffer(connectionId, desc);
- peer.SendAnswerHandler += desc => _signaling?.SendAnswer(connectionId, desc);
- peer.SendCandidateHandler += candidate => _signaling?.SendCandidate(connectionId, candidate);
- return peer;
- }
- void DeletePeerConnection(string connectionId)
- {
- if (!_mapConnectionIdAndPeer.TryGetValue(connectionId, out var peer))
- {
- return;
- }
- peer.Dispose();
- _mapConnectionIdAndPeer.Remove(connectionId);
- }
- void OnAnswer(ISignaling signaling, DescData e)
- {
- if (!_mapConnectionIdAndPeer.TryGetValue(e.connectionId, out var pc))
- {
- Debug.LogWarning($"connectionId:{e.connectionId}, peerConnection not exist");
- return;
- }
- RTCSessionDescription description = new RTCSessionDescription {type = RTCSdpType.Answer, sdp = e.sdp};
- _startCoroutine(pc.OnGotDescription(description, () => onGotAnswer?.Invoke(e.connectionId, e.sdp)));
- }
- void OnIceCandidate(ISignaling signaling, CandidateData e)
- {
- if (!_mapConnectionIdAndPeer.TryGetValue(e.connectionId, out var pc))
- {
- return;
- }
- RTCIceCandidateInit option = new RTCIceCandidateInit
- {
- candidate = e.candidate, sdpMLineIndex = e.sdpMLineIndex, sdpMid = e.sdpMid
- };
- pc.OnGotIceCandidate(new RTCIceCandidate(option));
- }
- void OnOffer(ISignaling signaling, DescData e)
- {
- var connectionId = e.connectionId;
- if (!_mapConnectionIdAndPeer.TryGetValue(connectionId, out var pc))
- {
- pc = CreatePeerConnection(connectionId, e.polite);
- }
- RTCSessionDescription description = new RTCSessionDescription {type = RTCSdpType.Offer, sdp = e.sdp};
- _startCoroutine(pc.OnGotDescription(description, () => onGotOffer?.Invoke(connectionId, e.sdp)));
- }
- }
- }
|