250 lines
7.6 KiB
C#
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}");
|
|
}
|
|
}
|