Hello everyone.

The Mixed Reality Forums here are no longer being used or maintained.

There are a few other places we would like to direct you to for support, both from Microsoft and from the community.

The first way we want to connect with you is our mixed reality developer program, which you can sign up for at https://aka.ms/IWantMR.

For technical questions, please use Stack Overflow, and tag your questions using either hololens or windows-mixed-reality.

If you want to join in discussions, please do so in the HoloDevelopers Slack, which you can join by going to https://aka.ms/holodevelopers, or in our Microsoft Tech Communities forums at https://techcommunity.microsoft.com/t5/mixed-reality/ct-p/MicrosoftMixedReality.

And always feel free to hit us up on Twitter @MxdRealityDev.
Options

Why is HoloLens not receiving network messages at a constant rate?

Hello,

I'm building a prototype that involves two application: App1 that is a Unity app running on a Windows PC, and App2 running on the HoloLens. Both application display the same object in each of their respective worlds. App1 sends position(Vector3) messages to App2 over WiFi to describe the object movement to the HoloLens, which updates the position of its object in the HoloLens world accordingly. I ahve verified that all connections are made accordingly (App1 acts as the server, and App2 acts as the client).

The problem is that App2 is not receiving App1 messages at a constant rate; instead it sits idle for a few frames, then receives anywhere from 1 to 12 position messages at once (i.e. in a single frame), which means I have to discard everything except for the last position message received in a burst and update the App2 object position using that one, which results in very choppy movement since App2 is effectively losing position data and sitting idle for frames where it's not receiving any data as it should be.

I have verified that w.r.t. the data that is being sent from App1 there is no message loss in App2 (I have replayed all the position data being received on the HoloLens side with observed delays due to wasted frames).

Here are implementation details for each app; any suggestions how to fix the wasted frames on the HoloLens side and receive data at a constant rate (ideally one position message per frame?)

App1 - Windows PC

`App1Connection.cs
public class App1Connection : MonoBehaviour
{
private ServerCommunication serverCommunication;
private DataProvider dataProvider;
private Vector3[] visualFeedbackPoints;
private string visualFeedbackMessageType;

[...]
void Update() {
   [...]
    if ((visualFeedbackMessageType.Length > 0) && (serverCommunication.IsReady())) {
        visualFeedbackPoints = dataProvider.GetVisualFeedbackCoordinates();
        SendMessage(MessageDestination.HOLOLENS, new MessageWrapper(visualFeedbackMessageType, visualFeedbackPoints, MAX_POINTS));
    }
}

private void SendMessage(MessageDestination destination,  MessageWrapper message) {
    string messageContent;
    string messageLength;
    string messageHeader = "";

    messageContent = JsonUtility.ToJson(message);
    messageLength = messageContent.Length.ToString();

    for (int i = 0; i < (MESSAGE_HEADER_SIZE - messageLength.Length); i++) {
        messageHeader += "0";
    }
    messageHeader += messageLength;
    if (destination == MessageDestination.HOLOLENS){
        serverCommunication.SendMessageToClient(messageContent);
    } else {
        Debug.LogError("[ERROR] Attempting to send message to unknown/unsupported destination!\n");
    }

}

ServerCommunication.cs

using System.Net;
using System.Net.Sockets;

public class ServerCommunication : MonoBehaviour
{

Socket client;

[...]
public void SendMessageToClient(string message) {
    string messageLength;
    string messageHeader = "";

    messageLength = message.Length.ToString();

    for (int i = 0; i < (MESSAGE_HEADER_SIZE - messageLength.Length); i++) {
        messageHeader += "0";
    }
    messageHeader += messageLength;
    client.Send(Encoding.ASCII.GetBytes(messageHeader));
    client.Send(Encoding.ASCII.GetBytes(message));
}

}`

Answers

  • Options

    App2 - HoloLens

    `App2Connection.cs

    if !UNITY_EDITOR && UNITY_WSA

    using System.Threading;
    using System.Threading.Tasks;

    endif

    [...]
    public class App2Connection : MonoBehaviour {
    private NetworkCommunication networkCommunication;
    private DataProvider dataProvider;
    private string currentReceivedData;
    MessageWrapper receivedMessage;
    GameObject sphere;
    public bool logToConsole;

    private float elapsed = 0;
    private int counter = 0;
    private int previousCounter = 0;
    private int currentCounter = 0;
    

    if !UNITY_EDITOR && UNITY_WSA

    private bool keepReceivingTaskAlive;
    private Task messageReceivingTask;
    

    endif

    void Start() {
        networkCommunication = GetComponent<NetworkCommunication>();
        dataProvider = GetComponent<DataProvider>();
    
        sphere = GameObject.Find("TestSphere (2.5\")");
        sphereTransform = sphere.GetComponent<Transform>();
    
        currentReceivedData = "-";
        networkCommunication.SetupConnection();
    

    if !UNITY_EDITOR && UNITY_WSA

        keepReceivingTaskAlive = true;
        messageReceivingTask = Task.Run(() => ReceiveDataOnTask());
        messageReceivingTask.Start();
    

    endif

    }
    

    if !UNITY_EDITOR && UNITY_WSA

    private void ReceiveDataOnTask() {
        while (keepReceivingTaskAlive) {
            currentReceivedData = networkCommunication.ReceiveData(MESSAGE_HEADER_SIZE);
            counter++;
        }
    }
    

    endif

    void Update() {
        elapsed = Time.deltaTime;
        previousCounter = currentCounter;
        currentCounter = counter;
        Debug.Log((currentCounter - previousCounter) + ", " + elapsed.ToString("F3") + "\n");
    

    if !UNITY_EDITOR && UNITY_WSA

        receivedMessage = JsonUtility.FromJson<MessageWrapper>(currentReceivedData);
        Vector3 newSpherePos = receivedMessage.coords[0].ToVector3();
        if (sphereTransform.position != newSpherePos)
        {
            sphereTransform.position = newSpherePos;
        }
    

    endif

    }
    
    void OnApplicationQuit() {
        networkCommunication.CloseConnection();
    

    if !UNITY_EDITOR && UNITY_WSA

        keepReceivingTaskAlive = false;
    

    endif

    }
    

    }

    NetworkCommunication.cs

    /** based on HoloTookit's RemoteMapping example **/
    using UnityEngine;
    using System;

    if !UNITY_EDITOR && UNITY_WSA

    using System.Collections.Generic;
    using Windows.Networking.Sockets;
    using Windows.Storage.Streams;
    using Windows.Networking;
    using Windows.Foundation;

    endif

    public class NetworkCommunication : MonoBehaviour {
    public string host;
    public int port;
    public bool logToConsole;
    private bool connectionReady = false;

    if !UNITY_EDITOR && UNITY_WSA

    private StreamSocket networkConnection;
    private DataReader networkDataReader;
    

    endif

    public void SetupConnection() {
    

    if !UNITY_EDITOR && UNITY_WSA

        HostName networkHost = new HostName(host.Trim());
        networkConnection = new StreamSocket();
        IAsyncAction outstandingAction = networkConnection.ConnectAsync(networkHost, port.ToString());
        AsyncActionCompletedHandler aach = new AsyncActionCompletedHandler(NetworkConnectedHandler);
        outstandingAction.Completed = aach;
    

    endif

    }
    

    if !UNITY_EDITOR && UNITY_WSA

    public string ReceiveData(uint messageHeaderSize) {
        string result = "-";
        if (!connectionReady) {
            Debug.LogError("[ERROR] attempting to receive data when network connection is not ready!");
            return result;
        }
        connectionReady = false;
    
        // Load and read message header/size.
        DataReaderLoadOperation drlo = networkDataReader.LoadAsync(messageHeaderSize);
        while (drlo.Status == AsyncStatus.Started) {} // just waiting.
        if (drlo.Status == AsyncStatus.Completed) {
            uint messageLength = UInt32.Parse(networkDataReader.ReadString(messageHeaderSize));
            if (messageLength == 0) {
                Debug.Log("[ERROR] Message size is 0!");
            }
    
            // Load and read message content.
            drlo = networkDataReader.LoadAsync(messageLength);
            while (drlo.Status == AsyncStatus.Started) {} // just waiting.
            if (drlo.Status == AsyncStatus.Completed) {
                string messageContent = networkDataReader.ReadString(messageLength);
                result = messageContent;
                if (logToConsole) {
                    Debug.Log("[SUCCESS] Received : " + messageContent+ "\n");
                }
            } else {
                Debug.Log("[ERROR] Problem occured during loading message content");
            }
        } else {
            Debug.Log("[ERROR] Problem occured during loading message header");
        }
        connectionReady = true;
        return result;
    }
    

    endif

    public void CloseConnection() {
    

    if !UNITY_EDITOR && UNITY_WSA

        if (!connectionReady) {
            return;
        }
        networkConnection.Dispose();
        connectionReady = false;
        if (logToConsole) {
            Debug.Log("[INFO] Connection closed\n");
        }
    

    endif

    }
    

    if !UNITY_EDITOR && UNITY_WSA

    public void NetworkConnectedHandler(IAsyncAction asyncInfo, AsyncStatus status) {
    
            if (status == AsyncStatus.Completed) {
                networkDataReader = new DataReader(networkConnection.InputStream);
                connectionReady = true;
                if (logToConsole) {
                    Debug.Log("[INFO] finished setting up network connection");
                }
            } else {
                Debug.Log("[ERROR] Failed to establish network connection. Error Code: " + asyncInfo.ErrorCode);
                connectionReady = false;
                networkConnection.Dispose();
            }
        }
    

    endif

    }`

    and here is the output generated by the Debug.Log() call in App2Connection's Update() function which shows how many messages have been received by the message receiving Task since the last Update() call ( you can see the idle frames indicated by the 0 messages received, followed by the occasional burst of messages received all at once)

    4, 0.017
    0, 0.016
    0, 0.016
    0, 0.016
    4, 0.016
    0, 0.017
    0, 0.017
    4, 0.016
    0, 0.017
    0, 0.017
    0, 0.017
    3, 0.017
    0, 0.017
    0, 0.017
    0, 0.016
    4, 0.016
    0, 0.017
    0, 0.017
    0, 0.017
    4, 0.017
    0, 0.017
    0, 0.016
    0, 0.017
    0, 0.017
    0, 0.016
    0, 0.017
    0, 0.017
    0, 0.017
    0, 0.017
    0, 0.016
    0, 0.017
    0, 0.017
    0, 0.017
    0, 0.017
    0, 0.017
    0, 0.016
    0, 0.016
    0, 0.017
    0, 0.016
    0, 0.017
    0, 0.017
    13, 0.017
    7, 0.016
    3, 0.017
    0, 0.017
    3, 0.016
    0, 0.016
    0, 0.017
    4, 0.017
    0, 0.016
    0, 0.016
    0, 0.017
    4, 0.016
    0, 0.017
    0, 0.017
    0, 0.017
    4, 0.017
    0, 0.016
    0, 0.017
    0, 0.017
    3, 0.016
    0, 0.016
    0, 0.017
    4, 0.017
    0, 0.017
    0, 0.016
    0, 0.017
    4, 0.017
    0, 0.017
    0, 0.017
    0, 0.016
    3, 0.017
    0, 0.017
    0, 0.017
    0, 0.017
    4, 0.016
    0, 0.017
    0, 0.017
    4, 0.016
    0, 0.016
    0, 0.017
    0, 0.016
    4, 0.017
    0, 0.016
    0, 0.017
    0, 0.017
    0, 0.017
    0, 0.017
    0, 0.017
    0, 0.016
    0, 0.017

Sign In or Register to comment.