From 8b326414accae284879c1eaa13f12f36a99034aa Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 10 Aug 2015 19:19:29 -0700 Subject: [PATCH] Start eye tracker streaming such that don't block Interface Start method is called in a separate thread. --- interface/src/Application.cpp | 5 +- interface/src/devices/EyeTracker.cpp | 94 +++++++++++++++++++--------- interface/src/devices/EyeTracker.h | 11 +++- 3 files changed, 77 insertions(+), 33 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2fd18a4fe2..cd919da2cc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2050,10 +2050,7 @@ void Application::setActiveEyeTracker() { bool isEyeTracking = Menu::getInstance()->isOptionChecked(MenuOption::SMIEyeTracking); bool isSimulating = Menu::getInstance()->isOptionChecked(MenuOption::SimulateEyeTracking); eyeTracker->setEnabled(isEyeTracking, isSimulating); - if (isEyeTracking && !eyeTracker->isEnabled()) { - Menu::getInstance()->setIsOptionChecked(MenuOption::SMIEyeTracking, false); - isEyeTracking = false; - } + Menu::getInstance()->getActionForOption(MenuOption::OnePointCalibration)->setEnabled(isEyeTracking && !isSimulating); Menu::getInstance()->getActionForOption(MenuOption::ThreePointCalibration)->setEnabled(isEyeTracking && !isSimulating); Menu::getInstance()->getActionForOption(MenuOption::FivePointCalibration)->setEnabled(isEyeTracking && !isSimulating); diff --git a/interface/src/devices/EyeTracker.cpp b/interface/src/devices/EyeTracker.cpp index 41ca6edccc..b513bd7ac7 100644 --- a/interface/src/devices/EyeTracker.cpp +++ b/interface/src/devices/EyeTracker.cpp @@ -11,7 +11,9 @@ #include "EyeTracker.h" +#include #include +#include #include @@ -125,9 +127,47 @@ void EyeTracker::init() { } else { _isInitialized = true; } + + connect(&_startStreamingWatcher, SIGNAL(finished()), this, SLOT(onStreamStarted())); #endif } +#ifdef HAVE_IVIEWHMD +int EyeTracker::startStreaming(bool simulate) { + return smi_startStreaming(simulate); // This call blocks execution. +} +#endif + +#ifdef HAVE_IVIEWHMD +void EyeTracker::onStreamStarted() { + int result = _startStreamingWatcher.result(); + _isStreaming = (result == SMI_RET_SUCCESS); + + if (result != SMI_RET_SUCCESS) { + qCWarning(interfaceapp) << "Eye Tracker: Error starting streaming:" << smiReturnValueToString(result); + // Display error dialog unless SMI SDK has already displayed an error message. + if (result != SMI_ERROR_HMD_NOT_SUPPORTED) { + QMessageBox::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result)); + } + } + + if (_isStreaming) { + // Automatically load calibration if one has been saved. + QString availableCalibrations = QString(smi_getAvailableCalibrations()); + if (availableCalibrations.contains(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION)) { + result = smi_loadCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION); + if (result != SMI_RET_SUCCESS) { + qCWarning(interfaceapp) << "Eye Tracker: Error loading calibration:" << smiReturnValueToString(result); + QMessageBox::warning(nullptr, "Eye Tracker Error", "Error loading calibration" + + smiReturnValueToString(result)); + } else { + qCDebug(interfaceapp) << "Eye Tracker: Loaded calibration"; + } + } + } +} +#endif + void EyeTracker::setEnabled(bool enabled, bool simulate) { if (!_isInitialized) { return; @@ -135,37 +175,29 @@ void EyeTracker::setEnabled(bool enabled, bool simulate) { #ifdef HAVE_IVIEWHMD qCDebug(interfaceapp) << "Eye Tracker: Set enabled =" << enabled << ", simulate =" << simulate; - if (enabled && !_isStreaming) { - // There is no smi_stopStreaming() method so keep streaming once started in case tracking is re-enabled after stopping. - int result = smi_startStreaming(simulate); + + // There is no smi_stopStreaming() method and after an smi_quit(), streaming cannot be restarted (at least not for + // simulated data). So keep streaming once started in case tracking is re-enabled after stopping. + + // Try to stop streaming if changing whether simulating or not. + if (enabled && _isStreaming && _isStreamSimulating != simulate) { + int result = smi_quit(); if (result != SMI_RET_SUCCESS) { - qCWarning(interfaceapp) << "Eye Tracker: Error starting streaming:" << smiReturnValueToString(result); - // Display error dialog except if SMI SDK has already displayed an error message. - if (result != SMI_ERROR_HMD_NOT_SUPPORTED) { - QMessageBox::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result)); - } - } - - _isStreaming = (result == SMI_RET_SUCCESS); - - if (_isStreaming) { - // Automatically load calibration if one has been saved. - QString availableCalibrations = QString(smi_getAvailableCalibrations()); - if (availableCalibrations.contains(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION)) { - result = smi_loadCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION); - if (result != SMI_RET_SUCCESS) { - qCWarning(interfaceapp) << "Eye Tracker: Error loading calibration:" << smiReturnValueToString(result); - QMessageBox::warning(nullptr, "Eye Tracker Error", "Error loading calibration" - + smiReturnValueToString(result)); - } else { - qCDebug(interfaceapp) << "Eye Tracker: Loaded calibration"; - } - } + qCWarning(interfaceapp) << "Eye Tracker: Error stopping streaming:" << smiReturnValueToString(result); } + _isStreaming = false; } - _isEnabled = enabled && _isStreaming; - _isSimulating = _isEnabled && simulate; + if (enabled && !_isStreaming) { + // Start SMI streaming in a separate thread because it blocks. + QFuture future = QtConcurrent::run(this, &EyeTracker::startStreaming, simulate); + _startStreamingWatcher.setFuture(future); + _isStreamSimulating = simulate; + } + + _isEnabled = enabled; + _isSimulating = simulate; + #endif } @@ -175,11 +207,17 @@ void EyeTracker::reset() { bool EyeTracker::isTracking() const { static const quint64 ACTIVE_TIMEOUT_USECS = 2000000; // 2 secs - return (usecTimestampNow() - _lastProcessDataTimestamp < ACTIVE_TIMEOUT_USECS); + return _isEnabled && (usecTimestampNow() - _lastProcessDataTimestamp < ACTIVE_TIMEOUT_USECS); } #ifdef HAVE_IVIEWHMD void EyeTracker::calibrate(int points) { + + if (!_isStreaming) { + qCWarning(interfaceapp) << "Eye Tracker: Cannot calibrate because not streaming"; + return; + } + smi_CalibrationHMDStruct* calibrationHMDStruct; smi_createCalibrationHMDStruct(&calibrationHMDStruct); diff --git a/interface/src/devices/EyeTracker.h b/interface/src/devices/EyeTracker.h index b1c71c0303..0e760d9454 100644 --- a/interface/src/devices/EyeTracker.h +++ b/interface/src/devices/EyeTracker.h @@ -13,6 +13,7 @@ #define hifi_EyeTracker_h #include +#include #include @@ -44,19 +45,27 @@ public: void processData(smi_CallbackDataStruct* data); void calibrate(int points); + + int startStreaming(bool simulate); + +private slots: + void onStreamStarted(); #endif private: QString smiReturnValueToString(int value); bool _isInitialized = false; - bool _isStreaming = false; bool _isEnabled = false; bool _isSimulating = false; + bool _isStreaming = false; + bool _isStreamSimulating = false; quint64 _lastProcessDataTimestamp; glm::vec3 _lookAtPosition; + + QFutureWatcher _startStreamingWatcher; }; #endif // hifi_EyeTracker_h