Files
webRtc/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/SignalingManagerInternalTest.cs
2026-04-28 16:48:04 +08:00

898 lines
39 KiB
C#
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Linq;
using NUnit.Framework;
using Unity.RenderStreaming.RuntimeTest.Signaling;
using Unity.WebRTC;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.RenderStreaming.RuntimeTest
{
enum TestMode
{
PrivateMode,
PublicMode
}
static class SignalingManagerInternalExtension
{
public static RTCRtpTransceiver AddSenderTrack(this SignalingManagerInternal target, string connectionId, MediaStreamTrack track)
{
RTCRtpTransceiverInit init = new RTCRtpTransceiverInit() { direction = RTCRtpTransceiverDirection.SendOnly };
return target.AddTransceiver(connectionId, track, init);
}
}
class SignalingManagerInternalTest
{
class MyMonoBehaviourTest : MonoBehaviour, IMonoBehaviourTest
{
public bool IsTestFinished
{
get { return true; }
}
}
private MonoBehaviourTest<MyMonoBehaviourTest> test;
[SetUp]
public void SetUp()
{
test = new MonoBehaviourTest<MyMonoBehaviourTest>();
}
[TearDown]
public void TearDown()
{
test.component.StopAllCoroutines();
UnityEngine.Object.Destroy(test.gameObject);
}
// workaround: More time for SetDescription process
const float ResendOfferInterval = 3f;
private RenderStreamingDependencies CreateDependencies()
{
return new RenderStreamingDependencies
{
signaling = new MockSignaling(),
config = new RTCConfiguration
{
iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } },
},
startCoroutine = test.component.StartCoroutine,
stopCoroutine = test.component.StopCoroutine,
resentOfferInterval = ResendOfferInterval,
};
}
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(10000)]
public IEnumerator Construct(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies = CreateDependencies();
var target = new SignalingManagerInternal(ref dependencies);
bool isStarted = false;
target.onStart += () => { isStarted = true; };
yield return new WaitUntil(() => isStarted);
Assert.That(isStarted, Is.True);
target.Dispose();
}
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(10000)]
public IEnumerator ConstructMultiple(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1);
yield return new WaitUntil(() => isStarted2);
Assert.That(isStarted1, Is.True);
Assert.That(isStarted2, Is.True);
target1.Dispose();
target2.Dispose();
}
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(10000)]
public IEnumerator OpenConnection(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies = CreateDependencies();
var target = new SignalingManagerInternal(ref dependencies);
bool isStarted = false;
target.onStart += () => { isStarted = true; };
yield return new WaitUntil(() => isStarted);
Assert.That(isStarted, Is.True);
string connectionId = "12345";
Assert.That(target.ExistConnection(connectionId), Is.False);
target.CreateConnection(connectionId);
bool isCreatedConnection = false;
target.onCreatedConnection += _ => { isCreatedConnection = true; };
yield return new WaitUntil(() => isCreatedConnection);
Assert.That(isCreatedConnection, Is.True);
Assert.That(target.ExistConnection(connectionId), Is.True);
target.DeleteConnection(connectionId);
bool isDeletedConnection = false;
target.onDeletedConnection += _ => { isDeletedConnection = true; };
yield return new WaitUntil(() => isDeletedConnection);
Assert.That(isDeletedConnection, Is.True);
Assert.That(target.ExistConnection(connectionId), Is.False);
target.Dispose();
}
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(10000)]
public IEnumerator OpenConnectionThrowException(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies = CreateDependencies();
var target = new SignalingManagerInternal(ref dependencies);
bool isStarted = false;
target.onStart += () => { isStarted = true; };
yield return new WaitUntil(() => isStarted);
Assert.That(isStarted, Is.True);
Assert.That(() => target.CreateConnection(null), Throws.TypeOf<ArgumentException>());
Assert.That(() => target.CreateConnection(string.Empty), Throws.TypeOf<ArgumentException>());
target.Dispose();
}
//todo:: crash in dispose process on standalone linux
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer })]
public IEnumerator AddTrack(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies = CreateDependencies();
var target = new SignalingManagerInternal(ref dependencies);
bool isStarted = false;
target.onStart += () => { isStarted = true; };
yield return new WaitUntil(() => isStarted);
Assert.That(isStarted, Is.True);
var connectionId = "12345";
bool isCreatedConnection = false;
target.onCreatedConnection += _ => { isCreatedConnection = true; };
target.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection);
Assert.That(isCreatedConnection, Is.True);
Assert.That(target.GetTransceivers(connectionId).Count(), Is.EqualTo(0));
var camObj = new GameObject("Camera");
var camera = camObj.AddComponent<Camera>();
VideoStreamTrack track = camera.CaptureStreamTrack(1280, 720);
var transceiver = target.AddSenderTrack(connectionId, track);
Assert.That(transceiver.Direction, Is.EqualTo(RTCRtpTransceiverDirection.SendOnly));
Assert.That(target.GetTransceivers(connectionId).Count(), Is.EqualTo(1));
target.RemoveSenderTrack(connectionId, track);
bool isDeletedConnection = false;
target.onDeletedConnection += _ => { isDeletedConnection = true; };
target.DeleteConnection(connectionId);
yield return new WaitUntil(() => isDeletedConnection);
Assert.That(isDeletedConnection, Is.True);
target.Dispose();
track.Dispose();
UnityEngine.Object.Destroy(camObj);
}
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest]
public IEnumerator AddTrackThrowException(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies = CreateDependencies();
var target = new SignalingManagerInternal(ref dependencies);
bool isStarted = false;
target.onStart += () => { isStarted = true; };
yield return new WaitUntil(() => isStarted);
Assert.That(isStarted, Is.True);
var connectionId = "12345";
target.CreateConnection(connectionId);
bool isCreatedConnection = false;
target.onCreatedConnection += _ => { isCreatedConnection = true; };
yield return new WaitUntil(() => isCreatedConnection);
Assert.That(isCreatedConnection, Is.True);
Assert.That(() => target.AddSenderTrack(null, null), Throws.TypeOf<ArgumentNullException>());
Assert.That(() => target.AddSenderTrack(connectionId, null), Throws.TypeOf<ArgumentNullException>());
Assert.That(() => target.RemoveSenderTrack(null, null), Throws.TypeOf<ArgumentNullException>());
Assert.That(() => target.RemoveSenderTrack(connectionId, null), Throws.TypeOf<InvalidOperationException>());
target.DeleteConnection(connectionId);
bool isDeletedConnection = false;
target.onDeletedConnection += _ => { isDeletedConnection = true; };
yield return new WaitUntil(() => isDeletedConnection);
Assert.That(isDeletedConnection, Is.True);
target.Dispose();
}
//todo:: crash in dispose process on standalone linux
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer })]
public IEnumerator AddTrackMultiple(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies = CreateDependencies();
var target = new SignalingManagerInternal(ref dependencies);
bool isStarted = false;
target.onStart += () => { isStarted = true; };
yield return new WaitUntil(() => isStarted);
Assert.That(isStarted, Is.True);
var connectionId = "12345";
target.CreateConnection(connectionId);
bool isCreatedConnection = false;
target.onCreatedConnection += _ => { isCreatedConnection = true; };
yield return new WaitUntil(() => isCreatedConnection);
Assert.That(isCreatedConnection, Is.True);
var camObj = new GameObject("Camera");
var camera = camObj.AddComponent<Camera>();
VideoStreamTrack track = camera.CaptureStreamTrack(1280, 720);
var transceiver1 = target.AddSenderTrack(connectionId, track);
Assert.That(transceiver1.Direction, Is.EqualTo(RTCRtpTransceiverDirection.SendOnly));
var camObj2 = new GameObject("Camera2");
var camera2 = camObj2.AddComponent<Camera>();
VideoStreamTrack track2 = camera2.CaptureStreamTrack(1280, 720);
var transceiver2 = target.AddSenderTrack(connectionId, track2);
Assert.That(transceiver2.Direction, Is.EqualTo(RTCRtpTransceiverDirection.SendOnly));
target.DeleteConnection(connectionId);
bool isDeletedConnection = false;
target.onDeletedConnection += _ => { isDeletedConnection = true; };
yield return new WaitUntil(() => isDeletedConnection);
Assert.That(isDeletedConnection, Is.True);
target.Dispose();
track.Dispose();
track2.Dispose();
UnityEngine.Object.Destroy(camObj);
UnityEngine.Object.Destroy(camObj2);
}
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(10000)]
public IEnumerator CreateChannel(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies = CreateDependencies();
var target = new SignalingManagerInternal(ref dependencies);
bool isStarted = false;
target.onStart += () => { isStarted = true; };
yield return new WaitUntil(() => isStarted);
Assert.That(isStarted, Is.True);
var connectionId = "12345";
target.CreateConnection(connectionId);
bool isCreatedConnection = false;
target.onCreatedConnection += _ => { isCreatedConnection = true; };
yield return new WaitUntil(() => isCreatedConnection);
string channelName = "test";
var channel = target.CreateChannel(connectionId, channelName);
Assert.That(channel.Label, Is.EqualTo(channelName));
target.DeleteConnection(connectionId);
bool isDeletedConnection = false;
target.onDeletedConnection += _ => { isDeletedConnection = true; };
yield return new WaitUntil(() => isDeletedConnection);
Assert.That(isDeletedConnection, Is.True);
target.Dispose();
channel.Dispose();
}
//todo:: crash in dispose process on standalone linux
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
public IEnumerator OnAddReceiverPrivateMode()
{
MockSignaling.Reset(true);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1 && isStarted2);
Assert.That(isStarted1, Is.True);
Assert.That(isStarted2, Is.True);
bool isCreatedConnection1 = false;
bool isCreatedConnection2 = false;
target1.onCreatedConnection += _ => { isCreatedConnection1 = true; };
target2.onCreatedConnection += _ => { isCreatedConnection2 = true; };
var connectionId = "12345";
// target1 is Receiver in private mode
target1.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection1);
Assert.That(isCreatedConnection1, Is.True);
// target2 is sender in private mode
target2.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection2);
Assert.That(isCreatedConnection2, Is.True);
bool isAddReceiver1 = false;
bool isGotAnswer2 = false;
target1.onAddTransceiver += (_, receiver) => { isAddReceiver1 = true; };
target1.onGotOffer += (_, sdp) => { target1.SendAnswer(connectionId); };
target2.onGotAnswer += (_, sdp) => { isGotAnswer2 = true; };
var camObj = new GameObject("Camera");
var camera = camObj.AddComponent<Camera>();
VideoStreamTrack track = camera.CaptureStreamTrack(1280, 720);
// send offer automatically after adding a Track
var transceiver = target2.AddSenderTrack(connectionId, track);
Assert.That(transceiver, Is.Not.Null);
Assert.That(transceiver.Direction, Is.EqualTo(RTCRtpTransceiverDirection.SendOnly));
yield return new WaitUntil(() => isAddReceiver1 && isGotAnswer2);
Assert.That(isAddReceiver1, Is.True);
Assert.That(isGotAnswer2, Is.True);
target1.DeleteConnection(connectionId);
target2.DeleteConnection(connectionId);
bool isDeletedConnection1 = false;
bool isDeletedConnection2 = false;
target1.onDeletedConnection += _ => { isDeletedConnection1 = true; };
target2.onDeletedConnection += _ => { isDeletedConnection2 = true; };
yield return new WaitUntil(() => isDeletedConnection1 && isDeletedConnection2);
Assert.That(isDeletedConnection1, Is.True);
Assert.That(isDeletedConnection2, Is.True);
target1.Dispose();
target2.Dispose();
track.Dispose();
UnityEngine.Object.Destroy(camObj);
}
//todo:: crash in dispose process on standalone linux
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
public IEnumerator OnAddReceiverPublicMode()
{
MockSignaling.Reset(false);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1 && isStarted2);
Assert.That(isStarted1, Is.True);
Assert.That(isStarted2, Is.True);
bool isCreatedConnection1 = false;
bool isOnGotOffer2 = false;
target1.onCreatedConnection += _ => { isCreatedConnection1 = true; };
target2.onGotOffer += (_, sdp) => { isOnGotOffer2 = true; };
var connectionId = "12345";
// target1 is Receiver in public mode
target1.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection1);
Assert.That(isCreatedConnection1, Is.True);
RTCRtpTransceiverInit init = new RTCRtpTransceiverInit()
{
direction = RTCRtpTransceiverDirection.RecvOnly
};
target1.AddTransceiver(connectionId, TrackKind.Video, init);
// target2 is sender in private mode
yield return new WaitUntil(() => isOnGotOffer2);
Assert.That(isOnGotOffer2, Is.True);
bool isAddReceiver1 = false;
bool isGotAnswer1 = false;
target1.onAddTransceiver += (_, receiver) => { isAddReceiver1 = true; };
target1.onGotAnswer += (_, sdp) => { isGotAnswer1 = true; };
var camObj = new GameObject("Camera");
var camera = camObj.AddComponent<Camera>();
VideoStreamTrack track = camera.CaptureStreamTrack(1280, 720);
var transceiver2 = target2.AddSenderTrack(connectionId, track);
Assert.That(transceiver2.Direction, Is.EqualTo(RTCRtpTransceiverDirection.SendOnly));
target2.SendAnswer(connectionId);
yield return new WaitUntil(() => isAddReceiver1 & isGotAnswer1);
target1.DeleteConnection(connectionId);
target2.DeleteConnection(connectionId);
bool isDeletedConnection1 = false;
bool isDeletedConnection2 = false;
target1.onDeletedConnection += _ => { isDeletedConnection1 = true; };
target2.onDeletedConnection += _ => { isDeletedConnection2 = true; };
yield return new WaitUntil(() => isDeletedConnection1 && isDeletedConnection2);
Assert.That(isDeletedConnection1, Is.True);
Assert.That(isDeletedConnection2, Is.True);
target1.Dispose();
target2.Dispose();
track.Dispose();
UnityEngine.Object.DestroyImmediate(camObj);
}
[UnityTest, Timeout(10000)]
public IEnumerator OnAddChannelPrivateMode()
{
MockSignaling.Reset(true);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1 && isStarted2);
bool isCreatedConnection1 = false;
bool isCreatedConnection2 = false;
target1.onCreatedConnection += _ => { isCreatedConnection1 = true; };
target2.onCreatedConnection += _ => { isCreatedConnection2 = true; };
var connectionId = "12345";
// target1 is Receiver in private mode
target1.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection1);
// target2 is sender in private mode
target2.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection2);
bool isAddChannel1 = false;
bool isGotOffer1 = false;
bool isGotAnswer2 = false;
target1.onAddChannel += (_, _channel) => { isAddChannel1 = true; };
target1.onGotOffer += (_, sdp) => { isGotOffer1 = true; };
target2.onGotAnswer += (_, sdp) => { isGotAnswer2 = true; };
// send offer automatically after creating channel
RTCDataChannel channel = target2.CreateChannel(connectionId, "test");
Assert.That(channel, Is.Not.Null);
yield return new WaitUntil(() => isGotOffer1);
Assert.That(isGotOffer1, Is.True);
target1.SendAnswer(connectionId);
yield return new WaitUntil(() => isAddChannel1 && isGotAnswer2);
Assert.That(isAddChannel1, Is.True);
Assert.That(isGotAnswer2, Is.True);
target1.DeleteConnection(connectionId);
target2.DeleteConnection(connectionId);
bool isDeletedConnection1 = false;
bool isDeletedConnection2 = false;
target1.onDeletedConnection += _ => { isDeletedConnection1 = true; };
target2.onDeletedConnection += _ => { isDeletedConnection2 = true; };
yield return new WaitUntil(() => isDeletedConnection1 && isDeletedConnection2);
Assert.That(isDeletedConnection1, Is.True);
Assert.That(isDeletedConnection2, Is.True);
target1.Dispose();
target2.Dispose();
}
[UnityTest, Timeout(10000), LongRunning]
public IEnumerator SendOfferThrowExceptionPrivateMode()
{
MockSignaling.Reset(true);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1 && isStarted2);
bool isCreatedConnection1 = false;
bool isCreatedConnection2 = false;
target1.onCreatedConnection += _ => { isCreatedConnection1 = true; };
target2.onCreatedConnection += _ => { isCreatedConnection2 = true; };
var connectionId = "12345";
// target1 is Receiver in private mode
target1.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection1);
// target2 is sender in private mode
target2.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection2);
bool isGotOffer1 = false;
bool isGotAnswer2 = false;
target1.onGotOffer += (_, sdp) => { isGotOffer1 = true; };
target2.onGotAnswer += (_, sdp) => { isGotAnswer2 = true; };
target2.SendOffer(connectionId);
// each peer are not stable, signaling process not complete.
yield return new WaitUntil(() => isGotOffer1);
Assert.That(target1.IsStable(connectionId), Is.False);
Assert.That(target2.IsStable(connectionId), Is.False);
Assert.That(() => target1.SendOffer(connectionId), Throws.TypeOf<InvalidOperationException>());
target1.SendAnswer(connectionId);
yield return new WaitUntil(() => isGotAnswer2);
Assert.That(isGotAnswer2, Is.True);
// If target1 processes resent Offer from target2, target1 is not stable.
Assert.That(target2.IsStable(connectionId), Is.True);
target1.DeleteConnection(connectionId);
target2.DeleteConnection(connectionId);
bool isDeletedConnection1 = false;
bool isDeletedConnection2 = false;
target1.onDeletedConnection += _ => { isDeletedConnection1 = true; };
target2.onDeletedConnection += _ => { isDeletedConnection2 = true; };
yield return new WaitUntil(() => isDeletedConnection1 && isDeletedConnection2);
Assert.That(isDeletedConnection1, Is.True);
Assert.That(isDeletedConnection2, Is.True);
target1.Dispose();
target2.Dispose();
}
[UnityTest, Timeout(30000), LongRunning]
public IEnumerator SwapTransceiverPrivateMode()
{
MockSignaling.Reset(true);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1 && isStarted2);
Assert.That(isStarted1, Is.True);
Assert.That(isStarted2, Is.True);
bool isCreatedConnection1 = false;
bool isCreatedConnection2 = false;
target1.onCreatedConnection += _ => { isCreatedConnection1 = true; };
target2.onCreatedConnection += _ => { isCreatedConnection2 = true; };
var connectionId = "12345";
// target1 has impolite peer (request first)
target1.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection1);
Assert.That(isCreatedConnection1, Is.True);
// target2 has polite peer (request second)
target2.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection2);
Assert.That(isCreatedConnection2, Is.True);
bool isGotOffer1 = false;
bool isGotOffer2 = false;
bool isGotAnswer1 = false;
target1.onGotOffer += (_, sdp) => { isGotOffer1 = true; };
target2.onGotOffer += (_, sdp) => { isGotOffer2 = true; };
target1.onGotAnswer += (_, sdp) => { isGotAnswer1 = true; };
RTCRtpTransceiverInit init1 = new RTCRtpTransceiverInit()
{
direction = RTCRtpTransceiverDirection.SendOnly
};
RTCRtpTransceiverInit init2 = new RTCRtpTransceiverInit()
{
direction = RTCRtpTransceiverDirection.SendOnly
};
target1.AddTransceiver(connectionId, TrackKind.Audio, init1);
target2.AddTransceiver(connectionId, TrackKind.Audio, init2);
// check each target invoke onGotOffer
yield return new WaitForSeconds(ResendOfferInterval * 5);
// ignore offer because impolite peer
Assert.That(isGotOffer1, Is.False, $"{nameof(isGotOffer1)} is not False.");
// accept offer because polite peer
Assert.That(isGotOffer2, Is.True, $"{nameof(isGotOffer2)} is not True.");
target2.SendAnswer(connectionId);
yield return new WaitUntil(() => isGotAnswer1);
Assert.That(isGotAnswer1, Is.True, $"{nameof(isGotAnswer1)} is not True.");
target1.DeleteConnection(connectionId);
target2.DeleteConnection(connectionId);
bool isDeletedConnection1 = false;
bool isDeletedConnection2 = false;
target1.onDeletedConnection += _ => { isDeletedConnection1 = true; };
target2.onDeletedConnection += _ => { isDeletedConnection2 = true; };
yield return new WaitUntil(() => isDeletedConnection1 && isDeletedConnection2);
Assert.That(isDeletedConnection1, Is.True, $"{nameof(isDeletedConnection1)} is not True.");
Assert.That(isDeletedConnection2, Is.True, $"{nameof(isDeletedConnection2)} is not True.");
target1.Dispose();
target2.Dispose();
}
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(30000), LongRunning]
public IEnumerator ResendOfferUntilGotAnswer(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1 && isStarted2);
bool isCreatedConnection1 = false;
bool isCreatedConnection2 = false;
target1.onCreatedConnection += _ => { isCreatedConnection1 = true; };
target2.onCreatedConnection += _ => { isCreatedConnection2 = true; };
var connectionId = "12345";
target1.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection1);
Assert.That(isCreatedConnection1, Is.True);
target2.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection2);
Assert.That(isCreatedConnection2, Is.True);
int countGotOffer2 = 0;
target2.onGotOffer += (_, sdp) => { countGotOffer2++; };
target1.SendOffer(connectionId);
yield return new WaitUntil(() => countGotOffer2 > 1);
Assert.That(countGotOffer2, Is.GreaterThan(1));
bool isGotAnswer1 = false;
target1.onGotAnswer += (_, sdp) => { isGotAnswer1 = true; };
target2.SendAnswer(connectionId);
yield return new WaitUntil(() => isGotAnswer1);
Assert.That(isGotAnswer1, Is.True);
yield return new WaitForSeconds(ResendOfferInterval * 2);
var currentCount = countGotOffer2;
yield return new WaitForSeconds(ResendOfferInterval * 2);
Assert.That(countGotOffer2, Is.EqualTo(currentCount),
$"{nameof(currentCount)} is not Equal {nameof(countGotOffer2)}");
target1.DeleteConnection(connectionId);
target2.DeleteConnection(connectionId);
bool isDeletedConnection1 = false;
bool isDeletedConnection2 = false;
target1.onDeletedConnection += _ => { isDeletedConnection1 = true; };
target2.onDeletedConnection += _ => { isDeletedConnection2 = true; };
yield return new WaitUntil(() => isDeletedConnection1 && isDeletedConnection2);
Assert.That(isDeletedConnection1, Is.True, $"{nameof(isDeletedConnection1)} is not True.");
Assert.That(isDeletedConnection2, Is.True, $"{nameof(isDeletedConnection2)} is not True.");
target1.Dispose();
target2.Dispose();
}
[TestCase(TestMode.PublicMode, ExpectedResult = null)]
[TestCase(TestMode.PrivateMode, ExpectedResult = null)]
[UnityTest, Timeout(30000), LongRunning]
public IEnumerator DeleteFailedPeers(TestMode mode)
{
MockSignaling.Reset(mode == TestMode.PrivateMode);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1 && isStarted2);
Assert.That(isStarted1, Is.True);
Assert.That(isStarted2, Is.True);
bool isCreatedConnection1 = false;
bool isCreatedConnection2 = false;
target1.onCreatedConnection += _ => { isCreatedConnection1 = true; };
target2.onCreatedConnection += _ => { isCreatedConnection2 = true; };
var connectionId = "12345";
// target1 has impolite peer (request first)
target1.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection1);
Assert.That(isCreatedConnection1, Is.True);
target2.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection2);
Assert.That(isCreatedConnection2, Is.True);
bool isGotOffer2 = false;
bool isGotAnswer1 = false;
target2.onGotOffer += (_, sdp) => { isGotOffer2 = true; };
target1.onGotAnswer += (_, sdp) => { isGotAnswer1 = true; };
RTCRtpTransceiverInit init1 = new RTCRtpTransceiverInit()
{
direction = RTCRtpTransceiverDirection.SendOnly
};
target1.AddTransceiver(connectionId, TrackKind.Video, init1);
yield return new WaitUntil(() => isGotOffer2);
Assert.That(isGotOffer2, Is.True, $"{nameof(isGotOffer2)} is not True.");
target2.SendAnswer(connectionId);
yield return new WaitUntil(() => isGotAnswer1);
Assert.That(isGotAnswer1, Is.True, $"{nameof(isGotAnswer1)} is not True.");
// Improperly dispose of target1 to force failed state on target2
target1.Dispose();
bool isDeletedConnection2 = false;
target2.onDeletedConnection += _ => { isDeletedConnection2 = true; };
yield return new WaitUntil(() => isDeletedConnection2);
Assert.That(isDeletedConnection2, Is.True, $"{nameof(isDeletedConnection2)} is not True.");
target2.Dispose();
}
[UnityTest, Timeout(10000)]
public IEnumerator ReNegotiationAfterReceivingFirstOffer()
{
MockSignaling.Reset(true);
var dependencies1 = CreateDependencies();
var dependencies2 = CreateDependencies();
var target1 = new SignalingManagerInternal(ref dependencies1);
var target2 = new SignalingManagerInternal(ref dependencies2);
bool isStarted1 = false;
bool isStarted2 = false;
target1.onStart += () => { isStarted1 = true; };
target2.onStart += () => { isStarted2 = true; };
yield return new WaitUntil(() => isStarted1 && isStarted2);
bool isCreatedConnection1 = false;
bool isCreatedConnection2 = false;
target1.onCreatedConnection += _ => { isCreatedConnection1 = true; };
target2.onCreatedConnection += _ => { isCreatedConnection2 = true; };
var connectionId = "12345";
// target1 has impolite peer (request first)
target1.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection1);
// target2 has polite peer (request second)
target2.CreateConnection(connectionId);
yield return new WaitUntil(() => isCreatedConnection2);
bool isGotOffer1 = false;
bool isGotOffer2 = false;
bool isGotAnswer1 = false;
bool isGotAnswer2 = false;
target1.onGotOffer += (_, sdp) => { isGotOffer1 = true; };
target2.onGotOffer += (_, sdp) => { isGotOffer2 = true; };
target1.onGotAnswer += (_, sdp) => { isGotAnswer1 = true; };
target2.onGotAnswer += (_, sdp) => { isGotAnswer2 = true; };
var init1 = new RTCRtpTransceiverInit() { direction = RTCRtpTransceiverDirection.SendOnly };
var init2 = new RTCRtpTransceiverInit() { direction = RTCRtpTransceiverDirection.RecvOnly };
var init3 = new RTCRtpTransceiverInit() { direction = RTCRtpTransceiverDirection.SendOnly };
var init4 = new RTCRtpTransceiverInit() { direction = RTCRtpTransceiverDirection.RecvOnly };
target1.AddTransceiver(connectionId, TrackKind.Video, init1);
target1.AddTransceiver(connectionId, TrackKind.Video, init2);
target2.AddTransceiver(connectionId, TrackKind.Video, init3);
target2.AddTransceiver(connectionId, TrackKind.Video, init4);
yield return new WaitUntil(() => isGotOffer2);
Assert.That(isGotOffer2, Is.True, $"{nameof(isGotOffer2)} is not True.");
target2.SendAnswer(connectionId);
yield return new WaitUntil(() => isGotAnswer1);
Assert.That(isGotAnswer1, Is.True, $"{nameof(isGotAnswer1)} is not True.");
yield return new WaitUntil(() => isGotOffer1);
Assert.That(isGotOffer1, Is.True, $"{nameof(isGotOffer1)} is not True.");
target1.SendAnswer(connectionId);
yield return new WaitUntil(() => isGotAnswer2);
Assert.That(isGotAnswer2, Is.True, $"{nameof(isGotAnswer2)} is not True.");
target1.DeleteConnection(connectionId);
target2.DeleteConnection(connectionId);
bool isDeletedConnection1 = false;
bool isDeletedConnection2 = false;
target1.onDeletedConnection += _ => { isDeletedConnection1 = true; };
target2.onDeletedConnection += _ => { isDeletedConnection2 = true; };
yield return new WaitUntil(() => isDeletedConnection1 && isDeletedConnection2);
Assert.That(isDeletedConnection1, Is.True, $"{nameof(isDeletedConnection1)} is not True.");
Assert.That(isDeletedConnection2, Is.True, $"{nameof(isDeletedConnection1)} is not True.");
target1.Dispose();
target2.Dispose();
}
}
}