-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathALXRRemoteModule.cs
148 lines (126 loc) · 5.05 KB
/
ALXRRemoteModule.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using VRCFaceTracking;
using ALXR;
using LibALXR;
using static ALXR.ModuleUtils;
namespace ALXRRemoteModule
{
public sealed class ALXRRemoteModule : ExtTrackingModule
{
private bool eyeActive = true;
private bool lipActive = true;
private ALXRModuleConfig config = new ALXRModuleConfig();
private XrPosefOneEuroFilter[] poseFilters = new XrPosefOneEuroFilter[2]
{
new XrPosefOneEuroFilter(),
new XrPosefOneEuroFilter(),
};
public override (bool SupportsEye, bool SupportsExpression) Supported => (true, true);
public override (bool eyeSuccess, bool expressionSuccess) Initialize(bool eyeAvailable, bool expressionAvailable)
{
try
{
ModuleInformation.Name = "ALXR Remote Module";
eyeActive = eyeAvailable;
lipActive = expressionAvailable;
config = LoadOrNewConfig(Logger);
Debug.Assert(config != null);
var filterParams = config.EyeTrackingConfig.EyeTrackingFilterParams.FilterParams;
Array.ForEach(poseFilters, p => p.FilterParams = filterParams);
LoadTrackingSensitivity(config, Logger);
return (eyeActive, lipActive);
}
catch (Exception ex)
{
Logger.Log(LogLevel.Error, ex.ToString());
return (false, false);
}
}
private TcpClient client = null;
private NetworkStream stream = null;
private const int ConnectionTimeoutMs = 2000;
private Stopwatch stopwatch = new Stopwatch();
public override void Update()
{
try
{
ConnectToServer();
var newPacket = ReadALXRFacialEyePacket(stream);
ApplyFilters(ref newPacket);
UpdateData(ref newPacket, eyeActive, lipActive);
}
catch (Exception e)
{
Logger.Log(LogLevel.Error, e.Message);
client?.Close();
stream = null;
client = null;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ApplyEyeGazeFilters(float deltaTime, ref ALXRFacialEyePacket packet)
{
packet.eyeGazePose0 = poseFilters[0].Filter(deltaTime, packet.eyeGazePose0);
packet.eyeGazePose1 = poseFilters[1].Filter(deltaTime, packet.eyeGazePose1);
}
private void ApplyFilters(ref ALXRFacialEyePacket newPacket)
{
if (!config.EyeTrackingConfig.EyeTrackingFilterParams.Enable)
return;
var deltaTime = (float)stopwatch.Elapsed.TotalSeconds;
stopwatch.Restart();
ApplyEyeGazeFilters(deltaTime, ref newPacket);
}
private void ConnectToServer()
{
if (client != null && client.Connected)
return;
client?.Close();
client = new TcpClient()
{
NoDelay = true,
};
var remoteConfig = config.RemoteConfig;
Logger.Log(LogLevel.Information, $"Attempting to establish a connection at {remoteConfig.ClientIpAddress}:{remoteConfig.PortNo}...");
var result = client.BeginConnect(remoteConfig.ClientIpAddress, remoteConfig.PortNo, null, null);
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(ConnectionTimeoutMs)))
{
throw new Exception($"Establishing connection timed-out");
}
client.EndConnect(result);
stream = client.GetStream();
Debug.Assert(stream != null);
stream.ReadTimeout = ConnectionTimeoutMs;
Array.ForEach(poseFilters, x => x.Reset());
Logger.Log(LogLevel.Information, $"Successfully connected to ALXR client: {remoteConfig.ClientIpAddress}:{remoteConfig.PortNo}");
Debug.Assert(client != null && stream != null);
}
private byte[] rawExprBuffer = new byte[Marshal.SizeOf<ALXRFacialEyePacket>()];
private ALXRFacialEyePacket ReadALXRFacialEyePacket(NetworkStream stream)
{
Debug.Assert(stream != null && stream.CanRead);
int offset = 0;
int readBytes = 0;
do
{
readBytes = stream.Read(rawExprBuffer, offset, rawExprBuffer.Length - offset);
offset += readBytes;
}
while (readBytes > 0 && offset < rawExprBuffer.Length);
if (offset < rawExprBuffer.Length)
throw new Exception("Failed read packet.");
return ALXRFacialEyePacket.ReadPacket(rawExprBuffer);
}
public override void Teardown()
{
client?.Close();
stream = null;
client = null;
}
}
}