// 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); } } }