summaryrefslogtreecommitdiffhomepage
path: root/tracker-tobii/thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tracker-tobii/thread.cpp')
-rw-r--r--tracker-tobii/thread.cpp109
1 files changed, 109 insertions, 0 deletions
diff --git a/tracker-tobii/thread.cpp b/tracker-tobii/thread.cpp
new file mode 100644
index 00000000..bdd48125
--- /dev/null
+++ b/tracker-tobii/thread.cpp
@@ -0,0 +1,109 @@
+#include "thread.hpp"
+#include "compat/sleep.hpp"
+
+tobii_thread::~tobii_thread()
+{
+ exit_thread = true;
+ wait();
+
+ if (device) tobii_device_destroy(device);
+ if (api) tobii_api_destroy(api);
+
+ quit();
+}
+
+void tobii_thread::run()
+{
+ /* See https://developer.tobii.com/consumer-eye-trackers/stream-engine/ */
+ if (tobii_api_create(&api, nullptr, nullptr) != TOBII_ERROR_NO_ERROR)
+ {
+ error_last = "Failed to initialize the Tobii Stream Engine API.";
+ exit_thread = true;
+ }
+
+ std::vector<std::string> devices;
+ if (tobii_enumerate_local_device_urls(api,
+ [](char const* url, void* user_data)
+ {
+ auto list = (std::vector<std::string>*) user_data;
+ list->push_back(url);
+ }, &devices) != TOBII_ERROR_NO_ERROR)
+ {
+ error_last = "Failed to enumerate devices.";
+ exit_thread = true;
+ }
+
+ if (devices.size() == 0)
+ {
+ tobii_api_destroy(api);
+ error_last = "No stream engine compatible device(s) found.";
+ exit_thread = true;
+ }
+ std::string selected_device = devices[0];
+
+ unsigned int retry = 0;
+ tobii_error_t tobii_error = TOBII_ERROR_NO_ERROR;
+ do
+ {
+ tobii_error = tobii_device_create(api, selected_device.c_str(), TOBII_FIELD_OF_USE_INTERACTIVE, &device);
+ if ((tobii_error != TOBII_ERROR_CONNECTION_FAILED) && (tobii_error != TOBII_ERROR_FIRMWARE_UPGRADE_IN_PROGRESS)) break;
+ portable::sleep(interval);
+ ++retry;
+ } while (retry < retries);
+ if (tobii_error != TOBII_ERROR_NO_ERROR) {
+ tobii_api_destroy(api);
+ error_last = "Failed to connect to device.";
+ exit_thread = true;
+ }
+
+ if (tobii_head_pose_subscribe(device, [](tobii_head_pose_t const* head_pose, void* user_data) {
+
+ if ((*head_pose).position_validity != TOBII_VALIDITY_VALID
+ || (*head_pose).rotation_validity_xyz[0] != TOBII_VALIDITY_VALID
+ || (*head_pose).rotation_validity_xyz[1] != TOBII_VALIDITY_VALID
+ || (*head_pose).rotation_validity_xyz[2] != TOBII_VALIDITY_VALID) return;
+
+ tobii_head_pose_t* tobii_head_pose_storage = (tobii_head_pose_t*)user_data;
+ *tobii_head_pose_storage = *head_pose;
+
+ }, head_pose) != TOBII_ERROR_NO_ERROR)
+ {
+ error_last = "Failed to subscribe to head pose stream.";
+ exit_thread = true;
+ }
+
+ tobii_error = TOBII_ERROR_NO_ERROR;
+ while (!exit_thread)
+ {
+ tobii_error = tobii_wait_for_callbacks(1, &device);
+ if (tobii_error == TOBII_ERROR_TIMED_OUT) continue;
+ else if (tobii_error != TOBII_ERROR_NO_ERROR)
+ {
+ error_last = "tobii_wait_for_callbacks failed.";
+ }
+
+ tobii_error = tobii_device_process_callbacks(device);
+ if (tobii_error == TOBII_ERROR_CONNECTION_FAILED)
+ {
+ unsigned int retry = 0;
+ auto tobii_error = TOBII_ERROR_NO_ERROR;
+ do
+ {
+ tobii_error = tobii_device_reconnect(device);
+ if ((tobii_error != TOBII_ERROR_CONNECTION_FAILED) && (tobii_error != TOBII_ERROR_FIRMWARE_UPGRADE_IN_PROGRESS)) break;
+ portable::sleep(interval);
+ ++retry;
+ } while (retry < retries);
+ if (tobii_error != TOBII_ERROR_NO_ERROR)
+ {
+ error_last = "Connection was lost and reconnection failed.";
+ exit_thread = true;
+ }
+ continue;
+ }
+ else if (tobii_error != TOBII_ERROR_NO_ERROR)
+ {
+ error_last = "tobii_device_process_callbacks failed.";
+ }
+ }
+}