Files
webRtc/Packages/com.unity.renderstreaming@3.1.0-exp.9/Tests/Runtime/SignalingHandlerTest.cs

1036 lines
47 KiB
C#
Raw Normal View History

2026-04-28 16:48:04 +08:00
using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using Unity.RenderStreaming.RuntimeTest.Signaling;
using Unity.WebRTC;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.RenderStreaming.RuntimeTest
{
class SingleConnectionBehaviourTest : SingleConnection, IMonoBehaviourTest
{
public bool IsTestFinished
{
get { return true; }
}
}
class BroadcastBehaviourTest : Broadcast, IMonoBehaviourTest
{
public bool IsTestFinished
{
get { return true; }
}
}
class VideoStreamSenderTester : VideoStreamSender
{
private Camera m_camera;
internal override WaitForCreateTrack CreateTrack()
{
m_camera = gameObject.AddComponent<Camera>();
var instruction = new WaitForCreateTrack();
instruction.Done(m_camera.CaptureStreamTrack(256, 256));
return instruction;
}
}
class VideoStreamReceiverTester : VideoStreamReceiver
{
}
class AudioStreamSenderTester : AudioStreamSender
{
private AudioSource m_audioSource;
internal override WaitForCreateTrack CreateTrack()
{
m_audioSource = gameObject.AddComponent<AudioSource>();
m_audioSource.clip = AudioClip.Create("test", 48000, 2, 48000, false);
var instruction = new WaitForCreateTrack();
instruction.Done(new AudioStreamTrack(m_audioSource));
return instruction;
}
}
class AudioStreamReceiverTester : AudioStreamReceiver
{
}
class DataChannelTest : DataChannelBase
{
public Action<string> OnReceiveMessage;
public void SetLocal(bool isLocal)
{
Type myClass = typeof(DataChannelBase);
FieldInfo fieldLocal = myClass.GetField("local",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
fieldLocal.SetValue(this, true);
}
public void SetLabel(string label)
{
Type myClass = typeof(DataChannelBase);
FieldInfo fieldLabel = myClass.GetField("label",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
fieldLabel.SetValue(this, label);
}
protected override void OnMessage(byte[] bytes)
{
OnReceiveMessage(System.Text.Encoding.UTF8.GetString(bytes));
}
}
class TestContainer<T> : IDisposable where T : SignalingHandlerBase, IMonoBehaviourTest
{
const float ResendOfferInterval = 3.0f;
public MonoBehaviourTest<T> test;
public SignalingManagerInternal instance;
public SignalingEventProvider provider;
private static RenderStreamingDependencies CreateDependencies(MonoBehaviour behaviour)
{
return new RenderStreamingDependencies
{
signaling = new MockSignaling(),
config = new RTCConfiguration
{
iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } },
},
startCoroutine = behaviour.StartCoroutine,
stopCoroutine = behaviour.StopCoroutine,
resentOfferInterval = ResendOfferInterval,
};
}
public static TestContainer<T> Create(string name)
{
var test = new MonoBehaviourTest<T>();
var dependencies = CreateDependencies(test.component);
var instance = new SignalingManagerInternal(ref dependencies);
var provider = new SignalingEventProvider(instance);
var container = new TestContainer<T> { test = test, instance = instance, provider = provider };
test.component.SetHandler(instance);
test.gameObject.name = name;
provider.Subscribe(test.component);
return container;
}
public void Dispose()
{
test.component.StopAllCoroutines();
instance.Dispose();
UnityEngine.Object.DestroyImmediate(test.gameObject);
}
}
class BroadcastTest
{
[SetUp]
public void SetUp()
{
MockSignaling.Reset(false);
}
//todo:: crash in dispose process on standalone linux
[Test]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer })]
public void AddAndRemoveStreamSource()
{
var container = TestContainer<BroadcastBehaviourTest>.Create("test");
var streamer = container.test.gameObject.AddComponent<VideoStreamSenderTester>();
Assert.That(streamer.Track, Is.Null);
Assert.That(streamer.Transceivers, Is.Empty);
Assert.That(container.test.component.Streams, Is.Empty);
container.test.component.AddComponent(streamer);
Assert.That(container.test.component.Streams, Has.Count.EqualTo(1));
container.test.component.RemoveComponent(streamer);
Assert.That(container.test.component.Streams, Is.Empty);
container.Dispose();
}
[Test]
public void AddDataChannel()
{
var container = TestContainer<BroadcastBehaviourTest>.Create("test");
var channel = container.test.gameObject.AddComponent<DataChannelTest>();
channel.SetLabel("test");
channel.SetLocal(true);
Assert.That(channel.IsLocal, Is.True);
Assert.That(channel.Label, Is.EqualTo("test"));
Assert.That(channel.IsConnected, Is.False);
container.test.component.AddComponent(channel);
container.Dispose();
}
//todo:: crash in dispose process on standalone linux
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
public IEnumerator ReceiveStream()
{
string connectionId = "12345";
var container1 = TestContainer<BroadcastBehaviourTest>.Create("test1");
var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
var streamer = container1.test.gameObject.AddComponent<AudioStreamSenderTester>();
bool isStartedStream1 = false;
bool isStoppedStream1 = false;
streamer.OnStartedStream += _ => isStartedStream1 = true;
streamer.OnStoppedStream += _ => isStoppedStream1 = true;
container1.test.component.AddComponent(streamer);
var receiver = container2.test.gameObject.AddComponent<AudioStreamReceiverTester>();
bool isStartedStream2 = false;
bool isStoppedStream2 = false;
receiver.OnStartedStream += _ => isStartedStream2 = true;
receiver.OnStoppedStream += _ => isStoppedStream2 = true;
container2.test.component.AddComponent(receiver);
container2.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
container2.test.component.SendOffer(connectionId);
yield return new WaitUntil(() => isStartedStream2 && isStartedStream1);
Assert.That(isStartedStream1, Is.True);
Assert.That(isStartedStream2, Is.True);
Assert.That(receiver.Track, Is.Not.Null);
Assert.That(receiver.Transceiver, Is.Not.Null);
yield return new WaitUntil(() => container1.test.component.IsConnected(connectionId));
yield return new WaitUntil(() => container2.test.component.IsConnected(connectionId));
container2.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => isStoppedStream1 && isStoppedStream2);
Assert.That(isStoppedStream1, Is.True);
Assert.That(isStoppedStream2, Is.True);
Assert.That(container1.test.component.ExistConnection(connectionId), Is.False);
Assert.That(container2.test.component.ExistConnection(connectionId), Is.False);
container1.Dispose();
container2.Dispose();
}
// todo:: Crash in dispose process on Linux standalone.
// todo:: Timeout error on iPhonePlayer.
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[]
{
RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor,
RuntimePlatform.LinuxPlayer, RuntimePlatform.IPhonePlayer, RuntimePlatform.Android
})]
public IEnumerator SetCodec()
{
string connectionId = "12345";
var container1 = TestContainer<BroadcastBehaviourTest>.Create("test1");
var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
var streamer = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
bool isStartedStream1 = false;
bool isStoppedStream1 = false;
streamer.OnStartedStream += _ => isStartedStream1 = true;
streamer.OnStoppedStream += _ => isStoppedStream1 = true;
var codec = VideoStreamSender.GetAvailableCodecs().FirstOrDefault(x => x.mimeType.Contains("VP9"));
Assert.That(codec, Is.Not.Null);
streamer.SetCodec(codec);
container1.test.component.AddComponent(streamer);
var receiver = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
bool isStartedStream2 = false;
bool isStoppedStream2 = false;
receiver.OnStartedStream += _ => isStartedStream2 = true;
receiver.OnStoppedStream += _ => isStoppedStream2 = true;
container2.test.component.AddComponent(receiver);
container2.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
container2.test.component.SendOffer(connectionId);
yield return new WaitUntil(() => isStartedStream2 && isStartedStream1);
Assert.That(isStartedStream1, Is.True);
Assert.That(isStartedStream2, Is.True);
Assert.That(receiver.Track, Is.Not.Null);
Assert.That(receiver.Transceiver, Is.Not.Null);
yield return new WaitUntil(() => container1.test.component.IsConnected(connectionId));
yield return new WaitUntil(() => container2.test.component.IsConnected(connectionId));
RTCCodecStats senderCodecStats = null;
while (senderCodecStats == null)
{
var statsOp = streamer.Transceivers[connectionId].Sender.GetStats();
yield return statsOp;
Assert.That(statsOp.IsError, Is.False);
var outboundStats =
statsOp.Value.Stats.Values.FirstOrDefault(x =>
x is RTCOutboundRTPStreamStats stats && stats.kind == "video") as RTCOutboundRTPStreamStats;
if (outboundStats == null || string.IsNullOrEmpty(outboundStats.codecId))
{
yield return new WaitForSeconds(0.1f);
continue;
}
senderCodecStats =
statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == outboundStats.codecId) as RTCCodecStats;
}
Assert.That(senderCodecStats.mimeType, Is.EqualTo(codec.mimeType));
Assert.That(senderCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
container2.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => isStoppedStream1 && isStoppedStream2);
Assert.That(isStoppedStream1, Is.True);
Assert.That(isStoppedStream2, Is.True);
Assert.That(container1.test.component.ExistConnection(connectionId), Is.False);
Assert.That(container2.test.component.ExistConnection(connectionId), Is.False);
container1.Dispose();
container2.Dispose();
}
//todo:: crash in dispose process on standalone linux
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
public IEnumerator DataChannelDisconnectWithMultipleConnections()
{
// Ignore signaling log errors due to multiple connections
LogAssert.ignoreFailingMessages = true;
string connectionId = "12345";
string connectionId2 = "54321";
var container1 = TestContainer<BroadcastBehaviourTest>.Create("test1");
var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
var container4 = TestContainer<SingleConnectionBehaviourTest>.Create("test4");
var channel1 = container1.test.gameObject.AddComponent<DataChannelTest>();
bool isStartedChannel1 = false;
bool isStoppedChannel1 = false;
channel1.OnStartedChannel += _ => isStartedChannel1 = true;
channel1.OnStoppedChannel += _ => isStoppedChannel1 = true;
container1.test.component.AddComponent(channel1);
container1.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
var channel2 = container2.test.gameObject.AddComponent<DataChannelTest>();
bool isStartedChannel2 = false;
bool isStoppedChannel2 = false;
channel2.OnStartedChannel += _ => isStartedChannel2 = true;
channel2.OnStoppedChannel += _ => isStoppedChannel2 = true;
channel2.SetLocal(true);
channel2.SetLabel("test");
Assert.That(channel2.IsConnected, Is.False);
Assert.That(channel2.IsLocal, Is.True);
Assert.That(channel2.Label, Is.EqualTo("test"));
container2.test.component.AddComponent(channel2);
container2.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedChannel1 && isStartedChannel2);
Assert.That(isStartedChannel1, Is.True);
Assert.That(isStartedChannel2, Is.True);
Assert.That(channel1.IsLocal, Is.False);
Assert.That(channel1.Label, Is.EqualTo("test"));
Assert.That(channel1.IsConnected, Is.True);
Assert.That(channel1.Channel, Is.Not.Null);
Assert.That(channel1.ConnectionId, Is.EqualTo(connectionId));
Assert.That(channel2.IsConnected, Is.True);
Assert.That(channel2.Channel, Is.Not.Null);
Assert.That(channel2.ConnectionId, Is.EqualTo(connectionId));
var channel3 = container1.test.gameObject.AddComponent<DataChannelTest>();
bool isStartedChannel3 = false;
bool isStoppedChannel3 = false;
channel3.OnStartedChannel += _ => isStartedChannel3 = true;
channel3.OnStoppedChannel += _ => isStoppedChannel3 = true;
container1.test.component.AddComponent(channel3);
container1.test.component.CreateConnection(connectionId2);
yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId2));
var channel4 = container4.test.gameObject.AddComponent<DataChannelTest>();
bool isStartedChannel4 = false;
bool isStoppedChannel4 = false;
channel4.OnStartedChannel += _ => isStartedChannel4 = true;
channel4.OnStoppedChannel += _ => isStoppedChannel4 = true;
channel4.SetLocal(true);
channel4.SetLabel("test2");
Assert.That(channel4.IsConnected, Is.False);
Assert.That(channel4.IsLocal, Is.True);
Assert.That(channel4.Label, Is.EqualTo("test2"));
container4.test.component.AddComponent(channel4);
container4.test.component.CreateConnection(connectionId2);
yield return new WaitUntil(() => container4.test.component.ExistConnection(connectionId2));
yield return new WaitUntil(() => isStartedChannel3 && isStartedChannel4);
Assert.That(isStartedChannel3, Is.True);
Assert.That(isStartedChannel4, Is.True);
Assert.That(channel3.IsLocal, Is.False);
Assert.That(channel3.Label, Is.EqualTo("test2"));
Assert.That(channel3.IsConnected, Is.True);
Assert.That(channel3.Channel, Is.Not.Null);
Assert.That(channel3.ConnectionId, Is.EqualTo(connectionId2));
Assert.That(channel4.IsConnected, Is.True);
Assert.That(channel4.Channel, Is.Not.Null);
Assert.That(channel4.ConnectionId, Is.EqualTo(connectionId2));
// send message from channel1 to channel2
string sendMessage = "hello";
string receivedMessage = null;
channel2.OnReceiveMessage = message => { receivedMessage = message; };
channel1.Send(sendMessage);
yield return new WaitUntil(() => !string.IsNullOrEmpty(receivedMessage));
Assert.That(receivedMessage, Is.EqualTo(sendMessage));
// send message from channel2 to channel1
receivedMessage = null;
channel1.OnReceiveMessage = message => { receivedMessage = message; };
channel2.Send(sendMessage);
yield return new WaitUntil(() => !string.IsNullOrEmpty(receivedMessage));
Assert.That(receivedMessage, Is.EqualTo(sendMessage));
// send message from channel3 to channel4
receivedMessage = null;
channel4.OnReceiveMessage = message => { receivedMessage = message; };
channel3.Send(sendMessage);
yield return new WaitUntil(() => !string.IsNullOrEmpty(receivedMessage));
Assert.That(receivedMessage, Is.EqualTo(sendMessage));
// send message from channel4 to channel3
receivedMessage = null;
channel3.OnReceiveMessage = message => { receivedMessage = message; };
channel4.Send(sendMessage);
yield return new WaitUntil(() => !string.IsNullOrEmpty(receivedMessage));
Assert.That(receivedMessage, Is.EqualTo(sendMessage));
container1.test.component.DeleteConnection(connectionId);
container2.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => isStoppedChannel1 && isStoppedChannel2);
Assert.That(isStoppedChannel1, Is.True);
Assert.That(isStoppedChannel2, Is.True);
Assert.That(isStoppedChannel3, Is.False);
Assert.That(isStoppedChannel4, Is.False);
container1.test.component.DeleteConnection(connectionId2);
container4.test.component.DeleteConnection(connectionId2);
yield return new WaitUntil(() => isStoppedChannel3 && isStoppedChannel4);
Assert.That(isStoppedChannel3, Is.True);
Assert.That(isStoppedChannel4, Is.True);
container1.Dispose();
container2.Dispose();
container4.Dispose();
LogAssert.ignoreFailingMessages = false;
}
}
class SingleConnectionTest
{
[SetUp]
public void SetUp()
{
MockSignaling.Reset(true);
}
//todo:: crash in dispose process on standalone Linux and Android
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
public IEnumerator AddAudioStreamSource()
{
string connectionId = "12345";
var container = TestContainer<SingleConnectionBehaviourTest>.Create("test");
var streamer = container.test.gameObject.AddComponent<AudioStreamSenderTester>();
Assert.That(streamer.Track, Is.Null);
Assert.That(streamer.Transceivers, Is.Empty);
container.test.component.AddComponent(streamer);
container.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container.test.component.ExistConnection(connectionId));
Assert.That(streamer.Track, Is.Not.Null);
Assert.That(streamer.Transceivers, Is.Not.Empty);
// SetCodec
streamer.SetCodec(null);
// SetBitrate
var maxBitrate = streamer.maxBitrate;
var minBitrate = streamer.maxBitrate;
streamer.SetBitrate(minBitrate, maxBitrate);
container.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => !container.test.component.ExistConnection(connectionId));
container.Dispose();
}
//todo:: crash in dispose process on standalone Linux and Android
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
public IEnumerator AddVideoStreamSource()
{
string connectionId = "12345";
var container = TestContainer<SingleConnectionBehaviourTest>.Create("test");
var streamer = container.test.gameObject.AddComponent<VideoStreamSenderTester>();
Assert.That(streamer.Track, Is.Null);
Assert.That(streamer.Transceivers, Is.Empty);
container.test.component.AddComponent(streamer);
container.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container.test.component.ExistConnection(connectionId));
Assert.That(streamer.Track, Is.Not.Null);
Assert.That(streamer.Transceivers, Is.Not.Empty);
// SetCodec
streamer.SetCodec(null);
// SetFramerate
var frameRate = streamer.frameRate;
streamer.SetFrameRate(frameRate);
// SetBitrate
var maxBitrate = streamer.maxBitrate;
var minBitrate = streamer.maxBitrate;
streamer.SetBitrate(minBitrate, maxBitrate);
// SetScaleResolutionDown
var scaleFactor = streamer.scaleResolutionDown;
streamer.SetScaleResolutionDown(scaleFactor);
// SetTextureSize
var width = streamer.width;
var height = streamer.height;
streamer.SetTextureSize(new Vector2Int((int)width, (int)height));
container.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => !container.test.component.ExistConnection(connectionId));
container.Dispose();
}
[UnityTest, Timeout(10000)]
public IEnumerator AddDataChannel()
{
string connectionId = "12345";
var container = TestContainer<SingleConnectionBehaviourTest>.Create("test");
var handler = container.test.component;
var channel = container.test.gameObject.AddComponent<DataChannelTest>();
channel.SetLocal(true);
channel.SetLabel("test");
handler.AddComponent(channel);
handler.CreateConnection(connectionId);
yield return new WaitUntil(() => container.test.component.ExistConnection(connectionId));
Assert.That(channel.IsLocal, Is.True);
Assert.That(channel.Label, Is.EqualTo("test"));
container.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => !container.test.component.ExistConnection(connectionId));
container.Dispose();
}
[UnityTest, Timeout(10000)]
public IEnumerator AddSource()
{
string connectionId = "12345";
var container = TestContainer<SingleConnectionBehaviourTest>.Create("test");
var channel = container.test.gameObject.AddComponent<DataChannelTest>();
channel.SetLocal(true);
channel.SetLabel("test");
Assert.That(channel.IsLocal, Is.True);
Assert.That(channel.IsConnected, Is.False);
Assert.That(channel.Label, Is.EqualTo("test"));
container.test.component.AddComponent(channel);
container.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container.test.component.ExistConnection(connectionId));
Assert.That(channel.IsLocal, Is.True);
Assert.That(channel.IsConnected, Is.False);
Assert.That(channel.Label, Is.EqualTo("test"));
container.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => !container.test.component.ExistConnection(connectionId));
container.Dispose();
}
// todo:: Crash in dispose process on Linux standalone
// todo:: Timeout error on iPhonePlayer
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.IPhonePlayer, RuntimePlatform.Android })]
public IEnumerator ReceiveStream()
{
string connectionId = "12345";
var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
var streamer = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
bool isStartedStream0 = false;
bool isStoppedStream0 = false;
streamer.OnStartedStream += _ => isStartedStream0 = true;
streamer.OnStoppedStream += _ => isStoppedStream0 = true;
container1.test.component.AddComponent(streamer);
container1.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedStream0);
Assert.That(isStartedStream0, Is.True);
var receiver = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
bool isStartedStream1 = false;
bool isStoppedStream1 = false;
receiver.OnStartedStream += _ => isStartedStream1 = true;
receiver.OnStoppedStream += _ => isStoppedStream1 = true;
Assert.That(receiver.Track, Is.Null);
Assert.That(receiver.Transceiver, Is.Null);
container2.test.component.AddComponent(receiver);
container2.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedStream1);
Assert.That(isStartedStream1, Is.True);
Assert.That(receiver.Track, Is.Not.Null);
Assert.That(receiver.Transceiver, Is.Not.Null);
container1.test.component.DeleteConnection(connectionId);
container2.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => isStoppedStream0 && isStoppedStream1);
Assert.That(isStoppedStream0, Is.True);
Assert.That(isStoppedStream1, Is.True);
container1.Dispose();
container2.Dispose();
}
//todo(kazuki):: Unknown error is occurred on Android
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.Android })]
public IEnumerator ReceiveDataChannel()
{
string connectionId = "12345";
var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
var channel1 = container1.test.gameObject.AddComponent<DataChannelTest>();
bool isStartedChannel1 = false;
bool isStoppedChannel1 = false;
channel1.OnStartedChannel += _ => isStartedChannel1 = true;
channel1.OnStoppedChannel += _ => isStoppedChannel1 = true;
container1.test.component.AddComponent(channel1);
container1.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
var channel2 = container2.test.gameObject.AddComponent<DataChannelTest>();
bool isStartedChannel2 = false;
bool isStoppedChannel2 = false;
channel2.OnStartedChannel += _ => isStartedChannel2 = true;
channel2.OnStoppedChannel += _ => isStoppedChannel2 = true;
channel2.SetLocal(true);
channel2.SetLabel("test");
Assert.That(channel2.IsConnected, Is.False);
Assert.That(channel2.IsLocal, Is.True);
Assert.That(channel2.Label, Is.EqualTo("test"));
container2.test.component.AddComponent(channel2);
container2.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedChannel1 && isStartedChannel2);
Assert.That(isStartedChannel1, Is.True);
Assert.That(isStartedChannel2, Is.True);
Assert.That(channel1.IsLocal, Is.False);
Assert.That(channel1.Label, Is.EqualTo("test"));
Assert.That(channel1.IsConnected, Is.True);
Assert.That(channel2.IsConnected, Is.True);
// send message from channel1 to channel2
string sendMessage = "hello";
string receivedMessage = null;
channel2.OnReceiveMessage = message => { receivedMessage = message; };
channel1.Send(sendMessage);
yield return new WaitUntil(() => !string.IsNullOrEmpty(receivedMessage));
Assert.That(receivedMessage, Is.EqualTo(sendMessage));
// send message from channel2 to channel1
receivedMessage = null;
channel1.OnReceiveMessage = message => { receivedMessage = message; };
channel2.Send(sendMessage);
yield return new WaitUntil(() => !string.IsNullOrEmpty(receivedMessage));
Assert.That(receivedMessage, Is.EqualTo(sendMessage));
container1.test.component.DeleteConnection(connectionId);
container2.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => isStoppedChannel1 && isStoppedChannel2);
Assert.That(isStoppedChannel1, Is.True);
Assert.That(isStoppedChannel2, Is.True);
container1.Dispose();
container2.Dispose();
}
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[] { RuntimePlatform.LinuxPlayer, RuntimePlatform.Android })]
public IEnumerator AssignTransceivers()
{
string connectionId = "12345";
var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
// prepare caller
var videoStreamer1 = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
bool isStartedVideoSourceStream1 = false;
bool isStoppedVideoSourceStream1 = false;
videoStreamer1.OnStartedStream += _ => isStartedVideoSourceStream1 = true;
videoStreamer1.OnStoppedStream += _ => isStoppedVideoSourceStream1 = true;
var audioStreamer1 = container1.test.gameObject.AddComponent<AudioStreamSenderTester>();
bool isStartedAudioSourceStream1 = false;
bool isStoppedAudioSourceStream1 = false;
audioStreamer1.OnStartedStream += _ => isStartedAudioSourceStream1 = true;
audioStreamer1.OnStoppedStream += _ => isStoppedAudioSourceStream1 = true;
var videoReceiver1 = container1.test.gameObject.AddComponent<VideoStreamReceiverTester>();
bool isStartedVideoReceiveStream1 = false;
bool isStoppedVideoReceiveStream1 = false;
videoReceiver1.OnStartedStream += _ => isStartedVideoReceiveStream1 = true;
videoReceiver1.OnStoppedStream += _ => isStoppedVideoReceiveStream1 = true;
var audioReceiver1 = container1.test.gameObject.AddComponent<AudioStreamReceiverTester>();
bool isStartedAudioReceiveStream1 = false;
bool isStoppedAudioReceiveStream1 = false;
audioReceiver1.OnStartedStream += _ => isStartedAudioReceiveStream1 = true;
audioReceiver1.OnStoppedStream += _ => isStoppedAudioReceiveStream1 = true;
container1.test.component.AddComponent(videoStreamer1);
container1.test.component.AddComponent(videoReceiver1);
container1.test.component.AddComponent(audioStreamer1);
container1.test.component.AddComponent(audioReceiver1);
// prepare callee
var videoStreamer2 = container2.test.gameObject.AddComponent<VideoStreamSenderTester>();
bool isStartedVideoSourceStream2 = false;
bool isStoppedVideoSourceStream2 = false;
videoStreamer2.OnStartedStream += _ => isStartedVideoSourceStream2 = true;
videoStreamer2.OnStoppedStream += _ => isStoppedVideoSourceStream2 = true;
var audioStreamer2 = container2.test.gameObject.AddComponent<AudioStreamSenderTester>();
bool isStartedAudioSourceStream2 = false;
bool isStoppedAudioSourceStream2 = false;
audioStreamer2.OnStartedStream += _ => isStartedAudioSourceStream2 = true;
audioStreamer2.OnStoppedStream += _ => isStoppedAudioSourceStream2 = true;
var videoReceiver2 = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
bool isStartedVideoReceiveStream2 = false;
bool isStoppedVideoReceiveStream2 = false;
videoReceiver2.OnStartedStream += _ => isStartedVideoReceiveStream2 = true;
videoReceiver2.OnStoppedStream += _ => isStoppedVideoReceiveStream2 = true;
var audioReceiver2 = container2.test.gameObject.AddComponent<AudioStreamReceiverTester>();
bool isStartedAudioReceiveStream2 = false;
bool isStoppedAudioReceiveStream2 = false;
audioReceiver2.OnStartedStream += _ => isStartedAudioReceiveStream2 = true;
audioReceiver2.OnStoppedStream += _ => isStoppedAudioReceiveStream2 = true;
container2.test.component.AddComponent(videoStreamer2);
container2.test.component.AddComponent(videoReceiver2);
container2.test.component.AddComponent(audioStreamer2);
container2.test.component.AddComponent(audioReceiver2);
// start signaling
container1.test.component.CreateConnection(connectionId);
container2.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() =>
container1.test.component.ExistConnection(connectionId) &&
container2.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedVideoSourceStream1 && isStartedAudioSourceStream1 && isStartedVideoSourceStream2 && isStartedAudioSourceStream2);
yield return new WaitUntil(() => isStartedVideoReceiveStream1 && isStartedAudioReceiveStream1 && isStartedVideoReceiveStream2 && isStartedAudioReceiveStream2);
yield return new WaitUntil(() =>
container1.test.component.IsStable(connectionId) && container2.test.component.IsStable(connectionId));
var transceivers1 = container1.instance.GetTransceivers(connectionId).ToList();
var count1 = transceivers1.Count;
Assert.That(count1, Is.EqualTo(4), $"{nameof(transceivers1)} count is {count1}");
Assert.That(transceivers1.Select(x => x.Direction),
Is.EquivalentTo(new[]
{
RTCRtpTransceiverDirection.SendOnly, RTCRtpTransceiverDirection.SendOnly,
RTCRtpTransceiverDirection.RecvOnly, RTCRtpTransceiverDirection.RecvOnly,
}));
var transceivers2 = container2.instance.GetTransceivers(connectionId).ToList();
var count2 = transceivers2.Count;
Assert.That(count2, Is.EqualTo(4), $"{nameof(transceivers2)} count is {count2}");
Assert.That(transceivers2.Select(x => x.Direction),
Is.EquivalentTo(new[]
{
RTCRtpTransceiverDirection.SendOnly, RTCRtpTransceiverDirection.SendOnly,
RTCRtpTransceiverDirection.RecvOnly, RTCRtpTransceiverDirection.RecvOnly,
}));
container1.test.component.DeleteConnection(connectionId);
container2.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => isStoppedVideoSourceStream1 && isStoppedAudioSourceStream1 && isStoppedVideoSourceStream2 && isStoppedAudioSourceStream2);
yield return new WaitUntil(() => isStoppedVideoReceiveStream1 && isStoppedAudioReceiveStream1 && isStoppedVideoReceiveStream2 && isStoppedAudioReceiveStream2);
yield return new WaitUntil(() =>
!container1.test.component.ExistConnection(connectionId) &&
!container2.test.component.ExistConnection(connectionId));
container1.Dispose();
container2.Dispose();
}
//todo:: crash in dispose process on standalone linux
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[]
{
RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor,
RuntimePlatform.LinuxPlayer, RuntimePlatform.Android
})]
public IEnumerator SetCodecOnSender()
{
string connectionId = "12345";
var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
var streamer = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
bool isStartedStream0 = false;
bool isStoppedStream0 = false;
streamer.OnStartedStream += _ => isStartedStream0 = true;
streamer.OnStoppedStream += _ => isStoppedStream0 = true;
var codec = VideoStreamSender.GetAvailableCodecs().FirstOrDefault(x => x.mimeType.Contains("VP9"));
Assert.That(codec, Is.Not.Null);
streamer.SetCodec(codec);
container1.test.component.AddComponent(streamer);
container1.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedStream0);
Assert.That(isStartedStream0, Is.True);
var receiver = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
bool isStartedStream1 = false;
bool isStoppedStream1 = false;
receiver.OnStartedStream += _ => isStartedStream1 = true;
receiver.OnStoppedStream += _ => isStoppedStream1 = true;
Assert.That(receiver.Track, Is.Null);
Assert.That(receiver.Transceiver, Is.Null);
container2.test.component.AddComponent(receiver);
container2.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedStream1);
Assert.That(isStartedStream1, Is.True);
Assert.That(receiver.Track, Is.Not.Null);
Assert.That(receiver.Transceiver, Is.Not.Null);
RTCCodecStats senderCodecStats = null;
while (senderCodecStats == null)
{
var statsOp = streamer.Transceivers[connectionId].Sender.GetStats();
yield return statsOp;
Assert.That(statsOp.IsError, Is.False);
var outboundStats =
statsOp.Value.Stats.Values.FirstOrDefault(x =>
x is RTCOutboundRTPStreamStats stats && stats.kind == "video") as RTCOutboundRTPStreamStats;
if (outboundStats == null || string.IsNullOrEmpty(outboundStats.codecId))
{
yield return new WaitForSeconds(0.1f);
continue;
}
senderCodecStats =
statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == outboundStats.codecId) as RTCCodecStats;
}
Assert.That(senderCodecStats.mimeType, Is.EqualTo(codec.mimeType));
Assert.That(senderCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
RTCCodecStats receiverCodecStats = null;
while (receiverCodecStats == null)
{
var statsOp = receiver.Transceiver.Receiver.GetStats();
yield return statsOp;
Assert.That(statsOp.IsError, Is.False);
var inboundStats =
statsOp.Value.Stats.Values.FirstOrDefault(x =>
x is RTCInboundRTPStreamStats stats && stats.kind == "video") as RTCInboundRTPStreamStats;
if (inboundStats == null || string.IsNullOrEmpty(inboundStats.codecId))
{
yield return new WaitForSeconds(0.1f);
continue;
}
receiverCodecStats =
statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == inboundStats.codecId) as RTCCodecStats;
}
Assert.That(receiverCodecStats.mimeType, Is.EqualTo(codec.mimeType));
Assert.That(receiverCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
container1.test.component.DeleteConnection(connectionId);
container2.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => isStoppedStream0 && isStoppedStream1);
Assert.That(isStoppedStream0, Is.True);
Assert.That(isStoppedStream1, Is.True);
container1.Dispose();
container2.Dispose();
}
//todo:: crash in dispose process on standalone linux
[UnityTest, Timeout(10000)]
[UnityPlatform(exclude = new[]
{
RuntimePlatform.WindowsEditor, RuntimePlatform.OSXEditor, RuntimePlatform.LinuxEditor,
RuntimePlatform.LinuxPlayer, RuntimePlatform.Android
})]
public IEnumerator SetCodecOnReceiver()
{
string connectionId = "12345";
var container1 = TestContainer<SingleConnectionBehaviourTest>.Create("test1");
var container2 = TestContainer<SingleConnectionBehaviourTest>.Create("test2");
var streamer = container1.test.gameObject.AddComponent<VideoStreamSenderTester>();
bool isStartedStream0 = false;
bool isStoppedStream0 = false;
streamer.OnStartedStream += _ => isStartedStream0 = true;
streamer.OnStoppedStream += _ => isStoppedStream0 = true;
container1.test.component.AddComponent(streamer);
container1.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container1.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedStream0);
Assert.That(isStartedStream0, Is.True);
var receiver = container2.test.gameObject.AddComponent<VideoStreamReceiverTester>();
bool isStartedStream1 = false;
bool isStoppedStream1 = false;
receiver.OnStartedStream += _ => isStartedStream1 = true;
receiver.OnStoppedStream += _ => isStoppedStream1 = true;
var codec = VideoStreamSender.GetAvailableCodecs().FirstOrDefault(x => x.mimeType.Contains("VP9"));
Assert.That(codec, Is.Not.Null);
streamer.SetCodec(codec);
Assert.That(receiver.Track, Is.Null);
Assert.That(receiver.Transceiver, Is.Null);
container2.test.component.AddComponent(receiver);
container2.test.component.CreateConnection(connectionId);
yield return new WaitUntil(() => container2.test.component.ExistConnection(connectionId));
yield return new WaitUntil(() => isStartedStream1);
Assert.That(isStartedStream1, Is.True);
Assert.That(receiver.Track, Is.Not.Null);
Assert.That(receiver.Transceiver, Is.Not.Null);
RTCCodecStats senderCodecStats = null;
while (senderCodecStats == null)
{
var statsOp = streamer.Transceivers[connectionId].Sender.GetStats();
yield return statsOp;
Assert.That(statsOp.IsError, Is.False);
var outboundStats =
statsOp.Value.Stats.Values.FirstOrDefault(x =>
x is RTCOutboundRTPStreamStats stats && stats.kind == "video") as RTCOutboundRTPStreamStats;
if (outboundStats == null || string.IsNullOrEmpty(outboundStats.codecId))
{
yield return new WaitForSeconds(0.1f);
continue;
}
senderCodecStats =
statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == outboundStats.codecId) as RTCCodecStats;
}
Assert.That(senderCodecStats.mimeType, Is.EqualTo(codec.mimeType));
Assert.That(senderCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
RTCCodecStats receiverCodecStats = null;
while (receiverCodecStats == null)
{
var statsOp = receiver.Transceiver.Receiver.GetStats();
yield return statsOp;
Assert.That(statsOp.IsError, Is.False);
var inboundStats =
statsOp.Value.Stats.Values.FirstOrDefault(x =>
x is RTCInboundRTPStreamStats stats && stats.kind == "video") as RTCInboundRTPStreamStats;
if (inboundStats == null || string.IsNullOrEmpty(inboundStats.codecId))
{
yield return new WaitForSeconds(0.1f);
continue;
}
receiverCodecStats =
statsOp.Value.Stats.Values.FirstOrDefault(x => x.Id == inboundStats.codecId) as RTCCodecStats;
}
Assert.That(receiverCodecStats.mimeType, Is.EqualTo(codec.mimeType));
Assert.That(receiverCodecStats.sdpFmtpLine, Is.EqualTo(codec.sdpFmtpLine));
container1.test.component.DeleteConnection(connectionId);
container2.test.component.DeleteConnection(connectionId);
yield return new WaitUntil(() => isStoppedStream0 && isStoppedStream1);
Assert.That(isStoppedStream0, Is.True);
Assert.That(isStoppedStream1, Is.True);
container1.Dispose();
container2.Dispose();
}
}
}