Skip to content

Instantly share code, notes, and snippets.

@gtk2k
Created August 17, 2023 03:49
Show Gist options
  • Save gtk2k/255841c97090778aba9c5c945c57b8a6 to your computer and use it in GitHub Desktop.
Save gtk2k/255841c97090778aba9c5c945c57b8a6 to your computer and use it in GitHub Desktop.
Uv4l signaling class (operation is not confirmed)
using Newtonsoft.Json;
using System;
using System.Threading;
using Unity.WebRTC;
using UnityEngine;
using WebSocketSharp;
public class Uv4lStreamingSignalingClient
{
public event Action OnOpen;
public event Action<RTCConfiguration> OnConfig;
public event Action<int> OnPlayerCount;
public event Action<RTCSessionDescription> OnOffer;
public event Action<RTCIceCandidate> OnIceCandidate;
public event Action<ushort, string> OnClose;
public event Action<Exception> OnError;
private SynchronizationContext ctx;
private WebSocket ws;
private JsonSerializerSettings jsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
[Serializable]
private class Uv4lMessage
{
public string what;
public string options;
public string data;
}
[Serializable]
private class Uv4lOptions
{
public bool force_hw_vcodec;
public int vformat;
public bool trickle_ice;
}
[Serializable]
private class Uv4lDesc
{
public string type;
public string sdp;
}
[Serializable]
private class Uv4lIceCandidate
{
public string candidate;
public int sdpMLineIndex;
}
public Uv4lStreamingSignalingClient(string url)
{
ctx = SynchronizationContext.Current;
ws = new WebSocket(url);
ws.OnOpen += Ws_OnOpen;
ws.OnMessage += Ws_OnMessage;
ws.OnClose += Ws_OnClose;
ws.OnError += Ws_OnError;
}
public void Call(bool useHardwareEncode, int frameRate, bool useTricleIce = true)
{
var options = new Uv4lOptions
{
force_hw_vcodec = useHardwareEncode,
vformat = frameRate,
trickle_ice = useTricleIce
};
var data = JsonConvert.SerializeObject(options, jsonSettings);
Send("call", data);
}
public void SendAnswer(RTCSessionDescription answer)
{
var desc = new Uv4lDesc
{
type = "answer",
sdp = answer.sdp
};
var data = JsonConvert.SerializeObject(desc, jsonSettings);
}
public void SendIceCandidate(RTCIceCandidate cand)
{
var msg = new Uv4lIceCandidate
{
candidate = cand.Candidate,
sdpMLineIndex = cand.SdpMLineIndex.Value
};
var data = JsonConvert.SerializeObject(msg, jsonSettings);
Send("iceCandidate", data);
}
private void Send(string type, string data, string options = null)
{
var msg = new Uv4lMessage
{
what = type,
data = data,
options = options
};
var sendData = JsonConvert.SerializeObject(msg, jsonSettings);
ws.Send(sendData);
}
public void Connect()
{
ws.Connect();
}
public void Close()
{
if (ws != null)
{
if (ws.ReadyState == WebSocketState.Open)
{
ws.Close();
}
ws = null;
}
}
private void Ws_OnOpen(object sender, EventArgs e)
{
ctx.Post(_ =>
{
OnOpen?.Invoke();
}, null);
}
private void Ws_OnMessage(object sender, MessageEventArgs e)
{
ctx.Post(_ =>
{
Debug.Log($"Receive <== {e.Data}");
var msg = JsonConvert.DeserializeObject<Uv4lMessage>(e.Data);
switch (msg.what)
{
case "offer":
{
var data = JsonConvert.DeserializeObject<Uv4lDesc>(msg.data);
var offer = new RTCSessionDescription
{
type = RTCSdpType.Offer,
sdp = data.sdp
};
OnOffer?.Invoke(offer);
break;
}
case "iceCandidate":
{
var data = JsonConvert.DeserializeObject<Uv4lIceCandidate>(msg.data);
var iceCandidate = new RTCIceCandidate(new RTCIceCandidateInit
{
candidate = data.candidate,
sdpMLineIndex = data.sdpMLineIndex
});
OnIceCandidate?.Invoke(iceCandidate);
break;
}
case "iceCandidates":
{
var data = JsonConvert.DeserializeObject<Uv4lIceCandidate[]>(msg.data);
for (var i = 0; i < data.Length; i++)
{
var iceCandidate = new RTCIceCandidate(new RTCIceCandidateInit
{
candidate = data[i].candidate,
sdpMLineIndex = data[i].sdpMLineIndex
});
OnIceCandidate?.Invoke(iceCandidate);
}
break;
}
}
}, null);
}
private void Ws_OnClose(object sender, CloseEventArgs e)
{
ctx.Post(_ =>
{
Debug.Log($"Ws_OnClose > code: {e.Code}, reason: {e.Reason}");
}, null);
}
private void Ws_OnError(object sender, ErrorEventArgs e)
{
ctx.Post(_ =>
{
Debug.LogError(e.Message);
}, null);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment