From a3cc0c2edee1fc2c49b0e998b704282114e1582a Mon Sep 17 00:00:00 2001 From: Stefan Schreistetter Date: Thu, 29 Aug 2019 18:02:17 +0200 Subject: [PATCH] Changed architecture to reflect separation between web socket server and eye tracker. --- GazeWebSocketServer.sln | 6 ++++++ GazeWebSocketServer/EyeTrackerClient.cs | 58 ---------------------------------------------------------- GazeWebSocketServer/GazeCoordinateBehavior.cs | 23 ++--------------------- GazeWebSocketServer/GazeData.cs | 35 ----------------------------------- GazeWebSocketServer/GazeDataProcessor.cs | 33 --------------------------------- GazeWebSocketServer/GazeServer.cs | 37 +++++++++++++++++++++++++++++++++++++ GazeWebSocketServer/GazeWebSocketServer.csproj | 10 +++++++--- GazeWebSocketServer/Program.cs | 39 +++++++++++++++++++++++++++++++-------- TobiiBridge/Class1.cs | 17 +++++++++++++++++ TobiiBridge/TobiiBridge.csproj | 15 +++++++++++++++ TrackerBridge/GazeData.cs | 35 +++++++++++++++++++++++++++++++++++ TrackerBridge/GazeDataProcessor.cs | 33 +++++++++++++++++++++++++++++++++ TrackerBridge/Properties/AssemblyInfo.cs | 36 ++++++++++++++++++++++++++++++++++++ TrackerBridge/TobiiEyeTracker.cs | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TrackerBridge/TrackerBridge.csproj | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TrackerBridge/packages.config | 4 ++++ 16 files changed, 396 insertions(+), 158 deletions(-) delete mode 100644 GazeWebSocketServer/EyeTrackerClient.cs delete mode 100644 GazeWebSocketServer/GazeData.cs delete mode 100644 GazeWebSocketServer/GazeDataProcessor.cs create mode 100644 GazeWebSocketServer/GazeServer.cs create mode 100644 TobiiBridge/Class1.cs create mode 100644 TobiiBridge/TobiiBridge.csproj create mode 100644 TrackerBridge/GazeData.cs create mode 100644 TrackerBridge/GazeDataProcessor.cs create mode 100644 TrackerBridge/Properties/AssemblyInfo.cs create mode 100644 TrackerBridge/TobiiEyeTracker.cs create mode 100644 TrackerBridge/TrackerBridge.csproj create mode 100644 TrackerBridge/packages.config diff --git a/GazeWebSocketServer.sln b/GazeWebSocketServer.sln index 9b2d5ef..b754b70 100644 --- a/GazeWebSocketServer.sln +++ b/GazeWebSocketServer.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29209.62 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GazeWebSocketServer", "GazeWebSocketServer\GazeWebSocketServer.csproj", "{F8F11E64-7946-4054-8C27-F0FCAF967F1A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrackerBridge", "TrackerBridge\TrackerBridge.csproj", "{64D52257-ECA7-4F4D-A901-B14D544A1D0A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {F8F11E64-7946-4054-8C27-F0FCAF967F1A}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8F11E64-7946-4054-8C27-F0FCAF967F1A}.Release|Any CPU.ActiveCfg = Release|Any CPU {F8F11E64-7946-4054-8C27-F0FCAF967F1A}.Release|Any CPU.Build.0 = Release|Any CPU + {64D52257-ECA7-4F4D-A901-B14D544A1D0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64D52257-ECA7-4F4D-A901-B14D544A1D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64D52257-ECA7-4F4D-A901-B14D544A1D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64D52257-ECA7-4F4D-A901-B14D544A1D0A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GazeWebSocketServer/EyeTrackerClient.cs b/GazeWebSocketServer/EyeTrackerClient.cs deleted file mode 100644 index 91f84ab..0000000 --- a/GazeWebSocketServer/EyeTrackerClient.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tobii.Research; - -namespace GazeWebSocketServer -{ - class EyeTrackerClient - { - private IEyeTracker eyeTracker; - private GazeDataProcessor gazeDataProcessor; - private List gazeCoordinateBehaviors; - - public EyeTrackerClient(ConfigurationData config) - { - gazeCoordinateBehaviors = new List(); - while (eyeTracker == null) - { - EyeTrackerCollection eyeTrackers = EyeTrackingOperations.FindAllEyeTrackers(); - if (eyeTrackers.Count > 0) - { - foreach(IEyeTracker t in eyeTrackers) - { - if(config.TrackerSerialNumber == t.SerialNumber) - { - eyeTracker = t; - } - } - } - } - gazeDataProcessor = new GazeDataProcessor(); - eyeTracker.SetGazeOutputFrequency(config.TrackerFrequency); - } - - public void Start(GazeCoordinateBehavior gazeCoordinateBehavior) - { - gazeCoordinateBehaviors.Add(gazeCoordinateBehavior); - eyeTracker.GazeDataReceived += GazeDataReceivedHandler; - } - - public void Stop() - { - eyeTracker.GazeDataReceived -= GazeDataReceivedHandler; - } - - private void GazeDataReceivedHandler(object sender, GazeDataEventArgs e) - { - GazeData gazeData = gazeDataProcessor.Extract(e); - foreach(GazeCoordinateBehavior behavior in gazeCoordinateBehaviors) - { - behavior.Publish(gazeData); - } - Console.WriteLine(gazeData.ToString()); - } - } -} \ No newline at end of file diff --git a/GazeWebSocketServer/GazeCoordinateBehavior.cs b/GazeWebSocketServer/GazeCoordinateBehavior.cs index 52dd255..e3c05fb 100644 --- a/GazeWebSocketServer/GazeCoordinateBehavior.cs +++ b/GazeWebSocketServer/GazeCoordinateBehavior.cs @@ -3,34 +3,15 @@ using WebSocketSharp; using WebSocketSharp.Server; using System.Collections.Generic; using System.Text; +using TrackerBridge; namespace GazeWebSocketServer { public class GazeCoordinateBehavior : WebSocketBehavior { - private EyeTrackerClient eyeTrackerClient; - - public GazeCoordinateBehavior(ConfigurationData config) + public GazeCoordinateBehavior() { Console.WriteLine("Creating behavior..."); - eyeTrackerClient = new EyeTrackerClient(config); - eyeTrackerClient.Start(this); - } - - //~GazeCoordinateBehavior() - //{ - // eyeTrackerClient.Stop(); - //} - - //protected override void OnOpen() - //{ - // throw new NotImplementedException(); - // //base.OnOpen(); - //} - - internal void Publish(GazeData gazeData) - { - Sessions?.Broadcast(gazeData.ToString()); } } } diff --git a/GazeWebSocketServer/GazeData.cs b/GazeWebSocketServer/GazeData.cs deleted file mode 100644 index c9db035..0000000 --- a/GazeWebSocketServer/GazeData.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace GazeWebSocketServer -{ - struct GazeData - { - public readonly float leftX; - public readonly float leftY; - public readonly float rightX; - public readonly float rightY; - - public readonly long trackerTimeStamp; - public readonly long systemTimeStamp; - - public GazeData(float leftX, float leftY, float rightX, float rightY, long trackerTimeStamp, long systemTimeStamp) - { - this.leftX = leftX; - this.leftY = leftY; - this.rightX = rightX; - this.rightY = rightY; - this.trackerTimeStamp = trackerTimeStamp; - this.systemTimeStamp = systemTimeStamp; - } - - public override string ToString() - { - FormattableString message = $"{leftX};{leftY};{rightX};{rightY};{trackerTimeStamp};{systemTimeStamp}"; - return FormattableString.Invariant(message); - } - } -} diff --git a/GazeWebSocketServer/GazeDataProcessor.cs b/GazeWebSocketServer/GazeDataProcessor.cs deleted file mode 100644 index adc6a58..0000000 --- a/GazeWebSocketServer/GazeDataProcessor.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Windows; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tobii.Research; - -namespace GazeWebSocketServer -{ - class GazeDataProcessor - { - readonly float screenHeight; - readonly float screenWidth; - - public GazeDataProcessor() - { - screenHeight = Convert.ToSingle(SystemParameters.PrimaryScreenHeight); - screenWidth = Convert.ToSingle(SystemParameters.PrimaryScreenWidth); - } - - public GazeData Extract(GazeDataEventArgs e) - { - GazeData data = new GazeData(e.LeftEye.GazePoint.PositionOnDisplayArea.X*screenWidth, - e.LeftEye.GazePoint.PositionOnDisplayArea.Y*screenHeight, - e.RightEye.GazePoint.PositionOnDisplayArea.X*screenWidth, - e.RightEye.GazePoint.PositionOnDisplayArea.Y*screenHeight, - e.DeviceTimeStamp, - e.SystemTimeStamp); - return data; - } - } -} diff --git a/GazeWebSocketServer/GazeServer.cs b/GazeWebSocketServer/GazeServer.cs new file mode 100644 index 0000000..f431e96 --- /dev/null +++ b/GazeWebSocketServer/GazeServer.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WebSocketSharp.Server; +using TrackerBridge; + +namespace GazeWebSocketServer +{ + class GazeServer + { + private WebSocketServer wssv; + public GazeServer(Int32 port, String endpoint) + { + wssv = new WebSocketServer(port); + wssv.Log.Level = WebSocketSharp.LogLevel.Trace; + wssv.AddWebSocketService(endpoint, () => new GazeCoordinateBehavior()); + } + public void Start() + { + wssv.Start(); + } + + public void Publish(GazeData gazeData) + { + WebSocketServiceManager wssm = wssv.WebSocketServices; + foreach(WebSocketServiceHost serviceHost in wssm.Hosts) + { + if (serviceHost.Type == typeof(GazeCoordinateBehavior)) + { + serviceHost.Sessions?.Broadcast(gazeData.ToString()); + } + } + } + } +} diff --git a/GazeWebSocketServer/GazeWebSocketServer.csproj b/GazeWebSocketServer/GazeWebSocketServer.csproj index b75a431..3b325fb 100644 --- a/GazeWebSocketServer/GazeWebSocketServer.csproj +++ b/GazeWebSocketServer/GazeWebSocketServer.csproj @@ -54,10 +54,8 @@ - - - + @@ -66,6 +64,12 @@ + + + {64d52257-eca7-4f4d-a901-b14d544a1d0a} + TrackerBridge + + diff --git a/GazeWebSocketServer/Program.cs b/GazeWebSocketServer/Program.cs index 19003e0..045f672 100644 --- a/GazeWebSocketServer/Program.cs +++ b/GazeWebSocketServer/Program.cs @@ -1,25 +1,48 @@ using System; +using System.Threading.Tasks; +using System.Threading; using WebSocketSharp; using WebSocketSharp.Server; using Tobii.Research; +using TrackerBridge; namespace GazeWebSocketServer { public class Program { + private static GazeServer gazeServer; public static void Main(string[] args) { ConfigurationData.InitializeUnexistingWithDefaults(); ConfigurationData config = ConfigurationData.ParseToObject(); - var wssv = new WebSocketServer(config.WebSocketPort); - wssv.KeepClean = true; - GazeCoordinateBehavior behavior = new GazeCoordinateBehavior(config); - wssv.AddWebSocketService(config.WebSocketEndpoint, () => behavior); - - wssv.Start(); - Console.ReadKey(true); - wssv.Stop(); + TobiiEyeTracker tobiiEyeTracker = new TobiiEyeTracker(config.TrackerSerialNumber); + tobiiEyeTracker.ConnectionEvent += OnConnectionEstablished; + tobiiEyeTracker.ConnectionTimeout += OnConnectionTimeout; + tobiiEyeTracker.GazeDataAvailable += OnGazeDataAvailable; + tobiiEyeTracker.Connect(); + + gazeServer = new GazeServer(config.WebSocketPort, config.WebSocketEndpoint); + gazeServer.Start(); + Console.ReadLine(); + } + + private static void OnGazeDataAvailable(TobiiEyeTracker sender, GazeData data) + { + Console.WriteLine(data); + gazeServer.Publish(data); + } + + private static void OnConnectionTimeout(TobiiEyeTracker sender) + { + Console.WriteLine("Timeout while searching for trackers."); + } + + private static void OnConnectionEstablished(TobiiEyeTracker sender) + { + Console.WriteLine($"Tracker {sender.ToString()} connected."); + ConfigurationData config = ConfigurationData.ParseToObject(); + sender.SetTrackingFrequency(config.TrackerFrequency); } } } \ No newline at end of file diff --git a/TobiiBridge/Class1.cs b/TobiiBridge/Class1.cs new file mode 100644 index 0000000..a84680e --- /dev/null +++ b/TobiiBridge/Class1.cs @@ -0,0 +1,17 @@ +using System; + +namespace TobiiBridge +{ + public class EyeTracker + { + public EyeTracker() + { + + } + + public EyeTracker(String serialNumber) + { + + } + } +} diff --git a/TobiiBridge/TobiiBridge.csproj b/TobiiBridge/TobiiBridge.csproj new file mode 100644 index 0000000..b9a4f46 --- /dev/null +++ b/TobiiBridge/TobiiBridge.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + + + + x64 + + + + + + + diff --git a/TrackerBridge/GazeData.cs b/TrackerBridge/GazeData.cs new file mode 100644 index 0000000..152a70b --- /dev/null +++ b/TrackerBridge/GazeData.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TrackerBridge +{ + public struct GazeData + { + public readonly float leftX; + public readonly float leftY; + public readonly float rightX; + public readonly float rightY; + + public readonly long trackerTimeStamp; + public readonly long systemTimeStamp; + + public GazeData(float leftX, float leftY, float rightX, float rightY, long trackerTimeStamp, long systemTimeStamp) + { + this.leftX = leftX; + this.leftY = leftY; + this.rightX = rightX; + this.rightY = rightY; + this.trackerTimeStamp = trackerTimeStamp; + this.systemTimeStamp = systemTimeStamp; + } + + public override string ToString() + { + FormattableString message = $"{leftX};{leftY};{rightX};{rightY};{trackerTimeStamp};{systemTimeStamp}"; + return FormattableString.Invariant(message); + } + } +} diff --git a/TrackerBridge/GazeDataProcessor.cs b/TrackerBridge/GazeDataProcessor.cs new file mode 100644 index 0000000..ca6545a --- /dev/null +++ b/TrackerBridge/GazeDataProcessor.cs @@ -0,0 +1,33 @@ +using System; +using System.Windows; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tobii.Research; + +namespace TrackerBridge +{ + public class GazeDataProcessor + { + readonly float screenHeight; + readonly float screenWidth; + + public GazeDataProcessor() + { + screenHeight = Convert.ToSingle(SystemParameters.PrimaryScreenHeight); + screenWidth = Convert.ToSingle(SystemParameters.PrimaryScreenWidth); + } + + public GazeData Extract(GazeDataEventArgs e) + { + GazeData data = new GazeData(e.LeftEye.GazePoint.PositionOnDisplayArea.X*screenWidth, + e.LeftEye.GazePoint.PositionOnDisplayArea.Y*screenHeight, + e.RightEye.GazePoint.PositionOnDisplayArea.X*screenWidth, + e.RightEye.GazePoint.PositionOnDisplayArea.Y*screenHeight, + e.DeviceTimeStamp, + e.SystemTimeStamp); + return data; + } + } +} diff --git a/TrackerBridge/Properties/AssemblyInfo.cs b/TrackerBridge/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d0d63ba --- /dev/null +++ b/TrackerBridge/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("TrackerBridge")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("OTH Regensburg")] +[assembly: AssemblyProduct("TrackerBridge")] +[assembly: AssemblyCopyright("Copyright © OTH Regensburg 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("64d52257-eca7-4f4d-a901-b14d544a1d0a")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/TrackerBridge/TobiiEyeTracker.cs b/TrackerBridge/TobiiEyeTracker.cs new file mode 100644 index 0000000..e7fe5c9 --- /dev/null +++ b/TrackerBridge/TobiiEyeTracker.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tobii.Research; + +namespace TrackerBridge +{ + public class TobiiEyeTracker + { + public delegate void ConnectionEventHandler(TobiiEyeTracker sender); + public delegate void GazeDataHandler(TobiiEyeTracker sender, GazeData data); + public event ConnectionEventHandler ConnectionEvent; + public event ConnectionEventHandler ConnectionTimeout; + public event GazeDataHandler GazeDataAvailable; + + public Boolean IsConnected { get; private set; } + + private IEyeTracker eyeTracker = null; + private String serialNumber = null; + private GazeDataProcessor gazeDataProcessor; + + public TobiiEyeTracker() + { + gazeDataProcessor = new GazeDataProcessor(); + } + + public TobiiEyeTracker(String serialNumber) : this() + { + this.serialNumber = serialNumber; + } + + public float GetTrackingFrequency() + { + if (eyeTracker != null) + { + return eyeTracker.GetGazeOutputFrequency(); + } + else + { + throw new NullReferenceException(); + } + } + public void SetTrackingFrequency(float value) + { + if (eyeTracker != null) + { + eyeTracker.SetGazeOutputFrequency(value); + } + } + + public void Connect() + { + Task task = new Task(() => InitiateConnection()); + task.Start(); + } + + private void InitiateConnection() + { + DateTime time = DateTime.Now; + while (eyeTracker == null) + { + EyeTrackerCollection eyeTrackers = EyeTrackingOperations.FindAllEyeTrackers(); + if (eyeTrackers.Count > 0) + { + if (serialNumber == null) + { + eyeTracker = eyeTrackers[0]; + break; + } + else + { + foreach (IEyeTracker t in eyeTrackers) + { + if (serialNumber == t.SerialNumber) + { + eyeTracker = t; + break; + } + } + } + } + + if (eyeTracker != null) + { + break; + } + + if ((DateTime.Now - time) > (new TimeSpan(0, 0, 30))) + { + ConnectionTimeout?.Invoke(this); + } + } + eyeTracker.GazeDataReceived += OnGazeDataReceived; + SetTrackingFrequency(600f); + ConnectionEvent?.Invoke(this); + } + + private void OnGazeDataReceived(object sender, GazeDataEventArgs e) + { + GazeData gazeData = gazeDataProcessor.Extract(e); + GazeDataAvailable?.Invoke(this, gazeData); + } + } +} \ No newline at end of file diff --git a/TrackerBridge/TrackerBridge.csproj b/TrackerBridge/TrackerBridge.csproj new file mode 100644 index 0000000..2b99db3 --- /dev/null +++ b/TrackerBridge/TrackerBridge.csproj @@ -0,0 +1,67 @@ + + + + + Debug + AnyCPU + {64D52257-ECA7-4F4D-A901-B14D544A1D0A} + Library + Properties + TrackerBridge + TrackerBridge + v4.7.2 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + x64 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + ..\packages\Tobii.Research.x64.1.7.0.1070\lib\net452\Tobii.Research.dll + + + + + + + + + + + + + + + + Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Verwenden Sie die Wiederherstellung von NuGet-Paketen, um die fehlenden Dateien herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}". + + + + \ No newline at end of file diff --git a/TrackerBridge/packages.config b/TrackerBridge/packages.config new file mode 100644 index 0000000..03fedc7 --- /dev/null +++ b/TrackerBridge/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file -- libgit2 0.26.0