using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
using LZ4Sharp;
namespace com.rfilkov.kinect
{
///
/// Kinect net-server listens for client connections and sends the data from the given sensor's streams to its clients over the network.
///
public class KinectNetServer : MonoBehaviour
{
[Tooltip("Depth sensor index - 0 is the 1st one, 1 - the 2nd one, etc.")]
public int sensorIndex = 0;
[Tooltip("The base port for all sensor frame streams (each frame stream listens on separate port).")]
public int baseListenPort = 11000;
[Tooltip("Whether to listen for auto-server-discovery broadcasts (local network only).")]
public bool listenForServerDiscovery = false;
[Tooltip("Whether to serve the body index frames along with the body frames.")]
private bool serveBodyIndexFrames = true;
[Tooltip("Whether to compress the raw data frames (like depth, body index, etc.) or not.")]
public bool compressRawFrames = true;
[Tooltip("UI-Text to display the connection status messages.")]
public Text connStatusText;
[Tooltip("UI-Text to display the server status messages.")]
public Text serverStatusText;
[Tooltip("UI-Text to display the server console messages.")]
public Text consoleText;
// references
private KinectManager kinectManager = null;
private KinectInterop.SensorData sensorData = null;
// keep-alive
private ulong lastKeepAliveFrameTime = 0;
private const int keepAliveInterval = 20000000; // 2 seconds
// sensor frame servers
private TcpNetServer controlFrameServer = null;
private TcpNetServer colorFrameServer = null;
private TcpNetServer depthFrameServer = null;
private TcpNetServer infraredFrameServer = null;
private TcpNetServer bodyDataFrameServer = null;
private TcpNetServer bodyIndexFrameServer = null;
private TcpNetServer poseFrameServer = null;
private TcpNetServer depth2colorFrameServer = null;
private TcpNetServer color2depthFrameServer = null;
private TcpNetServer color2infraredFrameServer = null;
private TcpNetServer color2bodyIndexFrameServer = null;
// auto-server-discovery broadcast server
private UdpBroadcastServer autoDiscoveryServer = null;
// sensor frame timestamps
//private ulong lastControlFrameTime = 0;
private ulong lastColorFrameTime = 0;
private ulong lastDepthFrameTime = 0;
private ulong lastInfraredFrameTime = 0;
private ulong lastBodyDataFrameTime = 0;
private ulong lastBodyIndexFrameTime = 0;
private ulong lastPoseFrameTime = 0;
private ulong lastDepth2ColorFrameTime = 0;
private ulong lastColor2DepthFrameTime = 0;
private ulong lastColor2InfraredFrameTime = 0;
private ulong lastColor2BodyIndexFrameTime = 0;
// stream 2d textures
//private Texture2D colorTex2d = null;
//private Texture2D depthTex2d = null;
private Texture2D infraredTex2d = null;
private Texture2D depth2colorTex2d = null;
private Texture2D color2infraredTex2d = null;
// depth & bi frame bytes
byte[] colorCamDepthFrameData = null;
byte[] colorCamBodyIndexFrameData = null;
// last sensor pose
private string lastSensorPoseStr = string.Empty;
//// whether color2depth is enabled or not
//private bool color2depthEnabled = false;
//private bool color2bodyIndexEnabled = false;
// compressors
private ILZ4Compressor controlFrameCompressor = null;
private ILZ4Compressor depthFrameCompressor = null;
private ILZ4Compressor bodyIndexFrameCompressor = null;
private ILZ4Compressor color2depthFrameCompressor = null;
private ILZ4Compressor color2bodyIndexFrameCompressor = null;
// console buffer
private System.Text.StringBuilder sbConsole = new System.Text.StringBuilder();
void Start()
{
kinectManager = KinectManager.Instance;
sensorData = kinectManager ? kinectManager.GetSensorData(sensorIndex) : null;
if(sensorData != null && sensorData.sensorInterface != null)
{
// cache space tables
Debug.Log("Caching space tables of sensor " + sensorIndex + "...");
sensorData.sensorInterface.GetDepthCameraSpaceTable(sensorData);
sensorData.sensorInterface.GetColorCameraSpaceTable(sensorData);
// init servers
Debug.Log("Initing network servers of sensor " + sensorIndex + "...");
KinectInterop.FrameSource dwFlags = ((DepthSensorBase)sensorData.sensorInterface).frameSourceFlags;
InitNetServers(dwFlags);
}
else
{
Debug.LogError("KinectManager not found or not initialized.");
if (serverStatusText)
{
serverStatusText.text = "KinectManager not found or not initialized.";
}
}
}
void OnDestroy()
{
// close all net servers
CloseNetServers();
}
void Update()
{
if(connStatusText)
{
// update conn status
int connCount = GetConnectionsCount();
connStatusText.text = string.Format("NetServer running: {0} connections.", connCount);
}
if(sbConsole.Length > 0)
{
// update console
lock(sbConsole)
{
if(consoleText)
consoleText.text += sbConsole.ToString();
sbConsole.Clear();
}
// scroll to end
ScrollRect scrollRect = consoleText ? consoleText.gameObject.GetComponentInParent() : null;
if (scrollRect)
{
Canvas.ForceUpdateCanvases();
scrollRect.verticalScrollbar.value = 0f;
Canvas.ForceUpdateCanvases();
}
}
// check for updated data
UpdateNetServers();
}
// initializes the sensor net servers
private void InitNetServers(KinectInterop.FrameSource dwFlags)
{
try
{
lastKeepAliveFrameTime = 0;
lastSensorPoseStr = string.Empty;
int minPort = int.MaxValue, maxPort = int.MinValue;
controlFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Control, "ControlServer", sbConsole);
controlFrameServer.ReceivedMessage += new ReceivedMessageEventHandler(ControlFrameReceived);
minPort = Mathf.Min(minPort, controlFrameServer.serverPort); maxPort = Mathf.Max(maxPort, controlFrameServer.serverPort);
if (compressRawFrames)
controlFrameCompressor = LZ4CompressorFactory.CreateNew();
if ((dwFlags & KinectInterop.FrameSource.TypeColor) != 0 && sensorData.colorImageTexture != null)
{
colorFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Color, "ColorServer", sbConsole);
minPort = Mathf.Min(minPort, colorFrameServer.serverPort); maxPort = Mathf.Max(maxPort, colorFrameServer.serverPort);
}
if((dwFlags & KinectInterop.FrameSource.TypeDepth) != 0)
{
depthFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Depth, "DepthServer", sbConsole);
minPort = Mathf.Min(minPort, depthFrameServer.serverPort); maxPort = Mathf.Max(maxPort, depthFrameServer.serverPort);
if(compressRawFrames)
depthFrameCompressor = LZ4CompressorFactory.CreateNew();
}
if ((dwFlags & KinectInterop.FrameSource.TypeInfrared) != 0)
{
infraredTex2d = new Texture2D(sensorData.depthImageWidth, sensorData.depthImageHeight, TextureFormat.ARGB32, false);
infraredFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Infrared, "InfraredServer", sbConsole);
minPort = Mathf.Min(minPort, infraredFrameServer.serverPort); maxPort = Mathf.Max(maxPort, infraredFrameServer.serverPort);
}
if ((dwFlags & KinectInterop.FrameSource.TypeBody) != 0)
{
bodyDataFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.BodyData, "BodyDataServer", sbConsole);
minPort = Mathf.Min(minPort, bodyDataFrameServer.serverPort); maxPort = Mathf.Max(maxPort, bodyDataFrameServer.serverPort);
}
if ((dwFlags & KinectInterop.FrameSource.TypeBodyIndex) != 0 && serveBodyIndexFrames)
{
bodyIndexFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.BodyIndex, "BodyIndexServer", sbConsole);
minPort = Mathf.Min(minPort, bodyIndexFrameServer.serverPort); maxPort = Mathf.Max(maxPort, bodyIndexFrameServer.serverPort);
if (compressRawFrames)
bodyIndexFrameCompressor = LZ4CompressorFactory.CreateNew();
}
if ((dwFlags & KinectInterop.FrameSource.TypePose) != 0)
{
poseFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Pose, "PoseServer", sbConsole);
minPort = Mathf.Min(minPort, poseFrameServer.serverPort); maxPort = Mathf.Max(maxPort, poseFrameServer.serverPort);
}
if ((dwFlags & KinectInterop.FrameSource.TypeColor) != 0 && (dwFlags & KinectInterop.FrameSource.TypeDepth) != 0)
{
depth2colorFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Depth2Color, "TColorServer", sbConsole);
minPort = Mathf.Min(minPort, depth2colorFrameServer.serverPort); maxPort = Mathf.Max(maxPort, depth2colorFrameServer.serverPort);
}
if ((dwFlags & KinectInterop.FrameSource.TypeColor) != 0 && (dwFlags & KinectInterop.FrameSource.TypeDepth) != 0)
{
color2depthFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Color2Depth, "TDepthServer", sbConsole);
minPort = Mathf.Min(minPort, color2depthFrameServer.serverPort); maxPort = Mathf.Max(maxPort, color2depthFrameServer.serverPort);
if (compressRawFrames)
color2depthFrameCompressor = LZ4CompressorFactory.CreateNew();
}
if ((dwFlags & KinectInterop.FrameSource.TypeColor) != 0 && (dwFlags & KinectInterop.FrameSource.TypeDepth) != 0)
{
color2infraredFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Color2Infrared, "TInfraredServer", sbConsole);
minPort = Mathf.Min(minPort, color2infraredFrameServer.serverPort); maxPort = Mathf.Max(maxPort, color2infraredFrameServer.serverPort);
}
if ((dwFlags & KinectInterop.FrameSource.TypeColor) != 0 && (dwFlags & KinectInterop.FrameSource.TypeDepth) != 0 && (dwFlags & KinectInterop.FrameSource.TypeBodyIndex) != 0)
{
color2bodyIndexFrameServer = new TcpNetServer(baseListenPort + (int)NetMessageType.Color2BodyIndex, "TBodyIndex", sbConsole);
minPort = Mathf.Min(minPort, color2bodyIndexFrameServer.serverPort); maxPort = Mathf.Max(maxPort, color2bodyIndexFrameServer.serverPort);
if (compressRawFrames)
color2bodyIndexFrameCompressor = LZ4CompressorFactory.CreateNew();
}
// get server ip address
string serverName = GetLocalNameOrIP();
if (listenForServerDiscovery)
{
int sensorType = (int)sensorData.sensorInterface.GetSensorPlatform();
string sensorId = sensorData.sensorInterface.GetSensorDeviceId();
string responseData = string.Format("KNS|{0}|{1}|{2}|{3}", serverName, baseListenPort, sensorType, sensorId);
autoDiscoveryServer = new UdpBroadcastServer(baseListenPort, "DiscoveryServer", "KNS", responseData, sbConsole);
}
if (serverStatusText)
{
serverStatusText.text = string.Format("NetServer listens on {0}:{1}-{2}", serverName, minPort, maxPort);
}
}
catch (System.Exception ex)
{
Debug.LogError("Error initing NetServer: " + ex.Message);
Debug.Log(ex);
if (serverStatusText)
{
serverStatusText.text = string.Format("Error initing NetServer: {0}", ex.Message);
}
}
}
// closes all sensor net servers
private void CloseNetServers()
{
try
{
if (controlFrameServer != null)
{
controlFrameServer.ReceivedMessage -= new ReceivedMessageEventHandler(ControlFrameReceived);
controlFrameServer.Close();
controlFrameServer = null;
controlFrameCompressor = null;
}
if (colorFrameServer != null)
{
colorFrameServer.Close();
colorFrameServer = null;
}
if (depthFrameServer != null)
{
depthFrameServer.Close();
depthFrameServer = null;
depthFrameCompressor = null;
}
if (infraredFrameServer != null)
{
infraredFrameServer.Close();
infraredFrameServer = null;
}
if (bodyDataFrameServer != null)
{
bodyDataFrameServer.Close();
bodyDataFrameServer = null;
}
if (bodyIndexFrameServer != null)
{
bodyIndexFrameServer.Close();
bodyIndexFrameServer = null;
bodyIndexFrameCompressor = null;
}
if (poseFrameServer != null)
{
poseFrameServer.Close();
poseFrameServer = null;
}
if (depth2colorFrameServer != null)
{
depth2colorFrameServer.Close();
depth2colorFrameServer = null;
}
if (color2depthFrameServer != null)
{
color2depthFrameServer.Close();
color2depthFrameServer = null;
color2depthFrameCompressor = null;
}
if (color2infraredFrameServer != null)
{
color2infraredFrameServer.Close();
color2infraredFrameServer = null;
}
if (color2bodyIndexFrameServer != null)
{
color2bodyIndexFrameServer.Close();
color2bodyIndexFrameServer = null;
color2bodyIndexFrameCompressor = null;
}
if(autoDiscoveryServer != null)
{
autoDiscoveryServer.Close();
autoDiscoveryServer = null;
}
if (serverStatusText)
{
serverStatusText.text = "NetServer closed.";
}
}
catch (System.Exception ex)
{
Debug.LogError("Error closing NetServer: " + ex.Message);
Debug.Log(ex);
if (serverStatusText)
{
serverStatusText.text = string.Format("Error closing NetServer: {0}", ex.Message);
}
}
}
// checks for updated sensor data and sends it to the connected clients
private void UpdateNetServers()
{
if (sensorData == null)
return;
try
{
// control - keep alive
ulong ulTimeNow = (ulong)System.DateTime.Now.Ticks;
bool isControlClientActive = controlFrameServer != null ? controlFrameServer.IsActive() : false;
if ((ulTimeNow - lastKeepAliveFrameTime) >= keepAliveInterval && isControlClientActive)
{
lastKeepAliveFrameTime = ulTimeNow;
SendControlMessage(ControlMessageType.KeepAlive);
}
// wait all current messages to be sent
if (GetMessageCount(false) > 0)
return;
// color frame
if (colorFrameServer != null && colorFrameServer.GetConnCount() > 0)
{
if(sensorData.lastColorFrameTime != lastColorFrameTime)
{
lastColorFrameTime = sensorData.lastColorFrameTime;
byte[] btColorData = ((Texture2D)sensorData.colorImageTexture).EncodeToJPG();
NetMessageData message = new NetMessageData(NetMessageType.Color, FrameEncodeType.Jpeg,
sensorData.colorImageWidth, sensorData.colorImageHeight, lastColorFrameTime);
message.SetData(btColorData);
colorFrameServer.SendMessageToAllConnections(message);
}
}
// depth frame
if (depthFrameServer != null && depthFrameServer.GetConnCount() > 0)
{
if (sensorData.lastDepthFrameTime != lastDepthFrameTime)
{
lastDepthFrameTime = sensorData.lastDepthFrameTime;
NetMessageData message = new NetMessageData(NetMessageType.Depth, FrameEncodeType.Raw,
sensorData.depthImageWidth, sensorData.depthImageHeight, lastDepthFrameTime);
message.SetData(sensorData.depthImage);
if (compressRawFrames)
{
message.SetCompressor(depthFrameCompressor);
message.CompressData();
}
depthFrameServer.SendMessageToAllConnections(message);
}
}
// infrared frame
if (infraredFrameServer != null && infraredFrameServer.GetConnCount() > 0)
{
if (sensorData.lastInfraredImageTime != lastInfraredFrameTime)
{
lastInfraredFrameTime = sensorData.lastInfraredImageTime;
byte[] btInfraredData = GetTextureAsJpeg(sensorData.infraredImageTexture, infraredTex2d);
NetMessageData message = new NetMessageData(NetMessageType.Color, FrameEncodeType.Jpeg,
sensorData.depthImageWidth, sensorData.depthImageHeight, lastInfraredFrameTime);
message.SetData(btInfraredData);
infraredFrameServer.SendMessageToAllConnections(message);
}
}
// body data frame
if (bodyDataFrameServer != null && bodyDataFrameServer.GetConnCount() > 0)
{
if (sensorData.lastBodyFrameTime != lastBodyDataFrameTime)
{
lastBodyDataFrameTime = sensorData.lastBodyFrameTime;
float fUnityTime = 0f;
string sBodyFrame = KinectInterop.GetBodyFrameAsCsv(ref sensorData.alTrackedBodies,
sensorData.trackedBodiesCount, sensorData.lastBodyFrameTime, sensorData.sensorSpaceScale, ref fUnityTime, '\t');
byte[] btBodyData = System.Text.Encoding.UTF8.GetBytes(sBodyFrame);
NetMessageData message = new NetMessageData(NetMessageType.BodyData, FrameEncodeType.K4b,
sensorData.depthImageWidth, sensorData.depthImageHeight, lastBodyDataFrameTime);
message.SetData(btBodyData);
bodyDataFrameServer.SendMessageToAllConnections(message);
}
}
// body index frame
if (bodyIndexFrameServer != null && bodyIndexFrameServer.GetConnCount() > 0)
{
if (sensorData.lastBodyIndexFrameTime != lastBodyIndexFrameTime)
{
lastBodyIndexFrameTime = sensorData.lastBodyIndexFrameTime;
NetMessageData message = new NetMessageData(NetMessageType.BodyIndex, FrameEncodeType.Raw,
sensorData.depthImageWidth, sensorData.depthImageHeight, lastBodyIndexFrameTime);
message.SetData(sensorData.bodyIndexImage);
if (compressRawFrames)
{
message.SetCompressor(bodyIndexFrameCompressor);
message.CompressData();
}
bodyIndexFrameServer.SendMessageToAllConnections(message);
}
}
// pose frame
if (poseFrameServer != null && poseFrameServer.GetConnCount() > 0)
{
if (sensorData.lastSensorPoseFrameTime != lastPoseFrameTime)
{
lastPoseFrameTime = sensorData.lastSensorPoseFrameTime;
string curSensorPoseStr = sensorData.sensorPosePosition.ToString() + " " + sensorData.sensorPoseRotation.eulerAngles.ToString();
if(lastSensorPoseStr != curSensorPoseStr)
{
lastSensorPoseStr = curSensorPoseStr;
KinectInterop.NetPoseData netPoseData = sensorData.sensorInterface.GetSensorNetPoseData(sensorData);
string sPoseData = JsonUtility.ToJson(netPoseData);
byte[] btPoseData = System.Text.Encoding.UTF8.GetBytes(sPoseData);
NetMessageData message = new NetMessageData(NetMessageType.Pose, FrameEncodeType.Json, 0, 0, lastPoseFrameTime);
message.SetData(btPoseData);
poseFrameServer.SendMessageToAllConnections(message);
}
}
}
// depth2color frame
if (depth2colorFrameServer != null && depth2colorFrameServer.GetConnCount() > 0)
{
if(depth2colorTex2d == null)
{
depth2colorTex2d = new Texture2D(sensorData.depthImageWidth, sensorData.depthImageHeight, sensorData.colorImageFormat, false);
sensorData.sensorInterface.EnableDepthCameraColorFrame(sensorData, true);
}
ulong frameTime = 0;
Texture depth2colorTex = sensorData.sensorInterface.GetDepthCameraColorFrameTexture(sensorData, ref depth2colorTex2d, ref frameTime);
if (depth2colorTex != null && frameTime != lastDepth2ColorFrameTime)
{
lastDepth2ColorFrameTime = frameTime;
byte[] btFrameData = depth2colorTex2d.EncodeToPNG();
//Debug.Log("Depth2ColorFrame length: " + btFrameData.Length);
NetMessageData message = new NetMessageData(NetMessageType.Depth2Color, FrameEncodeType.Jpeg,
sensorData.depthImageWidth, sensorData.depthImageHeight, frameTime);
message.SetData(btFrameData);
depth2colorFrameServer.SendMessageToAllConnections(message);
}
}
else if (depth2colorTex2d != null && depth2colorFrameServer != null && depth2colorFrameServer.GetConnCount() == 0)
{
// disable depth2color frame
depth2colorTex2d = null;
sensorData.sensorInterface.EnableDepthCameraColorFrame(sensorData, false);
}
// color2depth frame
if (color2depthFrameServer != null && color2depthFrameServer.GetConnCount() > 0)
{
if(colorCamDepthFrameData == null)
{
colorCamDepthFrameData = new byte[sensorData.colorImageWidth * sensorData.colorImageHeight * sizeof(ushort)];
sensorData.sensorInterface.EnableColorCameraDepthFrame(sensorData, true);
//color2depthEnabled = true;
}
ulong frameTime = 0;
byte[] btFrameData = sensorData.sensorInterface.GetColorCameraDepthFrameBytes(sensorData, ref colorCamDepthFrameData, ref frameTime);
if (btFrameData != null && frameTime != lastColor2DepthFrameTime)
{
lastColor2DepthFrameTime = frameTime;
NetMessageData message = new NetMessageData(NetMessageType.Color2Depth, FrameEncodeType.Raw,
sensorData.colorImageWidth, sensorData.colorImageHeight, frameTime);
message.SetData(btFrameData);
if (compressRawFrames)
{
message.SetCompressor(color2depthFrameCompressor);
message.CompressData();
}
color2depthFrameServer.SendMessageToAllConnections(message);
}
}
else if (colorCamDepthFrameData != null && color2depthFrameServer != null && color2depthFrameServer.GetConnCount() == 0)
{
// disable color2depth frame
//color2depthEnabled = false;
colorCamDepthFrameData = null;
sensorData.sensorInterface.EnableColorCameraDepthFrame(sensorData, false);
}
// color2infrared frame
if (color2infraredFrameServer != null && color2infraredFrameServer.GetConnCount() > 0)
{
if (color2infraredTex2d == null)
{
color2infraredTex2d = new Texture2D(sensorData.colorImageWidth, sensorData.colorImageHeight, TextureFormat.ARGB32, false);
sensorData.sensorInterface.EnableColorCameraInfraredFrame(sensorData, false, true);
}
ulong frameTime = 0;
Texture color2infraredTex = sensorData.sensorInterface.GetColorCameraInfraredFrameTexture(sensorData, ref color2infraredTex2d, ref frameTime);
if (color2infraredTex != null && frameTime != lastColor2InfraredFrameTime)
{
lastColor2InfraredFrameTime = frameTime;
byte[] btFrameData = color2infraredTex2d.EncodeToPNG();
//Debug.Log("Color2InfraredFrame length: " + btFrameData.Length);
NetMessageData message = new NetMessageData(NetMessageType.Color2Infrared, FrameEncodeType.Jpeg,
sensorData.colorImageWidth, sensorData.colorImageHeight, frameTime);
message.SetData(btFrameData);
color2infraredFrameServer.SendMessageToAllConnections(message);
}
}
else if (color2infraredTex2d != null && color2infraredFrameServer != null && color2infraredFrameServer.GetConnCount() == 0)
{
// disable color2infrared frame
color2infraredTex2d = null;
sensorData.sensorInterface.EnableColorCameraInfraredFrame(sensorData, false, false);
}
// color2bodyIndex frame
if (color2bodyIndexFrameServer != null && color2bodyIndexFrameServer.GetConnCount() > 0)
{
if(colorCamBodyIndexFrameData == null)
{
colorCamBodyIndexFrameData = new byte[sensorData.colorImageWidth * sensorData.colorImageHeight];
sensorData.sensorInterface.EnableColorCameraBodyIndexFrame(sensorData, true);
//color2bodyIndexEnabled = true;
}
ulong frameTime = 0;
byte[] btFrameData = sensorData.sensorInterface.GetColorCameraBodyIndexFrame(sensorData, ref colorCamBodyIndexFrameData, ref frameTime);
if (btFrameData != null && frameTime != lastColor2BodyIndexFrameTime)
{
lastColor2BodyIndexFrameTime = frameTime;
NetMessageData message = new NetMessageData(NetMessageType.Color2BodyIndex, FrameEncodeType.Raw,
sensorData.colorImageWidth, sensorData.colorImageHeight, frameTime);
message.SetData(btFrameData);
if (compressRawFrames)
{
message.SetCompressor(color2bodyIndexFrameCompressor);
message.CompressData();
}
color2bodyIndexFrameServer.SendMessageToAllConnections(message);
}
}
else if (colorCamBodyIndexFrameData != null && color2bodyIndexFrameServer != null && color2bodyIndexFrameServer.GetConnCount() == 0)
{
// disable color2bodyIndex frame
//color2bodyIndexEnabled = false;
colorCamBodyIndexFrameData = null;
sensorData.sensorInterface.EnableColorCameraBodyIndexFrame(sensorData, false);
}
}
catch (System.Exception ex)
{
Debug.LogError("Error updating NetServer: " + ex.Message);
Debug.LogError(ex);
}
}
// control frame received
private void ControlFrameReceived(object state, ReceivedMessageEventArgs args)
{
if (sensorData == null)
return;
try
{
if(args.message.frameData != null && args.message.frameData.Length > 0)
{
ControlMessageType ctrlMsgType = (ControlMessageType)args.message.frameData[0];
switch(ctrlMsgType)
{
case ControlMessageType.GetSensorData:
CtrlSendGetSensorData();
break;
case ControlMessageType.KeepAlive:
// do nothing
break;
case ControlMessageType.Disconnect:
// do nothing for now
break;
case ControlMessageType.GetDST:
CtrlSendGetDST();
break;
case ControlMessageType.GetCST:
CtrlSendGetCST();
break;
default:
throw new System.Exception("Invalid control message: " + args.message.frameData[0]);
}
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
}
}
// sends the net-sensor-data to clients
private void CtrlSendGetSensorData()
{
KinectInterop.NetSensorData netSensorData = sensorData.sensorInterface.GetNetSensorData(sensorData);
string sNetSensorData = netSensorData != null ? JsonUtility.ToJson(netSensorData) : null;
byte[] btNetSensorData = System.Text.Encoding.UTF8.GetBytes(sNetSensorData);
ulong ulTimeNow = (ulong)System.DateTime.Now.Ticks;
NetMessageData message = new NetMessageData(NetMessageType.Control, FrameEncodeType.SensorDataJson, 0, 0, ulTimeNow);
message.SetData(btNetSensorData);
if (compressRawFrames)
{
message.SetCompressor(controlFrameCompressor);
message.CompressData();
}
controlFrameServer.SendMessageToAllConnections(message);
}
// sends the net-dst data to clients
private void CtrlSendGetDST()
{
Vector3[] avSpaceTable = sensorData.sensorInterface.GetDepthCameraSpaceTable(sensorData);
if(avSpaceTable != null)
{
byte[] btSpaceTable = new byte[avSpaceTable.Length * 3 * sizeof(float)];
KinectInterop.CopyBytes(avSpaceTable, 3 * sizeof(float), btSpaceTable, sizeof(byte));
ulong ulTimeNow = (ulong)System.DateTime.Now.Ticks;
NetMessageData message = new NetMessageData(NetMessageType.Control, FrameEncodeType.DSTraw, sensorData.depthImageWidth, sensorData.depthImageHeight, ulTimeNow);
message.SetData(btSpaceTable);
if (compressRawFrames)
{
message.SetCompressor(controlFrameCompressor);
message.CompressData();
}
controlFrameServer.SendMessageToAllConnections(message);
}
}
// sends the net-cst data to clients
private void CtrlSendGetCST()
{
Vector3[] avSpaceTable = sensorData.sensorInterface.GetColorCameraSpaceTable(sensorData);
if (avSpaceTable != null)
{
byte[] btSpaceTable = new byte[avSpaceTable.Length * 3 * sizeof(float)];
KinectInterop.CopyBytes(avSpaceTable, 3 * sizeof(float), btSpaceTable, sizeof(byte));
ulong ulTimeNow = (ulong)System.DateTime.Now.Ticks;
NetMessageData message = new NetMessageData(NetMessageType.Control, FrameEncodeType.CSTraw, sensorData.colorImageWidth, sensorData.colorImageHeight, ulTimeNow);
message.SetData(btSpaceTable);
if (compressRawFrames)
{
message.SetCompressor(controlFrameCompressor);
message.CompressData();
}
controlFrameServer.SendMessageToAllConnections(message);
}
}
// convert render texture to jpg format
private byte[] GetTextureAsJpeg(RenderTexture tex, Texture2D tex2d)
{
KinectInterop.RenderTex2Tex2D(tex, ref tex2d);
byte[] btJpeg = tex2d.EncodeToJPG();
return btJpeg;
}
// returns local host name or ip address
private string GetLocalNameOrIP()
{
string localIP = "localhost";
try
{
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
localIP = ip.ToString();
if (localIP == "0.0.0.0" || localIP.StartsWith("169.254."))
continue;
break;
}
}
}
catch (System.Exception ex)
{
Debug.LogException(ex);
}
return localIP;
}
// returns the number of active connections
private int GetConnectionsCount()
{
int numConn = 0;
if (controlFrameServer != null)
numConn += controlFrameServer.GetConnCount();
if (colorFrameServer != null)
numConn += colorFrameServer.GetConnCount();
if (depthFrameServer != null)
numConn += depthFrameServer.GetConnCount();
if (infraredFrameServer != null)
numConn += infraredFrameServer.GetConnCount();
if (bodyDataFrameServer != null)
numConn += bodyDataFrameServer.GetConnCount();
if (bodyIndexFrameServer != null)
numConn += bodyIndexFrameServer.GetConnCount();
if (poseFrameServer != null)
numConn += poseFrameServer.GetConnCount();
if (depth2colorFrameServer != null)
numConn += depth2colorFrameServer.GetConnCount();
if (color2depthFrameServer != null)
numConn += color2depthFrameServer.GetConnCount();
if (color2infraredFrameServer != null)
numConn += color2infraredFrameServer.GetConnCount();
if (color2bodyIndexFrameServer != null)
numConn += color2bodyIndexFrameServer.GetConnCount();
return numConn;
}
// returns the number of unsent messages in all servers
private int GetMessageCount(bool inclCtrlMessages)
{
int numMessages = 0;
if (inclCtrlMessages && controlFrameServer != null && controlFrameServer.IsConnected())
numMessages += controlFrameServer.GetMessageCount();
if (colorFrameServer != null && colorFrameServer.IsConnected())
numMessages += colorFrameServer.GetMessageCount();
if (depthFrameServer != null && depthFrameServer.IsConnected())
numMessages += depthFrameServer.GetMessageCount();
if (infraredFrameServer != null && infraredFrameServer.IsConnected())
numMessages += infraredFrameServer.GetMessageCount();
if (bodyDataFrameServer != null && bodyDataFrameServer.IsConnected())
numMessages += bodyDataFrameServer.GetMessageCount();
if (bodyIndexFrameServer != null && bodyIndexFrameServer.IsConnected())
numMessages += bodyIndexFrameServer.GetMessageCount();
if (poseFrameServer != null && poseFrameServer.IsConnected())
numMessages += poseFrameServer.GetMessageCount();
if (depth2colorFrameServer != null && depth2colorFrameServer.IsConnected())
numMessages += depth2colorFrameServer.GetMessageCount();
if (color2depthFrameServer != null && color2depthFrameServer.IsConnected())
numMessages += color2depthFrameServer.GetMessageCount();
if (color2infraredFrameServer != null && color2infraredFrameServer.IsConnected())
numMessages += color2infraredFrameServer.GetMessageCount();
if (color2bodyIndexFrameServer != null && color2bodyIndexFrameServer.IsConnected())
numMessages += color2bodyIndexFrameServer.GetMessageCount();
return numMessages;
}
// sends control message to the server
private void SendControlMessage(ControlMessageType messageType)
{
if (controlFrameServer != null && controlFrameServer.IsActive())
{
ulong ulTimeNow = (ulong)System.DateTime.Now.Ticks;
NetMessageData msg = new NetMessageData(NetMessageType.Control, FrameEncodeType.Raw, 0, 0, ulTimeNow);
byte[] btMsgData = new byte[1];
btMsgData[0] = (byte)messageType;
msg.SetData(btMsgData);
controlFrameServer.SendMessageToAllConnections(msg);
//Debug.Log("Sending ctrl message " + messageType);
}
}
}
///
/// TcpNetServer provides network server functionality over tcp streams.
/// This class is based on the excellent work of Andy Wilson and Hrvoje Benko in "Room Alive Toolkit" - https://github.com/microsoft/RoomAliveToolkit
///
internal class TcpNetServer
{
public int serverPort = 11000;
//private const int bufferSize = 10240000;
public int tmpBufferSize = 640000;
private System.Text.StringBuilder sbConsole = null;
private TcpListener server;
private List connections = new List();
public bool isServerRunning = false;
// thread signal
public ManualResetEvent allDoneServer = new ManualResetEvent(false);
public string serverName = string.Empty;
public ReceivedMessageEventHandler ReceivedMessage = null;
public bool IsConnected()
{
return (connections.Count > 0);
}
public int GetConnCount()
{
return connections.Count;
}
public bool IsActive()
{
bool bActive = (connections.Count > 0) ? true : false;
foreach (NetConnData conn in connections)
{
if (!conn.isActive)
{
bActive = false;
break;
}
}
return bActive;
}
public bool IsReadyToSend()
{
bool bReady = (connections.Count > 0) ? true : false;
foreach (NetConnData conn in connections)
{
if (!conn.readyToSend)
{
bReady = false;
break;
}
}
return bReady;
}
public int GetMessageCount()
{
int count = 0;
foreach (NetConnData conn in connections)
{
count += conn.messageQueue.Count;
}
return count;
}
//public void CloseConnection(int connId)
//{
// foreach (NetConnData conn in connections)
// {
// if (conn.ID == connId)
// {
// //Debug.Log(serverName + " closing connection " + conn.ID + " to " + conn.remoteEP);
// LogToConsole(serverName + " closing connection to client " + conn.remoteIP);
// conn.isActive = false;
// connections.Remove(conn);
// break;
// }
// }
//}
public void CloseConnectionsTo(string remoteIP)
{
for (int i = connections.Count - 1; i >= 0; i--)
{
NetConnData conn = connections[i];
if (conn.remoteIP == remoteIP)
{
//Debug.Log(serverName + " closing connection " + conn.ID + " to " + conn.remoteEP);
LogToConsole(serverName + " closing connection to client " + conn.remoteIP);
conn.isActive = false;
connections.Remove(conn);
}
}
}
public void CloseAllConnections()
{
foreach (NetConnData conn in connections)
{
//Debug.Log(serverName + " closing connection " + conn.ID + " to " + conn.remoteEP);
LogToConsole(serverName + " closing connection to client " + conn.remoteIP);
conn.isActive = false;
}
connections.Clear();
}
public void SendMessageToAllConnections(NetMessageData message)
{
foreach (NetConnData conn in connections)
{
lock (conn.messageQueue)
{
if (conn.messageQueue.Count < NetConnData.MaxMessageQueueLength)
{
conn.messageQueue.Enqueue(message);
}
}
}
}
public void SendMessageToConnection(NetMessageData message, int connId)
{
foreach (NetConnData conn in connections)
{
if (conn.ID == connId)
{
lock (conn.messageQueue)
{
if (conn.messageQueue.Count < NetConnData.MaxMessageQueueLength)
{
conn.messageQueue.Enqueue(message);
}
}
break;
}
}
}
public TcpNetServer(int port, string name, System.Text.StringBuilder sbConsole)
{
serverPort = port;
serverName = name;
this.sbConsole = sbConsole;
isServerRunning = true;
Thread serverThread = new Thread(StartServer);
serverThread.Start();
}
public void Close()
{
isServerRunning = false;
allDoneServer.Set();
foreach (NetConnData cs in connections)
{
cs.isActive = false;
}
}
private void StartServer()
{
try
{
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
string localIP = "localhost";
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
localIP = ip.ToString();
if (localIP == "0.0.0.0" || localIP.StartsWith("169.254."))
continue;
break;
}
}
IPEndPoint listenEP = new IPEndPoint(IPAddress.Any, serverPort);
server = new TcpListener(listenEP);
server.Start();
//Debug.Log(serverName + " started on " + localIP + ":" + serverPort);
LogToConsole(serverName + " started on " + localIP + ":" + serverPort);
while (isServerRunning)
{
allDoneServer.Reset();
server.BeginAcceptTcpClient(new System.AsyncCallback(HandleNetClientConnected), server);
allDoneServer.WaitOne();
}
}
catch (SocketException e)
{
LogErrorToConsole(serverName + " SocketException: " + e.ToString());
}
finally
{
// Stop listening for new clients.
isServerRunning = false;
server.Stop();
LogToConsole(serverName + " stopped.");
}
}
private void HandleNetClientConnected(System.IAsyncResult ar)
{
TcpListener server = (TcpListener)ar.AsyncState;
try
{
NetConnData conn = new NetConnData();
conn.client = server.EndAcceptTcpClient(ar);
conn.stream = conn.client.GetStream();
conn.remoteIP = conn.client.Client.RemoteEndPoint.ToString();
int iP = conn.remoteIP.IndexOf(':');
if (iP >= 0)
conn.remoteIP = conn.remoteIP.Substring(0, iP);
CloseConnectionsTo(conn.remoteIP);
connections.Add(conn);
allDoneServer.Set();
LogToConsole(serverName + " connected to client " + conn.remoteIP);
NetClientProc(conn);
}
catch(System.ObjectDisposedException)
{
// do nothing
}
catch (System.Exception ex)
{
LogErrorToConsole(serverName + " error while connecting: " + ex.Message);
//Debug.LogException(ex);
allDoneServer.Set();
}
}
private void NetClientProc(NetConnData conn)
{
conn.isActive = true;
int bytesReceived = 0;
byte[] bufferTmp = new byte[tmpBufferSize];
try
{
while (conn.client.Connected && conn.isActive)
{
if (conn.readyToSend && conn.stream.CanWrite && conn.messageQueue.Count > 0)
{
byte[] sendBuffer;
lock (conn.messageQueue)
{
NetMessageData message = conn.messageQueue.Dequeue();
//int messageLen = message.frameData.Length;
sendBuffer = message.WrapMessage();
//if (message.msgType == NetMessageType.Depth)
// Debug.Log(" msg type: " + message.msgType + " - " + message.encType + ", ts: " + message.timestamp + ", frameLen: " + messageLen + " - " + message.frameData.Length + ", bufLen: " + sendBuffer.Length);
conn.readyToSend = false;
//Debug.Log("Sending message " + message.timestamp + " - " + message.msgType + " @ " + System.DateTime.Now.ToString("HH:mm:ss.fff"));
}
conn.stream.BeginWrite(sendBuffer, 0, sendBuffer.Length, new System.AsyncCallback(MessageSentToClient), conn);
}
bytesReceived = 0;
while (conn.stream.DataAvailable)
{
conn.messageReceiveTime = (ulong)System.DateTime.Now.Ticks;
bytesReceived = conn.stream.Read(bufferTmp, 0, bufferTmp.Length);
ProcessReceivedData(bufferTmp, bytesReceived, conn);
}
Thread.Sleep(KinectInterop.THREAD_SLEEP_TIME_MS);
}
}
catch (System.Exception ex)
{
LogErrorToConsole(ex);
}
conn.isActive = false;
conn.messageQueue.Clear();
LogToConsole(serverName + " connection to client " + conn.remoteIP + " closed.");
conn.stream.Close();
conn.client.Close();
if(connections.Contains(conn))
{
connections.Remove(conn);
}
}
private void MessageSentToClient(System.IAsyncResult ar)
{
NetConnData conn = (NetConnData)ar.AsyncState;
try
{
conn.stream.EndWrite(ar);
}
catch (System.Exception ex)
{
if(conn.isActive)
{
LogErrorToConsole(serverName + " error sending to client: " + ex.Message);
//Debug.LogException(ex);
conn.isActive = false;
}
}
conn.readyToSend = true;
}
private void ProcessReceivedData(byte[] buffer, int bytesReceived, NetConnData conn)
{
if (conn.bytesReceived == 0 && bytesReceived > 3) //new message
{
int newMessageSize = System.BitConverter.ToInt32(buffer, 0) + sizeof(int); //prefix is one int
if (newMessageSize != conn.messageSize)
{
conn.messageSize = newMessageSize;
conn.messageBuffer = new byte[newMessageSize];
}
}
int availableLength = conn.messageSize - conn.bytesReceived;
int copyLen = Mathf.Min(availableLength, bytesReceived);
conn.packetCounter++;
System.Array.Copy(buffer, 0, conn.messageBuffer, conn.bytesReceived, copyLen);
conn.bytesReceived += copyLen;
if (conn.bytesReceived == conn.messageSize)
{
conn.ResetCounters();
NetMessageData message = new NetMessageData();
//message.SetDecompressor(decompressor);
message.UnwrapMessage(conn.messageBuffer);
ReceivedMessage?.Invoke(conn, new ReceivedMessageEventArgs(message));
}
if (copyLen != bytesReceived)
{
byte[] newBuffer = new byte[bytesReceived - copyLen];
System.Array.Copy(buffer, copyLen, newBuffer, 0, bytesReceived - copyLen);
ProcessReceivedData(newBuffer, bytesReceived - copyLen, conn);
}
}
// logs message to the console
private void LogToConsole(string sMessage)
{
Debug.Log(sMessage);
lock(sbConsole)
{
sbConsole.Append(sMessage).AppendLine();
}
}
// logs error message to the console
private void LogErrorToConsole(string sMessage)
{
Debug.LogError(sMessage);
lock (sbConsole)
{
sbConsole.Append(sMessage).AppendLine();
}
}
// logs error message to the console
private void LogErrorToConsole(System.Exception ex)
{
LogErrorToConsole(ex.Message + "\n" + ex.StackTrace);
}
}
///
/// UdpBroadcastServer provides broadcast functionality over the network.
///
internal class UdpBroadcastServer
{
public int serverPort = 11000;
private UdpClient server;
public bool isServerRunning = false;
// thread signal
public ManualResetEvent allDoneServer = new ManualResetEvent(false);
public string serverName = string.Empty;
public string sRequestKey = string.Empty;
public string sResponseData = string.Empty;
public byte[] btResponseData = new byte[0];
private System.Text.StringBuilder sbConsole = null;
public UdpBroadcastServer(int port, string name, string requestKey, string responseData, System.Text.StringBuilder sbConsole)
{
serverPort = port;
serverName = name;
sRequestKey = requestKey;
sResponseData = responseData;
btResponseData = System.Text.Encoding.UTF8.GetBytes(sResponseData);
this.sbConsole = sbConsole;
isServerRunning = true;
Thread serverThread = new Thread(StartServer);
serverThread.Start();
}
public void Close()
{
isServerRunning = false;
allDoneServer.Set();
}
private void StartServer()
{
try
{
IPEndPoint ep = new IPEndPoint(IPAddress.Any, serverPort);
server = new UdpClient(ep);
//Debug.Log(serverName + " started on " + localIP + ":" + serverPort);
LogToConsole(serverName + " started on udp port " + serverPort);
while (isServerRunning)
{
allDoneServer.Reset();
UdpState state = new UdpState();
state.ep = ep;
state.uc = server;
//Debug.Log("Listening for udp requests.");
server.BeginReceive(new System.AsyncCallback(HandleNetClientConnected), state);
allDoneServer.WaitOne();
}
}
catch (SocketException e)
{
LogErrorToConsole(serverName + " SocketException: " + e.ToString());
}
finally
{
isServerRunning = false;
server.Close();
LogToConsole(serverName + " stopped.");
}
}
private void HandleNetClientConnected(System.IAsyncResult ar)
{
UdpState state = (UdpState)ar.AsyncState;
try
{
UdpClient uc = state.uc;
IPEndPoint ep = state.ep;
byte[] receiveBytes = uc.EndReceive(ar, ref ep);
string receiveString = System.Text.Encoding.UTF8.GetString(receiveBytes);
if (receiveString == sRequestKey)
{
LogToConsole(serverName + " received broadcast request from " + ep.Address.ToString());
uc.BeginSend(btResponseData, btResponseData.Length, ep, new System.AsyncCallback(MessageSentToClient), uc);
}
else
{
LogErrorToConsole(serverName + " received false request '" + receiveString + "' from " + ep.ToString());
}
}
catch (System.ObjectDisposedException)
{
// do nothing
}
catch (System.Exception ex)
{
LogErrorToConsole(serverName + " error while connecting: " + ex.Message);
//Debug.LogException(ex);
}
allDoneServer.Set();
}
private void MessageSentToClient(System.IAsyncResult ar)
{
UdpClient uc = (UdpClient)ar.AsyncState;
try
{
uc.EndSend(ar);
}
catch (System.Exception ex)
{
LogErrorToConsole(serverName + " error sending to client: " + ex.Message);
//Debug.LogException(ex);
}
}
// logs message to the console
private void LogToConsole(string sMessage)
{
Debug.Log(sMessage);
lock (sbConsole)
{
sbConsole.Append(sMessage).AppendLine();
}
}
// logs error message to the console
private void LogErrorToConsole(string sMessage)
{
Debug.LogError(sMessage);
lock (sbConsole)
{
sbConsole.Append(sMessage).AppendLine();
}
}
// logs error message to the console
private void LogErrorToConsole(System.Exception ex)
{
LogErrorToConsole(ex.Message + "\n" + ex.StackTrace);
}
}
}