[Remoting][TCSACR-430] Add new APIs for WebRTC 49/265349/31
authorHaesu Gwon <haesu.gwon@samsung.com>
Fri, 15 Oct 2021 09:09:04 +0000 (18:09 +0900)
committerHaesu Gwon <haesu.gwon@samsung.com>
Thu, 16 Jun 2022 07:52:50 +0000 (16:52 +0900)
Change-Id: I2c1515425548f6c5b1b4e04fc0fd1d3a6750b471

39 files changed:
tct-suite-vs/Tizen.WebRTC.Tests/Program.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/Tizen.WebRTC.Tests.csproj [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/Tizen.WebRTC.Tests.sln [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/res/test.h264 [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/shared/res/Tizen.WebRTC.Tests.png [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaCameraSource.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaMicrophoneSource.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketBufferStatusChangedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketSource.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketSourceConfiguration.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaScreenSource.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaSource.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaStreamTrack.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaTestSource.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.DataChannel.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.FrameEncoded.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceCandidate.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceConnectionStateChanged.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceGatheringStateChanged.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.NegotiationNeeded.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.PeerConnectionStateChanged.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.SignalingStateChanged.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.StateChanged.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.TrackAdded.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannel.Events.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannel.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannelEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannelMessageReceivedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCFrameEncodedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceCandidateEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceConnectionStateChangedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceGatheringStateChangedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCPeerConnectionStateChangedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCSignalingStateChangedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCStateChangedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCTrackAddedEventArgs.cs [new file with mode: 0755]
tct-suite-vs/Tizen.WebRTC.Tests/testcase/support/TestBase.cs [new file with mode: 0644]
tct-suite-vs/Tizen.WebRTC.Tests/tizen-manifest.xml [new file with mode: 0755]

diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/Program.cs b/tct-suite-vs/Tizen.WebRTC.Tests/Program.cs
new file mode 100755 (executable)
index 0000000..e1efbb1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using System;
+using NUnitLite.TUnit;
+using AutoTemplate;
+
+namespace XamarinForTizen.Tizen
+{
+
+    class Program : global::Xamarin.Forms.Platform.Tizen.FormsApplication
+    {
+        private static App _app;
+        protected override void OnCreate()
+        {
+            base.OnCreate();
+
+            Console.WriteLine("TCT : OnCreate()");
+            _app = new App();
+            LoadApplication(_app);
+
+            TRunner t = new TRunner();
+            t.LoadTestsuite();
+            t.Execute();
+        }
+
+        public static App getApp()
+        {
+            return _app;
+        }
+        static void Main(string[] args)
+        {
+            Console.WriteLine("TCT : Main()");
+            var app = new Program();
+            global::Xamarin.Forms.Forms.Init(app);
+            app.Run(args);
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/Tizen.WebRTC.Tests.csproj b/tct-suite-vs/Tizen.WebRTC.Tests/Tizen.WebRTC.Tests.csproj
new file mode 100755 (executable)
index 0000000..54c2b9c
--- /dev/null
@@ -0,0 +1,41 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <!-- Property Group for .NET Core Project -->
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>tizen10.0</TargetFramework>
+    <TargetFrameworkIdentifier>Tizen</TargetFrameworkIdentifier>
+  </PropertyGroup>
+
+  <!-- Property Group for Tizen Project -->
+  <PropertyGroup>
+    <TizenCreateTpkOnBuild>true</TizenCreateTpkOnBuild>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>None</DebugType>
+  </PropertyGroup>
+
+  <ItemGroup>
+       <Folder Include="lib\" />
+  </ItemGroup>
+
+  <Import Project="..\Common\dependencies.props" />
+
+  <ItemGroup>
+    <PackageReference Include="Tizen.NET" Version="$(TizenNETVersion)">
+      <ExcludeAssets>Runtime</ExcludeAssets>
+    </PackageReference>
+    <PackageReference Include="Tizen.NET.Sdk" Version="$(TizenNETSdkVersion)" />
+  </ItemGroup>
+
+  <!-- Include Nuget Package for Tizen Project building -->
+  <ItemGroup>
+    <ProjectReference Include="..\Template\AutoTemplate\AutoTemplate.csproj" />
+    <ProjectReference Include="..\Tizen.Multimedia.Support.Library\Tizen.Multimedia.Support.Library.csproj" />
+  </ItemGroup>
+
+</Project>
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/Tizen.WebRTC.Tests.sln b/tct-suite-vs/Tizen.WebRTC.Tests/Tizen.WebRTC.Tests.sln
new file mode 100755 (executable)
index 0000000..950b072
--- /dev/null
@@ -0,0 +1,92 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31424.327
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "nunit.framework", "..\nunit.framework\nunit.framework.csproj", "{B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "nunitlite", "..\nunitlite\nunitlite.csproj", "{FDB8025A-C029-461F-895E-287B4C65939B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Multimedia.Support.Library", "..\Tizen.Multimedia.Support.Library\Tizen.Multimedia.Support.Library.csproj", "{B42F7C98-0918-4141-8C93-4B6263931E6E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoTemplate", "..\Template\AutoTemplate\AutoTemplate.csproj", "{B11ABB0C-C3C1-4B5C-8251-A15628A775F3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.WebRTC.Tests", "Tizen.WebRTC.Tests.csproj", "{BD0FBD95-D0F5-4096-9B28-413A57467CA3}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Debug|x64 = Debug|x64
+               Debug|x86 = Debug|x86
+               Release|Any CPU = Release|Any CPU
+               Release|x64 = Release|x64
+               Release|x86 = Release|x86
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Debug|x64.Build.0 = Debug|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Debug|x86.Build.0 = Debug|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Release|Any CPU.Build.0 = Release|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Release|x64.ActiveCfg = Release|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Release|x64.Build.0 = Release|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Release|x86.ActiveCfg = Release|Any CPU
+               {B9E7C1FD-CB38-42F7-AC43-7BD2E5B4D216}.Release|x86.Build.0 = Release|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Debug|x64.Build.0 = Debug|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Debug|x86.Build.0 = Debug|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Release|Any CPU.Build.0 = Release|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Release|x64.ActiveCfg = Release|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Release|x64.Build.0 = Release|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Release|x86.ActiveCfg = Release|Any CPU
+               {FDB8025A-C029-461F-895E-287B4C65939B}.Release|x86.Build.0 = Release|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Debug|x64.Build.0 = Debug|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Debug|x86.Build.0 = Debug|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Release|Any CPU.Build.0 = Release|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Release|x64.ActiveCfg = Release|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Release|x64.Build.0 = Release|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Release|x86.ActiveCfg = Release|Any CPU
+               {B42F7C98-0918-4141-8C93-4B6263931E6E}.Release|x86.Build.0 = Release|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Debug|x64.Build.0 = Debug|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Debug|x86.Build.0 = Debug|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Release|Any CPU.Build.0 = Release|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Release|x64.ActiveCfg = Release|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Release|x64.Build.0 = Release|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Release|x86.ActiveCfg = Release|Any CPU
+               {B11ABB0C-C3C1-4B5C-8251-A15628A775F3}.Release|x86.Build.0 = Release|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Debug|x64.ActiveCfg = Debug|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Debug|x64.Build.0 = Debug|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Debug|x86.ActiveCfg = Debug|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Debug|x86.Build.0 = Debug|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Release|Any CPU.Build.0 = Release|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Release|x64.ActiveCfg = Release|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Release|x64.Build.0 = Release|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Release|x86.ActiveCfg = Release|Any CPU
+               {BD0FBD95-D0F5-4096-9B28-413A57467CA3}.Release|x86.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {ED382B91-9930-40B6-B3D7-362304C78680}
+       EndGlobalSection
+EndGlobal
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/res/test.h264 b/tct-suite-vs/Tizen.WebRTC.Tests/res/test.h264
new file mode 100755 (executable)
index 0000000..83016b9
Binary files /dev/null and b/tct-suite-vs/Tizen.WebRTC.Tests/res/test.h264 differ
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/shared/res/Tizen.WebRTC.Tests.png b/tct-suite-vs/Tizen.WebRTC.Tests/shared/res/Tizen.WebRTC.Tests.png
new file mode 100755 (executable)
index 0000000..9765b1b
Binary files /dev/null and b/tct-suite-vs/Tizen.WebRTC.Tests/shared/res/Tizen.WebRTC.Tests.png differ
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaCameraSource.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaCameraSource.cs
new file mode 100755 (executable)
index 0000000..4af5b50
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaCameraSource Tests")]
+    public class MediaCameraSourceTests
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Create the MediaCameraSource instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaCameraSource.MediaCameraSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaCameraSource_INIT()
+        {
+            var mediaCameraSource = new MediaCameraSource();
+            Assert.IsNotNull(mediaCameraSource, "MediaCameraSource should not be null.");
+            Assert.IsInstanceOf<MediaCameraSource>(mediaCameraSource, "Should return MediaCameraSource instance.");
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaMicrophoneSource.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaMicrophoneSource.cs
new file mode 100755 (executable)
index 0000000..4abf9c4
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaMicrophoneSource Tests")]
+    public class MediaMicrophoneSourceTests
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Create the MediaMicrophoneSource instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaMicrophoneSource.MediaMicrophoneSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaMicrophoneSource_INIT()
+        {
+            var mediaMicrohponeSource = new MediaMicrophoneSource();
+            Assert.IsNotNull(mediaMicrohponeSource, "MediaMicrophoneSource should not be null.");
+            Assert.IsInstanceOf<MediaMicrophoneSource>(mediaMicrohponeSource, "Should return MediaMicrophoneSource instance.");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test ApplyAudioStreamPolicy whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaMicrophoneSource.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void ApplyAudioStreamPolicy_NO_EXCEPTION()
+        {
+            using (var webRtc = new WebRTC())
+            {
+                var mediaMicrohponeSource = new MediaMicrophoneSource();
+                var audioStreamPolicy = new AudioStreamPolicy(AudioStreamType.Media);
+
+                webRtc.AddSource(mediaMicrohponeSource);
+
+                Assert.That(() => mediaMicrohponeSource.ApplyAudioStreamPolicy(audioStreamPolicy), Throws.Nothing,
+                    "Should not throw exception");
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test ApplyAudioStreamPolicy with null argument whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaMicrophoneSource.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void ApplyAudioStreamPolicy_CHECK_EXCEPTION()
+        {
+            var mediaMicrohponeSource = new MediaMicrophoneSource();
+
+            Assert.That(() => mediaMicrohponeSource.ApplyAudioStreamPolicy(null), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test ApplyAudioStreamPolicy whether throws exception if webrtc is already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaMicrophoneSource.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void ApplyAudioStreamPolicy_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var webRtc = new WebRTC();
+            var mediaMicrohponeSource = new MediaMicrophoneSource();
+            var audioStreamPolicy = new AudioStreamPolicy(AudioStreamType.Media);
+
+            webRtc.AddSource(mediaMicrohponeSource);
+
+            webRtc.Dispose();
+
+            Assert.That(() => mediaMicrohponeSource.ApplyAudioStreamPolicy(audioStreamPolicy),
+                Throws.TypeOf<ObjectDisposedException>(), "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test ApplyAudioStreamPolicy whether throws exception if invalid state.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaMicrophoneSource.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ApplyAudioStreamPolicy_THROWS_IF_INVALID_STATE()
+        {
+            using (var webRtc = new WebRTC())
+            {
+                var mediaMicrohponeSource = new MediaMicrophoneSource();
+                var audioStreamPolicy = new AudioStreamPolicy(AudioStreamType.Media);
+
+                webRtc.AddSource(mediaMicrohponeSource);
+
+                await webRtc.StartAsync();
+
+                Assert.That(() => mediaMicrohponeSource.ApplyAudioStreamPolicy(audioStreamPolicy),
+                    Throws.InvalidOperationException, "Should throw InvalidOperationException");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketBufferStatusChangedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketBufferStatusChangedEventArgs.cs
new file mode 100755 (executable)
index 0000000..39d81a3
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaPacketBufferStatusChangedEventArgs Tests")]
+    public class MediaPacketBufferStatusChangedEventArgsTests : TestBase
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether SourceId returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketBufferStatusChangedEventArgs.SourceId A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SourceId_CHECK_RETURN()
+        {
+            bool needToPush = true;
+
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(
+                    new VideoMediaFormat(MediaFormatVideoMimeType.H264SP, 640, 480));
+                mediaPacketSource.VideoConfiguration.BufferStatusChanged += (s, e) =>
+                {
+                    Assert.IsInstanceOf<uint>(e.SourceId, "Should be uint");
+                    Assert.That(e.SourceId > 0, "Should return valid sourceId");
+
+                    if (needToPush && e.Status == MediaPacketBufferStatus.Underrun)
+                    {
+                        needToPush = false;
+                        new VideoDecoderParser(VideoFilePath).Feed(packet => mediaPacketSource.Push(packet));
+                    }
+                };
+
+                webRtc.AddSource(mediaPacketSource);
+
+                await webRtc.StartAsync();
+            }
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Status returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketBufferStatusChangedEventArgs.Status A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Status_CHECK_RETURN()
+        {
+            bool needToPush = true;
+
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(
+                new VideoMediaFormat(MediaFormatVideoMimeType.H264SP, 640, 480));
+                mediaPacketSource.VideoConfiguration.BufferStatusChanged += (s, e) =>
+                {
+                    Assert.IsInstanceOf<MediaPacketBufferStatus>(e.Status, "Should be uint");
+                    Assert.That(e.Status == MediaPacketBufferStatus.Underrun, "Should return valid status");
+
+                    if (needToPush && e.Status == MediaPacketBufferStatus.Underrun)
+                    {
+                        needToPush = false;
+                        new VideoDecoderParser(VideoFilePath).Feed(packet => mediaPacketSource.Push(packet));
+                    }
+                };
+
+                webRtc.AddSource(mediaPacketSource);
+
+                await webRtc.StartAsync();
+            }
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketBufferStatusChangedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            bool needToPush = true;
+
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(
+                new VideoMediaFormat(MediaFormatVideoMimeType.H264SP, 640, 480));
+                mediaPacketSource.VideoConfiguration.BufferStatusChanged += (s, e) =>
+                {
+                    Assert.AreEqual($"Source ID={e.SourceId}, Buffer status={e.Status}", e.ToString(),
+                        "Should be same string");
+
+                    if (needToPush && e.Status == MediaPacketBufferStatus.Underrun)
+                    {
+                        needToPush = false;
+                        new VideoDecoderParser(VideoFilePath).Feed(packet => mediaPacketSource.Push(packet));
+                    }
+                };
+
+                webRtc.AddSource(mediaPacketSource);
+
+                await webRtc.StartAsync();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketSource.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketSource.cs
new file mode 100755 (executable)
index 0000000..14c717a
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using System;
+using System.Linq;
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaPacketSource Tests")]
+    public class MediaPacketSourceTests : TestBase
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Create the MediaPacketSource instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.MediaPacketSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("COVPARAM", "VideoMediaFormat")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaPacketSource_VIDEO_INIT()
+        {
+            var mediaPacketSource = new MediaPacketSource(VideoDecoderParser.Format);
+
+            Assert.IsNotNull(mediaPacketSource, "MediaPacketSource should not be null.");
+            Assert.IsInstanceOf<MediaPacketSource>(mediaPacketSource, "Should return MediaPacketSource instance.");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Create the MediaPacketSource instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.MediaPacketSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("COVPARAM", "AudioMediaFormat")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaPacketSource_AUDIO_INIT()
+        {
+            var mediaPacketSource = new MediaPacketSource(new AudioMediaFormat(MediaFormatAudioMimeType.Opus, 2, 440000, 16, 64000));
+
+            Assert.IsNotNull(mediaPacketSource, "MediaPacketSource should not be null.");
+            Assert.IsInstanceOf<MediaPacketSource>(mediaPacketSource, "Should return MediaPacketSource instance.");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Create the MediaPacketSource instance with null parameter and check whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.MediaPacketSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTN")]
+        [Property("COVPARAM", "AudioMediaFormat")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaPacketSource_AUDIO_CHECK_EXCEPTION_WITH_NULL_PARAM()
+        {
+            AudioMediaFormat audioMediaFormat = null;
+            Assert.That(() => new MediaPacketSource(audioMediaFormat), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Create the MediaPacketSource instance with null parameter and check whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.MediaPacketSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTN")]
+        [Property("COVPARAM", "VideoMediaFormat")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaPacketSource_VIDEO_CHECK_EXCEPTION_WITH_NULL_PARAM()
+        {
+            VideoMediaFormat videoMediaFormat = null;
+            Assert.That(() => new MediaPacketSource(videoMediaFormat), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Create the MediaPacketSource instance with invalid parameter and check whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.MediaPacketSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTX")]
+        [Property("COVPARAM", "AudioMediaFormat")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaPacketSource_AUDIO_CHECK_EXCEPTION_WITH_INVALID_FORMAT()
+        {
+            var audioMediaFormat = new AudioMediaFormat(MediaFormatAudioMimeType.Dts, 2, 80000, 10, 100);
+            Assert.That(() => new MediaPacketSource(audioMediaFormat), Throws.ArgumentException,
+                "Should throw ArgumentException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether SupportedAudioTypes returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.SupportedAudioTypes A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SupportedAudioTypes_READ_ONLY()
+        {
+            var supportedAudioTypes = MediaPacketSource.SupportedAudioTypes;
+
+            Assert.IsNotNull(supportedAudioTypes, "MediaPacketSource should not be null.");
+            Assert.That(supportedAudioTypes.Contains(MediaFormatAudioMimeType.Vorbis), "Should contain vorbis");
+            Assert.That(supportedAudioTypes.Contains(MediaFormatAudioMimeType.Opus), "Should contain opus");
+            Assert.That(supportedAudioTypes.Contains(MediaFormatAudioMimeType.Pcm), "Should contain pcm");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether SupportedVideoTypes returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.SupportedVideoTypes A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SupportedVideoTypes_READ_ONLY()
+        {
+            var supportedVideoTypes = MediaPacketSource.SupportedVideoTypes;
+
+            Assert.IsNotNull(supportedVideoTypes, "MediaPacketSource should not be null.");
+            Assert.That(supportedVideoTypes.Contains(MediaFormatVideoMimeType.H264HP), "Should contain H264HP");
+            Assert.That(supportedVideoTypes.Contains(MediaFormatVideoMimeType.H264MP), "Should contain H264MP");
+            Assert.That(supportedVideoTypes.Contains(MediaFormatVideoMimeType.H264SP), "Should contain H264SP");
+            Assert.That(supportedVideoTypes.Contains(MediaFormatVideoMimeType.MJpeg), "Should contain MJpeg");
+            Assert.That(supportedVideoTypes.Contains(MediaFormatVideoMimeType.Vp8), "Should contain Vp8");
+            Assert.That(supportedVideoTypes.Contains(MediaFormatVideoMimeType.Vp9), "Should contain Vp9");
+            Assert.That(supportedVideoTypes.Contains(MediaFormatVideoMimeType.I420), "Should contain I420");
+            Assert.That(supportedVideoTypes.Contains(MediaFormatVideoMimeType.NV12), "Should contain NV12");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether AudioConfiguration returns expected valur or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.AudioConfiguration A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AudioConfiguration_READ_ONLY()
+        {
+            var mediaPacketSource = new MediaPacketSource(new AudioMediaFormat(MediaFormatAudioMimeType.Opus, 2, 440000, 16, 64000));
+
+            Assert.IsNull(mediaPacketSource.VideoConfiguration, "VideoConfiguration should be null.");
+            Assert.IsNotNull(mediaPacketSource.AudioConfiguration, "AudioConfiguration should not be null.");
+            Assert.IsInstanceOf<MediaPacketSourceConfiguration>(mediaPacketSource.AudioConfiguration,
+                 "Should return MediaPacketSourceConfiguration instance.");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether VideoConfiguration returns expected valur or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.VideoConfiguration A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void VideoConfiguration_READ_ONLY()
+        {
+            var mediaPacketSource = new MediaPacketSource(VideoDecoderParser.Format);
+
+            Assert.IsNull(mediaPacketSource.AudioConfiguration, "AudioConfiguration should be null.");
+            Assert.IsNotNull(mediaPacketSource.VideoConfiguration, "VideoConfiguration should not be null.");
+            Assert.IsInstanceOf<MediaPacketSourceConfiguration>(mediaPacketSource.VideoConfiguration,
+                "Should return MediaPacketSourceConfiguration instance.");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test Push whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.Push M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Push_CHECK_RETURN()
+        {
+            bool needToPush = true;
+            var tcsPreview = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(
+                        new VideoMediaFormat(MediaFormatVideoMimeType.H264SP, 640, 480));
+                mediaPacketSource.VideoConfiguration.BufferStatusChanged += (s, e) =>
+                {
+                    if (needToPush && e.Status == MediaPacketBufferStatus.Underrun)
+                    {
+                        needToPush = false;
+                        new VideoDecoderParser(VideoFilePath).Feed(packet =>
+                            Assert.That(() => mediaPacketSource.Push(packet), Throws.Nothing, "Should not throw"));
+                    }
+                };
+
+                webRtc.AddSource(mediaPacketSource);
+
+                await webRtc.StartAsync();
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Push before calling AddSource whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.Push M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Push_CHECK_EXCEPTION_WITHOUT_ADDSOURCE()
+        {
+            var mediaPacketSource = new MediaPacketSource(VideoDecoderParser.Format);
+
+            Assert.Throws<InvalidOperationException>(() => mediaPacketSource.Push(MediaPacket.Create(VideoDecoderParser.Format)),
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Push without packet whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.Push M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Push_CHECK_EXCEPTION_ARGUMENT_NULL()
+        {
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(VideoDecoderParser.Format);
+                webRtc.AddSource(mediaPacketSource);
+
+                Assert.Throws<ArgumentNullException>(() => mediaPacketSource.Push(null),
+                    "Should throw ArgumentNullException");
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Push with disposed packet whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.Push M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Push_CHECK_EXCEPTION_WITH_DISPOSED_PACKET()
+        {
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(VideoDecoderParser.Format);
+                webRtc.AddSource(mediaPacketSource);
+
+                var packet = MediaPacket.Create(VideoDecoderParser.Format);
+                packet.Dispose();
+
+                Assert.Throws<ObjectDisposedException>(() => mediaPacketSource.Push(packet),
+                    "Should throw ObjectDisposedException");
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Push with invalid format type whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.Push M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Push_CHECK_EXCEPTION_WITH_TYPE_MISMATCH()
+        {
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(VideoDecoderParser.Format);
+                webRtc.AddSource(mediaPacketSource);
+
+                var packet = MediaPacket.Create(new TextMediaFormat(MediaFormatTextMimeType.MP4, MediaFormatTextType.MP4));
+
+                Assert.Throws<ArgumentException>(() => mediaPacketSource.Push(packet),
+                    "Should throw ArgumentException");
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Push with invalid format type whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSource.Push M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Push_CHECK_EXCEPTION_WITH_TYPE_MISMATCH_AUDIO()
+        {
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(VideoDecoderParser.Format);
+                webRtc.AddSource(mediaPacketSource);
+
+                var packet = MediaPacket.Create(new AudioMediaFormat(MediaFormatAudioMimeType.Vorbis, 2, 44000, 8, 16));
+
+                Assert.Throws<ArgumentException>(() => mediaPacketSource.Push(packet),
+                    "Should throw ArgumentException");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketSourceConfiguration.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaPacketSourceConfiguration.cs
new file mode 100755 (executable)
index 0000000..4ddbc0f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaPacketSourceConfiguration Tests")]
+    public class MediaPacketSourceConfigurationTests : TestBase
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether BufferStatusChanged event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaPacketSourceConfiguration.BufferStatusChanged E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task BufferStatusChanged_CHECK_RETURN()
+        {
+            bool needToPush = true;
+            var tcsBufferStateChanged = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var webRtc = new WebRTC())
+            {
+                var mediaPacketSource = new MediaPacketSource(
+                        new VideoMediaFormat(MediaFormatVideoMimeType.H264SP, 640, 480));
+                mediaPacketSource.VideoConfiguration.BufferStatusChanged += (s, e) =>
+                {
+                    if (needToPush && e.Status == MediaPacketBufferStatus.Underrun)
+                    {
+                        needToPush = false;
+                        new VideoDecoderParser(VideoFilePath).Feed(packet => mediaPacketSource.Push(packet));
+
+                        tcsBufferStateChanged.TrySetResult(true);
+                    }
+                };
+
+                webRtc.AddSource(mediaPacketSource);
+
+                await webRtc.StartAsync();
+
+                Assert.That(await tcsBufferStateChanged.Task, "Event should be raised");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaScreenSource.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaScreenSource.cs
new file mode 100755 (executable)
index 0000000..c8c4ce5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaScreenSource Tests")]
+    public class MediaScreenSourceTests
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Create the MediaScreenSource instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaScreenSource.MediaScreenSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaScreenSource_INIT()
+        {
+            var mediaScreenSource = new MediaScreenSource();
+            Assert.IsNotNull(mediaScreenSource, "MediaScreenSource should not be null.");
+            Assert.IsInstanceOf<MediaScreenSource>(mediaScreenSource, "Should return MediaScreenSource instance.");
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaSource.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaSource.cs
new file mode 100755 (executable)
index 0000000..d3196f2
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaSource Tests")]
+    public class MediaSourceTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether TransceiverDirection returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.TransceiverDirection A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void TransceiverDirection_READ_WRITE()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            source.TransceiverDirection = TransceiverDirection.SendOnly;
+            Assert.That(source.TransceiverDirection == TransceiverDirection.SendOnly,
+                "Should return same value");
+
+            source.TransceiverDirection = TransceiverDirection.RecvOnly;
+            Assert.That(source.TransceiverDirection == TransceiverDirection.RecvOnly,
+                "Should return same value");
+
+            source.TransceiverDirection = TransceiverDirection.SendRecv;
+            Assert.That(source.TransceiverDirection == TransceiverDirection.SendRecv,
+                "Should return same value");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether TransceiverDirection throws exception when it's not attached.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.TransceiverDirection A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void TransceiverDirection_THROWS_IF_NOT_ATTACHED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+
+            Assert.That(() => source.TransceiverDirection = TransceiverDirection.SendOnly, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+
+            Assert.That(() => source.TransceiverDirection, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether TransceiverDirection throws exception when it's already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.TransceiverDirection A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void TransceiverDirection_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            _offerClient.Dispose();
+
+            Assert.That(() => source.TransceiverDirection, Throws.TypeOf<ObjectDisposedException>(),
+                "Should return ObjectDisposedException");
+
+            Assert.That(() => source.TransceiverDirection = TransceiverDirection.SendOnly, Throws.TypeOf<ObjectDisposedException>(),
+                "Should return ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Pause returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.Pause A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Pause_READ_WRITE()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            source.Pause = true;
+            Assert.That(source.Pause == true, "Should return same value");
+
+            source.Pause = false;
+            Assert.That(source.Pause == false, "Should return same value");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether Pause throws exception when it's not attached.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.Pause A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Pause_THROWS_IF_NOT_ATTACHED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+
+            Assert.That(() => source.Pause = true, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+
+            Assert.That(() => source.Pause, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether Pause throws exception when it's already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.Pause A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Pause_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            _offerClient.Dispose();
+
+            Assert.That(() => source.Pause, Throws.TypeOf<ObjectDisposedException>(),
+                "Should return ObjectDisposedException");
+
+            Assert.That(() => source.Pause = true, Throws.TypeOf<ObjectDisposedException>(),
+                "Should return ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Mute returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.Mute A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Mute_READ_WRITE()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            source.Mute = true;
+            Assert.That(source.Mute == true, "Should return same value");
+
+            source.Mute = false;
+            Assert.That(source.Mute == false, "Should return same value");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether Mute throws exception when it's not attached.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.Mute A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Mute_THROWS_IF_NOT_ATTACHED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+
+            Assert.That(() => source.Mute = true, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+
+            Assert.That(() => source.Mute, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether Mute throws exception when it's already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.Mute A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Mute_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            _offerClient.Dispose();
+
+            Assert.That(() => source.Mute, Throws.TypeOf<ObjectDisposedException>(),
+                "Should return ObjectDisposedException");
+
+            Assert.That(() => source.Mute = true, Throws.TypeOf<ObjectDisposedException>(),
+                "Should return ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether VideoResolution returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.VideoResolution A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void VideoResolution_READ_WRITE()
+        {
+            var size = new Size(640, 480);
+
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            source.VideoResolution = size;
+            Assert.That(source.VideoResolution == size, "Should return same value");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether VideoResolution throws exception when it's not attached.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.VideoResolution A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void VideoResolution_THROWS_IF_NOT_ATTACHED()
+        {
+            var size = new Size(640, 480);
+
+            var source = new MediaTestSource(MediaType.Video);
+
+            Assert.That(() => source.VideoResolution = size, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+
+            Assert.That(() => source.VideoResolution, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether VideoResolution throws exception when it's already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.VideoResolution A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void VideoResolution_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var size = new Size(640, 480);
+
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            _offerClient.Dispose();
+
+            Assert.That(() => source.VideoResolution, Throws.TypeOf<ObjectDisposedException>(),
+                "Should return ObjectDisposedException");
+
+            Assert.That(() => source.VideoResolution = size, Throws.TypeOf<ObjectDisposedException>(),
+                "Should return ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether VideoResolution throws exception when it's already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.VideoResolution A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void VideoResolution_THROWS_IF_SOURCE_IS_NOT_VIDEO_TYPE()
+        {
+            var size = new Size(640, 480);
+
+            var source = new MediaTestSource(MediaType.Audio);
+            _offerClient.AddSource(source);
+
+            Assert.That(() => source.VideoResolution, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+
+            Assert.That(() => source.VideoResolution = size, Throws.InvalidOperationException,
+                "Should return InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test EnableAudioLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableAudioLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableAudioLoopback_CHECK_RETURN()
+        {
+            var source = new MediaTestSource(MediaType.Audio);
+            _offerClient.AddSource(source);
+
+            var mediaStreamTrack = source.EnableAudioLoopback(new AudioStreamPolicy(AudioStreamType.Media));
+
+            Assert.IsNotNull(mediaStreamTrack, "Should not null");
+            Assert.IsInstanceOf<MediaStreamTrack>(mediaStreamTrack, "Should return MediaStreamTrack instance");
+            Assert.That(mediaStreamTrack.Type == MediaType.Audio, "Should be same value");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check EnableAudioLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableAudioLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableAudioLoopback_THROWS_POLICY_IS_NULL()
+        {
+            var source = new MediaTestSource(MediaType.Audio);
+            _offerClient.AddSource(source);
+
+            Assert.That(() => source.EnableAudioLoopback(null), Throws.ArgumentNullException,
+                "Should throws ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check EnableAudioLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableAudioLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableAudioLoopback_THROWS_SOURCE_IS_NOT_AUDIO()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            Assert.That(() => source.EnableAudioLoopback(new AudioStreamPolicy(AudioStreamType.Media)),
+                Throws.InvalidOperationException, "Should throws InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check EnableAudioLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableAudioLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableAudioLoopback_THROWS_POLICY_ALREADY_DISPOSED()
+        {
+            var source = new MediaTestSource(MediaType.Audio);
+            _offerClient.AddSource(source);
+
+            var policy = new AudioStreamPolicy(AudioStreamType.Media);
+            policy.Dispose();
+
+            Assert.That(() => source.EnableAudioLoopback(policy),
+                Throws.TypeOf<ObjectDisposedException>(), "Should throws ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check EnableAudioLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableAudioLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableAudioLoopback_THROWS_WEBRTC_ALREADY_DISPOSED()
+        {
+            var source = new MediaTestSource(MediaType.Audio);
+            _offerClient.AddSource(source);
+
+            var policy = new AudioStreamPolicy(AudioStreamType.Media);
+            _offerClient.Dispose();
+
+            Assert.That(() => source.EnableAudioLoopback(policy),
+                Throws.TypeOf<ObjectDisposedException>(), "Should throws ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test EnableVideoLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableVideoLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableVideoLoopback_CHECK_RETURN()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+            var mediaStreamTrack = source.EnableVideoLoopback(new Display(CreateWindow()));
+
+            Assert.IsNotNull(mediaStreamTrack, "Should not null");
+            Assert.IsInstanceOf<MediaStreamTrack>(mediaStreamTrack, "Should return MediaStreamTrack instance");
+            Assert.That(mediaStreamTrack.Type == MediaType.Video, "Should be same value");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check EnableVideoLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableVideoLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableVideoLoopback_THROWS_DISPLAY_IS_ALREADY_ALLOCATED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            var display = new Display(CreateWindow());
+            _offerClient.AddSource(source);
+
+            var mediaStreamTrack = source.EnableVideoLoopback(display);
+
+            Assert.That(() => source.EnableVideoLoopback(display), Throws.ArgumentException,
+                "Should throws ArgumentException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check EnableVideoLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableVideoLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableVideoLoopback_THROWS_POLICY_IS_NULL()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            Assert.That(() => source.EnableVideoLoopback(null), Throws.ArgumentNullException,
+                "Should throws ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check EnableVideoLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableVideoLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableVideoLoopback_THROWS_SOURCE_IS_NOT_VIDEO()
+        {
+            var source = new MediaTestSource(MediaType.Audio);
+            _offerClient.AddSource(source);
+
+            Assert.That(() => source.EnableVideoLoopback(new Display(CreateWindow())),
+                Throws.InvalidOperationException, "Should throws InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check EnableVideoLoopback whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaSource.EnableVideoLoopback M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void EnableVideoLoopback_THROWS_ALREADY_DISPOSED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(source);
+
+            _offerClient.Dispose();
+
+            Assert.That(() => source.EnableVideoLoopback(new Display(CreateWindow())),
+                Throws.TypeOf<ObjectDisposedException>(), "Should throws ObjectDisposedException");
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaStreamTrack.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaStreamTrack.cs
new file mode 100755 (executable)
index 0000000..8d91ad5
--- /dev/null
@@ -0,0 +1,562 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaStreamTrack Tests")]
+    public class MeidaStreamTrackTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+        }
+
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Type returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.Type A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Type_READ_ONLY()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                Assert.That(e.MediaStreamTrack.Type == MediaType.Audio, "Should return same value");
+
+                tcsAnswerTrackAdded.TrySetResult(true);
+            };
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Audio));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            await tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Display returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.Display A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Display_READ_ONLY()
+        {
+            var answerWindow = CreateWindow();
+
+            var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                Assert.DoesNotThrow(() => e.MediaStreamTrack.Display = new Display(answerWindow),
+                    "Should not throw exception");
+
+                tcsAnswerTrackAdded.TrySetResult(true);
+            };
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            await tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether Display throw exception when the Type of MediaStreamTrack is Audio.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.Display A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Display_THROWS_IF_INVALID_MEDIATYPE()
+        {
+            var window = CreateWindow();
+
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                Assert.That(() => e.MediaStreamTrack.Display = new Display(window), Throws.InvalidOperationException,
+                    "Should throw InvalidOperationException");
+
+                tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+            };
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Audio));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            await tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether Display throw exception when Display is not called in TrackAdded event.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.Display A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Display_THROWS_IF_NOT_CALLED_IN_TRACKADDED_EVENT()
+        {
+            var window = CreateWindow();
+
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var mediaStreamTrack = await tcsAnswerTrackAdded.Task;
+
+            Assert.That(() => mediaStreamTrack.Display = new Display(window), Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether DisplayMode returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.DisplayMode A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DisplayMode_READ_WRITE()
+        {
+            var answerWindow = CreateWindow();
+
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                e.MediaStreamTrack.Display = new Display(answerWindow);
+
+                tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+            };
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var track = await tcsAnswerTrackAdded.Task;
+
+            Assert.That(() => track.DisplayMode = WebRTCDisplayMode.OriginSize, Throws.Nothing,
+                "Should not throw exception");
+
+            Assert.That(() => track.DisplayMode, Is.EqualTo(WebRTCDisplayMode.OriginSize),
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether DisplayVisible returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.DisplayVisible A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DisplayVisible_READ_WRITE()
+        {
+            var offerWindow = CreateWindow();
+            var answerWindow = CreateWindow();
+
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                e.MediaStreamTrack.Display = new Display(answerWindow);
+
+                tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+            };
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var track = await tcsAnswerTrackAdded.Task;
+
+            Assert.That(() => track.DisplayVisible = true, Throws.Nothing,
+                "Should not throw exception");
+
+            Assert.That(() => track.DisplayVisible, Is.EqualTo(true),
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether DisplayMode throws exception when Display property is not set.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.DisplayMode A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DisplayMode_THROWS_IF_DISPLAY_IS_NOT_SET()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var track = await tcsAnswerTrackAdded.Task;
+
+            Assert.That(() => track.DisplayMode = WebRTCDisplayMode.OriginSize, Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether DisplayMode throws exception when input invalid DisplayMode.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.DisplayMode A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DisplayMode_THROWS_IF_INVALID_DISPLAYMODE()
+        {
+            var window = CreateWindow();
+
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                e.MediaStreamTrack.Display = new Display(window);
+                tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+            };
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var track = await tcsAnswerTrackAdded.Task;
+
+            Assert.That(() => track.DisplayMode = (WebRTCDisplayMode)4, Throws.ArgumentException,
+                "Should throw ArgumentException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether DisplayMode throws exception when the Type of MediaStreamTrack is Audio.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.DisplayMode A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DisplayMode_THROWS_IF_INVALID_MEDIATYPE()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Audio));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var track = await tcsAnswerTrackAdded.Task;
+
+            Assert.That(() => track.DisplayMode = WebRTCDisplayMode.OriginSize, Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether DisplayVisible throws exception when Display property is not set.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.DisplayVisible A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DisplayVisible_THROWS_IF_DISPLAY_IS_NOT_SET()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var track = await tcsAnswerTrackAdded.Task;
+
+            Assert.That(() => track.DisplayVisible = true, Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether DisplayVisible throws exception when the Type of MediaStreamTrack is Audio.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.DisplayVisible A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DisplayVisible_THROWS_IF_INVALID_MEDIATYPE()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Audio));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var track = await tcsAnswerTrackAdded.Task;
+
+            Assert.That(() => track.DisplayVisible = true, Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ApplyAudioStreamPolicy returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ApplyAudioStreamPolicy_CHECK_RETURN()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                var policy = new AudioStreamPolicy(AudioStreamType.Media);
+                Assert.That(() => e.MediaStreamTrack.ApplyAudioStreamPolicy(policy), Throws.Nothing,
+                    "Should not throw exception");
+
+                tcsAnswerTrackAdded.TrySetResult(true);
+            };
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Audio));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            Assert.That(await tcsAnswerTrackAdded.Task, "Event shoud be raised");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether ApplyAudioStreamPolicy throws exception when it's not called in TrackAdded event.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ApplyAudioStreamPolicy_THROWS_IF_NOT_CALLED_IN_TRACKADDED_EVENT()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Audio));
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var track = await tcsAnswerTrackAdded.Task;
+
+            var policy = new AudioStreamPolicy(AudioStreamType.Media);
+            Assert.That(() => track.ApplyAudioStreamPolicy(policy), Throws.InvalidOperationException,
+                "InvalidOperationException should be thrown");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether ApplyAudioStreamPolicy throws exception when AudioFrameEncoded event is set.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ApplyAudioStreamPolicy_THROWS_IF_AUDIOFRAMEENCODED_IS_SET()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                var policy = new AudioStreamPolicy(AudioStreamType.Media);
+
+                try
+                {
+                    e.MediaStreamTrack.ApplyAudioStreamPolicy(policy);
+                }
+                catch (InvalidOperationException)
+                {
+                    tcsAnswerTrackAdded.TrySetResult(true);
+                    return;
+                }
+
+                tcsAnswerTrackAdded.TrySetResult(false);
+            };
+
+            _answerClient.AudioFrameEncoded += (s, e) => Log.Info(LogInfo.Tag, "Enter");
+
+            var offerSource = new MediaTestSource(MediaType.Audio);
+
+            _offerClient.AddSource(offerSource);
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            Assert.That(await tcsAnswerTrackAdded.Task, Is.EqualTo(true),
+                "InvalidOperationException should be thrown");
+
+            offerSource.Pause = true;
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether ApplyAudioStreamPolicy throws exception when policy is already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ApplyAudioStreamPolicy_THROWS_IF_POLICY_IS_DISPOSED()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                var policy = new AudioStreamPolicy(AudioStreamType.Media);
+                policy.Dispose();
+
+                try
+                {
+                    e.MediaStreamTrack.ApplyAudioStreamPolicy(policy);
+                }
+                catch (ObjectDisposedException)
+                {
+                    tcsAnswerTrackAdded.TrySetResult(true);
+                    return;
+                }
+
+                tcsAnswerTrackAdded.TrySetResult(false);
+            };
+
+            _answerClient.AudioFrameEncoded += (s, e) => Log.Info(LogInfo.Tag, "Enter");
+
+            var offerSource = new MediaTestSource(MediaType.Audio);
+
+            _offerClient.AddSource(offerSource);
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            Assert.That(await tcsAnswerTrackAdded.Task, Is.EqualTo(true),
+                "ObjectDisposedException should be thrown");
+
+            offerSource.Pause = true;
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether ApplyAudioStreamPolicy throws exception when policy is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaStreamTrack.ApplyAudioStreamPolicy M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ApplyAudioStreamPolicy_THROWS_IF_NULL_PARAM()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += (s, e) =>
+            {
+                try
+                {
+                    e.MediaStreamTrack.ApplyAudioStreamPolicy(null);
+                }
+                catch (ArgumentNullException)
+                {
+                    tcsAnswerTrackAdded.TrySetResult(true);
+                    return;
+                }
+
+                tcsAnswerTrackAdded.TrySetResult(false);
+            };
+
+            _answerClient.AudioFrameEncoded += (s, e) => Log.Info(LogInfo.Tag, "Enter");
+
+            var offerSource = new MediaTestSource(MediaType.Audio);
+
+            _offerClient.AddSource(offerSource);
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            Assert.That(await tcsAnswerTrackAdded.Task, Is.EqualTo(true),
+                "ObjectDisposedException should be thrown");
+
+            offerSource.Pause = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaTestSource.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSMediaTestSource.cs
new file mode 100755 (executable)
index 0000000..af8a4aa
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.MediaTestSource Tests")]
+    public class MediaTestSourceTests
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Create the MediaCameraMediaTestSourceSource instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaTestSource.MediaTestSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaTestSource_INIT_AUDIO()
+        {
+            var mediaAudioTestSource = new MediaTestSource(MediaType.Audio);
+            Assert.IsNotNull(mediaAudioTestSource, "MediaTestSource should not be null.");
+            Assert.IsInstanceOf<MediaTestSource>(mediaAudioTestSource, "Should return MediaTestSource instance.");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Create the MediaCameraMediaTestSourceSource instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.MediaTestSource.MediaTestSource C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void MediaTestSource_INIT_VIDEO()
+        {
+            var mediaVideoTestSource = new MediaTestSource(MediaType.Audio);
+            Assert.IsNotNull(mediaVideoTestSource, "MediaTestSource should not be null.");
+            Assert.IsInstanceOf<MediaTestSource>(mediaVideoTestSource, "Should return MediaTestSource instance.");
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.DataChannel.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.DataChannel.cs
new file mode 100755 (executable)
index 0000000..b026197
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.DataChannel Tests")]
+    public class DataChannelEventTests : TestBase
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether DataChannel event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.DataChannel E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DataChannel_CHECK_EVENT()
+        {
+            var tcsAnswerDataChannel = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var offerClient = new WebRTC())
+            using (var answerClient = new WebRTC())
+            {
+                offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+                var offerDataChannel = new WebRTCDataChannel(offerClient, "offerClient");
+
+                answerClient.DataChannel += (s, e) => tcsAnswerDataChannel.TrySetResult(true);
+                answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(true);
+
+                await offerClient.StartAsync();
+                await answerClient.StartAsync();
+
+                await ConnectPeerAsync(offerClient, answerClient);
+
+                Assert.That(await tcsAnswerDataChannel.Task, "Event should be raised.");
+
+                await tcsAnswerTrackAdded.Task;
+            }
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.FrameEncoded.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.FrameEncoded.cs
new file mode 100755 (executable)
index 0000000..a18edad
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.FrameEncoded Tests")]
+    public class FrameEncodedEventTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsAnswerAudioFrameEncoded, _tcsAnswerVideoFrameEncoded;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            Initialize();
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsAnswerAudioFrameEncoded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerVideoFrameEncoded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether AudioFrameEncoded event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AudioFrameEncoded E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AudioFrameEncoded_CHECK_EVENT()
+        {
+            _answerClient.AudioFrameEncoded += (s, e) => _tcsAnswerAudioFrameEncoded.TrySetResult(true);
+
+            var offerSource = new MediaTestSource(MediaType.Audio);
+            _offerClient.AddSource(offerSource);
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            Assert.That(await _tcsAnswerAudioFrameEncoded.Task, "Event should be raised");
+
+            offerSource.Pause = true;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether VideoFrameEncoded event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.VideoFrameEncoded E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task VideoFrameEncoded_CHECK_EVENT()
+        {
+            var offerSource = new MediaTestSource(MediaType.Video);
+            _offerClient.AddSource(offerSource);
+
+            _answerClient.VideoFrameEncoded += (s, e) => _tcsAnswerVideoFrameEncoded.TrySetResult(true);
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            Assert.That(await _tcsAnswerVideoFrameEncoded.Task, "Event should be raised");
+
+            offerSource.Pause = true;
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceCandidate.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceCandidate.cs
new file mode 100755 (executable)
index 0000000..2fc5ec2
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.IceCandidate Tests")]
+    public class IceCandidateEventTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether IceCandidate event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.IceCandidate E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task IceCandidate_CHECK_EVENT()
+        {
+            Assert.That(_offerClient.IceConnectionState == WebRTCIceConnectionState.New, "Should be New state");
+            Assert.That(_answerClient.IceConnectionState == WebRTCIceConnectionState.New, "Should be New state");
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            Assert.That(_offerIceCandidate.Count > 0, "Event should be raised");
+            Assert.That(_answerIceCandidate.Count > 0, "Event should be raised");
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task.ConfigureAwait(false);
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceConnectionStateChanged.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceConnectionStateChanged.cs
new file mode 100755 (executable)
index 0000000..80b986f
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.WebRTC.Tests Test class")]
+    public class WebRTCIceConnectionStateChangedEventsTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<bool> _tcsOfferIceConnectionStateCompleted, _tcsAnswerIceConnectionStateCompleted;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceConnectionStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceConnectionStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.IceConnectionStateChanged += OfferIceConnectionStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.IceConnectionStateChanged += AnswerIceConnectionStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceConnectionStateChangeEventHandler(object s, WebRTCIceConnectionStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceConnectionState.Completed)
+            {
+                _tcsOfferIceConnectionStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceConnectionStateChangeEventHandler(object s, WebRTCIceConnectionStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceConnectionState.Completed)
+            {
+                _tcsAnswerIceConnectionStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether IceConnectionStateChanged event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.IceConnectionStateChanged E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task IceConnectionStateChanged_CHECK_EVENT()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            var results = await Task.WhenAll(_tcsOfferIceConnectionStateCompleted.Task, _tcsAnswerIceConnectionStateCompleted.Task);
+            foreach (var result in results)
+            {
+                Assert.That(result, "IceConnectionStateChanged event should be raised");
+            }
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether IceConnectionState returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.IceConnectionState A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task IceConnectionState_READ_ONLY()
+        {
+            Assert.That(_offerClient.IceConnectionState == WebRTCIceConnectionState.New, "Should be New state");
+            Assert.That(_answerClient.IceConnectionState == WebRTCIceConnectionState.New, "Should be New state");
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferIceConnectionStateCompleted.Task, _tcsAnswerIceConnectionStateCompleted.Task);
+
+            Assert.That(_offerClient.IceConnectionState == WebRTCIceConnectionState.Completed, "Should be Completed state");
+            Assert.That(_answerClient.IceConnectionState == WebRTCIceConnectionState.Completed, "Should be Completed state");
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceGatheringStateChanged.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.IceGatheringStateChanged.cs
new file mode 100755 (executable)
index 0000000..0efa291
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.IceGatheringStateChanged Tests")]
+    public class IceGatheringEventTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<bool> _tcsOfferIceConnectionStateCompleted, _tcsAnswerIceConnectionStateCompleted;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceConnectionStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceConnectionStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.IceConnectionStateChanged += OfferIceConnectionStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.IceConnectionStateChanged += AnswerIceConnectionStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Gathering)
+            {
+                Assert.That(_offerClient.IceGatheringState == WebRTCIceGatheringState.Gathering, "Should be Gathering state");
+            }
+            else if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                Assert.That(_offerClient.IceGatheringState == WebRTCIceGatheringState.Completed, "Should be Completed state");
+
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceConnectionStateChangeEventHandler(object s, WebRTCIceConnectionStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceConnectionState.Completed)
+            {
+                _tcsOfferIceConnectionStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Gathering)
+            {
+                Assert.That(_answerClient.IceGatheringState == WebRTCIceGatheringState.Gathering, "Should be Gathering state");
+            }
+            else if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                Assert.That(_answerClient.IceGatheringState == WebRTCIceGatheringState.Completed, "Should be Completed state");
+
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceConnectionStateChangeEventHandler(object s, WebRTCIceConnectionStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceConnectionState.Completed)
+            {
+                _tcsAnswerIceConnectionStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether IceGatheringStateChanged event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.IceGatheringStateChanged E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task IceGatheringStateChanged_CHECK_EVENT()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            Assert.That(_offerClient.IceGatheringState == WebRTCIceGatheringState.New, "Should be New state");
+            Assert.That(_answerClient.IceGatheringState == WebRTCIceGatheringState.New, "Should be New state");
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            var results = await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+            foreach (var result in results)
+            {
+                Assert.That(result, "IceGatheringStateChanged event should be raised");
+            }
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether IceGatheringState returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.IceGatheringState A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task IceGatheringState_READ_ONLY()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            Assert.That(_offerClient.IceGatheringState == WebRTCIceGatheringState.New, "Should be New state");
+            Assert.That(_answerClient.IceGatheringState == WebRTCIceGatheringState.New, "Should be New state");
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            // Checked IceGatheringState(Gathering state) in event handler
+
+            // Checked IceGatheringState(Completed state) in event handler
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.NegotiationNeeded.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.NegotiationNeeded.cs
new file mode 100755 (executable)
index 0000000..efe0f9a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.NegotiationNeeded Tests")]
+    public class NegotiationNeededEventTests
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether NegotiationNeeded event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.NegotiationNeeded E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task NegotiationNeeded_CHECK_EVENT()
+        {
+            using (var webRtc = new WebRTC())
+            using (var EventWaiter = EventAwaiter<EventArgs>.Create())
+            {
+                webRtc.NegotiationNeeded += EventWaiter;
+
+                webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+                webRtc.Start();
+
+                Assert.That(await EventWaiter.IsRaisedAsync(), "Event should be raised.");
+
+                webRtc.NegotiationNeeded -= EventWaiter;
+            }
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.PeerConnectionStateChanged.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.PeerConnectionStateChanged.cs
new file mode 100755 (executable)
index 0000000..2a1aa03
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.PeerConnection Tests")]
+    public class PeerConnectionEventTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<bool> _tcsOfferPeerConnectionStateConnecting, _tcsAnswerPeerConnectionStateConnecting;
+        TaskCompletionSource<bool> _tcsOfferPeerConnectionStateConnected, _tcsAnswerPeerConnectionStateConnected;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferPeerConnectionStateConnecting = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerPeerConnectionStateConnecting = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferPeerConnectionStateConnected = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerPeerConnectionStateConnected = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.PeerConnectionStateChanged += OfferPeerConnectionStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.PeerConnectionStateChanged += AnswerPeerConnectionStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferPeerConnectionStateChangeEventHandler(object s, WebRTCPeerConnectionStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCPeerConnectionState.Connecting)
+            {
+                _tcsOfferPeerConnectionStateConnecting.TrySetResult(true);
+            }
+            else if (e.State == WebRTCPeerConnectionState.Connected)
+            {
+                _tcsOfferPeerConnectionStateConnected.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerPeerConnectionStateChangeEventHandler(object s, WebRTCPeerConnectionStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCPeerConnectionState.Connecting)
+            {
+                _tcsAnswerPeerConnectionStateConnecting.TrySetResult(true);
+            }
+            else if (e.State == WebRTCPeerConnectionState.Connected)
+            {
+                _tcsAnswerPeerConnectionStateConnected.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether PeerConnectionStateChanged event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.PeerConnectionStateChanged E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task PeerConnectionStateChanged_CHECK_EVENT()
+        {
+            Assert.That(_offerClient.PeerConnectionState == WebRTCPeerConnectionState.New, "Should be New state");
+            Assert.That(_answerClient.PeerConnectionState == WebRTCPeerConnectionState.New, "Should be New state");
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferPeerConnectionStateConnecting.Task, _tcsAnswerPeerConnectionStateConnecting.Task);
+
+            Assert.That(_offerClient.PeerConnectionState == WebRTCPeerConnectionState.Connecting, "Should be Connecting state");
+            Assert.That(_answerClient.PeerConnectionState == WebRTCPeerConnectionState.Connecting, "Should be Connecting state");
+
+            await Task.WhenAll(_tcsOfferPeerConnectionStateConnected.Task, _tcsAnswerPeerConnectionStateConnected.Task);
+
+            Assert.That(_offerClient.PeerConnectionState == WebRTCPeerConnectionState.Connected, "Should be Connected state");
+            Assert.That(_answerClient.PeerConnectionState == WebRTCPeerConnectionState.Connected, "Should be Connected state");
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether PeerConnectionState returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.PeerConnectionState A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task PeerConnectionState_READ_ONLY()
+        {
+            Assert.That(_offerClient.PeerConnectionState == WebRTCPeerConnectionState.New, "Should be New state");
+            Assert.That(_answerClient.PeerConnectionState == WebRTCPeerConnectionState.New, "Should be New state");
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferPeerConnectionStateConnecting.Task, _tcsAnswerPeerConnectionStateConnecting.Task);
+
+            Assert.That(_offerClient.PeerConnectionState == WebRTCPeerConnectionState.Connecting, "Should be Connecting state");
+            Assert.That(_answerClient.PeerConnectionState == WebRTCPeerConnectionState.Connecting, "Should be Connecting state");
+
+            await Task.WhenAll(_tcsOfferPeerConnectionStateConnected.Task, _tcsAnswerPeerConnectionStateConnected.Task);
+
+            Assert.That(_offerClient.PeerConnectionState == WebRTCPeerConnectionState.Connected, "Should be Connected state");
+            Assert.That(_answerClient.PeerConnectionState == WebRTCPeerConnectionState.Connected, "Should be Connected state");
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.SignalingStateChanged.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.SignalingStateChanged.cs
new file mode 100755 (executable)
index 0000000..6ee211e
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.SignalingStateChanged Tests")]
+    public class SignalingStateChangedEventTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<bool> _tcsOfferSignalingStateHaveLocalOffer, _tcsAnswerSignalingStateHaveRemoteOffer;
+        TaskCompletionSource<bool> _tcsOfferSignalingStateStable, _tcsAnswerSignalingStateStable;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferSignalingStateHaveLocalOffer = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerSignalingStateHaveRemoteOffer = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferSignalingStateStable = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerSignalingStateStable = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.SignalingStateChanged += OfferSignalingStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.SignalingStateChanged += AnswerSignalingStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferSignalingStateChangeEventHandler(object s, WebRTCSignalingStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCSignalingState.HaveLocalOffer)
+            {
+                _tcsOfferSignalingStateHaveLocalOffer.TrySetResult(true);
+            }
+            else if (e.State == WebRTCSignalingState.Stable)
+            {
+                _tcsOfferSignalingStateStable.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerSignalingStateChangeEventHandler(object s, WebRTCSignalingStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCSignalingState.HaveRemoteOffer)
+            {
+                _tcsAnswerSignalingStateHaveRemoteOffer.TrySetResult(true);
+            }
+            else if (e.State == WebRTCSignalingState.Stable)
+            {
+                _tcsAnswerSignalingStateStable.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether SignalingStateChanged event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SignalingStateChanged E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SignalingStateChanged_CHECK_EVENT()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await _tcsOfferSignalingStateHaveLocalOffer.Task;
+            Assert.That(_offerClient.SignalingState == WebRTCSignalingState.HaveLocalOffer, "Should be HaveLocalOffer state");
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            Assert.That(_answerClient.SignalingState == WebRTCSignalingState.HaveRemoteOffer, "Should be HaveRemoteOffer state");
+
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            Assert.That(_offerClient.SignalingState == WebRTCSignalingState.Stable, "Should be Stable state");
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether SignalingState returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SignalingState A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SignalingState_READ_ONLY()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await _tcsOfferSignalingStateHaveLocalOffer.Task;
+            Assert.That(_offerClient.SignalingState == WebRTCSignalingState.HaveLocalOffer, "Should be HaveLocalOffer state");
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+
+            Assert.That(_answerClient.SignalingState == WebRTCSignalingState.HaveRemoteOffer, "Should be HaveRemoteOffer state");
+
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            Assert.That(_offerClient.SignalingState == WebRTCSignalingState.Stable, "Should be Stable state");
+
+            await _tcsAnswerSignalingStateStable.Task;
+            Assert.That(_answerClient.SignalingState == WebRTCSignalingState.Stable, "Should be Stable state");
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.StateChanged.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.StateChanged.cs
new file mode 100755 (executable)
index 0000000..9135a5d
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.StateChanged Tests")]
+    public class StateChangedEventTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStateNegotiating, _tcsAnswerStateNegotiating;
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStateNegotiating = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStateNegotiating = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Negotiating)
+            {
+                _tcsOfferStateNegotiating.TrySetResult(true);
+            }
+            else if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Negotiating)
+            {
+                _tcsAnswerStateNegotiating.TrySetResult(true);
+            }
+            else if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether StateChanged event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.StateChanged E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task StateChanged_CHECK_EVENT()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            var results = await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+            foreach (var result in results)
+            {
+                Assert.That(result == true, "Event should be raised");
+            }
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether State returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.State A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task State_READ_ONLY()
+        {
+            Assert.That(_offerClient.State == WebRTCState.Idle, "Should be Idle state");
+            Assert.That(_answerClient.State == WebRTCState.Idle, "Should be Idle state");
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            Assert.That(_offerClient.State == WebRTCState.Negotiating, "Should be Negotiating state");
+            Assert.That(_answerClient.State == WebRTCState.Negotiating, "Should be Negotiating state");
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            Assert.That(_offerClient.State == WebRTCState.Playing, "Should be Playing state");
+            Assert.That(_answerClient.State == WebRTCState.Playing, "Should be Playing state");
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.TrackAdded.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.Events.TrackAdded.cs
new file mode 100755 (executable)
index 0000000..727e78f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.TrackAdded Tests")]
+    public class TrackAddedEventTests : TestBase
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether TrackAdded event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.TrackAdded E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task TrackAdded_CHECK_EVENT()
+        {
+            using (var offerClient = new WebRTC())
+            using (var answerClient = new WebRTC())
+            {
+                var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+                offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+                answerClient.TrackAdded += (s, e) =>
+                {
+                    tcsAnswerTrackAdded.TrySetResult(true);
+                };
+
+                await offerClient.StartAsync();
+                await answerClient.StartAsync();
+
+                await ConnectPeerAsync(offerClient, answerClient);
+
+                Assert.That(await tcsAnswerTrackAdded.Task, "TrackAdded event Should be raised");
+            }
+
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTC.cs
new file mode 100755 (executable)
index 0000000..41324de
--- /dev/null
@@ -0,0 +1,1136 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTC Tests")]
+    public class WebRTCTests : TestBase
+    {
+        private WebRTC _webRtc;
+
+        private readonly string _turnServer = "https://turnserver.address";
+
+        [SetUp]
+        public void Init()
+        {
+            _webRtc = new WebRTC();
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _webRtc?.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Create the WebRTC instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.WebRTC C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void WebRTC_INIT()
+        {
+            var webRtc = new WebRTC();
+            Assert.IsNotNull(webRtc, "webRtc should not be null.");
+            Assert.IsInstanceOf<WebRTC>(webRtc, "Should return WebRTC instance.");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test Start whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.Start M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Start_NO_EXCEPTION()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            Assert.That(() => _webRtc.Start(), Throws.Nothing, "Should not throw exception");
+
+            using (var eventWaiter = EventAwaiter<WebRTCStateChangedEventArgs>.Create())
+            {
+                try
+                {
+                    _webRtc.StateChanged += eventWaiter;
+                    await eventWaiter.IsRaisedAsync();
+                }
+                finally
+                {
+                    _webRtc.StateChanged -= eventWaiter;
+                }
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Start whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.Start M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Start_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.Start(), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Start whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.Start M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Start_THROWS_IF_INVALID_STATE()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.Start(), Throws.TypeOf<InvalidOperationException>(),
+                "Should throw InvalidOperationException for invalid state");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test StartAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.StartAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task StartAsync_NO_EXCEPTION()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            try
+            {
+                await _webRtc.StartAsync();
+            }
+            catch (Exception e)
+            {
+                Assert.Fail("Should not throw exception." + e.Message);
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test StartAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.StartAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void StartAsync_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.StartAsync(), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test StartAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.StartAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task StartAsync_THROWS_IF_INVALID_STATE()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.StartAsync(), Throws.TypeOf<InvalidOperationException>(),
+                "Should throw InvalidOperationException for invalid state");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test Stop whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.Stop M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Stop_NO_EXCEPTION()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.Stop(), Throws.Nothing, "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Stop whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.Stop M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Stop_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.Stop(), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test Stop whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.Stop M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Stop_THROWS_IF_INVALID_STATE()
+        {
+            Assert.That(() => _webRtc.Stop(), Throws.TypeOf<InvalidOperationException>(),
+                "Should throw InvalidOperationException for invalid state");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test CreateOfferAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.CreateOfferAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task CreateOfferAsync_CHECK_RETURN()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            var offer = _webRtc.CreateOfferAsync();
+
+            Assert.That(offer != null, "Should not null");
+            Assert.That(offer.Result.Contains("offer"), "Should be offer sdp");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test CreateOfferAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.CreateOfferAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task CreateOfferAsync_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.CreateOfferAsync(), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test CreateOfferAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.CreateOfferAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void CreateOfferAsync_THROWS_IF_INVALID_STATE()
+        {
+            Assert.That(() => _webRtc.CreateOfferAsync(), Throws.TypeOf<InvalidOperationException>(),
+                "Should throw InvalidOperationException for invalid state");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test CreateAnswerAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.CreateAnswerAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task CreateAnswerAsync_CHECK_RETURN()
+        {
+            using (var offerClient = new WebRTC())
+            using (var answerClient = new WebRTC())
+            {
+                offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+                await offerClient.StartAsync();
+                await answerClient.StartAsync();
+
+                var offer = await offerClient.CreateOfferAsync();
+
+                await SetRemoteDescriptionAsync(answerClient, offer);
+                var answer = await answerClient.CreateAnswerAsync();
+                Assert.That(answer != null, "Should not null");
+                Assert.That(answer.Contains("answer"), "Should be answer sdp");
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test CreateAnswerAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.CreateAnswerAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task CreateAnswerAsync_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.CreateAnswerAsync(), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test CreateAnswerAsync whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.CreateAnswerAsync M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void CreateAnswerAsync_THROWS_IF_INVALID_STATE()
+        {
+            Assert.That(() => _webRtc.CreateAnswerAsync(), Throws.TypeOf<InvalidOperationException>(),
+                "Should throw InvalidOperationException for invalid state");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test SetLocalDescription whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetLocalDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SetLocalDescription_NO_EXCEPTION()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            var offer = await _webRtc.CreateOfferAsync();
+
+            using (var eventWaiter = EventAwaiter<WebRTCSignalingStateChangedEventArgs>.Create())
+            {
+                _webRtc.SignalingStateChanged += eventWaiter;
+
+                Assert.That(() => _webRtc.SetLocalDescription(offer), Throws.Nothing,
+                    "Should not throw exception");
+
+                _webRtc.SignalingStateChanged -= eventWaiter;
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetLocalDescription whether throws ArgumentException if parameter is empty string.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetLocalDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SetLocalDescription_THROWS_IF_EMPTY_STRING()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.SetLocalDescription(""), Throws.ArgumentException,
+                "Should not throw ArgumentException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetLocalDescription whether throws ArgumentException if parameter is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetLocalDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SetLocalDescription_THROWS_IF_NULL_PARAM()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.SetLocalDescription(null), Throws.ArgumentNullException,
+                "Should not throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetLocalDescription whether throws InvalidOperationException if state is invalid.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetLocalDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetLocalDescription_THROWS_IF_INVALID_STATE()
+        {
+            Assert.That(() => _webRtc.SetLocalDescription("offer"), Throws.InvalidOperationException,
+                "Should not throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetLocalDescription whether throws ObjectDisposedException if webrtc is already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetLocalDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetLocalDescription_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.SetLocalDescription("offer"), Throws.TypeOf<ObjectDisposedException>(),
+                "Should not throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test SetRemoteDescription whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetRemoteDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SetRemoteDescription_NO_EXCEPTION()
+        {
+            using (var answerClient = new WebRTC())
+            using (var eventWaiter = EventAwaiter<WebRTCSignalingStateChangedEventArgs>.Create())
+            {
+                _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+                await _webRtc.StartAsync();
+                await answerClient.StartAsync();
+
+                answerClient.SignalingStateChanged += eventWaiter;
+
+                var offer = await _webRtc.CreateOfferAsync();
+
+                Assert.That(() => answerClient.SetRemoteDescription(offer), Throws.Nothing,
+                    "Should not throw exception");
+
+                await eventWaiter.IsRaisedAsync();
+
+                answerClient.SignalingStateChanged -= eventWaiter;
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetRemoteDescription whether throws ArgumentException if parameter is empty string.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetRemoteDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SetRemoteDescription_THROWS_IF_EMPTY_STRING()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.SetRemoteDescription(""), Throws.ArgumentException,
+                "Should not throw ArgumentException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetRemoteDescription whether throws ArgumentException if parameter is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetRemoteDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task SetRemoteDescription_THROWS_IF_NULL_PARAM()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.SetRemoteDescription(null), Throws.ArgumentNullException,
+                "Should not throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetRemoteDescription whether throws InvalidOperationException if state is invalid.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetRemoteDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetRemoteDescription_THROWS_IF_INVALID_STATE()
+        {
+            Assert.That(() => _webRtc.SetRemoteDescription("offer"), Throws.InvalidOperationException,
+                "Should not throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetRemoteDescription whether throws ObjectDisposedException if webrtc is already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetRemoteDescription M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetRemoteDescription_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.SetRemoteDescription("offer"), Throws.TypeOf<ObjectDisposedException>(),
+                "Should not throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test AddIceCandidate whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidate M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddIceCandidate_NO_EXCEPTION()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+            var offer = await _webRtc.CreateOfferAsync();
+
+            using (var eventWaiter = EventAwaiter<WebRTCIceCandidateEventArgs>.Create())
+            using (var eventWaiter2 = EventAwaiter<WebRTCIceConnectionStateChangedEventArgs>.Create())
+            {
+                _webRtc.IceCandidate += eventWaiter;
+                _webRtc.IceConnectionStateChanged += eventWaiter2;
+
+                try
+                {
+                    _webRtc.SetLocalDescription(offer);
+
+                    var result = await eventWaiter.GetResultAsync();
+
+                    Assert.That(() => _webRtc.AddIceCandidate(result.ICECandidate), Throws.Nothing,
+                        "Should not throw exception");
+                }
+                finally
+                {
+                    _webRtc.IceCandidate -= eventWaiter;
+                    _webRtc.IceConnectionStateChanged -= eventWaiter2;
+                }
+            }
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddIceCandidate whether throws ArgumentException if ice is empty string.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidate M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddIceCandidate_THROWS_IF_EMPTY_STRING()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.AddIceCandidate(""), Throws.ArgumentException,
+                "Should throw ArgumentException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddIceCandidate whether throws ArgumentNullException if ice is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidate M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddIceCandidate_THROWS_IF_NULL_PARAM()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.AddIceCandidate(null), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddIceCandidate whether throws InvalidOperationException if state is invalid.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidate M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AddIceCandidate_THROWS_IF_INVALID_STATE()
+        {
+            Assert.That(() => _webRtc.AddIceCandidate("ICE"), Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddIceCandidate whether throws ObjectDisposedException if webrtc is already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidate M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddIceCandidate_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.AddIceCandidate("ICE"), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test AddIceCandidate whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidates M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddIceCandidates_NO_EXCEPTION()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+            var offer = await _webRtc.CreateOfferAsync();
+
+            using (var eventWaiter = EventAwaiter<WebRTCIceCandidateEventArgs>.Create())
+            {
+                _webRtc.IceCandidate += eventWaiter;
+
+                _webRtc.SetLocalDescription(offer);
+
+                var result = await eventWaiter.GetResultAsync();
+
+                _webRtc.IceCandidate -= eventWaiter;
+
+                var iceCandidates = new List<string>();
+                iceCandidates.Add(result.ICECandidate);
+                Assert.That(() => _webRtc.AddIceCandidates(iceCandidates), Throws.Nothing,
+                    "Should not throw exception");
+
+            }
+        }
+        [Test]
+        [Category("P2")]
+        [Description("Test AddIceCandidates whether throws ArgumentException if ice is empty string.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidates M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddIceCandidates_THROWS_IF_EMPTY_STRING()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            var iceCandidates = new List<string>();
+            iceCandidates.Add("");
+
+            Assert.That(() => _webRtc.AddIceCandidates(iceCandidates), Throws.ArgumentException,
+                "Should throw ArgumentException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddIceCandidates whether throws ArgumentNullException if ice is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidates M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddIceCandidates_THROWS_IF_NULL_PARAM()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.AddIceCandidates(null), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddIceCandidates whether throws InvalidOperationException if state is invalid.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidates M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AddIceCandidates_THROWS_IF_INVALID_STATE()
+        {
+            var iceCandidates = new List<string>();
+            iceCandidates.Add("ICE");
+
+            Assert.That(() => _webRtc.AddIceCandidates(iceCandidates), Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddIceCandidates whether throws ObjectDisposedException if webrtc is already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddIceCandidates M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddIceCandidates_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+            await _webRtc.StartAsync();
+
+            _webRtc.Dispose();
+
+            var iceCandidates = new List<string>();
+            iceCandidates.Add("ICE");
+
+            Assert.That(() => _webRtc.AddIceCandidates(iceCandidates), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test AddSource whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddSource M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AddSource_NO_EXCEPTION()
+        {
+            Assert.That(() => _webRtc.AddSource(new MediaTestSource(MediaType.Video)),
+                Throws.Nothing, "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddSource whether throws exception if argument is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddSource M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AddSource_THROWS_IF_SOURCE_IS_NULL()
+        {
+            Assert.That(() => _webRtc.AddSource(null), Throws.ArgumentNullException,
+                 "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddSource whether throws exception if state is invalid.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddSource M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddSource_THROWS_IF_INVALID_STATE()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.AddSource(new MediaTestSource(MediaType.Video)),
+                 Throws.InvalidOperationException, "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddSource whether throws exception if .")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddSource M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AddSource_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.AddSource(new MediaTestSource(MediaType.Video)),
+                 Throws.TypeOf<ObjectDisposedException>(), "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test AddSources whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddSources M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AddSources_NO_EXCEPTION()
+        {
+            Assert.That(() => _webRtc.AddSources(new MediaTestSource(MediaType.Video),
+                new MediaTestSource(MediaType.Video)), Throws.Nothing,
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddSources whether throws exception if argument is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddSources M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AddSources_THROWS_IF_SOURCE_IS_NULL()
+        {
+            Assert.That(() => _webRtc.AddSources(null), Throws.ArgumentNullException,
+                 "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddSources whether throws exception if state is invalid.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddSources M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task AddSources_THROWS_IF_INVALID_STATE()
+        {
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.AddSources(new MediaTestSource(MediaType.Video)),
+                 Throws.InvalidOperationException, "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test AddSources whether throws exception if .")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.AddSources M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void AddSources_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.AddSource(new MediaTestSource(MediaType.Video)),
+                 Throws.TypeOf<ObjectDisposedException>(), "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test RemoveSource whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.RemoveSource M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void RemoveSource_NO_EXCEPTION()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _webRtc.AddSource(source);
+
+            Assert.That(() => _webRtc.RemoveSource(source), Throws.Nothing,
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test RemoveSource whether throws ArgumentNullException if parameter is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.RemoveSource M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void RemoveSource_THROWS_IF_NULL_PARAM()
+        {
+            Assert.That(() => _webRtc.RemoveSource(null), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test RemoveSource whether throws InvalidOperationException if state is invalid.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.RemoveSource M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task RemoveSource_THROWS_IF_INVALID_STATE()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _webRtc.AddSource(source);
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.RemoveSource(source), Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test RemoveSource whether throws ObjectDisposedException if webrtc is already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.RemoveSource M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void RemoveSource_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _webRtc.AddSource(source);
+
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.RemoveSource(source), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test RemoveSources whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.RemoveSources M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void RemoveSources_NO_EXCEPTION()
+        {
+            var list = new List<MediaTestSource>();
+            list.Add(new MediaTestSource(MediaType.Video));
+            list.Add(new MediaTestSource(MediaType.Video));
+            _webRtc.AddSources(list.ToArray());
+
+            Assert.That(() => _webRtc.RemoveSources(list.ToArray()), Throws.Nothing,
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test RemoveSources whether throws ArgumentNullException if parameter is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.RemoveSources M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void RemoveSources_THROWS_IF_NULL_PARAM()
+        {
+            Assert.That(() => _webRtc.RemoveSource(null), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test RemoveSources whether throws InvalidOperationException if state is invalid.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.RemoveSources M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task RemoveSources_THROWS_IF_INVALID_STATE()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _webRtc.AddSource(source);
+            await _webRtc.StartAsync();
+
+            Assert.That(() => _webRtc.RemoveSources(source), Throws.InvalidOperationException,
+                "Should throw InvalidOperationException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test RemoveSources whether throws ObjectDisposedException if webrtc is already disposed.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.RemoveSources M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void RemoveSources_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var source = new MediaTestSource(MediaType.Video);
+            _webRtc.AddSource(source);
+
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.RemoveSources(source), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test SetTurnServer whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetTurnServer M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetTurnServer_NO_EXCEPTION()
+        {
+            Assert.That(() => _webRtc.SetTurnServer(_turnServer), Throws.Nothing,
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetTurnServer whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetTurnServer M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetTurnServer_THROWS_IF_NULL_PARAMETER()
+        {
+            Assert.That(() => _webRtc.SetTurnServer(null), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetTurnServer whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetTurnServer M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetTurnServer_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.SetTurnServer(_turnServer), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test SetTurnServers whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetTurnServers M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetTurnServers_NO_EXCEPTION()
+        {
+            Assert.That(() => _webRtc.SetTurnServers(_turnServer), Throws.Nothing,
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetTurnServers whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetTurnServers M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetTurnServers_THROWS_IF_NULL_PARAMETER()
+        {
+            Assert.That(() => _webRtc.SetTurnServers(null), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Test SetTurnServers whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.SetTurnServers M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void SetTurnServers_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.Dispose();
+
+            Assert.That(() => _webRtc.SetTurnServers(_turnServer), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Test GetTurnServer whether throws exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.GetTurnServer M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void GetTurnServer_NO_EXCEPTION()
+        {
+            Assert.That(() => _webRtc.GetTurnServer(), Throws.Nothing,
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether StunServer returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.StunServer A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void StunServer_READ_WRITE()
+        {
+            var stunServer = "stun://stun.l.google.com:19302";
+
+            Assert.That(() => _webRtc.StunServer = stunServer, Throws.Nothing,
+                "Should not throws exception");
+
+            Assert.That(_webRtc.StunServer, Is.EqualTo(stunServer),
+                "Should return same value");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether StunServer throws ArgumentNullException if parameter is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.StunServer A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void StunServer_THROWS_IF_NULL_PARAM()
+        {
+            Assert.That(() => _webRtc.StunServer = null, Throws.ArgumentNullException,
+                "Should throws ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether StunServer returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.StunServer A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void StunServer_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var stunServer = "stun://stun.l.google.com:19302";
+
+            _webRtc.Dispose();
+
+            Assert.Throws<ObjectDisposedException>(() => _webRtc.StunServer = stunServer,
+                "Should throws ObjectDisposedException");
+
+            Assert.That(() => _webRtc.StunServer, Throws.TypeOf<ObjectDisposedException>(),
+                "Should throws ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether IceTransportPolicy returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.IceTransportPolicy A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void IceTransportPolicy_READ_WRITE()
+        {
+            Assert.That(() => _webRtc.IceTransportPolicy = IceTransportPolicy.All, Throws.Nothing,
+                "Should not throws exception");
+
+            Assert.That(_webRtc.IceTransportPolicy, Is.EqualTo(IceTransportPolicy.All),
+                "Should return same value");
+
+            Assert.That(() => _webRtc.IceTransportPolicy = IceTransportPolicy.Relay, Throws.Nothing,
+                "Should not throws exception");
+
+            Assert.That(_webRtc.IceTransportPolicy, Is.EqualTo(IceTransportPolicy.Relay),
+                "Should return same value");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether IceTransportPolicy returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTC.IceTransportPolicy A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRW")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void IceTransportPolicy_THROWS_IF_ALREADY_DISPOSED()
+        {
+            _webRtc.Dispose();
+
+            Assert.Throws<ObjectDisposedException>(() => _webRtc.IceTransportPolicy = IceTransportPolicy.All,
+                "Should throws ObjectDisposedException");
+
+            Assert.That(() => _webRtc.IceTransportPolicy, Throws.TypeOf<ObjectDisposedException>(),
+                "Should throws ObjectDisposedException");
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannel.Events.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannel.Events.cs
new file mode 100755 (executable)
index 0000000..c69f8e2
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCDataChannel event Tests")]
+    public class WebRTCDataChannelEventTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+        private WebRTCDataChannel _offerDataChannel;
+
+        TaskCompletionSource<bool> _tcsOfferDataChannelOpened, _tcsOfferDataChannelClosed;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            _offerDataChannel = new WebRTCDataChannel(_offerClient, "offerDataChannel");
+
+            Initialize();
+        }
+
+       [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferDataChannelOpened = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferDataChannelClosed = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += AnswerTrackAddedEventHandler;
+        }
+
+        private void OfferDataChannelOpendEventHandler(object s, EventArgs e)
+        {
+            _tcsOfferDataChannelOpened.TrySetResult(true);
+        }
+
+        private void OfferDataChannelClosedEventHandler(object s, EventArgs e)
+        {
+            _tcsOfferDataChannelClosed.TrySetResult(true);
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Opened event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.Opened E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Opened_CHECK_EVENT()
+        {
+            _offerDataChannel.Opened += OfferDataChannelOpendEventHandler;
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            Assert.That(await _tcsOfferDataChannelOpened.Task, "Event should be raised");
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Closed event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.Closed E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Closed_CHECK_EVENT()
+        {
+            _offerDataChannel.Opened += OfferDataChannelOpendEventHandler;
+            _offerDataChannel.Closed += OfferDataChannelClosedEventHandler;
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            await _tcsOfferDataChannelOpened.Task;
+
+            await _tcsAnswerTrackAdded.Task;
+
+            _offerDataChannel.Dispose();
+
+            Assert.That(await _tcsOfferDataChannelClosed.Task, "Event should be raised");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether MessageReceived event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.MessageReceived E")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "EVL")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task MessageReceived_CHECK_EVENT()
+        {
+            var greetingMessage = "HELLO";
+
+            var tcsDataChannel = new TaskCompletionSource<WebRTCDataChannel>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var tcsDataChannelMessageReceived = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.DataChannel += (s, e) =>
+            {
+                // DataChannel from peer
+                tcsDataChannel.TrySetResult(e.DataChannel);
+            };
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var answerDataChannel = await tcsDataChannel.Task;
+            answerDataChannel.MessageReceived += (s, e) =>
+            {
+                if (e.Message.Equals(greetingMessage))
+                {
+                    tcsDataChannelMessageReceived.TrySetResult(true);
+                }
+            };
+
+            await _tcsAnswerTrackAdded.Task;
+
+            _offerDataChannel.Send(greetingMessage);
+
+            Assert.That(await tcsDataChannelMessageReceived.Task, "Event should be raised");
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannel.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannel.cs
new file mode 100755 (executable)
index 0000000..938185e
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCDataChannel Tests")]
+    public class WebRTCDataChannelTests
+    {
+        private WebRTC _webRtc;
+
+
+        [SetUp]
+        public void Init()
+        {
+            _webRtc = new WebRTC();
+            _webRtc.AddSource(new MediaTestSource(MediaType.Video));
+        }
+
+       [TearDown]
+        public void Destroy()
+        {
+            _webRtc?.Dispose();
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Create the WebRTCDataChannel instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.WebRTCDataChannel C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("COVPARAM", "WebRTC, string")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void WebRTCDataChannel_INIT()
+        {
+            var webRtcDataChannel = new WebRTCDataChannel(_webRtc, "test");
+            Assert.IsNotNull(webRtcDataChannel, "WebRTCDataChannel should not be null.");
+            Assert.IsInstanceOf<WebRTCDataChannel>(webRtcDataChannel, "Should return WebRTCDataChannel instance.");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether throw exception if label is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.WebRTCDataChannel C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTX")]
+        [Property("COVPARAM", "WebRTC, string")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void WebRTCDataChannel_THROWS_IF_LABEL_IS_NULL()
+        {
+            Assert.That(() => new WebRTCDataChannel(_webRtc, null), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Create the WebRTCDataChannel instance and check whether instance is created property or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.WebRTCDataChannel C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTR")]
+        [Property("COVPARAM", "WebRTC, string, Bundle")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void WebRTCDataChannel_WIDHT_BUNDLE_INIT()
+        {
+            var webRtcDataChannel = new WebRTCDataChannel(_webRtc, "test", new Applications.Bundle());
+            Assert.IsNotNull(webRtcDataChannel, "WebRTCDataChannel should not be null.");
+            Assert.IsInstanceOf<WebRTCDataChannel>(webRtcDataChannel, "Should return WebRTCDataChannel instance.");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether throw exception if label is null.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.WebRTCDataChannel C")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "CONSTX")]
+        [Property("COVPARAM", "WebRTC, string, Bundle")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void WebRTCDataChannel_WITH_BUNDLE_THROWS_IF_LABEL_IS_NULL()
+        {
+            Assert.That(() => new WebRTCDataChannel(_webRtc, null, new Applications.Bundle()), Throws.ArgumentNullException,
+                "Should throw ArgumentNullException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Label returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.Label A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Label_READ_ONLY()
+        {
+            var webRtcDataChannel = new WebRTCDataChannel(_webRtc, "test");
+            Assert.That(webRtcDataChannel.Label, Is.EqualTo("test"), "Should return same value");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Send throw exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.Send M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("COVPARAM", "string")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Send_CHECK_RETURN()
+        {
+            var webRtcDataChannel = new WebRTCDataChannel(_webRtc, "test");
+            Assert.That(() => webRtcDataChannel.Send("test"), Throws.Nothing,
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether Send throw ObjectDisposedException or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.Send M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("COVPARAM", "string")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Send_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var webRtcDataChannel = new WebRTCDataChannel(_webRtc, "test");
+            webRtcDataChannel.Dispose();
+
+            Assert.That(() => webRtcDataChannel.Send("test"), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Send throw exception or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.Send M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("COVPARAM", "byte[]")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Send_WITH_BYTE_CHECK_RETURN()
+        {
+            var webRtcDataChannel = new WebRTCDataChannel(_webRtc, "test");
+            var data = new byte[10];
+
+            Assert.That(() => webRtcDataChannel.Send(data), Throws.Nothing,
+                "Should not throw exception");
+        }
+
+        [Test]
+        [Category("P2")]
+        [Description("Check whether Send throw ObjectDisposedException or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannel.Send M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MEX")]
+        [Property("COVPARAM", "byte[]")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public void Send_WITH_BYTE_THROWS_IF_ALREADY_DISPOSED()
+        {
+            var webRtcDataChannel = new WebRTCDataChannel(_webRtc, "test");
+            webRtcDataChannel.Dispose();
+
+            var data = new byte[10];
+            Assert.That(() => webRtcDataChannel.Send(data), Throws.TypeOf<ObjectDisposedException>(),
+                "Should throw ObjectDisposedException");
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannelEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannelEventArgs.cs
new file mode 100755 (executable)
index 0000000..37ad4ca
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCDataChannelEventArgs Tests")]
+    public class WebRTCDataChannelEventArgsTests : TestBase
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether DataChannel event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannelEventArgs.DataChannel A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task DataChannel_READ_ONLY()
+        {
+            var tcsOfferDataChannel = new TaskCompletionSource<WebRTCDataChannel>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var offerClient = new WebRTC())
+            using (var answerClient = new WebRTC())
+            {
+                answerClient.DataChannel += (s, e) => tcsOfferDataChannel.TrySetResult(e.DataChannel);
+                answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(true);
+
+                var offerDataChannel = new WebRTCDataChannel(offerClient, "offerDataChannel");
+
+                offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+                await offerClient.StartAsync();
+                await answerClient.StartAsync();
+
+                await ConnectPeerAsync(offerClient, answerClient);
+
+                var dataChannel = await tcsOfferDataChannel.Task;
+
+                await tcsAnswerTrackAdded.Task;
+
+                Assert.IsNotNull(dataChannel, "DataChannel should not be null.");
+                Assert.IsInstanceOf<WebRTCDataChannel>(dataChannel, "Should return WebRTCDataChannel instance.");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannelMessageReceivedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCDataChannelMessageReceivedEventArgs.cs
new file mode 100755 (executable)
index 0000000..c1d7bd3
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCDataChannelMessageReceivedEventArgs Tests")]
+    public class WebRTCDataChannelMessageReceivedEventArgsTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+        private WebRTCDataChannel _offerDataChannel;
+
+        TaskCompletionSource<WebRTCDataChannel> _tcsOfferDataChannel;
+        TaskCompletionSource<WebRTCDataChannelMessageReceivedEventArgs> _tcsOfferDataChannelMessageReceived;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        private readonly string _greetingMessage = "HELLO";
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            _offerDataChannel = new WebRTCDataChannel(_offerClient, "offerDataChannel");
+
+            Initialize();
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferDataChannel = new TaskCompletionSource<WebRTCDataChannel>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferDataChannelMessageReceived =
+                new TaskCompletionSource<WebRTCDataChannelMessageReceivedEventArgs>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.TrackAdded += AnswerTrackAddedEventHandler;
+            _answerClient.DataChannel += AnswerDataChannelEventHandler;
+        }
+
+        private void AnswerDataChannelEventHandler(object s, WebRTCDataChannelEventArgs e)
+        {
+            _tcsOfferDataChannel.TrySetResult(e.DataChannel);
+        }
+
+        private void AnswerDataChannelMessageReceivedEventHandler(object s, WebRTCDataChannelMessageReceivedEventArgs e)
+        {
+            _tcsOfferDataChannelMessageReceived.TrySetResult(e);
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Type event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannelMessageReceivedEventArgs.Type A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Type_READ_ONLY_STRINGS()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var receivedDataChannel = await _tcsOfferDataChannel.Task;
+            receivedDataChannel.MessageReceived += AnswerDataChannelMessageReceivedEventHandler;
+
+            await _tcsAnswerTrackAdded.Task;
+
+            _offerDataChannel.Send(_greetingMessage);
+
+            var dataChannelMessage = await _tcsOfferDataChannelMessageReceived.Task;
+
+            Assert.That(dataChannelMessage.Type == DataChannelType.Strings, "Should return same value");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Type event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannelMessageReceivedEventArgs.Type A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Type_READ_ONLY_BYTES()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var receivedDataChannel = await _tcsOfferDataChannel.Task;
+            receivedDataChannel.MessageReceived += AnswerDataChannelMessageReceivedEventHandler;
+
+            await _tcsAnswerTrackAdded.Task;
+
+            var data = new byte[] {1, 2};
+            _offerDataChannel.Send(data);
+
+            var dataChannelMessage = await _tcsOfferDataChannelMessageReceived.Task;
+
+            Assert.That(dataChannelMessage.Type == DataChannelType.Bytes, "Should return same value");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Message event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannelMessageReceivedEventArgs.Message A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Message_READ_ONLY()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var receivedDataChannel = await _tcsOfferDataChannel.Task;
+            receivedDataChannel.MessageReceived += AnswerDataChannelMessageReceivedEventHandler;
+
+            await _tcsAnswerTrackAdded.Task;
+
+            _offerDataChannel.Send(_greetingMessage);
+
+            var dataChannelMessage = await _tcsOfferDataChannelMessageReceived.Task;
+
+            Assert.That(dataChannelMessage.Message, Is.EqualTo(_greetingMessage),
+                "Should return same value");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Data event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannelMessageReceivedEventArgs.Data A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Data_READ_ONLY()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var receivedDataChannel = await _tcsOfferDataChannel.Task;
+            receivedDataChannel.MessageReceived += AnswerDataChannelMessageReceivedEventHandler;
+
+            await _tcsAnswerTrackAdded.Task;
+
+            var data = new byte[5] {1, 2, 3, 4, 5};
+            _offerDataChannel.Send(data);
+
+            var dataChannelMessage = await _tcsOfferDataChannelMessageReceived.Task;
+
+            Assert.That(dataChannelMessage.Data, Is.EqualTo(data),
+                "Should return same value");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCDataChannelMessageReceivedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            var receivedDataChannel = await _tcsOfferDataChannel.Task;
+            receivedDataChannel.MessageReceived += AnswerDataChannelMessageReceivedEventHandler;
+
+            await _tcsAnswerTrackAdded.Task;
+
+            _offerDataChannel.Send(_greetingMessage);
+
+            var dataChannelMessage = await _tcsOfferDataChannelMessageReceived.Task;
+
+            Assert.AreEqual($"Channel type={dataChannelMessage.Type}, Message={dataChannelMessage.Message}",
+                dataChannelMessage.ToString(), "Should return same value");
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCFrameEncodedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCFrameEncodedEventArgs.cs
new file mode 100755 (executable)
index 0000000..14b8830
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCFrameEncodedEventArgs Tests")]
+    public class WebRTCFrameEncodedEventArgsTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+        private WebRTCDataChannel _offerDataChannel;
+
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerDataChannel = new WebRTCDataChannel(_offerClient, "offerDataChannel");
+
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _answerClient.TrackAdded += AnswerTrackAddedEventHandler;
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether MediaStreamTrack event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCFrameEncodedEventArgs.MediaStreamTrack A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task MediaStreamTrack_READ_ONLY()
+        {
+            var offerSource = new MediaTestSource(MediaType.Video);
+
+            _offerClient.AddSource(offerSource);
+
+            var tcsAnswerVideoFrameEncoded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.VideoFrameEncoded += (s, e) =>
+            {
+                Assert.IsNotNull(e.MediaStreamTrack, "MediaStreamTrack should not be null.");
+                Assert.IsInstanceOf<MediaStreamTrack>(e.MediaStreamTrack,
+                    "Should return MediaStreamTrack instance.");
+
+                tcsAnswerVideoFrameEncoded.TrySetResult(true);
+            };
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            await _tcsAnswerTrackAdded.Task;
+
+            await tcsAnswerVideoFrameEncoded.Task;
+
+            offerSource.Pause = true;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Packet event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCFrameEncodedEventArgs.Packet A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Packet_READ_ONLY()
+        {
+            var offerSource = new MediaTestSource(MediaType.Video);
+
+            _offerClient.AddSource(offerSource);
+
+            var tcsAnswerVideoFrameEncoded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.VideoFrameEncoded += (s, e) =>
+            {
+                Assert.IsNotNull(e.Packet, "Packet should not be null.");
+                Assert.IsInstanceOf<MediaPacket>(e.Packet, "Should return MediaPacket instance.");
+
+                tcsAnswerVideoFrameEncoded.TrySetResult(true);
+            };
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            await _tcsAnswerTrackAdded.Task;
+
+            await tcsAnswerVideoFrameEncoded.Task;
+
+            offerSource.Pause = true;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCFrameEncodedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            var offerSource = new MediaTestSource(MediaType.Video);
+
+            _offerClient.AddSource(offerSource);
+
+            var tcsAnswerVideoFrameEncoded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _answerClient.VideoFrameEncoded += (s, e) =>
+            {
+                Assert.AreEqual($"MediaType={e.MediaStreamTrack.Type}", e.ToString(),
+                    "Should be the same value");
+
+                tcsAnswerVideoFrameEncoded.TrySetResult(true);
+            };
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            await ConnectPeerAsync(_offerClient, _answerClient);
+
+            await _tcsAnswerTrackAdded.Task;
+
+            await tcsAnswerVideoFrameEncoded.Task;
+
+            offerSource.Pause = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceCandidateEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceCandidateEventArgs.cs
new file mode 100755 (executable)
index 0000000..a3a5b6e
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCIceCandidateEventArgs Tests")]
+    public class WebRTCIceCandidateEventArgsTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+        private WebRTCDataChannel _offerDataChannel;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            _offerDataChannel = new WebRTCDataChannel(_offerClient, "offerDataChannel");
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                Assert.AreEqual($"ICE candidate={e.ICECandidate}", e.ToString(),
+                "Should be the same value");
+
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                Assert.AreEqual($"ICE candidate={e.ICECandidate}", e.ToString(),
+                "Should be the same value");
+
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ICECandidate event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCIceCandidateEventArgs.ICECandidate A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ICECandidate_READ_ONLY()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            Assert.That(_offerIceCandidate.Count > 0, "Event should be raised");
+            Assert.That(_answerIceCandidate.Count > 0, "Event should be raised");
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCIceCandidateEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            // ToString() is checked in event handler.
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceConnectionStateChangedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceConnectionStateChangedEventArgs.cs
new file mode 100755 (executable)
index 0000000..641aed1
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCIceConnectionStateChangedEventArgs Tests")]
+    public class WebRTCIceConnectionStateChangedEventArgsTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<WebRTCIceConnectionState> _tcsOfferIceConnectionState, _tcsAnswerIceConnectionState;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceConnectionState = new TaskCompletionSource<WebRTCIceConnectionState>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceConnectionState = new TaskCompletionSource<WebRTCIceConnectionState>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+                webRtc.IceConnectionStateChanged += OfferIceConnectionStateChangeEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.IceConnectionStateChanged += AnswerIceConnectionStateChangeEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void OfferIceConnectionStateChangeEventHandler(object s, WebRTCIceConnectionStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceConnectionState.Connected ||
+                e.State == WebRTCIceConnectionState.Completed)
+            {
+                Assert.AreEqual($"State={e.State}", e.ToString(), "Should be the same string");
+                _tcsOfferIceConnectionState.TrySetResult(e.State);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerIceConnectionStateChangeEventHandler(object s, WebRTCIceConnectionStateChangedEventArgs e)
+        {
+            Assert.AreEqual($"State={e.State}", e.ToString(), "Should be the same string");
+
+            _tcsAnswerIceConnectionState.TrySetResult(e.State);
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether State event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCIceConnectionStateChangedEventArgs.State A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task State_READ_ONLY()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            var state = await _tcsOfferIceConnectionState.Task;
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+
+            Assert.IsNotNull(state, "state should not be null.");
+            Assert.IsInstanceOf<WebRTCIceConnectionState>(state, "Should return WebRTCIceConnectionState instance.");
+            Assert.That(state == WebRTCIceConnectionState.Connected ||
+                        state == WebRTCIceConnectionState.Completed, "Should return same value");
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCIceConnectionStateChangedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            // ToString() is checked in event handler.
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceGatheringStateChangedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCIceGatheringStateChangedEventArgs.cs
new file mode 100755 (executable)
index 0000000..e7ff678
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCIceGatheringStateChangedEventArgs Tests")]
+    public class WebRTCIceGatheringStateChangedEventArgsTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateGathering, _tcsAnswerIceGatheringStateGathering;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateGathering = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateGathering = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            Assert.IsNotNull(e.State, "state should not be null.");
+            Assert.IsInstanceOf<WebRTCIceGatheringState>(e.State, "Should return WebRTCIceGatheringState instance.");
+
+            Assert.AreEqual($"State={e.State}", e.ToString(), "Should be the same string");
+
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            Assert.IsNotNull(e.State, "state should not be null.");
+            Assert.IsInstanceOf<WebRTCIceGatheringState>(e.State, "Should return WebRTCIceGatheringState instance.");
+
+            Assert.AreEqual($"State={e.State}", e.ToString(), "Should be the same string");
+
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether State event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCIceGatheringStateChangedEventArgs.State A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task State_READ_ONLY()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            // State property is checked in EventHandler
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCIceGatheringStateChangedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            // ToString() is checked in event handler.
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCPeerConnectionStateChangedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCPeerConnectionStateChangedEventArgs.cs
new file mode 100755 (executable)
index 0000000..ee07687
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCPeerConnectionStateChangedEventArgs Tests")]
+    public class WebRTCPeerConnectionStateChangedEventArgsTests : TestBase
+    {
+        private WebRTC _offerClient, _answerClient;
+
+        TaskCompletionSource<bool> _tcsOfferStatePlaying, _tcsAnswerStatePlaying;
+        TaskCompletionSource<bool> _tcsOfferIceGatheringStateCompleted, _tcsAnswerIceGatheringStateCompleted;
+        TaskCompletionSource<WebRTCPeerConnectionState> _tcsOfferPeerConnectionState, _tcsAnswerPeerConnectionState;
+        TaskCompletionSource<bool> _tcsAnswerTrackAdded;
+
+        List<string> _offerIceCandidate, _answerIceCandidate;
+
+        [SetUp]
+        public void Init()
+        {
+            _offerClient = new WebRTC();
+            _answerClient = new WebRTC();
+
+            _offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+            Initialize();
+
+            RegisterEvents(_offerClient, true);
+            RegisterEvents(_answerClient, false);
+
+            _offerIceGathering = true;
+            _answerIceGathering = true;
+        }
+
+        [TearDown]
+        public void Destroy()
+        {
+            _offerClient?.Dispose();
+            _answerClient?.Dispose();
+        }
+
+        private void Initialize()
+        {
+            _tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsOfferPeerConnectionState = new TaskCompletionSource<WebRTCPeerConnectionState>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerPeerConnectionState = new TaskCompletionSource<WebRTCPeerConnectionState>(TaskCreationOptions.RunContinuationsAsynchronously);
+            _tcsAnswerTrackAdded = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            _offerIceCandidate = new List<string>();
+            _answerIceCandidate = new List<string>();
+        }
+
+        private void RegisterEvents(WebRTC webRtc, bool isOffer)
+        {
+            if (isOffer)
+            {
+                webRtc.StateChanged += OfferStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += OfferIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += OfferIceCandidateEventHandler;
+                webRtc.PeerConnectionStateChanged += OfferPeerConnectionStateChangeEventHandler;
+            }
+            else
+            {
+                webRtc.StateChanged += AnswerStateChangeEventHandler;
+                webRtc.IceGatheringStateChanged += AnswerIceGatheringStateChangeEventHandler;
+                webRtc.IceCandidate += AnswerIceCandidateEventHandler;
+                webRtc.PeerConnectionStateChanged += AnswerPeerConnectionStateChangeEventHandler;
+                webRtc.TrackAdded += AnswerTrackAddedEventHandler;
+            }
+        }
+
+        private void OfferStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsOfferStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _offerIceGathering = false;
+                _tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void OfferIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_offerIceGathering)
+            {
+                _offerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void OfferPeerConnectionStateChangeEventHandler(object s, WebRTCPeerConnectionStateChangedEventArgs e)
+        {
+            Assert.IsNotNull(e.State, "state should not be null.");
+            Assert.IsInstanceOf<WebRTCPeerConnectionState>(e.State, "Should return WebRTCPeerConnectionState instance.");
+
+            Assert.AreEqual($"State={e.State}", e.ToString(), "Should be the same string");
+        }
+
+        private void AnswerStateChangeEventHandler(object s, WebRTCStateChangedEventArgs e)
+        {
+            if (e.Current == WebRTCState.Playing)
+            {
+                _tcsAnswerStatePlaying.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceGatheringStateChangeEventHandler(object s, WebRTCIceGatheringStateChangedEventArgs e)
+        {
+            if (e.State == WebRTCIceGatheringState.Completed)
+            {
+                _answerIceGathering = false;
+                _tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+            }
+        }
+
+        private void AnswerIceCandidateEventHandler(object s, WebRTCIceCandidateEventArgs e)
+        {
+            if (_answerIceGathering)
+            {
+                _answerIceCandidate.Add(e.ICECandidate);
+            }
+        }
+
+        private void AnswerPeerConnectionStateChangeEventHandler(object s, WebRTCPeerConnectionStateChangedEventArgs e)
+        {
+            Assert.IsNotNull(e.State, "state should not be null.");
+            Assert.IsInstanceOf<WebRTCPeerConnectionState>(e.State, "Should return WebRTCPeerConnectionState instance.");
+
+            Assert.AreEqual($"State={e.State}", e.ToString(), "Should be the same string");
+        }
+
+        private void AnswerTrackAddedEventHandler(object s, WebRTCTrackAddedEventArgs e)
+        {
+            _tcsAnswerTrackAdded.TrySetResult(true);
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether State event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCPeerConnectionStateChangedEventArgs.State A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task State_READ_ONLY()
+        {
+            Assert.That(_offerClient.PeerConnectionState == WebRTCPeerConnectionState.New, "Should be New state");
+            Assert.That(_answerClient.PeerConnectionState == WebRTCPeerConnectionState.New, "Should be New state");
+
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            // State property is checked in event handler
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCPeerConnectionStateChangedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            await _offerClient.StartAsync();
+            await _answerClient.StartAsync();
+
+            var sdpOffer = await _offerClient.CreateOfferAsync();
+            _offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(_answerClient, sdpOffer);
+            var sdpAnswer = await _answerClient.CreateAnswerAsync();
+            _answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(_offerClient, sdpAnswer);
+
+            await Task.WhenAll(_tcsOfferIceGatheringStateCompleted.Task, _tcsAnswerIceGatheringStateCompleted.Task);
+
+            _offerClient.AddIceCandidates(_answerIceCandidate);
+            _answerClient.AddIceCandidates(_offerIceCandidate);
+
+            await Task.WhenAll(_tcsOfferStatePlaying.Task, _tcsAnswerStatePlaying.Task);
+
+            // ToString() is checked in event handler
+
+            await _tcsAnswerTrackAdded.Task;
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCSignalingStateChangedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCSignalingStateChangedEventArgs.cs
new file mode 100755 (executable)
index 0000000..6779aef
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests {
+
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCSignalingStateChangedEventArgs Tests")]
+    public class WebRTCSignalingStateChangedEventArgsTests
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether State event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCSignalingStateChangedEventArgs.State A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task State_READ_ONLY()
+        {
+            var tcsOfferSignalingState = new TaskCompletionSource<WebRTCSignalingState>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var webRtc = new WebRTC())
+            {
+                webRtc.SignalingStateChanged += (s, e) => tcsOfferSignalingState.TrySetResult(e.State);
+
+                await webRtc.StartAsync();
+
+                var sdpOffer = await webRtc.CreateOfferAsync();
+                webRtc.SetLocalDescription(sdpOffer);
+
+                var state = await tcsOfferSignalingState.Task;
+
+                Assert.IsNotNull(state, "state should not be null.");
+                Assert.IsInstanceOf<WebRTCSignalingState>(state, "Should return WebRTCSignalingState instance.");
+                Assert.That(state == WebRTCSignalingState.HaveLocalOffer, "Should return same value");
+            }
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCSignalingStateChangedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            var tcsOfferSignalingState = new TaskCompletionSource<WebRTCSignalingStateChangedEventArgs>(
+                    TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var webRtc = new WebRTC())
+            {
+                webRtc.SignalingStateChanged += (s, e) => tcsOfferSignalingState.TrySetResult(e);
+
+                await webRtc.StartAsync();
+
+                var sdpOffer = await webRtc.CreateOfferAsync();
+                webRtc.SetLocalDescription(sdpOffer);
+
+                var args = await tcsOfferSignalingState.Task;
+
+                Assert.AreEqual($"State={args.State}", args.ToString(), "Should be the same string");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCStateChangedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCStateChangedEventArgs.cs
new file mode 100755 (executable)
index 0000000..1d520ca
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCWebRTCStateChangedEventArgs Test class")]
+    public class WebRTCWebRTCStateChangedEventArgsTests
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Previous event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCStateChangedEventArgs.Previous A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Previous_READ_ONLY()
+        {
+            var tcsOfferStateNegotiating = new TaskCompletionSource<WebRTCStateChangedEventArgs>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var webRtc = new WebRTC())
+            {
+                webRtc.StateChanged += (s, e) => tcsOfferStateNegotiating.TrySetResult(e);
+
+                await webRtc.StartAsync();
+
+                var result = await tcsOfferStateNegotiating.Task;
+
+                Assert.That(result.Previous == WebRTCState.Idle, "Should return proper state");
+            }
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether Current event is invoked or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCStateChangedEventArgs.Current A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task Current_READ_ONLY()
+        {
+            var tcsOfferStateNegotiating = new TaskCompletionSource<WebRTCStateChangedEventArgs>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var webRtc = new WebRTC())
+            {
+                webRtc.StateChanged += (s, e) => tcsOfferStateNegotiating.TrySetResult(e);
+
+                await webRtc.StartAsync();
+
+                var result = await tcsOfferStateNegotiating.Task;
+
+                Assert.That(result.Current == WebRTCState.Negotiating, "Should return proper state");
+            }
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCStateChangedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            var tcsOfferStateNegotiating = new TaskCompletionSource<WebRTCStateChangedEventArgs>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var webRtc = new WebRTC())
+            {
+                webRtc.StateChanged += (s, e) => tcsOfferStateNegotiating.TrySetResult(e);
+
+                await webRtc.StartAsync();
+
+                var result = await tcsOfferStateNegotiating.Task;
+
+                Assert.AreEqual($"Previous state={result.Previous}, Current state={result.Current}",
+                    result.ToString(), "Should be the same string");
+            }
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCTrackAddedEventArgs.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/TSWebRTCTrackAddedEventArgs.cs
new file mode 100755 (executable)
index 0000000..4a86074
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using NUnit.Framework;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    [TestFixture]
+    [Description("Tizen.Multimedia.Remoting.WebRTCTrackAddedEventArgs Tests")]
+    public class WebRTCTrackAddedEventArgsTests : TestBase
+    {
+        [Test]
+        [Category("P1")]
+        [Description("Check whether MediaStreamTrack returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCTrackAddedEventArgs.MediaStreamTrack A")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "PRO")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task MediaStreamTrack_CHECK_EVENT()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<MediaStreamTrack>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var offerClient = new WebRTC())
+            using (var answerClient = new WebRTC())
+            {
+                answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(e.MediaStreamTrack);
+
+                offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+                await offerClient.StartAsync();
+                await answerClient.StartAsync();
+
+                await ConnectPeerAsync(offerClient, answerClient);
+
+                var track = await tcsAnswerTrackAdded.Task;
+
+                Assert.IsNotNull(track, "Should not null");
+                Assert.IsInstanceOf<MediaStreamTrack>(track, "Should be MediaStreamTrack instance");
+                Assert.That(track.Type == MediaType.Video, "Should return proper value");
+            }
+        }
+
+        [Test]
+        [Category("P1")]
+        [Description("Check whether ToString returns expected value or not.")]
+        [Property("SPEC", "Tizen.Multimedia.Remoting.WebRTCTrackAddedEventArgs.ToString M")]
+        [Property("SPEC_URL", "-")]
+        [Property("CRITERIA", "MR")]
+        [Property("AUTHOR", "Haesu Gwon, haesu.gwon@samsung.com")]
+        public async Task ToString_CHECK_VALUE()
+        {
+            var tcsAnswerTrackAdded = new TaskCompletionSource<WebRTCTrackAddedEventArgs>(TaskCreationOptions.RunContinuationsAsynchronously);
+
+            using (var offerClient = new WebRTC())
+            using (var answerClient = new WebRTC())
+            {
+                answerClient.TrackAdded += (s, e) => tcsAnswerTrackAdded.TrySetResult(e);
+
+                offerClient.AddSource(new MediaTestSource(MediaType.Video));
+
+                await offerClient.StartAsync();
+                await answerClient.StartAsync();
+
+                await ConnectPeerAsync(offerClient, answerClient);
+
+                var result = await tcsAnswerTrackAdded.Task;
+
+                Assert.AreEqual($"MediaType={result.MediaStreamTrack.Type}", result.ToString(),
+                    "Should be the same string");
+            }
+        }
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/testcase/support/TestBase.cs b/tct-suite-vs/Tizen.WebRTC.Tests/testcase/support/TestBase.cs
new file mode 100644 (file)
index 0000000..a557ff1
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *  Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+using ElmSharp;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Tizen.Multimedia.Remoting.Tests
+{
+    public class TestBase
+    {
+        protected const string VideoFilePath = "/opt/usr/home/owner/share/res/test.h264";
+
+        protected readonly MediaFormat SimpleFormat =
+            new VideoMediaFormat(MediaFormatVideoMimeType.Mpeg4SP, 640, 480);
+
+        protected bool _offerIceGathering = false, _answerIceGathering = false;
+
+        protected async Task SetRemoteDescriptionAsync(WebRTC webRtc, string sdp)
+        {
+            var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            WebRTCSignalingState targetState = sdp.Contains("offer") ?
+                                                WebRTCSignalingState.HaveRemoteOffer :
+                                                WebRTCSignalingState.Stable;
+
+            EventHandler<WebRTCSignalingStateChangedEventArgs> handler = (s, e) =>
+            {
+                if (e.State == targetState)
+                {
+                    tcs.TrySetResult(true);
+                }
+            };
+
+            try
+            {
+                webRtc.SignalingStateChanged += handler;
+
+                webRtc.SetRemoteDescription(sdp);
+
+                await tcs.Task;
+            }
+            finally
+            {
+                webRtc.SignalingStateChanged -= handler;
+            }
+        }
+
+        protected async Task ConnectPeerAsync(WebRTC offerClient, WebRTC answerClient)
+        {
+            var tcsOfferIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var tcsAnswerIceGatheringStateCompleted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var tcsOfferStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var tcsAnswerStatePlaying = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
+            var offerIceCandidate = new List<string>();
+            var answerIceCandidate = new List<string>();
+            bool offerIceGathering = true, answerIceGathering = true;
+
+            offerClient.IceGatheringStateChanged += (s, e) =>
+            {
+                if (e.State == WebRTCIceGatheringState.Completed)
+                {
+                    offerIceGathering = false;
+                    tcsOfferIceGatheringStateCompleted.TrySetResult(true);
+                }
+            };
+            offerClient.StateChanged += (s, e) =>
+            {
+                if (e.Current == WebRTCState.Playing)
+                {
+                    tcsOfferStatePlaying.TrySetResult(true);
+                }
+            };
+            offerClient.IceCandidate += (s, e) =>
+            {
+                if (offerIceGathering)
+                {
+                    offerIceCandidate.Add(e.ICECandidate);
+                }
+            };
+
+            answerClient.IceGatheringStateChanged += (s, e) =>
+            {
+                if (e.State == WebRTCIceGatheringState.Completed)
+                {
+                    answerIceGathering = false;
+                    tcsAnswerIceGatheringStateCompleted.TrySetResult(true);
+                }
+            };
+            answerClient.StateChanged += (s, e) =>
+            {
+                if (e.Current == WebRTCState.Playing)
+                {
+                    tcsAnswerStatePlaying.TrySetResult(true);
+                }
+            };
+            answerClient.IceCandidate += (s, e) =>
+            {
+                if (answerIceGathering)
+                {
+                    answerIceCandidate.Add(e.ICECandidate);
+                }
+            };
+
+            var sdpOffer = await offerClient.CreateOfferAsync();
+            offerClient.SetLocalDescription(sdpOffer);
+
+            await SetRemoteDescriptionAsync(answerClient, sdpOffer);
+            var sdpAnswer = await answerClient.CreateAnswerAsync();
+            answerClient.SetLocalDescription(sdpAnswer);
+
+            await SetRemoteDescriptionAsync(offerClient, sdpAnswer);
+
+            await Task.WhenAll(tcsOfferIceGatheringStateCompleted.Task, tcsAnswerIceGatheringStateCompleted.Task);
+
+            offerClient.AddIceCandidates(answerIceCandidate);
+            answerClient.AddIceCandidates(offerIceCandidate);
+
+            await Task.WhenAll(tcsOfferStatePlaying.Task, tcsAnswerStatePlaying.Task);
+        }
+
+        internal static Window CreateWindow()
+        {
+            var w = new Window("");
+            w.Resize(100, 100);
+            w.Realize(null);
+            return w;
+        }
+    }
+
+    internal static class LogInfo
+    {
+        internal static readonly string Tag = "Tizen.WebRTC.Tests";
+    }
+}
diff --git a/tct-suite-vs/Tizen.WebRTC.Tests/tizen-manifest.xml b/tct-suite-vs/Tizen.WebRTC.Tests/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..8f94c66
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="9" package="Tizen.WebRTC.Tests" version="1.0.0">
+    <profile name="common" />
+    <ui-application appid="Tizen.WebRTC.Tests"
+                    exec="Tizen.WebRTC.Tests.dll"
+                    type="dotnet"
+                    multiple="false"
+                    taskmanage="true"
+                    launch_mode="single">
+    <icon>Tizen.WebRTC.Tests.png</icon>
+    <label>Tizen.WebRTC.Tests</label>
+    </ui-application>
+    <privileges>
+        <privilege>http://tizen.org/privilege/camera</privilege>
+        <privilege>http://tizen.org/privilege/recorder</privilege>
+        <privilege>http://tizen.org/privilege/internet</privilege>
+        <privilege>http://tizen.org/privilege/mediastorage</privilege>
+        <privilege>http://tizen.org/privilege/externalstorage</privilege>
+        <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+    </privileges>
+</manifest>