2026-03-18 20:09:32 +03:00

250 lines
7.6 KiB
C#

using System.Collections;
using System.Collections.Generic;
using Unity.WebRTC;
using Unity.WebRTC.Samples;
using UnityEngine;
using UnityEngine.UI;
class MungeSDPSample : MonoBehaviour
{
#pragma warning disable 0649
[SerializeField] private Button startButton;
[SerializeField] private Button callButton;
[SerializeField] private Button createOfferButton;
[SerializeField] private Button setOfferButton;
[SerializeField] private Button createAnswerButton;
[SerializeField] private Button setAnswerButton;
[SerializeField] private Button hangUpButton;
[SerializeField] private Camera cam;
[SerializeField] private RawImage sourceImage;
[SerializeField] private RawImage receiveImage;
[SerializeField] private InputField offerSdpInput;
[SerializeField] private InputField answerSdpInput;
[SerializeField] private Transform rotateObject;
#pragma warning restore 0649
private RTCConfiguration configuration = new RTCConfiguration
{
iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } }
};
private RTCPeerConnection pcLocal, pcRemote;
private MediaStream sourceVideoStream, receiveVideoStream;
private Coroutine updateCoroutine;
private void Start()
{
startButton.onClick.AddListener(Setup);
callButton.onClick.AddListener(Call);
createOfferButton.onClick.AddListener(() => StartCoroutine(CreateOffer()));
setOfferButton.onClick.AddListener(() => StartCoroutine(SetOffer()));
createAnswerButton.onClick.AddListener(() => StartCoroutine(CreateAnswer()));
setAnswerButton.onClick.AddListener(() => StartCoroutine(SetAnswer()));
hangUpButton.onClick.AddListener(HangUp);
startButton.interactable = true;
callButton.interactable = false;
hangUpButton.interactable = false;
}
private void Update()
{
if (rotateObject != null)
{
rotateObject.Rotate(1, 2, 3);
}
}
private void Setup()
{
Debug.Log("Set up source/receive streams");
sourceVideoStream = cam.CaptureStream(WebRTCSettings.StreamSize.x, WebRTCSettings.StreamSize.y);
sourceImage.texture = cam.targetTexture;
updateCoroutine = StartCoroutine(WebRTC.Update());
receiveVideoStream = new MediaStream();
receiveVideoStream.OnAddTrack = e =>
{
if (e.Track is VideoStreamTrack track)
{
track.OnVideoReceived += tex =>
{
receiveImage.texture = tex;
};
}
};
startButton.interactable = false;
callButton.interactable = true;
}
private void Call()
{
Debug.Log("Starting calls");
pcLocal = new RTCPeerConnection(ref configuration);
pcRemote = new RTCPeerConnection(ref configuration);
pcRemote.OnTrack = e => receiveVideoStream.AddTrack(e.Track);
pcLocal.OnIceCandidate = candidate => pcRemote.AddIceCandidate(candidate);
pcRemote.OnIceCandidate = candidate => pcLocal.AddIceCandidate(candidate);
Debug.Log("pc1: created local and remote peer connection object");
var senders = new List<RTCRtpSender>();
foreach (var track in sourceVideoStream.GetTracks())
{
senders.Add(pcLocal.AddTrack(track, sourceVideoStream));
}
if (WebRTCSettings.UseVideoCodec != null)
{
var codecs = new[] { WebRTCSettings.UseVideoCodec };
foreach (var transceiver in pcLocal.GetTransceivers())
{
if (senders.Contains(transceiver.Sender))
{
transceiver.SetCodecPreferences(codecs);
}
}
}
Debug.Log("Adding local stream to pcLocal");
callButton.interactable = false;
createOfferButton.interactable = true;
createAnswerButton.interactable = true;
setOfferButton.interactable = true;
setAnswerButton.interactable = true;
hangUpButton.interactable = true;
}
private IEnumerator CreateOffer()
{
var op = pcLocal.CreateOffer();
yield return op;
if (op.IsError)
{
OnCreateSessionDescriptionError(op.Error);
yield break;
}
offerSdpInput.text = op.Desc.sdp;
offerSdpInput.interactable = true;
}
private IEnumerator SetOffer()
{
var offer = new RTCSessionDescription { type = RTCSdpType.Offer, sdp = offerSdpInput.text };
Debug.Log($"Modified Offer from LocalPeerConnection\n{offer.sdp}");
var opLocal = pcLocal.SetLocalDescription(ref offer);
yield return opLocal;
if (opLocal.IsError)
{
OnSetSessionDescriptionError(opLocal.Error);
yield break;
}
Debug.Log("Set Local session description success on LocalPeerConnection");
var opRemote = pcRemote.SetRemoteDescription(ref offer);
yield return opRemote;
if (opRemote.IsError)
{
OnSetSessionDescriptionError(opRemote.Error);
yield break;
}
Debug.Log("Set Remote session description success on RemotePeerConnection");
}
private IEnumerator CreateAnswer()
{
var op = pcRemote.CreateAnswer();
yield return op;
if (op.IsError)
{
OnCreateSessionDescriptionError(op.Error);
yield break;
}
answerSdpInput.text = op.Desc.sdp;
answerSdpInput.interactable = true;
}
private IEnumerator SetAnswer()
{
var answer = new RTCSessionDescription { type = RTCSdpType.Answer, sdp = answerSdpInput.text };
Debug.Log($"Modified Answer from RemotePeerConnection\n{answer.sdp}");
var opLocal = pcRemote.SetLocalDescription(ref answer);
yield return opLocal;
if (opLocal.IsError)
{
OnSetSessionDescriptionError(opLocal.Error);
yield break;
}
Debug.Log("Set Local session description success on RemotePeerConnection");
var opRemote = pcLocal.SetRemoteDescription(ref answer);
yield return opRemote;
if (opRemote.IsError)
{
OnSetSessionDescriptionError(opRemote.Error);
yield break;
}
Debug.Log("Set Remote session description success on LocalPeerConnection");
}
private void HangUp()
{
StopCoroutine(updateCoroutine);
updateCoroutine = null;
sourceVideoStream.Dispose();
sourceVideoStream = null;
sourceImage.texture = null;
receiveVideoStream.Dispose();
receiveVideoStream = null;
receiveImage.texture = null;
offerSdpInput.text = string.Empty;
answerSdpInput.text = string.Empty;
pcLocal.Close();
pcRemote.Close();
pcLocal.Dispose();
pcRemote.Dispose();
pcLocal = null;
pcRemote = null;
startButton.interactable = true;
callButton.interactable = false;
createOfferButton.interactable = false;
createAnswerButton.interactable = false;
setOfferButton.interactable = false;
setAnswerButton.interactable = false;
hangUpButton.interactable = false;
offerSdpInput.interactable = false;
answerSdpInput.interactable = false;
}
private static void OnCreateSessionDescriptionError(RTCError error)
{
Debug.LogError($"Failed to create session description: {error.message}");
}
private static void OnSetSessionDescriptionError(RTCError error)
{
Debug.LogError($"Failed to set session description: {error.message}");
}
}