ScottHerz Posted October 8, 2019 Author Share Posted October 8, 2019 sample_getdatathread will abort the producer thread on disable/stop. That's not great for other reasons, but it shouldn't lock up Unity. Although in my experience it does cause instability and crashing if you happen to ahort it in the middle of the GetEyeData call (the one meaty call in that function). Link to comment Share on other sites More sharing options...
ScottHerz Posted October 8, 2019 Author Share Posted October 8, 2019 (edited) FWIW, here's what I ended up doing (to avoid aborting the thread and the reach-in for EyeData on who-knows-what-thread). using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.Threading; using System.IO; using ViveSR.anipal.Eye; public class ViveProEyeProducerThread : MonoBehaviour { public Action<EyeData> NewOffThreadEyeDataAction; private EyeData EyeData = new EyeData(); private Thread Thread; private const int FrequencyControl = 1; private bool Abort = false; void Start() { Abort = false; Thread = new Thread(QueryEyeData); Thread.Start(); } private void OnApplicationQuit() { Abort = true; } private void OnDisable() { Abort = true; } void QueryEyeData() { int PrevFrameSequence = 0, CurrFrameSequence = 0; while (Abort == false) { ViveSR.Error error = SRanipal_Eye.GetEyeData(ref EyeData); if (error == ViveSR.Error.WORK) { CurrFrameSequence = EyeData.frame_sequence; if (CurrFrameSequence != PrevFrameSequence) { PrevFrameSequence = CurrFrameSequence; if (Abort == false && NewOffThreadEyeDataAction != null) { NewOffThreadEyeDataAction(EyeData); } } } Thread.Sleep(FrequencyControl); } } } Edited October 8, 2019 by ScottHerz Fixed a typeo Link to comment Share on other sites More sharing options...
alwyuyang Posted February 10, 2020 Share Posted February 10, 2020 On 10/8/2019 at 11:23 PM, ScottHerz said: FWIW, here's what I ended up doing (to avoid aborting the thread and the reach-in for EyeData on who-knows-what-thread). using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.Threading; using System.IO; using ViveSR.anipal.Eye; public class ViveProEyeProducerThread : MonoBehaviour { public Action<EyeData> NewOffThreadEyeDataAction; private EyeData EyeData = new EyeData(); private Thread Thread; private const int FrequencyControl = 1; private bool Abort = false; void Start() { Abort = false; Thread = new Thread(QueryEyeData); Thread.Start(); } private void OnApplicationQuit() { Abort = true; } private void OnDisable() { Abort = true; } void QueryEyeData() { int PrevFrameSequence = 0, CurrFrameSequence = 0; while (Abort == false) { ViveSR.Error error = SRanipal_Eye.GetEyeData(ref EyeData); if (error == ViveSR.Error.WORK) { CurrFrameSequence = EyeData.frame_sequence; if (CurrFrameSequence != PrevFrameSequence) { PrevFrameSequence = CurrFrameSequence; if (Abort == false && NewOffThreadEyeDataAction != null) { NewOffThreadEyeDataAction(EyeData); } } } Thread.Sleep(FrequencyControl); } } } Is this the alternative "Sample_GetDataThread.cs", could you please add the "Sample_MainThread.cs". I don't understand " public Action<EyeData> NewOffThreadEyeDataAction; private EyeData EyeData = new EyeData(); ", which are different to the version before. Could you explain a little bit, thank you very much. Link to comment Share on other sites More sharing options...
alwyuyang Posted February 11, 2020 Share Posted February 11, 2020 On 6/19/2019 at 3:25 PM, jason_lu said: Hi kadakadakScott: You can follow these step to get 120 frame data per second. - Create an empty scene and add SRanipal_Framework into the scene. (The framework GameObject will be in Prefab folder) - Create an empty GameObject and attach below two script on it. - Start the scene preview then you can check the EyeData's frame sequence and timestamp in DataRecord.txt Notice, If you use this method to get EyeData or VerboseData, you should not use other function in SRanipal_Eye simultaneously since the function in SRanipal_Eye are implement within Unity's main thread. Best Regards Jason // Sample_MainThread.csusing System.Collections;using System.Collections.Generic;using UnityEngine;using ViveSR.anipal.Eye;namespace Test120FPS{ public class Sample_MainThread : MonoBehaviour { private Sample_GetDataThread DataThread = null; private EyeData data = new EyeData(); // Use this for initialization void Start() { DataThread = FindObjectOfType<Sample_GetDataThread>(); if (DataThread == null) return; } // You can get data from another thread and use MonoBehaviour's method here. // But in Unity's Update function, you can only have 90 FPS. void Update() { data = DataThread.data; Debug.Log("Left eye openness: " + data.verbose_data.left.eye_openness); Debug.Log("Right eye openness: " + data.verbose_data.right.eye_openness); } }} // Sample_GetDataThread.csusing System.Collections;using System.Collections.Generic;using UnityEngine;using System;using System.Threading;using System.IO;using ViveSR.anipal.Eye;namespace Test120FPS{ public class Sample_GetDataThread : MonoBehaviour { public EyeData data = new EyeData(); private Thread thread; private const int FrequencyControl = 1; private const int MaxFrameCount = 3600; void Start() { thread = new Thread(QueryEyeData); thread.Start(); } private void OnApplicationQuit() { thread.Abort(); } private void OnDisable() { thread.Abort(); } // You can only use C# native function in Unity's thread. // Use EyeData's frame_sequence to calculate frame numbers and record data in file. void QueryEyeData() { int FrameCount = 0; int PrevFrameSequence = 0, CurrFrameSequence = 0; bool StartRecord = false; while (FrameCount < MaxFrameCount) { ViveSR.Error error = SRanipal_Eye.GetEyeData(ref data); if (error == ViveSR.Error.WORK) { CurrFrameSequence = data.frame_sequence; if (CurrFrameSequence != PrevFrameSequence) { FrameCount ++; PrevFrameSequence = CurrFrameSequence; StartRecord = true; } } // Record time stamp every 120 frame. if (FrameCount % 120 == 0 && StartRecord) { long ms = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; string text = "CurrentFrameSequence: " + CurrFrameSequence + " CurrentSystemTime(ms): " + ms.ToString() + Environment.NewLine; File.AppendAllText("DataRecord.txt", text); FrameCount = 0; } Thread.Sleep(FrequencyControl); } } }} I used this code, but I cannot close my application when it should be closed. Could you please give me a hand? @Daniel_Y @VIVE_Jason_Lu Link to comment Share on other sites More sharing options...
ScottHerz Posted February 13, 2020 Author Share Posted February 13, 2020 On 2/10/2020 at 9:37 AM, alwyuyang said: Is this the alternative "Sample_GetDataThread.cs", could you please add the "Sample_MainThread.cs". I don't understand " public Action<EyeData> NewOffThreadEyeDataAction; private EyeData EyeData = new EyeData(); ", which are different to the version before. Could you explain a little bit, thank you very much. This is just something I (not an HTC employee) did. I think they've updated the API since. I used Action's instead of callbacks, as I prefer them. Here's the C# documentation on them: https://docs.microsoft.com/en-us/dotnet/api/system.action-1?view=netframework-4.8 Link to comment Share on other sites More sharing options...
fayre Posted May 16, 2020 Share Posted May 16, 2020 Thank you @ScottHerz and @jason_lu for sharing your code. I ended up with a similar version but Unity keeps freezing and crashing after running the code, both my version and your versions. Did you experience similar issues? Everything works fine though when I access the eye data in the main thread, so I thought that this might be caused by race conditions or the thread not being closed correctly, but I can't figure out a workaround. Link to comment Share on other sites More sharing options...
wdrake Posted June 21, 2020 Share Posted June 21, 2020 @imarin18 @VIVE_Jason_Lu @jason_lu What change did you make to the while loop in sample_getdatathread.cs to get it to work? Unity keeps crashing for me. I'd like to track where the user is looking (x, y) over time - will these scripts help me do that? I appreciate all help. Link to comment Share on other sites More sharing options...
ScottHerz Posted June 22, 2020 Author Share Posted June 22, 2020 Make sure any code in your action is threadsafe. I think I just added the record to a threadsafe queue and pulled from it on the main thread. That said, have you all tried the newer API? I've moved on from this tracker, but my understanding is they've reworked how you grab events. @Daniel_Y Link to comment Share on other sites More sharing options...
Corvus Posted June 23, 2020 Share Posted June 23, 2020 @wdrake @fayre If anyone is experiencing crashes with Unity and threads feel free to use the callback method in the SDK. The thread crashes may be due to aborting a thread during an eye data update. The callback method has been reliable in my testing. using UnityEngine; using ViveSR.anipal.Eye; using System.Runtime.InteropServices; public class CallbackExample : MonoBehaviour { private EyeData eyeData = new EyeData(); private bool eye_callback_registered = false; private void Update() { if (SRanipal_Eye_Framework.Status != SRanipal_Eye_Framework.FrameworkStatus.WORKING) return; if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback == true && eye_callback_registered == false) { SRanipal_Eye.WrapperRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback)); eye_callback_registered = true; } else if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback == false && eye_callback_registered == true) { SRanipal_Eye.WrapperUnRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback)); eye_callback_registered = false; } } private void OnDisable() { Release(); } void OnApplicationQuit() { Release(); } private void Release() { if (eye_callback_registered == true) { SRanipal_Eye.WrapperUnRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback)); eye_callback_registered = false; } } private void EyeCallback(ref EyeData eye_data) { eyeData = eye_data; // do stuff with eyeData.. } } Link to comment Share on other sites More sharing options...
PavelP Posted June 26, 2020 Share Posted June 26, 2020 On 6/23/2020 at 5:15 PM, Corvus said: @wdrake @fayre If anyone is experiencing crashes with Unity and threads feel free to use the callback method in the SDK. The thread crashes may be due to aborting a thread during an eye data update. The callback method has been reliable in my testing. using UnityEngine; using ViveSR.anipal.Eye; using System.Runtime.InteropServices; public class CallbackExample : MonoBehaviour { private EyeData eyeData = new EyeData(); private bool eye_callback_registered = false; private void Update() { if (SRanipal_Eye_Framework.Status != SRanipal_Eye_Framework.FrameworkStatus.WORKING) return; if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback == true && eye_callback_registered == false) { SRanipal_Eye.WrapperRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback)); eye_callback_registered = true; } else if (SRanipal_Eye_Framework.Instance.EnableEyeDataCallback == false && eye_callback_registered == true) { SRanipal_Eye.WrapperUnRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback)); eye_callback_registered = false; } } private void OnDisable() { Release(); } void OnApplicationQuit() { Release(); } private void Release() { if (eye_callback_registered == true) { SRanipal_Eye.WrapperUnRegisterEyeDataCallback(Marshal.GetFunctionPointerForDelegate((SRanipal_Eye.CallbackBasic)EyeCallback)); eye_callback_registered = false; } } private void EyeCallback(ref EyeData eye_data) { eyeData = eye_data; // do stuff with eyeData.. } } Hi @Corvus, I've tried your callback method solution, unfortunately it is still crashing the Unity when I stop the game. Moreover it pretty soon throws a NullReferenceException, usually after a second or so. I attached the image with the exception. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now