Files
webRtc/Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/SignalingManagerInternal.cs

498 lines
16 KiB
C#
Raw Normal View History

2026-04-28 16:48:04 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.RenderStreaming.Signaling;
using Unity.WebRTC;
using UnityEngine;
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;
2026-04-29 15:13:24 +08:00
/// <summary>
/// 参与者加入事件 (connectionId, participantId)
/// </summary>
public event Action<string, string> onParticipantJoined;
/// <summary>
/// 参与者离开事件 (connectionId, participantId)
/// </summary>
public event Action<string, string> onParticipantLeft;
/// <summary>
/// 呼叫请求事件 (connectionId, data)
/// </summary>
public event Action<string, string> onCallRequest;
/// <summary>
/// 自定义消息事件 (connectionId, participantId, message)
/// </summary>
public event Action<string, string, string> onMessage;
2026-04-28 16:48:04 +08:00
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;
2026-04-29 15:13:24 +08:00
_signaling.OnParticipantJoined += OnParticipantJoinedHandler;
_signaling.OnParticipantLeft += OnParticipantLeftHandler;
_signaling.OnCallRequest += OnCallRequestHandler;
_signaling.OnMessage += OnMessageHandler;
2026-04-28 16:48:04 +08:00
_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;
2026-04-29 15:13:24 +08:00
_signaling.OnParticipantJoined -= OnParticipantJoinedHandler;
_signaling.OnParticipantLeft -= OnParticipantLeftHandler;
_signaling.OnCallRequest -= OnCallRequestHandler;
_signaling.OnMessage -= OnMessageHandler;
2026-04-28 16:48:04 +08:00
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 += () =>
{
2026-04-30 23:27:34 +08:00
// PeerConnection失败时不自动发送disconnect避免重复断开通知。
// 主动断开由 Handler 的 DeleteConnection 触发,远端断开由服务器的 disconnect 消息触发。
// 这里只触发 onDisconnect 事件通知 Handler 进行资源清理。
2026-04-28 16:48:04 +08:00
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))
{
RenderStreaming.Logger.Log(LogType.Warning, $"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);
}
2026-04-30 15:35:47 +08:00
// 先触发 onGotOffer让 Handler 在 SetRemoteDescription 之前添加 transceiver
// 这样 transceiver 会在 offer 的媒体行内正确匹配
onGotOffer?.Invoke(connectionId, e.sdp);
// 然后设置远程描述,完成后自动 SendAnswer
2026-04-28 16:48:04 +08:00
RTCSessionDescription description = new RTCSessionDescription { type = RTCSdpType.Offer, sdp = e.sdp };
2026-04-30 15:35:47 +08:00
_startCoroutine(pc.OnGotDescription(description, () =>
{
// SetRemoteDescription 成功后,自动创建并发送 answer
pc.SendAnswer();
}));
2026-04-28 16:48:04 +08:00
}
2026-04-29 15:13:24 +08:00
void OnParticipantJoinedHandler(ISignaling signaling, ParticipantEventData e)
{
onParticipantJoined?.Invoke(e.connectionId, e.participantId);
}
void OnParticipantLeftHandler(ISignaling signaling, ParticipantEventData e)
{
2026-04-30 23:27:34 +08:00
// 参与者离开时只销毁对应的PeerConnection不触发onDeletedConnection事件
// 因为onParticipantLeft已经会通知Handler进行资源清理避免重复通知
2026-04-29 15:13:24 +08:00
if (_mapConnectionIdAndPeer.ContainsKey(e.participantId))
{
2026-04-30 23:27:34 +08:00
DeletePeerConnection(e.participantId);
2026-04-29 15:13:24 +08:00
}
onParticipantLeft?.Invoke(e.connectionId, e.participantId);
}
void OnCallRequestHandler(ISignaling signaling, CallRequestData e)
{
onCallRequest?.Invoke(e.connectionId, e.data);
}
void OnMessageHandler(ISignaling signaling, OnMessageData e)
{
onMessage?.Invoke(e.connectionId, e.participantId, e.message);
}
2026-04-28 16:48:04 +08:00
}
}