【m】插件上传
This commit is contained in:
413
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/HttpSignaling.cs
vendored
Normal file
413
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/HttpSignaling.cs
vendored
Normal file
@@ -0,0 +1,413 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using Unity.WebRTC;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.RenderStreaming.Signaling
|
||||
{
|
||||
public class HttpSignaling : ISignaling
|
||||
{
|
||||
private static HashSet<HttpSignaling> instances = new HashSet<HttpSignaling>();
|
||||
|
||||
private readonly string m_url;
|
||||
private readonly int m_timeout;
|
||||
private readonly SynchronizationContext m_mainThreadContext;
|
||||
private bool m_running;
|
||||
private Thread m_signalingThread;
|
||||
|
||||
private string m_sessionId;
|
||||
private long m_lastTimeGetAllRequest;
|
||||
public string participantId;
|
||||
public string Url { get { return m_url; } }
|
||||
|
||||
public HttpSignaling(SignalingSettings signalingSettings, SynchronizationContext mainThreadContext)
|
||||
{
|
||||
if (signalingSettings == null)
|
||||
throw new ArgumentNullException(nameof(signalingSettings));
|
||||
if (!(signalingSettings is HttpSignalingSettings settings))
|
||||
throw new ArgumentException("signalingSettings is not HttpSignalingSettings");
|
||||
m_url = settings.url;
|
||||
m_timeout = settings.interval;
|
||||
m_mainThreadContext = mainThreadContext;
|
||||
|
||||
if (m_url.StartsWith("https"))
|
||||
{
|
||||
ServicePointManager.ServerCertificateValidationCallback =
|
||||
(sender, certificate, chain, errors) => true;
|
||||
}
|
||||
|
||||
if (instances.Any(x => x.Url == m_url))
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Warning, $"Other {nameof(HttpSignaling)} exists with same URL:{m_url}. Signaling process may be in conflict.");
|
||||
}
|
||||
|
||||
instances.Add(this);
|
||||
}
|
||||
|
||||
~HttpSignaling()
|
||||
{
|
||||
Stop();
|
||||
instances.Remove(this);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (m_running)
|
||||
throw new InvalidOperationException("This object is already started.");
|
||||
m_running = true;
|
||||
m_signalingThread = new Thread(HTTPPolling);
|
||||
m_signalingThread.IsBackground = true;
|
||||
m_signalingThread.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
m_running = false;
|
||||
|
||||
if (m_signalingThread != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Note: Allow for twice the configured m_timeout duration when joining to account for the polling sleep
|
||||
// and the time it takes to send a disconnect to the signaling server.
|
||||
if (!m_signalingThread.Join(m_timeout * 2))
|
||||
{
|
||||
m_signalingThread.Abort();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error, "Signaling: HTTP stopping thread error : " + e);
|
||||
}
|
||||
|
||||
m_signalingThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public event OnStartHandler OnStart;
|
||||
public event OnConnectHandler OnCreateConnection;
|
||||
public event OnDisconnectHandler OnDestroyConnection;
|
||||
public event OnOfferHandler OnOffer;
|
||||
public event OnAnswerHandler OnAnswer;
|
||||
public event OnIceCandidateHandler OnIceCandidate;
|
||||
|
||||
public void SendOffer(string connectionId, RTCSessionDescription offer)
|
||||
{
|
||||
DescData data = new DescData();
|
||||
data.connectionId = connectionId;
|
||||
data.sdp = offer.sdp;
|
||||
|
||||
ThreadPool.QueueUserWorkItem(_ => { HTTPPost("signaling/offer", data); });
|
||||
}
|
||||
|
||||
public void SendAnswer(string connectionId, RTCSessionDescription answer)
|
||||
{
|
||||
DescData data = new DescData();
|
||||
data.connectionId = connectionId;
|
||||
data.sdp = answer.sdp;
|
||||
|
||||
ThreadPool.QueueUserWorkItem(_ => { HTTPPost("signaling/answer", data); });
|
||||
}
|
||||
|
||||
public void SendCandidate(string connectionId, RTCIceCandidate candidate)
|
||||
{
|
||||
CandidateData data = new CandidateData();
|
||||
data.connectionId = connectionId;
|
||||
data.candidate = candidate.Candidate;
|
||||
data.sdpMLineIndex = candidate.SdpMLineIndex.GetValueOrDefault(0);
|
||||
data.sdpMid = candidate.SdpMid;
|
||||
|
||||
ThreadPool.QueueUserWorkItem(_ => { HTTPPost("signaling/candidate", data); });
|
||||
}
|
||||
|
||||
public void OpenConnection(string connectionId)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => { HTTPConnect(connectionId); });
|
||||
}
|
||||
|
||||
public void CloseConnection(string connectionId)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => { HTTPDisonnect(connectionId); });
|
||||
}
|
||||
|
||||
private void HTTPPolling()
|
||||
{
|
||||
// ignore messages arrived before 30 secs ago
|
||||
m_lastTimeGetAllRequest = DateTime.UtcNow.Millisecond - 30000;
|
||||
|
||||
while (m_running && string.IsNullOrEmpty(m_sessionId))
|
||||
{
|
||||
HTTPCreate();
|
||||
try
|
||||
{
|
||||
Thread.Sleep(m_timeout);
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
// Thread.Abort() called from main thread. Ignore
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (m_running)
|
||||
{
|
||||
try
|
||||
{
|
||||
HTTPGetAll();
|
||||
Thread.Sleep(m_timeout);
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
// Thread.Abort() called from main thread. Ignore
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error, "Signaling: HTTP polling error : " + e);
|
||||
}
|
||||
}
|
||||
HTTPDelete();
|
||||
|
||||
RenderStreaming.Logger.Log("Signaling: HTTP polling thread ended");
|
||||
}
|
||||
|
||||
private static HttpWebResponse HTTPGetResponse(HttpWebRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
return response;
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error, $"Signaling: {response.ResponseUri} HTTP request failed ({response.StatusCode})");
|
||||
response.Close();
|
||||
}
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
// Thread.Abort() called from main thread. Ignore
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error, $"Signaling: HTTP request error. url:{request.RequestUri} exception:{e}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static T HTTPParseJsonResponse<T>(HttpWebResponse response) where T : class
|
||||
{
|
||||
if (response == null) return null;
|
||||
|
||||
T obj = null;
|
||||
|
||||
using (Stream dataStream = response.GetResponseStream())
|
||||
{
|
||||
StreamReader reader = new StreamReader(dataStream);
|
||||
string responseFromServer = reader.ReadToEnd();
|
||||
obj = JsonUtility.FromJson<T>(responseFromServer);
|
||||
}
|
||||
|
||||
response.Close();
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static string HTTPParseTextResponse(HttpWebResponse response)
|
||||
{
|
||||
if (response == null) return null;
|
||||
|
||||
string str = null;
|
||||
|
||||
using (Stream dataStream = response.GetResponseStream())
|
||||
{
|
||||
StreamReader reader = new StreamReader(dataStream);
|
||||
str = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
response.Close();
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
private bool HTTPCreate()
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"{m_url}/signaling");
|
||||
request.Method = "PUT";
|
||||
request.ContentType = "application/json";
|
||||
request.KeepAlive = false;
|
||||
request.ContentLength = 0;
|
||||
|
||||
RenderStreaming.Logger.Log($"Signaling: Connecting HTTP {m_url}");
|
||||
|
||||
OpenSessionData resp = HTTPParseJsonResponse<OpenSessionData>(HTTPGetResponse(request));
|
||||
|
||||
if (resp != null)
|
||||
{
|
||||
m_sessionId = resp.sessionId;
|
||||
RenderStreaming.Logger.Log("Signaling: HTTP connected, sessionId : " + m_sessionId);
|
||||
|
||||
m_mainThreadContext.Post(d => OnStart?.Invoke(this), null);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HTTPDelete()
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"{m_url}/signaling");
|
||||
request.Method = "DELETE";
|
||||
request.ContentType = "application/json";
|
||||
request.KeepAlive = false;
|
||||
request.Headers.Add("Session-Id", m_sessionId);
|
||||
|
||||
RenderStreaming.Logger.Log($"Signaling: Removing HTTP connection from {m_url}");
|
||||
|
||||
return (HTTPParseTextResponse(HTTPGetResponse(request)) != null);
|
||||
}
|
||||
|
||||
private bool HTTPPost(string path, object data)
|
||||
{
|
||||
string str = JsonUtility.ToJson(data);
|
||||
byte[] bytes = new System.Text.UTF8Encoding().GetBytes(str);
|
||||
|
||||
RenderStreaming.Logger.Log("Signaling: Posting HTTP data: " + str);
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"{m_url}/{path}");
|
||||
request.Method = "POST";
|
||||
request.ContentType = "application/json";
|
||||
request.Headers.Add("Session-Id", m_sessionId);
|
||||
request.KeepAlive = false;
|
||||
|
||||
using (Stream dataStream = request.GetRequestStream())
|
||||
{
|
||||
dataStream.Write(bytes, 0, bytes.Length);
|
||||
dataStream.Close();
|
||||
}
|
||||
|
||||
return (HTTPParseTextResponse(HTTPGetResponse(request)) != null);
|
||||
}
|
||||
|
||||
private bool HTTPConnect(string connectionId)
|
||||
{
|
||||
HttpWebRequest request =
|
||||
(HttpWebRequest)WebRequest.Create($"{m_url}/signaling/connection");
|
||||
request.Method = "PUT";
|
||||
request.ContentType = "application/json";
|
||||
request.Headers.Add("Session-Id", m_sessionId);
|
||||
request.KeepAlive = false;
|
||||
|
||||
using (Stream dataStream = request.GetRequestStream())
|
||||
{
|
||||
byte[] bytes = new System.Text.UTF8Encoding().GetBytes($"{{\"connectionId\":\"{connectionId}\"}}");
|
||||
dataStream.Write(bytes, 0, bytes.Length);
|
||||
dataStream.Close();
|
||||
}
|
||||
|
||||
HttpWebResponse response = HTTPGetResponse(request);
|
||||
CreateConnectionResData data = HTTPParseJsonResponse<CreateConnectionResData>(response);
|
||||
|
||||
if (data == null) return false;
|
||||
|
||||
RenderStreaming.Logger.Log($"Signaling: HTTP create connection, connectionId: {connectionId}, polite:{data.polite}");
|
||||
m_mainThreadContext.Post(d => OnCreateConnection?.Invoke(this, data.connectionId, data.polite), null);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HTTPDisonnect(string connectionId)
|
||||
{
|
||||
HttpWebRequest request =
|
||||
(HttpWebRequest)WebRequest.Create($"{m_url}/signaling/connection");
|
||||
request.Method = "Delete";
|
||||
request.ContentType = "application/json";
|
||||
request.Headers.Add("Session-Id", m_sessionId);
|
||||
request.KeepAlive = false;
|
||||
|
||||
using (Stream dataStream = request.GetRequestStream())
|
||||
{
|
||||
byte[] bytes = new System.Text.UTF8Encoding().GetBytes($"{{\"connectionId\":\"{connectionId}\"}}");
|
||||
dataStream.Write(bytes, 0, bytes.Length);
|
||||
dataStream.Close();
|
||||
}
|
||||
|
||||
var data = HTTPParseTextResponse(HTTPGetResponse(request));
|
||||
|
||||
if (data == null) return false;
|
||||
|
||||
RenderStreaming.Logger.Log("Signaling: HTTP delete connection, connectionId : " + connectionId);
|
||||
m_mainThreadContext.Post(d => OnDestroyConnection?.Invoke(this, connectionId), null);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HTTPGetAll()
|
||||
{
|
||||
HttpWebRequest request =
|
||||
(HttpWebRequest)WebRequest.Create($"{m_url}/signaling?fromtime={m_lastTimeGetAllRequest}");
|
||||
request.Method = "GET";
|
||||
request.ContentType = "application/json";
|
||||
request.Headers.Add("Session-Id", m_sessionId);
|
||||
request.KeepAlive = false;
|
||||
|
||||
HttpWebResponse response = HTTPGetResponse(request);
|
||||
AllResData data = HTTPParseJsonResponse<AllResData>(response);
|
||||
|
||||
if (data == null) return false;
|
||||
|
||||
m_lastTimeGetAllRequest =
|
||||
long.TryParse(data.datetime, out var result) ? result : DateTime.Now.ToJsMilliseconds();
|
||||
|
||||
foreach (var msg in data.messages)
|
||||
{
|
||||
if (string.IsNullOrEmpty(msg.type))
|
||||
continue;
|
||||
|
||||
if (msg.type == "disconnect")
|
||||
{
|
||||
m_mainThreadContext.Post(d => OnDestroyConnection?.Invoke(this, msg.connectionId), null);
|
||||
}
|
||||
else if (msg.type == "offer")
|
||||
{
|
||||
DescData offer = new DescData();
|
||||
offer.connectionId = msg.connectionId;
|
||||
offer.sdp = msg.sdp;
|
||||
offer.polite = msg.polite;
|
||||
m_mainThreadContext.Post(d => OnOffer?.Invoke(this, offer), null);
|
||||
}
|
||||
else if (msg.type == "answer")
|
||||
{
|
||||
DescData answer = new DescData
|
||||
{
|
||||
connectionId = msg.connectionId,
|
||||
sdp = msg.sdp
|
||||
};
|
||||
m_mainThreadContext.Post(d => OnAnswer?.Invoke(this, answer), null);
|
||||
}
|
||||
else if (msg.type == "candidate")
|
||||
{
|
||||
CandidateData candidate = new CandidateData
|
||||
{
|
||||
connectionId = msg.connectionId,
|
||||
candidate = msg.candidate,
|
||||
sdpMLineIndex = msg.sdpMLineIndex,
|
||||
sdpMid = msg.sdpMid
|
||||
};
|
||||
m_mainThreadContext.Post(d => OnIceCandidate?.Invoke(this, candidate), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4673647ba304609a37e2762bb1fae36
|
||||
timeCreated: 1586218423
|
||||
130
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/HttpSignalingSettings.cs
vendored
Normal file
130
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/HttpSignalingSettings.cs
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.RenderStreaming.Signaling;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.RenderStreaming
|
||||
{
|
||||
[Serializable, SignalingType("http")]
|
||||
public class HttpSignalingSettings : SignalingSettings
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override Type signalingClass => typeof(HttpSignaling);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override IReadOnlyCollection<IceServer> iceServers => m_iceServers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string url => m_url;
|
||||
|
||||
/// <summary>
|
||||
/// Polling interval
|
||||
/// </summary>
|
||||
public int interval => m_interval;
|
||||
|
||||
[SerializeField, Tooltip("Set the polling frequency (in milliseconds) to the signaling server.")]
|
||||
private int m_interval;
|
||||
[SerializeField, Tooltip("Set the signaling server URL. you should specify a URL starting with \"http\" or \"https\".")]
|
||||
protected string m_url;
|
||||
[SerializeField, Tooltip("Set a list of STUN/TURN servers.")]
|
||||
protected IceServer[] m_iceServers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="iceServers"></param>
|
||||
/// <param name="interval"></param>
|
||||
public HttpSignalingSettings(string url, IceServer[] iceServers = null, int interval = 5000)
|
||||
{
|
||||
if (url == null)
|
||||
throw new ArgumentNullException("url");
|
||||
if (!Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
|
||||
throw new ArgumentException("url is not well formed Uri");
|
||||
|
||||
m_url = url;
|
||||
m_iceServers = iceServers == null ? Array.Empty<IceServer>() : iceServers.Select(server => server.Clone()).ToArray();
|
||||
m_interval = interval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public HttpSignalingSettings()
|
||||
{
|
||||
m_url = "http://127.0.0.1";
|
||||
m_iceServers = new[]
|
||||
{
|
||||
new IceServer (urls: new[] {"stun:stun.l.google.com:19302"})
|
||||
};
|
||||
m_interval = 5000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="argumetns"></param>
|
||||
/// <returns></returns>
|
||||
public override bool ParseArguments(string[] arguments)
|
||||
{
|
||||
if (arguments == null)
|
||||
throw new ArgumentNullException("arguments");
|
||||
if (arguments.Length == 0)
|
||||
throw new ArgumentException("arguments is empty");
|
||||
if (!CommandLineParser.TryParse(arguments))
|
||||
return false;
|
||||
|
||||
if (CommandLineParser.ImportJson.Value != null)
|
||||
{
|
||||
CommandLineInfo info = CommandLineParser.ImportJson.Value.Value;
|
||||
|
||||
if (info.signalingUrl != null)
|
||||
m_url = info.signalingUrl;
|
||||
if (info.iceServers != null && info.iceServers.Length != 0)
|
||||
m_iceServers = info.iceServers.Select(v => new IceServer(v)).ToArray();
|
||||
}
|
||||
if (CommandLineParser.SignalingUrl.Value != null)
|
||||
m_url = CommandLineParser.SignalingUrl.Value;
|
||||
|
||||
var username = CommandLineParser.IceServerUsername != null
|
||||
? CommandLineParser.IceServerUsername.Value
|
||||
: null;
|
||||
var credential = CommandLineParser.IceServerCredential != null
|
||||
? CommandLineParser.IceServerCredential.Value
|
||||
: null;
|
||||
var credentialType = CommandLineParser.IceServerCredentialType != null
|
||||
? CommandLineParser.IceServerCredentialType.Value
|
||||
: null;
|
||||
var urls = CommandLineParser.IceServerUrls != null
|
||||
? CommandLineParser.IceServerUrls.Value
|
||||
: null;
|
||||
|
||||
if (m_iceServers.Length > 0)
|
||||
m_iceServers[0] = m_iceServers[0].Clone(
|
||||
username: username,
|
||||
credential: credential,
|
||||
credentialType: credentialType,
|
||||
urls: urls);
|
||||
else
|
||||
m_iceServers = new IceServer[]
|
||||
{
|
||||
new IceServer(
|
||||
username: username,
|
||||
credential: credential,
|
||||
credentialType: credentialType.GetValueOrDefault(),
|
||||
urls: urls)
|
||||
};
|
||||
|
||||
if (CommandLineParser.PollingInterval.Value != null)
|
||||
m_interval = CommandLineParser.PollingInterval.Value.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6fb58902f9c27e4688c3a6fe70d9560
|
||||
timeCreated: 1674112040
|
||||
32
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/ISignaling.cs
vendored
Normal file
32
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/ISignaling.cs
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
using Unity.WebRTC;
|
||||
|
||||
namespace Unity.RenderStreaming.Signaling
|
||||
{
|
||||
public delegate void OnStartHandler(ISignaling signaling);
|
||||
public delegate void OnConnectHandler(ISignaling signaling, string connectionId, bool polite);
|
||||
public delegate void OnDisconnectHandler(ISignaling signaling, string connectionId);
|
||||
public delegate void OnOfferHandler(ISignaling signaling, DescData e);
|
||||
public delegate void OnAnswerHandler(ISignaling signaling, DescData e);
|
||||
public delegate void OnIceCandidateHandler(ISignaling signaling, CandidateData e);
|
||||
|
||||
public interface ISignaling
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
event OnStartHandler OnStart;
|
||||
event OnConnectHandler OnCreateConnection;
|
||||
event OnDisconnectHandler OnDestroyConnection;
|
||||
event OnOfferHandler OnOffer;
|
||||
event OnAnswerHandler OnAnswer;
|
||||
event OnIceCandidateHandler OnIceCandidate;
|
||||
|
||||
string Url { get; }
|
||||
|
||||
void OpenConnection(string connectionId);
|
||||
void CloseConnection(string connectionId);
|
||||
void SendOffer(string connectionId, RTCSessionDescription offer);
|
||||
void SendAnswer(string connectionId, RTCSessionDescription answer);
|
||||
void SendCandidate(string connectionId, RTCIceCandidate candidate);
|
||||
}
|
||||
}
|
||||
3
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/ISignaling.cs.meta
vendored
Normal file
3
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/ISignaling.cs.meta
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac843bc417af42759d8bd83db0c33d76
|
||||
timeCreated: 1586218157
|
||||
110
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/SignalingMessage.cs
vendored
Normal file
110
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/SignalingMessage.cs
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.RenderStreaming
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
[Serializable]
|
||||
public class DescData
|
||||
{
|
||||
public string connectionId;
|
||||
public string sdp;
|
||||
public bool polite;
|
||||
public DateTime dateTime;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class CandidateData
|
||||
{
|
||||
public string connectionId;
|
||||
public string participantId;
|
||||
public string candidate;
|
||||
public string sdpMid;
|
||||
public int sdpMLineIndex;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class SignalingMessage
|
||||
{
|
||||
public string status;
|
||||
public string message;
|
||||
public string sessionId;
|
||||
public string connectionId;
|
||||
public string participantId;
|
||||
public bool polite;
|
||||
public string sdp;
|
||||
public string type;
|
||||
public string candidate;
|
||||
public string sdpMid;
|
||||
public int sdpMLineIndex;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class RoutedMessage<T>
|
||||
{
|
||||
public string from;
|
||||
public string to;
|
||||
public string type;
|
||||
public string participantId;
|
||||
public T data;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class OpenSessionData
|
||||
{
|
||||
public string sessionId;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class CreateConnectionResData
|
||||
{
|
||||
public string connectionId;
|
||||
public bool polite;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class DestroyConnectionResData
|
||||
{
|
||||
public string connectionId;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class ConnectionResDataList
|
||||
{
|
||||
public DescData[] connections;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class OfferResDataList
|
||||
{
|
||||
public DescData[] offers;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class AnswerResDataList
|
||||
{
|
||||
public DescData[] answers;
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
class CandidateContainerResDataList
|
||||
{
|
||||
public CandidateContainerResData[] candidates;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class CandidateContainerResData
|
||||
{
|
||||
public string connectionId;
|
||||
public CandidateData[] candidates;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class AllResData
|
||||
{
|
||||
public SignalingMessage[] messages;
|
||||
public string datetime;
|
||||
}
|
||||
|
||||
#pragma warning restore 0649
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ee3c31b4dd467b47a7050eff711f2c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
187
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/SignalingSettings.cs
vendored
Normal file
187
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/SignalingSettings.cs
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.WebRTC;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.RenderStreaming
|
||||
{
|
||||
/// <summary>
|
||||
/// The attribute is used for commandline argument of "-signalingType".
|
||||
/// </summary>
|
||||
public sealed class SignalingTypeAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string typename => m_typename;
|
||||
|
||||
private string m_typename;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="typename"></param>
|
||||
public SignalingTypeAttribute(string name)
|
||||
{
|
||||
m_typename = name;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SignalingSettingsAttribute : PropertyAttribute { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum IceCredentialType
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
Password = 0,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
OAuth = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class IceServer
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<string> urls => m_urls;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string username => m_username;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public IceCredentialType credentialType => m_credentialType;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string credential => m_credential;
|
||||
|
||||
[SerializeField]
|
||||
private string[] m_urls;
|
||||
[SerializeField]
|
||||
private string m_username;
|
||||
[SerializeField]
|
||||
private IceCredentialType m_credentialType;
|
||||
[SerializeField]
|
||||
private string m_credential;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="server"></param>
|
||||
public static explicit operator RTCIceServer(IceServer server)
|
||||
{
|
||||
var iceServer = new RTCIceServer
|
||||
{
|
||||
urls = server.urls.ToArray(),
|
||||
username = server.username,
|
||||
credential = server.credential,
|
||||
credentialType = (RTCIceCredentialType)server.credentialType
|
||||
};
|
||||
return iceServer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IceServer Clone()
|
||||
{
|
||||
return new IceServer(this.urls.ToArray(), this.username, this.credentialType, this.credential);
|
||||
}
|
||||
|
||||
public IceServer Clone(string[] urls = null, string username = null, IceCredentialType? credentialType = null, string credential = null)
|
||||
{
|
||||
var server = new IceServer(this.urls.ToArray(), this.username, this.credentialType, this.credential);
|
||||
if (urls != null)
|
||||
server.m_urls = urls;
|
||||
if (username != null)
|
||||
server.m_username = username;
|
||||
if (credentialType != null)
|
||||
server.m_credentialType = credentialType.Value;
|
||||
if (credential != null)
|
||||
server.m_credential = credential;
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="urls"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="credentialType"></param>
|
||||
/// <param name="credential"></param>
|
||||
public IceServer(string[] urls = null, string username = null, IceCredentialType credentialType = IceCredentialType.Password, string credential = null)
|
||||
{
|
||||
m_urls = urls?.ToArray();
|
||||
m_username = username;
|
||||
m_credential = credential;
|
||||
m_credentialType = credentialType;
|
||||
}
|
||||
|
||||
internal IceServer(RTCIceServer server)
|
||||
{
|
||||
m_urls = server.urls.ToArray();
|
||||
m_username = server.username;
|
||||
m_credential = server.credential;
|
||||
m_credentialType = (IceCredentialType)server.credentialType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class SignalingSettings
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract IReadOnlyCollection<IceServer> iceServers { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract Type signalingClass { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="arguments"></param>
|
||||
/// <returns></returns>
|
||||
public abstract bool ParseArguments(string[] arguments);
|
||||
}
|
||||
|
||||
internal static class RuntimeTypeCache<T> where T : class
|
||||
{
|
||||
private static Type[] s_types;
|
||||
|
||||
public static Type[] GetTypesDerivedFrom()
|
||||
{
|
||||
if (s_types != null)
|
||||
return s_types;
|
||||
|
||||
s_types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(domainAssembly => domainAssembly.GetTypes())
|
||||
.Where(type => typeof(T).IsAssignableFrom(type) && !type.IsAbstract).ToArray();
|
||||
return s_types;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff254cc8ca9e409bbfe92d5c717e71ab
|
||||
timeCreated: 1674112040
|
||||
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.RenderStreaming
|
||||
{
|
||||
internal class SignalingSettingsObject : ScriptableObject
|
||||
{
|
||||
[SerializeReference]
|
||||
public SignalingSettings settings;
|
||||
|
||||
public static SignalingSettingsObject Create()
|
||||
{
|
||||
var instance = CreateInstance<SignalingSettingsObject>();
|
||||
instance.settings = new WebSocketSignalingSettings();
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22c294fb286b37446a86664f4fb41023
|
||||
timeCreated: 1674112040
|
||||
304
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/WebSocketSignaling.cs
vendored
Normal file
304
Packages/com.unity.renderstreaming@3.1.0-exp.9/Runtime/Scripts/Signaling/WebSocketSignaling.cs
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Authentication;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Unity.WebRTC;
|
||||
using UnityEngine;
|
||||
using WebSocketSharp;
|
||||
|
||||
namespace Unity.RenderStreaming.Signaling
|
||||
{
|
||||
public class WebSocketSignaling : ISignaling
|
||||
{
|
||||
private static HashSet<WebSocketSignaling> instances = new HashSet<WebSocketSignaling>();
|
||||
|
||||
private readonly string m_url;
|
||||
private readonly float m_timeout;
|
||||
private readonly SynchronizationContext m_mainThreadContext;
|
||||
private bool m_running;
|
||||
private Thread m_signalingThread;
|
||||
private readonly AutoResetEvent m_wsCloseEvent;
|
||||
private WebSocket m_webSocket;
|
||||
public string participantId;
|
||||
public string Url { get { return m_url; } }
|
||||
|
||||
public WebSocketSignaling(SignalingSettings signalingSettings, SynchronizationContext mainThreadContext)
|
||||
{
|
||||
if (signalingSettings == null)
|
||||
throw new ArgumentNullException(nameof(signalingSettings));
|
||||
if (!(signalingSettings is WebSocketSignalingSettings settings))
|
||||
throw new ArgumentException("signalingSettings is not WebSocketSignalingSettings");
|
||||
m_url = settings.url;
|
||||
m_timeout = 5.0f;
|
||||
m_mainThreadContext = mainThreadContext;
|
||||
m_wsCloseEvent = new AutoResetEvent(false);
|
||||
|
||||
if (instances.Any(x => x.Url == m_url))
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Warning, $"Other {nameof(WebSocketSignaling)} exists with same URL:{m_url}. Signaling process may be in conflict.");
|
||||
}
|
||||
|
||||
instances.Add(this);
|
||||
}
|
||||
|
||||
~WebSocketSignaling()
|
||||
{
|
||||
if (m_running)
|
||||
Stop();
|
||||
|
||||
instances.Remove(this);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (m_running)
|
||||
throw new InvalidOperationException("This object is already started.");
|
||||
m_running = true;
|
||||
m_signalingThread = new Thread(WSManage);
|
||||
m_signalingThread.Start();
|
||||
}
|
||||
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (m_running)
|
||||
{
|
||||
m_running = false;
|
||||
m_webSocket?.Close();
|
||||
|
||||
if (m_signalingThread.ThreadState == ThreadState.WaitSleepJoin)
|
||||
{
|
||||
m_signalingThread.Abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_signalingThread.Join(1000);
|
||||
}
|
||||
m_signalingThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public event OnStartHandler OnStart;
|
||||
public event OnConnectHandler OnCreateConnection;
|
||||
public event OnDisconnectHandler OnDestroyConnection;
|
||||
public event OnOfferHandler OnOffer;
|
||||
#pragma warning disable 0067
|
||||
// this event is never used in this class
|
||||
public event OnAnswerHandler OnAnswer;
|
||||
#pragma warning restore 0067
|
||||
public event OnIceCandidateHandler OnIceCandidate;
|
||||
|
||||
public void SendOffer(string connectionId, RTCSessionDescription offer)
|
||||
{
|
||||
DescData data = new DescData();
|
||||
data.connectionId = connectionId;
|
||||
data.sdp = offer.sdp;
|
||||
data.dateTime = DateTime.Now;
|
||||
|
||||
RoutedMessage<DescData> routedMessage = new RoutedMessage<DescData>();
|
||||
routedMessage.from = connectionId;
|
||||
routedMessage.data = data;
|
||||
routedMessage.type = "offer";
|
||||
routedMessage.participantId =participantId;
|
||||
WSSend(routedMessage);
|
||||
}
|
||||
|
||||
public void SendAnswer(string connectionId, RTCSessionDescription answer)
|
||||
{
|
||||
DescData data = new DescData();
|
||||
data.connectionId = connectionId;
|
||||
data.sdp = answer.sdp;
|
||||
|
||||
RoutedMessage<DescData> routedMessage = new RoutedMessage<DescData>();
|
||||
routedMessage.from = connectionId;
|
||||
routedMessage.data = data;
|
||||
routedMessage.type = "answer";
|
||||
routedMessage.participantId =participantId;
|
||||
WSSend(routedMessage);
|
||||
}
|
||||
|
||||
public void SendCandidate(string connectionId, RTCIceCandidate candidate)
|
||||
{
|
||||
CandidateData data = new CandidateData();
|
||||
data.connectionId = connectionId;
|
||||
data.candidate = candidate.Candidate;
|
||||
data.sdpMLineIndex = candidate.SdpMLineIndex.GetValueOrDefault(0);
|
||||
data.sdpMid = candidate.SdpMid;
|
||||
|
||||
RoutedMessage<CandidateData> routedMessage = new RoutedMessage<CandidateData>();
|
||||
routedMessage.from = connectionId;
|
||||
routedMessage.data = data;
|
||||
routedMessage.type = "candidate";
|
||||
|
||||
WSSend(routedMessage);
|
||||
}
|
||||
|
||||
public void OpenConnection(string connectionId)
|
||||
{
|
||||
this.WSSend($"{{\"type\":\"connect\", \"connectionId\":\"{connectionId}\"}}");
|
||||
}
|
||||
|
||||
public void CloseConnection(string connectionId)
|
||||
{
|
||||
this.WSSend($"{{\"type\":\"disconnect\", \"connectionId\":\"{connectionId}\"}}");
|
||||
}
|
||||
|
||||
private void WSManage()
|
||||
{
|
||||
while (m_running)
|
||||
{
|
||||
WSCreate();
|
||||
|
||||
try
|
||||
{
|
||||
m_wsCloseEvent.WaitOne();
|
||||
|
||||
Thread.Sleep((int)(m_timeout * 1000));
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
// Thread.Abort() called from main thread. Ignore
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RenderStreaming.Logger.Log("Signaling: WS managing thread ended");
|
||||
}
|
||||
|
||||
private void WSCreate()
|
||||
{
|
||||
m_webSocket = new WebSocket(m_url);
|
||||
if (m_url.StartsWith("wss"))
|
||||
{
|
||||
m_webSocket.SslConfiguration.EnabledSslProtocols =
|
||||
SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
|
||||
}
|
||||
|
||||
m_webSocket.OnOpen += WSConnected;
|
||||
m_webSocket.OnMessage += WSProcessMessage;
|
||||
m_webSocket.OnError += WSError;
|
||||
m_webSocket.OnClose += WSClosed;
|
||||
|
||||
Monitor.Enter(m_webSocket);
|
||||
|
||||
RenderStreaming.Logger.Log($"Signaling: Connecting WS {m_url}");
|
||||
m_webSocket.ConnectAsync();
|
||||
}
|
||||
|
||||
private void WSProcessMessage(object sender, MessageEventArgs e)
|
||||
{
|
||||
var content = Encoding.UTF8.GetString(e.RawData);
|
||||
RenderStreaming.Logger.Log($"Signaling: Receiving message: {content}");
|
||||
|
||||
try
|
||||
{
|
||||
var routedMessage = JsonUtility.FromJson<RoutedMessage<SignalingMessage>>(content);
|
||||
|
||||
SignalingMessage msg;
|
||||
if (!string.IsNullOrEmpty(routedMessage.type))
|
||||
{
|
||||
msg = routedMessage.data;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = JsonUtility.FromJson<SignalingMessage>(content);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(routedMessage.type))
|
||||
{
|
||||
if (routedMessage.type == "connect")
|
||||
{
|
||||
msg = JsonUtility.FromJson<SignalingMessage>(content);
|
||||
m_mainThreadContext.Post(d => OnCreateConnection?.Invoke(this, msg.connectionId, msg.polite), null);
|
||||
participantId=msg.participantId;
|
||||
}
|
||||
else if (routedMessage.type == "disconnect")
|
||||
{
|
||||
msg = JsonUtility.FromJson<SignalingMessage>(content);
|
||||
m_mainThreadContext.Post(d => OnDestroyConnection?.Invoke(this, msg.connectionId), null);
|
||||
}
|
||||
else if (routedMessage.type == "offer")
|
||||
{
|
||||
DescData offer = new DescData();
|
||||
offer.connectionId = routedMessage.from;
|
||||
offer.sdp = msg.sdp;
|
||||
offer.polite = msg.polite;
|
||||
m_mainThreadContext.Post(d => OnOffer?.Invoke(this, offer), null);
|
||||
}
|
||||
else if (routedMessage.type == "answer")
|
||||
{
|
||||
DescData answer = new DescData
|
||||
{
|
||||
connectionId = routedMessage.from,
|
||||
sdp = msg.sdp
|
||||
};
|
||||
m_mainThreadContext.Post(d => OnAnswer?.Invoke(this, answer), null);
|
||||
}
|
||||
else if (routedMessage.type == "candidate")
|
||||
{
|
||||
CandidateData candidate = new CandidateData
|
||||
{
|
||||
connectionId = routedMessage.@from,
|
||||
candidate = msg.candidate,
|
||||
sdpMLineIndex = msg.sdpMLineIndex,
|
||||
sdpMid = msg.sdpMid
|
||||
};
|
||||
m_mainThreadContext.Post(d => OnIceCandidate?.Invoke(this, candidate), null);
|
||||
}
|
||||
else if (routedMessage.type == "error")
|
||||
{
|
||||
msg = JsonUtility.FromJson<SignalingMessage>(content);
|
||||
RenderStreaming.Logger.Log(LogType.Error, msg.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error, "Signaling: Failed to parse message: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void WSConnected(object sender, EventArgs e)
|
||||
{
|
||||
RenderStreaming.Logger.Log("Signaling: WS connected.");
|
||||
m_mainThreadContext.Post(d => OnStart?.Invoke(this), null);
|
||||
}
|
||||
|
||||
|
||||
private void WSError(object sender, ErrorEventArgs e)
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error, $"Signaling: WS connection error: {e.Message}");
|
||||
}
|
||||
|
||||
private void WSClosed(object sender, CloseEventArgs e)
|
||||
{
|
||||
RenderStreaming.Logger.Log($"Signaling: WS connection closed, code: {e.Code}");
|
||||
|
||||
m_wsCloseEvent.Set();
|
||||
m_webSocket = null;
|
||||
}
|
||||
|
||||
private void WSSend(object data)
|
||||
{
|
||||
if (m_webSocket == null || m_webSocket.ReadyState != WebSocketState.Open)
|
||||
{
|
||||
RenderStreaming.Logger.Log(LogType.Error, "Signaling: WS is not connected. Unable to send message");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data is string s)
|
||||
{
|
||||
RenderStreaming.Logger.Log("Signaling: Sending WS data: " + s);
|
||||
m_webSocket.Send(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
string str = JsonUtility.ToJson(data);
|
||||
RenderStreaming.Logger.Log("Signaling: Sending WS data: " + str);
|
||||
m_webSocket.Send(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad8d529710094c2895227a94d10eb8a6
|
||||
timeCreated: 1586218434
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.RenderStreaming.Signaling;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.RenderStreaming
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Serializable, SignalingType("websocket")]
|
||||
public class WebSocketSignalingSettings : SignalingSettings
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override Type signalingClass => typeof(WebSocketSignaling);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override IReadOnlyCollection<IceServer> iceServers => m_iceServers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string url => m_url;
|
||||
|
||||
[SerializeField, Tooltip("Set the signaling server URL. you should specify a URL starting with \"ws\" or \"wss\".")]
|
||||
protected string m_url;
|
||||
|
||||
[SerializeField, Tooltip("Set a list of STUN/TURN servers.")]
|
||||
protected IceServer[] m_iceServers;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="iceServers"></param>
|
||||
public WebSocketSignalingSettings(string url, IceServer[] iceServers = null)
|
||||
{
|
||||
if (url == null)
|
||||
throw new ArgumentNullException("url");
|
||||
if (!Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
|
||||
throw new ArgumentException("url is not well formed Uri");
|
||||
|
||||
m_url = url;
|
||||
m_iceServers = iceServers == null ? Array.Empty<IceServer>() : iceServers.Select(server => server.Clone()).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public WebSocketSignalingSettings()
|
||||
{
|
||||
m_url = "ws://127.0.0.1";
|
||||
m_iceServers = new[]
|
||||
{
|
||||
new IceServer (urls: new[] {"stun:stun.l.google.com:19302"})
|
||||
};
|
||||
}
|
||||
|
||||
public override bool ParseArguments(string[] arguments)
|
||||
{
|
||||
if (arguments == null)
|
||||
throw new ArgumentNullException("arguments");
|
||||
if (arguments.Length == 0)
|
||||
throw new ArgumentException("arguments is empty");
|
||||
|
||||
if (!CommandLineParser.TryParse(arguments))
|
||||
return false;
|
||||
|
||||
if (CommandLineParser.ImportJson.Value != null)
|
||||
{
|
||||
CommandLineInfo info = CommandLineParser.ImportJson.Value.Value;
|
||||
|
||||
if (info.signalingUrl != null)
|
||||
m_url = info.signalingUrl;
|
||||
if (info.iceServers != null && info.iceServers.Length != 0)
|
||||
m_iceServers = info.iceServers.Select(v => new IceServer(v)).ToArray();
|
||||
}
|
||||
if (CommandLineParser.SignalingUrl.Value != null)
|
||||
m_url = CommandLineParser.SignalingUrl.Value;
|
||||
|
||||
var username = CommandLineParser.IceServerUsername != null
|
||||
? CommandLineParser.IceServerUsername.Value
|
||||
: null;
|
||||
var credential = CommandLineParser.IceServerCredential != null
|
||||
? CommandLineParser.IceServerCredential.Value
|
||||
: null;
|
||||
var credentialType = CommandLineParser.IceServerCredentialType != null
|
||||
? CommandLineParser.IceServerCredentialType.Value
|
||||
: null;
|
||||
var urls = CommandLineParser.IceServerUrls != null
|
||||
? CommandLineParser.IceServerUrls.Value
|
||||
: null;
|
||||
|
||||
if (m_iceServers.Length > 0)
|
||||
m_iceServers[0] = m_iceServers[0].Clone(
|
||||
username: username,
|
||||
credential: credential,
|
||||
credentialType: credentialType,
|
||||
urls: urls);
|
||||
else
|
||||
m_iceServers = new IceServer[]
|
||||
{
|
||||
new IceServer(
|
||||
username: username,
|
||||
credential: credential,
|
||||
credentialType: credentialType.GetValueOrDefault(),
|
||||
urls: urls)
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb4c44f4a1edb4d4a9a787ca2046cd1c
|
||||
timeCreated: 1674112040
|
||||
Reference in New Issue
Block a user