// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using UnityEngine;
using Microsoft.MixedReality.WebRTC.Unity;
using System.Threading;
using System.Collections;
namespace Microsoft.MixedReality.WebRTC.Unity
{
///
/// Simple signaler using two peer connections in the same process,
/// and hard-coding their SDP message delivery to avoid the need for
/// any kind of networking to deliver SDP messages.
///
/// This component is designed to be used in demos where both peers
/// are present in the same scene.
///
public class LocalOnlySignaler : WorkQueue
{
///
/// First peer to connect, which will generate an offer.
///
public PeerConnection Peer1;
///
/// Second peer to connect, which will wait for an offer from the first peer.
///
public PeerConnection Peer2;
///
/// Check if the last connection attempt successfully completed. This is reset to false each
/// time is called, and is updated after
/// returned to indicate if the connection succeeded.
///
public bool IsConnected { get; private set; } = false;
private ManualResetEventSlim _remoteApplied1 = new ManualResetEventSlim();
private ManualResetEventSlim _remoteApplied2 = new ManualResetEventSlim();
///
/// Initiate a connection by having send an offer to ,
/// and wait until the SDP exchange completed. To wait for completion, use
/// then check the value of after that to determine if
/// terminated due to the connection being established or
/// if it timed out.
///
/// true if the exchange started successfully, or false otherwise.
///
public bool StartConnection()
{
EnsureIsMainAppThread();
_remoteApplied1.Reset();
_remoteApplied2.Reset();
IsConnected = false;
return Peer1.StartConnection();
}
///
/// Wait for the connection being established.
///
/// Timeout in milliseconds to wait for the connection.
/// An enumerator used to yield while waiting.
///
/// Assert.IsTrue(signaler.StartConnection());
/// yield return signaler.WaitForConnection(millisecondsTimeout: 10000);
/// Assert.IsTrue(signaler.IsConnected);
///
public IEnumerator WaitForConnection(int millisecondsTimeout)
{
float timeoutTime = Time.time + (millisecondsTimeout / 1000f);
while (true)
{
if (_remoteApplied1.IsSet && _remoteApplied2.IsSet)
{
IsConnected = true;
break;
}
if (Time.time >= timeoutTime)
{
break;
}
yield return null;
}
}
private void Start()
{
Peer1.OnInitialized.AddListener(OnInitialized1);
Peer2.OnInitialized.AddListener(OnInitialized2);
}
private void OnInitialized1()
{
Peer1.Peer.LocalSdpReadytoSend += Peer1_LocalSdpReadytoSend;
Peer1.Peer.IceCandidateReadytoSend += Peer1_IceCandidateReadytoSend;
}
private void OnInitialized2()
{
Peer2.Peer.LocalSdpReadytoSend += Peer2_LocalSdpReadytoSend;
Peer2.Peer.IceCandidateReadytoSend += Peer2_IceCandidateReadytoSend;
}
private void Peer1_LocalSdpReadytoSend(Microsoft.MixedReality.WebRTC.SdpMessage message)
{
InvokeOnAppThread(async () =>
{
if (Peer2.Peer == null)
{
Debug.Log("Discarding SDP message for peer #2 (disabled)");
return;
}
await Peer2.HandleConnectionMessageAsync(message);
_remoteApplied2.Set();
if (message.Type == Microsoft.MixedReality.WebRTC.SdpMessageType.Offer)
{
Peer2.Peer.CreateAnswer();
}
});
}
private void Peer2_LocalSdpReadytoSend(Microsoft.MixedReality.WebRTC.SdpMessage message)
{
InvokeOnAppThread(async () =>
{
if (Peer1.Peer == null)
{
Debug.Log("Discarding SDP message for peer #1 (disabled)");
return;
}
await Peer1.HandleConnectionMessageAsync(message);
_remoteApplied1.Set();
if (message.Type == Microsoft.MixedReality.WebRTC.SdpMessageType.Offer)
{
Peer1.Peer.CreateAnswer();
}
});
}
private void Peer1_IceCandidateReadytoSend(Microsoft.MixedReality.WebRTC.IceCandidate candidate)
{
if (Peer2.Peer == null)
{
Debug.Log("Discarding ICE message for peer #2 (disabled)");
return;
}
Peer2.Peer.AddIceCandidate(candidate);
}
private void Peer2_IceCandidateReadytoSend(Microsoft.MixedReality.WebRTC.IceCandidate candidate)
{
if (Peer1.Peer == null)
{
Debug.Log("Discarding ICE message for peer #1 (disabled)");
return;
}
Peer1.Peer.AddIceCandidate(candidate);
}
}
}