AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
RemoteMeshSource.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using UnityEngine;
5 
6 #if !UNITY_EDITOR && UNITY_WSA
7 using System.Collections.Generic;
8 using Windows.Networking.Sockets;
9 using Windows.Storage.Streams;
10 using Windows.Networking;
11 using Windows.Foundation;
12 #endif
13 
14 namespace HoloToolkit.Unity.SpatialMapping
15 {
19  public class RemoteMeshSource : Singleton<RemoteMeshSource>
20  {
21  [Tooltip("The IPv4 Address of the machine running the Unity editor. Copy and paste this value from RemoteMeshTarget.")]
22  public string ServerIP;
23 
24  [Tooltip("The connection port on the machine to use.")]
25  public int ConnectionPort = 11000;
26 
27 #if !UNITY_EDITOR && UNITY_WSA
28  private StreamSocket networkConnection;
32 
36  private bool Sending = false;
37 
41  private byte[] nextDataBufferToSend;
42 
46  private Queue<byte[]> dataQueue = new Queue<byte[]>();
47 
51  private float deferTime = 0.0f;
52 
56  private float timeToDeferFailedConnections = 10.0f;
57 
58  public void Update()
59  {
60  // Check to see if deferTime has been set.
61  // DeferUpdates will set the Sending flag to true for
62  // deferTime seconds.
63  if (deferTime > 0.0f)
64  {
65  DeferUpdates(deferTime);
66  deferTime = 0.0f;
67  }
68 
69  // If we aren't sending a mesh, but we have a mesh to send, send it.
70  if (!Sending && dataQueue.Count > 0)
71  {
72  byte[] nextPacket = dataQueue.Dequeue();
73  SendDataOverNetwork(nextPacket);
74  }
75  }
76 
81  void DeferUpdates(float timeout)
82  {
83  Sending = true;
84  Invoke("EnableUpdates", timeout);
85  }
86 
90  void EnableUpdates()
91  {
92  Sending = false;
93  }
94 
99  public void SendData(byte[] dataBufferToSend)
100  {
101  dataQueue.Enqueue(dataBufferToSend);
102  }
103 
108  private void SendDataOverNetwork(byte[] dataBufferToSend)
109  {
110  if (Sending)
111  {
112  // This shouldn't happen, but just in case.
113  Debug.Log("one at a time please");
114  return;
115  }
116 
117  // Track that we are sending a data buffer.
118  Sending = true;
119 
120  // Set the next buffer to send when the connection is made.
121  nextDataBufferToSend = dataBufferToSend;
122 
123  // Setup a connection to the server.
124  HostName networkHost = new HostName(ServerIP.Trim());
125  networkConnection = new StreamSocket();
126 
127  // Connections are asynchronous.
128  // !!! NOTE These do not arrive on the main Unity Thread. Most Unity operations will throw in the callback !!!
129  IAsyncAction outstandingAction = networkConnection.ConnectAsync(networkHost, ConnectionPort.ToString());
130  AsyncActionCompletedHandler aach = new AsyncActionCompletedHandler(NetworkConnectedHandler);
131  outstandingAction.Completed = aach;
132  }
133 
140  public void NetworkConnectedHandler(IAsyncAction asyncInfo, AsyncStatus status)
141  {
142  // Status completed is successful.
143  if (status == AsyncStatus.Completed)
144  {
145  DataWriter networkDataWriter;
146 
147  // Since we are connected, we can send the data we set aside when establishing the connection.
148  using(networkDataWriter = new DataWriter(networkConnection.OutputStream))
149  {
150  // Write how much data we are sending.
151  networkDataWriter.WriteInt32(nextDataBufferToSend.Length);
152 
153  // Then write the data.
154  networkDataWriter.WriteBytes(nextDataBufferToSend);
155 
156  // Again, this is an async operation, so we'll set a callback.
157  DataWriterStoreOperation dswo = networkDataWriter.StoreAsync();
158  dswo.Completed = new AsyncOperationCompletedHandler<uint>(DataSentHandler);
159  }
160  }
161  else
162  {
163  Debug.Log("Failed to establish connection. Error Code: " + asyncInfo.ErrorCode);
164  // In the failure case we'll requeue the data and wait before trying again.
165  networkConnection.Dispose();
166 
167  // Didn't send, so requeue the data.
168  dataQueue.Enqueue(nextDataBufferToSend);
169 
170  // And set the defer time so the update loop can do the 'Unity things'
171  // on the main Unity thread.
172  deferTime = timeToDeferFailedConnections;
173  }
174  }
175 
182  public void DataSentHandler(IAsyncOperation<uint> operation, AsyncStatus status)
183  {
184  // If we failed, requeue the data and set the deferral time.
185  if (status == AsyncStatus.Error)
186  {
187  // didn't send, so requeue
188  dataQueue.Enqueue(nextDataBufferToSend);
189  deferTime = timeToDeferFailedConnections;
190  }
191  else
192  {
193  // If we succeeded, clear the sending flag so we can send another mesh
194  Sending = false;
195  }
196 
197  // Always disconnect here since we will reconnect when sending the next mesh.
198  networkConnection.Dispose();
199  }
200 #endif
201  }
202 }
RemoteMeshSource will try to send meshes from the HoloLens to a remote system that is running the Uni...
Singleton behaviour class, used for components that should only have one instance.
Definition: Singleton.cs:14