From e1d37f21670aa7531bf1fb5d8add5edf7195057d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 1 Jun 2017 23:29:22 +0100 Subject: [PATCH 001/157] saving work --- .../src/controllers/InputConfiguration.cpp | 17 ++++++++++++ .../src/controllers/InputConfiguration.h | 26 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 libraries/controllers/src/controllers/InputConfiguration.cpp create mode 100644 libraries/controllers/src/controllers/InputConfiguration.h diff --git a/libraries/controllers/src/controllers/InputConfiguration.cpp b/libraries/controllers/src/controllers/InputConfiguration.cpp new file mode 100644 index 0000000000..863bdbf675 --- /dev/null +++ b/libraries/controllers/src/controllers/InputConfiguration.cpp @@ -0,0 +1,17 @@ +// +// Created by Dante Ruiz on 6/1/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#include "InputConfiguration.h" + +namespace controller { + + InputConfiguration::InputConfiguration() { + + } +} diff --git a/libraries/controllers/src/controllers/InputConfiguration.h b/libraries/controllers/src/controllers/InputConfiguration.h new file mode 100644 index 0000000000..0a7f01a7a1 --- /dev/null +++ b/libraries/controllers/src/controllers/InputConfiguration.h @@ -0,0 +1,26 @@ +// +// Created by Dante Ruiz on 6/1/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_InputConfiguration_h +#define hifi_InputConfiguration_h + +#include + +#include +#include + +namespace controller { + + class InputConfiguration : public QObject, public Dependency { + public: + InputConfiguration(); + ~InputConfiguration() {} + }; +} + +#endif From f0f10f74c69b82850c4075aa25c5e4c46069bd6a Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Sat, 3 Jun 2017 00:30:00 +0100 Subject: [PATCH 002/157] inpput configutration stub --- .../qml/hifi/tablet/InputConfiguration.qml | 95 ++++++++++++++++++ .../resources/qml/styles-uit/Separator.qml | 26 +++++ interface/src/Application.cpp | 2 + interface/src/Menu.cpp | 7 ++ interface/src/ui/overlays/Web3DOverlay.cpp | 3 +- .../plugins/src/plugins/.#PluginManager.h | Bin 0 -> 78 bytes .../src/plugins}/InputConfiguration.cpp | 15 ++- .../src/plugins}/InputConfiguration.h | 19 ++-- 8 files changed, 154 insertions(+), 13 deletions(-) create mode 100644 interface/resources/qml/hifi/tablet/InputConfiguration.qml create mode 100644 interface/resources/qml/styles-uit/Separator.qml create mode 100644 libraries/plugins/src/plugins/.#PluginManager.h rename libraries/{controllers/src/controllers => plugins/src/plugins}/InputConfiguration.cpp (50%) rename libraries/{controllers/src/controllers => plugins/src/plugins}/InputConfiguration.h (63%) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml new file mode 100644 index 0000000000..fc65f8a3d4 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -0,0 +1,95 @@ +// +// Created by Dante Ruiz on 6/1/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtGraphicalEffects 1.0 +import "../../styles-uit" +import "../../controls" +import "../../controls-uit" as HifiControls + +Rectangle { + id: inputConfiguration + anchors.fill: parent + + HifiConstants { id: hifi } + + color: hifi.colors.baseGray + + Rectangle { + width: inputConfiguration.width + height: 1 + color: hifi.colors.baseGrayShadow + x: -hifi.dimensions.contentMargin.x + } + + RalewayBold { + id: header + text: "Controller Settings" + size: 22 + color: "white" + + anchors.top: inputConfiguration.top + anchors.left: inputConfiguration.left + anchors.leftMargin: 20 + anchors.topMargin: 20 + } + + + Separator { + id: headerSeparator + width: inputConfiguration.width + anchors.top: header.bottom + anchors.topMargin: 10 + } + + RalewayBold { + id: configuration + text: "SELECT DEVICE" + size: 18 + color: hifi.colors.lightGray + + + anchors.top: headerSeparator.bottom + anchors.left: inputConfiguration.left + anchors.leftMargin: 20 + anchors.topMargin: 20 + } + + Row { + id: configRow + + anchors.top: configuration.bottom + anchors.topMargin: 20 + anchors.left: configuration.left + anchors.leftMargin: 40 + spacing: 10 + HifiControls.ComboBox { + id: box + width: 160 + + colorScheme: hifi.colorSchemes.dark + model: inputPlugins() + } + + HifiControls.CheckBox { + onClicked: { + if (checked) { + console.log("button checked"); + Tablet.getTablet(""); + InputConfiguration.inputPlugins(); + } + } + } + + } + + function inputPlugins() { + var plugins = ["temp"]; + return plugins + } +} diff --git a/interface/resources/qml/styles-uit/Separator.qml b/interface/resources/qml/styles-uit/Separator.qml new file mode 100644 index 0000000000..1067de3b29 --- /dev/null +++ b/interface/resources/qml/styles-uit/Separator.qml @@ -0,0 +1,26 @@ +// +// Created by Dante Ruiz on 6/1/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtGraphicalEffects 1.0 + +Item { + Rectangle { + id: shadows + width: parent.width + height: 2 + color: hifi.colors.baseGrayShadow + } + + Rectangle { + width: parent.width + height: 1 + anchors.top: shadows.bottom + color: hifi.colors.baseGrayHighlight + } +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 46c4c0bd4e..eda3a14533 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -522,6 +523,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED } }); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(true, qApp, qApp); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 4138798484..8fd560dcf3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -311,6 +312,12 @@ Menu::Menu() { QString("../../hifi/tablet/TabletLodPreferences.qml"), "LodPreferencesDialog"); }); + action = addActionToQMenuAndActionHash(settingsMenu, "InputConfiguration"); + connect(action, &QAction::triggered, [] { + auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); + tablet->loadQMLSource("InputConfiguration.qml"); + }); + // Settings > Control with Speech [advanced] #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::get(); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 75c793bf77..8dcbc254f6 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -51,6 +51,7 @@ #include "ui/AvatarInputs.h" #include "avatar/AvatarManager.h" #include "scripting/GlobalServicesScriptingInterface.h" +#include #include "ui/Snapshot.h" static const float DPI = 30.47f; @@ -201,7 +202,7 @@ void Web3DOverlay::loadSourceURL() { _webSurface->getRootContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); _webSurface->getRootContext()->setContextProperty("AvatarList", DependencyManager::get().data()); _webSurface->getRootContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance()); - + _webSurface->getRootContext()->setContextProperty("InputConfiguration", DependencyManager::get().data()); _webSurface->getRootContext()->setContextProperty("pathToFonts", "../../"); tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data()); diff --git a/libraries/plugins/src/plugins/.#PluginManager.h b/libraries/plugins/src/plugins/.#PluginManager.h new file mode 100644 index 0000000000000000000000000000000000000000..6d0a3bdbacae8dd149c37fa40847309629686543 GIT binary patch literal 78 zcmW;5F$#iE007W;6gxn|2aN`i1jWIjNIgJ0u`2k(%*Kd)(=pZUI(9%hR{ c +#include #include -#include -namespace controller { - - class InputConfiguration : public QObject, public Dependency { - public: - InputConfiguration(); - ~InputConfiguration() {} - }; -} +class InputConfiguration : public QObject, public Dependency { + Q_OBJECT +public: + InputConfiguration(); + + void inputPlugins(); +public slots: + void enabledInputPlugins(); +}; #endif From 016cf45d0f1b4f2ecd6b37abbaff628d741e36ae Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Sat, 3 Jun 2017 00:35:19 +0100 Subject: [PATCH 003/157] removed emacs garbage files --- libraries/plugins/src/plugins/.#PluginManager.h | Bin 78 -> 0 bytes libraries/plugins/src/plugins/InputConfiguration.h | 1 - 2 files changed, 1 deletion(-) delete mode 100644 libraries/plugins/src/plugins/.#PluginManager.h diff --git a/libraries/plugins/src/plugins/.#PluginManager.h b/libraries/plugins/src/plugins/.#PluginManager.h deleted file mode 100644 index 6d0a3bdbacae8dd149c37fa40847309629686543..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78 zcmW;5F$#iE007W;6gxn|2aN`i1jWIjNIgJ0u`2k(%*Kd)(=pZUI(9%hR{ c Date: Tue, 6 Jun 2017 00:32:20 +0100 Subject: [PATCH 004/157] base ui working --- .../resources/qml/controls-uit/ComboBox.qml | 1 + .../qml/hifi/tablet/InputConfiguration.qml | 18 ++++++--- .../src/plugins/InputConfiguration.cpp | 40 +++++++++++++++---- .../plugins/src/plugins/InputConfiguration.h | 11 +++-- libraries/plugins/src/plugins/InputPlugin.h | 3 +- plugins/hifiCodec/CMakeLists.txt | 2 +- plugins/hifiNeuron/CMakeLists.txt | 2 +- plugins/hifiSdl2/CMakeLists.txt | 2 +- plugins/hifiSixense/CMakeLists.txt | 2 +- plugins/openvr/src/ViveControllerManager.cpp | 3 ++ plugins/openvr/src/ViveControllerManager.h | 3 ++ plugins/pcmCodec/CMakeLists.txt | 2 +- 12 files changed, 66 insertions(+), 23 deletions(-) diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index be6a439e57..3ce297ef80 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -20,6 +20,7 @@ FocusScope { HifiConstants { id: hifi } property alias model: comboBox.model; + property alias editable: comboBox.editable property alias comboBox: comboBox readonly property alias currentText: comboBox.currentText; property alias currentIndex: comboBox.currentIndex; diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index fc65f8a3d4..10f03f9edf 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -20,6 +20,8 @@ Rectangle { color: hifi.colors.baseGray + property var pluginSettings: null + Rectangle { width: inputConfiguration.width height: 1 @@ -71,17 +73,22 @@ Rectangle { HifiControls.ComboBox { id: box width: 160 - + editable: true colorScheme: hifi.colorSchemes.dark model: inputPlugins() + + onCurrentIndexChanged: { + var object = {"Test": "hello"}; + InputConfiguration.configurationSettings(object, box.currentText); + } } HifiControls.CheckBox { onClicked: { if (checked) { - console.log("button checked"); - Tablet.getTablet(""); - InputConfiguration.inputPlugins(); + box.model = InputConfiguration.activeInputPlugins(); + } else { + box.model = InputConfiguration.inputPlugins(); } } } @@ -89,7 +96,6 @@ Rectangle { } function inputPlugins() { - var plugins = ["temp"]; - return plugins + return InputConfiguration.inputPlugins(); } } diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index c15316406b..8f8daf716a 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -8,19 +8,43 @@ #include "InputConfiguration.h" - +#include "DisplayPlugin.h" +#include "InputPlugin.h" #include "PluginManager.h" InputConfiguration::InputConfiguration() { - } -void InputConfiguration::inputPlugins() { - PluginManager* inputPlugin = PluginManager::getInstance(); -} - -void InputConfiguration::enabledInputPlugins() { - qDebug() << "getting enabled plugins"; +QStringList InputConfiguration::inputPlugins() { + QStringList inputPlugins; + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { + inputPlugins << QString(plugin->getName()); + } + return inputPlugins; } +QStringList InputConfiguration::activeInputPlugins() { + QStringList activePlugins; + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { + if (plugin->isActive()) { + activePlugins << QString(plugin->getName()); + } + } + return activePlugins; +} + +QString InputConfiguration::configurationLayout(QString pluginName) { + QString sourcePath; + + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { + if (plugin->getName() == pluginName) { + qDebug() << "------------> testing <----------"; + } + } + return sourcePath; +} + +void InputConfiguration::configurationSettings(QJsonObject configurationSettings, QString pluginName) { + qDebug() << configurationSettings["Test"]; +} diff --git a/libraries/plugins/src/plugins/InputConfiguration.h b/libraries/plugins/src/plugins/InputConfiguration.h index d8174737cf..2a0093d5b2 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.h +++ b/libraries/plugins/src/plugins/InputConfiguration.h @@ -12,15 +12,20 @@ #include #include +#include +#include +#include #include class InputConfiguration : public QObject, public Dependency { Q_OBJECT public: InputConfiguration(); - - void inputPlugins(); - void enabledInputPlugins(); + + Q_INVOKABLE QStringList inputPlugins(); + Q_INVOKABLE QStringList activeInputPlugins(); + Q_INVOKABLE QString configurationLayout(QString pluginName); + Q_INVOKABLE void configurationSettings(QJsonObject configurationSettings, QString pluginName); }; #endif diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index 0db0b24420..eb8aca660b 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -11,6 +11,7 @@ #pragma once #include "Plugin.h" +#include namespace controller { struct InputCalibrationData; @@ -25,5 +26,5 @@ public: // If an input plugin is only a single device, it will only return it's primary name. virtual QStringList getSubdeviceNames() { return { getName() }; }; virtual bool isHandController() const = 0; + virtual void inputPluginConfigurationSettings(const QJsonObject configurationSettings) { } }; - diff --git a/plugins/hifiCodec/CMakeLists.txt b/plugins/hifiCodec/CMakeLists.txt index 28c1dc3807..15572e8266 100644 --- a/plugins/hifiCodec/CMakeLists.txt +++ b/plugins/hifiCodec/CMakeLists.txt @@ -8,7 +8,7 @@ set(TARGET_NAME hifiCodec) setup_hifi_client_server_plugin() -link_hifi_libraries(audio plugins) +link_hifi_libraries(audio plugins input-plugins display-plugins) add_dependency_external_projects(hifiAudioCodec) target_include_directories(${TARGET_NAME} PRIVATE ${HIFIAUDIOCODEC_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${HIFIAUDIOCODEC_LIBRARIES}) diff --git a/plugins/hifiNeuron/CMakeLists.txt b/plugins/hifiNeuron/CMakeLists.txt index a9ed8cca6e..e3a725ca2f 100644 --- a/plugins/hifiNeuron/CMakeLists.txt +++ b/plugins/hifiNeuron/CMakeLists.txt @@ -10,7 +10,7 @@ if (APPLE OR WIN32) set(TARGET_NAME hifiNeuron) setup_hifi_plugin(Script Qml Widgets) - link_hifi_libraries(shared controllers ui plugins input-plugins) + link_hifi_libraries(shared controllers ui plugins input-plugins display-plugins) target_neuron() endif() diff --git a/plugins/hifiSdl2/CMakeLists.txt b/plugins/hifiSdl2/CMakeLists.txt index 7e499e314a..86bda5a15d 100644 --- a/plugins/hifiSdl2/CMakeLists.txt +++ b/plugins/hifiSdl2/CMakeLists.txt @@ -8,5 +8,5 @@ set(TARGET_NAME hifiSdl2) setup_hifi_plugin(Script Qml Widgets) -link_hifi_libraries(shared controllers ui plugins input-plugins script-engine) +link_hifi_libraries(shared controllers ui plugins input-plugins script-engine display-plugins) target_sdl2() diff --git a/plugins/hifiSixense/CMakeLists.txt b/plugins/hifiSixense/CMakeLists.txt index 14676217db..54884bddff 100644 --- a/plugins/hifiSixense/CMakeLists.txt +++ b/plugins/hifiSixense/CMakeLists.txt @@ -9,6 +9,6 @@ if (NOT ANDROID) set(TARGET_NAME hifiSixense) setup_hifi_plugin(Script Qml Widgets) - link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins) + link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins display-plugins) target_sixense() endif () diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 53500a3353..d505e91511 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -94,6 +94,9 @@ bool ViveControllerManager::isSupported() const { return openVrSupported(); } +void ViveControllerManager::inputPluginConfigurationSettings(const QJsonObject configurationSettings) { +} + bool ViveControllerManager::activate() { InputPlugin::activate(); diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index a76adaa8f9..1ac920228a 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -42,6 +42,8 @@ public: bool isHandController() const override { return true; } + void inputPluginConfigurationSettings(const QJsonObject configurationSettings) override; + bool activate() override; void deactivate() override; @@ -145,6 +147,7 @@ private: bool _triggersPressedHandled { false }; bool _calibrated { false }; bool _timeTilCalibrationSet { false }; + bool _calibrate { false }; mutable std::recursive_mutex _lock; QString configToString(Config config); diff --git a/plugins/pcmCodec/CMakeLists.txt b/plugins/pcmCodec/CMakeLists.txt index 900a642a88..5e52705033 100644 --- a/plugins/pcmCodec/CMakeLists.txt +++ b/plugins/pcmCodec/CMakeLists.txt @@ -8,6 +8,6 @@ set(TARGET_NAME pcmCodec) setup_hifi_client_server_plugin() -link_hifi_libraries(shared plugins) +link_hifi_libraries(shared plugins input-plugins display-plugins) install_beside_console() From bb7c424d47396d310f4198419efa1df532b30984 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 6 Jun 2017 21:09:09 +0100 Subject: [PATCH 005/157] get ui working --- .../resources/qml/controls-uit/CheckBox.qml | 2 +- .../qml/hifi/tablet/InputConfiguration.qml | 43 ++- .../qml/hifi/tablet/OpenVrConfiguration.qml | 253 ++++++++++++++++++ .../src/plugins/InputConfiguration.cpp | 2 +- libraries/plugins/src/plugins/InputPlugin.h | 3 +- plugins/openvr/src/ViveControllerManager.cpp | 8 +- plugins/openvr/src/ViveControllerManager.h | 3 +- 7 files changed, 305 insertions(+), 9 deletions(-) create mode 100644 interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 916a7d4889..5c49a0775d 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -21,7 +21,7 @@ Original.CheckBox { readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light property bool isRedCheck: false property int boxSize: 14 - readonly property int boxRadius: 3 + property int boxRadius: 3 readonly property int checkSize: Math.max(boxSize - 8, 10) readonly property int checkRadius: 2 activeFocusOnPress: true diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index 10f03f9edf..56f0e0fe14 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -64,7 +64,7 @@ Rectangle { Row { id: configRow - + z: 999 anchors.top: configuration.bottom anchors.topMargin: 20 anchors.left: configuration.left @@ -73,13 +73,14 @@ Rectangle { HifiControls.ComboBox { id: box width: 160 + z: 999 editable: true colorScheme: hifi.colorSchemes.dark model: inputPlugins() onCurrentIndexChanged: { - var object = {"Test": "hello"}; - InputConfiguration.configurationSettings(object, box.currentText); + loader.source = "" + loader.source = InputConfiguration.configurationLayout(box.currentText); } } @@ -95,6 +96,42 @@ Rectangle { } + + Separator { + id: configurationSeperator + z: 0 + width: inputConfiguration.width + anchors.top: configRow.bottom + anchors.topMargin: 10 + } + + Row { + z: 0 + id: configurationHeader + anchors.top: configurationSeperator.bottom + anchors.topMargin: 20 + anchors.left: inputConfiguration.left + anchors.leftMargin: 40 + spacing: 10 + RalewayBold { + text: "CONFIGURATION" + size: 18 + color: hifi.colors.lightGray + } + } + + Loader { + id: loader + asynchronous: false + + width: configurationHeader.width + anchors.left: inputConfiguration.left + anchors.right: inputConfiguration.right + anchors.top: configurationHeader.bottom + anchors.topMargin: 10 + anchors.bottom: inputConfiguration.bottom + } + function inputPlugins() { return InputConfiguration.inputPlugins(); } diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml new file mode 100644 index 0000000000..c20f01ad6e --- /dev/null +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -0,0 +1,253 @@ +// +// Created by Dante Ruiz on 6/5/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtGraphicalEffects 1.0 +import "../../styles-uit" +import "../../controls" +import "../../controls-uit" as HifiControls + + +Rectangle { + id: openVrConfiguration + + width: parent.width + height: parent.height + anchors.fill: parent + + property int leftMargin: 55 + + HifiConstants { id: hifi } + + color: hifi.colors.baseGray + + RalewayBold { + id: head + + text: "Head:" + size: 15 + + color: "white" + + anchors.left: parent.left + anchors.leftMargin: leftMargin + } + + Row { + id: headConfig + anchors.top: head.bottom + anchors.topMargin: 5 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 20 + spacing: 10 + + HifiControls.CheckBox { + id: headBox + width: 15 + height: 15 + boxRadius: 7 + } + + RalewayBold { + size: 15 + text: "Vive HMD" + color: hifi.colors.lightGrayText + } + + HifiControls.CheckBox { + id: headPuckBox + width: 15 + height: 15 + boxRadius: 7 + } + + RalewayBold { + size: 15 + text: "Tracker" + color: hifi.colors.lightGrayText + } + } + + RalewayBold { + id: hands + + text: "Hands:" + size: 15 + + color: "white" + + anchors.top: headConfig.bottom + anchors.topMargin: 10 + anchors.left: parent.left + anchors.leftMargin: leftMargin + } + + Row { + id: handConfig + anchors.top: hands.bottom + anchors.topMargin: 5 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 20 + spacing: 10 + + HifiControls.CheckBox { + id: handBox + width: 15 + height: 15 + boxRadius: 7 + } + + RalewayBold { + size: 15 + text: "Controllers" + color: hifi.colors.lightGrayText + } + + HifiControls.CheckBox { + id: handPuckBox + width: 15 + height: 15 + boxRadius: 7 + } + + RalewayBold { + size: 15 + text: "Trackers" + color: hifi.colors.lightGrayText + } + } + + RalewayBold { + id: additional + + text: "Additional Trackers" + size: 15 + + color: hifi.colors.white + + anchors.top: handConfig.bottom + anchors.topMargin: 10 + anchors.left: parent.left + anchors.leftMargin: leftMargin + } + + Row { + id: feetConfig + anchors.top: additional.bottom + anchors.topMargin: 15 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 20 + spacing: 10 + + HifiControls.CheckBox { + id: feetBox + width: 15 + height: 15 + boxRadius: 7 + } + + RalewayBold { + size: 15 + text: "Feet" + color: hifi.colors.lightGrayText + } + } + + Row { + id: hipConfig + anchors.top: feetConfig.bottom + anchors.topMargin: 15 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 20 + spacing: 10 + + HifiControls.CheckBox { + id: hipBox + width: 15 + height: 15 + boxRadius: 7 + } + + RalewayBold { + size: 15 + text: "Hips" + color: hifi.colors.lightGrayText + } + + RalewayBold { + size: 12 + text: "requires feet" + color: hifi.colors.lightGray + } + } + + + Row { + id: chestConfig + anchors.top: hipConfig.bottom + anchors.topMargin: 15 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 20 + spacing: 10 + + HifiControls.CheckBox { + id: chestBox + width: 15 + height: 15 + boxRadius: 7 + } + + RalewayBold { + size: 15 + text: "Chest" + color: hifi.colors.lightGrayText + } + + RalewayBold { + size: 12 + text: "requires hips" + color: hifi.colors.lightGray + } + } + + + Row { + id: shoulderConfig + anchors.top: chestConfig.bottom + anchors.topMargin: 15 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 20 + spacing: 10 + + HifiControls.CheckBox { + id: shoulderBox + width: 15 + height: 15 + boxRadius: 7 + } + + RalewayBold { + size: 15 + text: "Shoulders" + color: hifi.colors.lightGrayText + } + + RalewayBold { + size: 12 + text: "requires hips" + color: hifi.colors.lightGray + } + } + + Separator { + id: bottomSeperator + width: parent.width + anchors.top: shoulderConfig.bottom + anchors.topMargin: 10 + } +} diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 8f8daf716a..14472a5ec7 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -39,7 +39,7 @@ QString InputConfiguration::configurationLayout(QString pluginName) { for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->getName() == pluginName) { - qDebug() << "------------> testing <----------"; + return plugin->configurationLayout(); } } return sourcePath; diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index eb8aca660b..94c7595eb9 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -26,5 +26,6 @@ public: // If an input plugin is only a single device, it will only return it's primary name. virtual QStringList getSubdeviceNames() { return { getName() }; }; virtual bool isHandController() const = 0; - virtual void inputPluginConfigurationSettings(const QJsonObject configurationSettings) { } + virtual void configurationSettings(const QJsonObject configurationSettings) { } + virtual QString configurationLayout() { return QString(); } }; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index c33dd30360..2337c6161b 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -39,7 +39,7 @@ extern PoseData _nextSimPoseData; vr::IVRSystem* acquireOpenVrSystem(); void releaseOpenVrSystem(); - +static const QString OPENVR_LAYOUT = QString("OpenVrConfiguration.qml"); static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; const quint64 CALIBRATION_TIMELAPSE = 1 * USECS_PER_SECOND; @@ -120,7 +120,11 @@ bool ViveControllerManager::isSupported() const { return openVrSupported(); } -void ViveControllerManager::inputPluginConfigurationSettings(const QJsonObject configurationSettings) { +void ViveControllerManager::configurationSettings(const QJsonObject configurationSettings) { +} + +QString ViveControllerManager::configurationLayout() { + return OPENVR_LAYOUT; } bool ViveControllerManager::activate() { diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index bf3a7af3fb..b8a6206d60 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -42,7 +42,8 @@ public: bool isHandController() const override { return true; } - void inputPluginConfigurationSettings(const QJsonObject configurationSettings) override; + QString configurationLayout() override; + void configurationSettings(const QJsonObject configurationSettings) override; bool activate() override; void deactivate() override; From 70ba344f1bc5107f737af5a4de0120ded42c91fc Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 7 Jun 2017 00:25:08 +0100 Subject: [PATCH 006/157] finished openvr ui --- .../qml/hifi/tablet/InputConfiguration.qml | 78 +++++++++++----- .../qml/hifi/tablet/OpenVrConfiguration.qml | 90 +++++++++++++++---- .../qml/styles-uit/HifiConstants.qml | 1 + .../src/plugins/InputConfiguration.cpp | 8 ++ .../plugins/src/plugins/InputConfiguration.h | 1 + libraries/plugins/src/plugins/InputPlugin.h | 2 + 6 files changed, 138 insertions(+), 42 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index 56f0e0fe14..9393906b06 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -29,7 +29,7 @@ Rectangle { x: -hifi.dimensions.contentMargin.x } - RalewayBold { + RalewayRegular { id: header text: "Controller Settings" size: 22 @@ -49,25 +49,38 @@ Rectangle { anchors.topMargin: 10 } - RalewayBold { - id: configuration - text: "SELECT DEVICE" - size: 18 - color: hifi.colors.lightGray - + HiFiGlyphs { + id: sourceGlyph + text: hifi.glyphs.source + size: 36 + color: hifi.colors.blueHighlight anchors.top: headerSeparator.bottom anchors.left: inputConfiguration.left - anchors.leftMargin: 20 + anchors.leftMargin: 40 anchors.topMargin: 20 } + RalewayRegular { + id: configuration + text: "SELECT DEVICE" + size: 15 + color: hifi.colors.lightGrayText + + + anchors.top: headerSeparator.bottom + anchors.left: sourceGlyph.right + anchors.leftMargin: 10 + anchors.topMargin: 30 + anchors.verticalCenter: sourceGlyph.horizontalCenter + } + Row { id: configRow z: 999 - anchors.top: configuration.bottom + anchors.top: sourceGlyph.bottom anchors.topMargin: 20 - anchors.left: configuration.left + anchors.left: sourceGlyph.left anchors.leftMargin: 40 spacing: 10 HifiControls.ComboBox { @@ -98,38 +111,57 @@ Rectangle { Separator { - id: configurationSeperator + id: configurationSeparator z: 0 width: inputConfiguration.width anchors.top: configRow.bottom anchors.topMargin: 10 } - Row { - z: 0 - id: configurationHeader - anchors.top: configurationSeperator.bottom - anchors.topMargin: 20 + + HiFiGlyphs { + id: sliderGlyph + text: hifi.glyphs.sliders + size: 36 + color: hifi.colors.blueHighlight + + anchors.top: configurationSeparator.bottom anchors.left: inputConfiguration.left anchors.leftMargin: 40 - spacing: 10 - RalewayBold { - text: "CONFIGURATION" - size: 18 - color: hifi.colors.lightGray - } + anchors.topMargin: 20 + } + + RalewayRegular { + id: configurationHeader + text: "CONFIGURATION" + size: 15 + color: hifi.colors.lightGrayText + + + anchors.top: configurationSeparator.bottom + anchors.left: sliderGlyph.right + anchors.leftMargin: 10 + anchors.topMargin: 30 + anchors.verticalCenter: sliderGlyph.horizontalCenter } Loader { id: loader asynchronous: false - width: configurationHeader.width + width: inputConfiguration.width anchors.left: inputConfiguration.left anchors.right: inputConfiguration.right anchors.top: configurationHeader.bottom anchors.topMargin: 10 anchors.bottom: inputConfiguration.bottom + + + onLoaded: { + if (loader.item.hasOwnProeprty("pluginName")) { + loader.item.pluginName = box.currentText + } + } } function inputPlugins() { diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index c20f01ad6e..434ee12f28 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -7,6 +7,7 @@ // import QtQuick 2.5 +import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 import "../../styles-uit" import "../../controls" @@ -20,7 +21,8 @@ Rectangle { height: parent.height anchors.fill: parent - property int leftMargin: 55 + property int leftMargin: 75 + property string pluginName: "" HifiConstants { id: hifi } @@ -30,7 +32,7 @@ Rectangle { id: head text: "Head:" - size: 15 + size: 12 color: "white" @@ -54,7 +56,7 @@ Rectangle { } RalewayBold { - size: 15 + size: 12 text: "Vive HMD" color: hifi.colors.lightGrayText } @@ -67,7 +69,7 @@ Rectangle { } RalewayBold { - size: 15 + size: 12 text: "Tracker" color: hifi.colors.lightGrayText } @@ -77,7 +79,7 @@ Rectangle { id: hands text: "Hands:" - size: 15 + size: 12 color: "white" @@ -103,20 +105,20 @@ Rectangle { } RalewayBold { - size: 15 + size: 12 text: "Controllers" color: hifi.colors.lightGrayText } HifiControls.CheckBox { id: handPuckBox - width: 15 + width: 12 height: 15 boxRadius: 7 } RalewayBold { - size: 15 + size: 12 text: "Trackers" color: hifi.colors.lightGrayText } @@ -126,7 +128,7 @@ Rectangle { id: additional text: "Additional Trackers" - size: 15 + size: 12 color: hifi.colors.white @@ -152,7 +154,7 @@ Rectangle { } RalewayBold { - size: 15 + size: 12 text: "Feet" color: hifi.colors.lightGrayText } @@ -174,12 +176,12 @@ Rectangle { } RalewayBold { - size: 15 + size: 12 text: "Hips" color: hifi.colors.lightGrayText } - RalewayBold { + RalewayRegular { size: 12 text: "requires feet" color: hifi.colors.lightGray @@ -203,12 +205,12 @@ Rectangle { } RalewayBold { - size: 15 + size: 12 text: "Chest" color: hifi.colors.lightGrayText } - RalewayBold { + RalewayRegular { size: 12 text: "requires hips" color: hifi.colors.lightGray @@ -216,7 +218,7 @@ Rectangle { } - Row { + Row { id: shoulderConfig anchors.top: chestConfig.bottom anchors.topMargin: 15 @@ -232,22 +234,72 @@ Rectangle { } RalewayBold { - size: 15 + size: 12 text: "Shoulders" color: hifi.colors.lightGrayText } - RalewayBold { + RalewayRegular { size: 12 text: "requires hips" color: hifi.colors.lightGray } - } - + } + Separator { id: bottomSeperator width: parent.width anchors.top: shoulderConfig.bottom anchors.topMargin: 10 } + + + Rectangle { + id: calibrationButton + width: 200 + height: 35 + radius: 6 + + color: hifi.colors.blueHighlight + + anchors.top: bottomSeperator.bottom + anchors.topMargin: 10 + anchors.left: parent.left + anchors.leftMargin: leftMargin + + + HiFiGlyphs { + id: calibrationGlyph + text: hifi.glyphs.sliders + size: 36 + color: hifi.colors.white + + anchors.horizontalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 30 + + } + + RalewayRegular { + id: calibrate + text: "CALIBRATE" + size: 17 + color: hifi.colors.white + + anchors.left: calibrationGlyph.right + anchors.top: parent.top + anchors.topMargin: 8 + } + + MouseArea { + anchors.fill: parent + + onClicked: { + InputCalibration.calibratePlugin(pluginName); + } + } + } + + + } diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index 7b6efbd573..12bbb09fba 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -333,5 +333,6 @@ Item { readonly property string vol_x_2: "\ue015" readonly property string vol_x_3: "\ue016" readonly property string vol_x_4: "\ue017" + readonly property string source: "\ue01c" } } diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 14472a5ec7..051bb3281c 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -48,3 +48,11 @@ QString InputConfiguration::configurationLayout(QString pluginName) { void InputConfiguration::configurationSettings(QJsonObject configurationSettings, QString pluginName) { qDebug() << configurationSettings["Test"]; } + +void InputConfiguration::calibratePlugin(QString pluginName) { + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { + if (plugin->getName() == pluginName) { + //calibrtate plugin + } + } +} diff --git a/libraries/plugins/src/plugins/InputConfiguration.h b/libraries/plugins/src/plugins/InputConfiguration.h index 2a0093d5b2..a560c02e5a 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.h +++ b/libraries/plugins/src/plugins/InputConfiguration.h @@ -26,6 +26,7 @@ public: Q_INVOKABLE QStringList activeInputPlugins(); Q_INVOKABLE QString configurationLayout(QString pluginName); Q_INVOKABLE void configurationSettings(QJsonObject configurationSettings, QString pluginName); + Q_INVOKABLE void calibratePlugin(QString pluginName); }; #endif diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index 94c7595eb9..1850dcbc18 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -28,4 +28,6 @@ public: virtual bool isHandController() const = 0; virtual void configurationSettings(const QJsonObject configurationSettings) { } virtual QString configurationLayout() { return QString(); } + virtual void calibrate() {} + virtual bool configurable() { return false; } }; From 4ba1fdc323cc526165dffea7163a77536797e3c0 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 7 Jun 2017 00:48:12 +0100 Subject: [PATCH 007/157] elimated uncofigurable items from the list --- interface/resources/qml/hifi/tablet/InputConfiguration.qml | 4 ++++ libraries/plugins/src/plugins/InputConfiguration.cpp | 2 +- plugins/openvr/src/ViveControllerManager.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index 9393906b06..8c183986b2 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -101,8 +101,12 @@ Rectangle { onClicked: { if (checked) { box.model = InputConfiguration.activeInputPlugins(); + loader.source = ""; + loader.source = InputConfiguration.configurationLayout(box.currentText); } else { box.model = InputConfiguration.inputPlugins(); + loader.source = ""; + loader.source = InputConfiguration.configurationLayout(box.currentText); } } } diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 051bb3281c..fcafb51c35 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -27,7 +27,7 @@ QStringList InputConfiguration::inputPlugins() { QStringList InputConfiguration::activeInputPlugins() { QStringList activePlugins; for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { - if (plugin->isActive()) { + if (plugin->configurable()) { activePlugins << QString(plugin->getName()); } } diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index b8a6206d60..a4ec35c400 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -41,6 +41,7 @@ public: const QString getName() const override { return NAME; } bool isHandController() const override { return true; } + bool configurable() override { return true; } QString configurationLayout() override; void configurationSettings(const QJsonObject configurationSettings) override; From 7b10b8a6c3dd4a5b6ea58cfb232e7bbc257562a6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 6 Jun 2017 19:04:12 -0700 Subject: [PATCH 008/157] Fix SharedNodePointer leak --- libraries/networking/src/LimitedNodeList.cpp | 18 +++++++++++------- libraries/networking/src/Node.h | 2 +- .../networking/src/ReceivedPacketProcessor.h | 4 +++- libraries/shared/src/GenericThread.cpp | 2 ++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index cba1e664ab..7981c7d598 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -586,7 +586,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t return matchingNode; } else { // we didn't have this node, so add them - Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, connectionSecret, this); + Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, connectionSecret); if (nodeType == NodeType::AudioMixer) { LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer); @@ -619,24 +619,28 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t } // insert the new node and release our read lock - _nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer)); + _nodeHash.emplace(newNode->getUUID(), newNodePointer); readLocker.unlock(); qCDebug(networking) << "Added" << *newNode; + auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambdas to hold a strong ref + emit nodeAdded(newNodePointer); if (newNodePointer->getActiveSocket()) { emit nodeActivated(newNodePointer); } else { - connect(newNodePointer.data(), &NetworkPeer::socketActivated, this, [=] { - emit nodeActivated(newNodePointer); - disconnect(newNodePointer.data(), &NetworkPeer::socketActivated, this, 0); + connect(newNodePointer.data(), &NetworkPeer::socketActivated, this, [this, weakPtr] { + auto sharedPtr = weakPtr.lock(); + if (sharedPtr) { + emit nodeActivated(sharedPtr); + disconnect(sharedPtr.data(), &NetworkPeer::socketActivated, this, 0); + } }); } // Signal when a socket changes, so we can start the hole punch over. - auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambda to hold a strong ref - connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [=] { + connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [this, weakPtr] { emit nodeSocketUpdated(weakPtr); }); diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index d1bbffd817..55a2bfffed 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -40,7 +40,7 @@ public: Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions, const QUuid& connectionSecret = QUuid(), - QObject* parent = 0); + QObject* parent = nullptr); bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; } bool operator!=(const Node& otherNode) const { return !(*this == otherNode); } diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index dd790a9b3d..4e4a3d1d11 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -20,6 +20,8 @@ class ReceivedPacketProcessor : public GenericThread { Q_OBJECT public: + static const unsigned long MAX_WAIT_TIME { 100 }; + ReceivedPacketProcessor(); /// Add packet from network receive thread to the processing queue. @@ -64,7 +66,7 @@ protected: virtual bool process() override; /// Determines the timeout of the wait when there are no packets to process. Default value means no timeout - virtual unsigned long getMaxWait() const { return ULONG_MAX; } + virtual unsigned long getMaxWait() const { return MAX_WAIT_TIME; } /// Override to do work before the packets processing loop. Default does nothing. virtual void preProcess() { } diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index 00a80a2864..2e126f12c9 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -10,6 +10,7 @@ // #include +#include #include "GenericThread.h" @@ -73,6 +74,7 @@ void GenericThread::threadRoutine() { } while (!_stopThread) { + QCoreApplication::processEvents(); // override this function to do whatever your class actually does, return false to exit thread early if (!process()) { From 11409aae9b33cd7d632a547d15150917da74a2ed Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 8 Jun 2017 00:34:52 +0100 Subject: [PATCH 009/157] connect the ui with the input plugins --- .../qml/hifi/tablet/InputConfiguration.qml | 2 +- .../qml/hifi/tablet/OpenVrConfiguration.qml | 133 ++++++++++++++++++ .../src/plugins/InputConfiguration.cpp | 17 ++- .../plugins/src/plugins/InputConfiguration.h | 4 +- libraries/plugins/src/plugins/InputPlugin.h | 5 +- plugins/openvr/src/ViveControllerManager.cpp | 51 ++++++- plugins/openvr/src/ViveControllerManager.h | 21 ++- 7 files changed, 223 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index 8c183986b2..b26134c7fd 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -162,7 +162,7 @@ Rectangle { onLoaded: { - if (loader.item.hasOwnProeprty("pluginName")) { + if (loader.item.hasOwnProperty("pluginName")) { loader.item.pluginName = box.currentText } } diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 434ee12f28..26ca0c644f 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -24,6 +24,15 @@ Rectangle { property int leftMargin: 75 property string pluginName: "" + readonly property bool feetChecked: feetBox.checked + readonly property bool hipsChecked: hipBox.checked + readonly property bool chestChecked: chestBox.checked + readonly property bool shouldersChecked: shoulderBox.checked + readonly property bool hmdHead: headBox.checked + readonly property bool headPuck: headPuckBox.checked + readonly property bool handController: handBox.checked + readonly property bool handPuck: handPuckBox.checked + HifiConstants { id: hifi } color: hifi.colors.baseGray @@ -53,6 +62,15 @@ Rectangle { width: 15 height: 15 boxRadius: 7 + + onClicked: { + if (checked) { + headPuckBox.checked = false; + } else { + checked = true; + } + composeConfigurationSettings(); + } } RalewayBold { @@ -66,6 +84,15 @@ Rectangle { width: 15 height: 15 boxRadius: 7 + + onClicked: { + if (checked) { + headBox.checked = false; + } else { + checked = true; + } + composeConfigurationSettings(); + } } RalewayBold { @@ -102,6 +129,15 @@ Rectangle { width: 15 height: 15 boxRadius: 7 + + onClicked: { + if (checked) { + handPuckBox.checked = false; + } else { + checked = true; + } + composeConfigurationSettings(); + } } RalewayBold { @@ -115,6 +151,15 @@ Rectangle { width: 12 height: 15 boxRadius: 7 + + onClicked: { + if (checked) { + handBox.checked = false; + } else { + checked = true; + } + composeConfigurationSettings(); + } } RalewayBold { @@ -151,6 +196,13 @@ Rectangle { width: 15 height: 15 boxRadius: 7 + + onClicked: { + if (hipsChecked) { + checked = true; + } + composeConfigurationSettings(); + } } RalewayBold { @@ -173,6 +225,17 @@ Rectangle { width: 15 height: 15 boxRadius: 7 + + onClicked: { + if (checked) { + feetBox.checked = true; + } + + if (chestChecked) { + checked = true; + } + composeConfigurationSettings(); + } } RalewayBold { @@ -202,6 +265,14 @@ Rectangle { width: 15 height: 15 boxRadius: 7 + + onClicked: { + if (checked) { + hipBox.checked = true; + feetBox.checked = true; + } + composeConfigurationSettings(); + } } RalewayBold { @@ -231,6 +302,14 @@ Rectangle { width: 15 height: 15 boxRadius: 7 + + onClicked: { + if (checked) { + hipBox.checked = true; + feetBox.checked = true; + } + composeConfigurationSettings(); + } } RalewayBold { @@ -300,6 +379,60 @@ Rectangle { } } + HifiControls.SpinBox { + id: timeToCalibrate + + anchors.top: calibrationButton.bottom + anchors.topMargin: 40 + anchors.left: parent.left + anchors.leftMargin: leftMargin + + label: "Time til calibration ( in seconds )" + colorScheme: hifi.colorSchemes.dark + } + + Component.onCompleted: { + var settings = InputConfiguration.configurationSettings(pluginName); + } + function composeConfigurationSettings() { + var trackerConfiguration = ""; + var overrideHead = false; + var overrideHandController = false; + + if (shouldersChecked && chestChecked) { + trackerConfiguration = "FeetHipsChestAndShoulders"; + } else if (shouldersChecked) { + trackerConfiguration = "FeetHipsAndShoulders"; + } else if (chestChecked) { + trackerConfiguration = "FeetHipsChest"; + } else if (hipsChecked) { + trackerConfiguration = "FeetAndHips"; + } else if (feetChecked) { + trackerConfiguration = "Feet"; + } + + if (headPuck) { + overrideHead = true; + } else if (hmdHead) { + overrideHead = false; + } + + if (handController) { + overrideHandController = false; + } else if (handPuck) { + overrideHandController = true; + } + + + var settingsObject = { + "trackerConfiguration": trackerConfiguration, + "overrideHead": overrideHead, + "overrideHandController": overrideHandController + } + + InputConfiguration.setConfigurationSettings(settingsObject, pluginName); + + } } diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index fcafb51c35..515033bf7b 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -45,14 +45,25 @@ QString InputConfiguration::configurationLayout(QString pluginName) { return sourcePath; } -void InputConfiguration::configurationSettings(QJsonObject configurationSettings, QString pluginName) { - qDebug() << configurationSettings["Test"]; +void InputConfiguration::setConfigurationSettings(QJsonObject configurationSettings, QString pluginName) { + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { + if (plugin->getName() == pluginName) { + plugin->setConfigurationSettings(configurationSettings); + } + } +} + +QJsonObject InputConfiguration::configurationSettings(QString pluginName) { + return QJsonObject(); } void InputConfiguration::calibratePlugin(QString pluginName) { for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->getName() == pluginName) { - //calibrtate plugin + plugin->calibrate(); } } } + +void InputConfiguration::calibrated() { +} diff --git a/libraries/plugins/src/plugins/InputConfiguration.h b/libraries/plugins/src/plugins/InputConfiguration.h index a560c02e5a..2171afca34 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.h +++ b/libraries/plugins/src/plugins/InputConfiguration.h @@ -25,8 +25,10 @@ public: Q_INVOKABLE QStringList inputPlugins(); Q_INVOKABLE QStringList activeInputPlugins(); Q_INVOKABLE QString configurationLayout(QString pluginName); - Q_INVOKABLE void configurationSettings(QJsonObject configurationSettings, QString pluginName); + Q_INVOKABLE void setConfigurationSettings(QJsonObject configurationSettings, QString pluginName); Q_INVOKABLE void calibratePlugin(QString pluginName); + Q_INVOKABLE QJsonObject configurationSettings(QString pluginName); + void calibrated(); }; #endif diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index 1850dcbc18..e73a047efa 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -26,8 +26,9 @@ public: // If an input plugin is only a single device, it will only return it's primary name. virtual QStringList getSubdeviceNames() { return { getName() }; }; virtual bool isHandController() const = 0; - virtual void configurationSettings(const QJsonObject configurationSettings) { } + virtual void setConfigurationSettings(const QJsonObject configurationSettings) { } + virtual QJsonObject configurationSettings() { return QJsonObject(); } virtual QString configurationLayout() { return QString(); } - virtual void calibrate() {} + virtual bool calibrate() { return false; } virtual bool configurable() { return false; } }; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 2337c6161b..87bd8ac1a5 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -120,7 +120,18 @@ bool ViveControllerManager::isSupported() const { return openVrSupported(); } -void ViveControllerManager::configurationSettings(const QJsonObject configurationSettings) { +void ViveControllerManager::setConfigurationSettings(const QJsonObject configurationSettings) { + if (isSupported()) { + _inputDevice->configureCalibrationSettings(configurationSettings); + } +} + +QJsonObject ViveControllerManager::configurationSettings() { + if (isSupported()) { + return _inputDevice->configurationSettings(); + } + + return QJsonObject(); } QString ViveControllerManager::configurationLayout() { @@ -281,6 +292,44 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle _lastSimPoseData = _nextSimPoseData; } +void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJsonObject configurationSettings) { + Locker locker(_lock); + + if (!configurationSettings.empty()) { + auto iter = configurationSettings.begin(); + auto end = configurationSettings.end(); + while (iter != end) { + if (iter.key() == "trackerConfiguration") { + setConfigFromString(iter.value().toString()); + } else if (iter.key() == "overrideHead") { + bool overrideHead = iter.value().toBool(); + if (overrideHead) { + _headConfig = HeadConfig::Puck; + } else { + _headConfig = HeadConfig::HMD; + } + } else if (iter.key() == "overrideHandController") { + bool overrideHands = iter.value().toBool(); + if (overrideHands) { + _handConfig = HandConfig::Pucks; + } else { + _handConfig = HandConfig::HandController; + } + } + iter++; + } + } +} + +QJsonObject ViveControllerManager::InputDevice::configurationSettings() { + Locker locker(_lock); + QJsonObject configurationSettings; + configurationSettings["trackerConfiguration"] = configToString(_config); + configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD) ? true : false; + configurationSettings["handController"] = (_handConfig == HandConfig::HandController) ? true : false; + return configurationSettings; +} + void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) { uint32_t poseIndex = controller::TRACKED_OBJECT_00 + deviceIndex; printDeviceTrackingResultChange(deviceIndex); diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index a4ec35c400..257baf9fb5 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -44,7 +44,8 @@ public: bool configurable() override { return true; } QString configurationLayout() override; - void configurationSettings(const QJsonObject configurationSettings) override; + void setConfigurationSettings(const QJsonObject configurationSettings) override; + QJsonObject configurationSettings() override; bool activate() override; void deactivate() override; @@ -70,6 +71,8 @@ private: void calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration); void calibrate(const controller::InputCalibrationData& inputCalibration); void uncalibrate(); + void configureCalibrationSettings(const QJsonObject configurationSettings); + QJsonObject configurationSettings(); controller::Pose addOffsetToPuckPose(int joint) const; glm::mat4 recalculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration); void updateCalibratedLimbs(); @@ -128,10 +131,23 @@ private: FeetHipsAndChest, FeetHipsAndShoulders, FeetHipsChestAndHead, - FeetHipsAndHead + FeetHipsAndHead, }; + + enum class HeadConfig { + HMD, + Puck + }; + + enum class HandConfig { + HandController, + Pucks + }; + Config _config { Config::Auto }; Config _preferedConfig { Config::Auto }; + HeadConfig _headConfig { HeadConfig::HMD }; + HandConfig _handConfig { HandConfig::HandController }; FilteredStick _filteredLeftStick; FilteredStick _filteredRightStick; @@ -157,6 +173,7 @@ private: bool _timeTilCalibrationSet { false }; bool _calibrate { false }; bool _overrideHead { false }; + bool _overrideHands { false }; mutable std::recursive_mutex _lock; QString configToString(Config config); From c97ea84cbf549d0101653cadaaa268dedea9a138 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 8 Jun 2017 17:44:55 +0100 Subject: [PATCH 010/157] saving work --- .../qml/hifi/tablet/OpenVrConfiguration.qml | 45 +++++++++++++++++++ .../src/plugins/InputConfiguration.cpp | 5 +++ plugins/openvr/src/ViveControllerManager.cpp | 1 + 3 files changed, 51 insertions(+) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 26ca0c644f..3679ffe919 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -393,6 +393,51 @@ Rectangle { Component.onCompleted: { var settings = InputConfiguration.configurationSettings(pluginName); + + var configurationType = settings["trackerConfiguration"]; + displayTrackerConfiguration(configurationType); + + + var HmdHead = settings["HMDHead"]; + var viveController = settings["handController"]; + + console.log(HmdHead); + console.log(viveController); + if (HmdHead) { + headBox.checked = true; + } else { + headPuckBox.checked = true; + } + + if (viveController) { + handBox.checked = true; + } else { + handPuckBox.checked = true; + } + } + + + function displayTrackerConfiguration(type) { + + if (type === "Feet") { + feetBox.checked = true; + } else if (type === "FeetAndHips") { + feetBox.checked = true; + hipBox.checked = true; + } else if (type === "FeetHipsChest") { + feetBox.checked = true; + hipBox.checked = true; + chestBox.checked = true; + } else if (type === "FeetHipsAndShoulders") { + feetBox.checked = true; + hipBox.checked = true; + shoulderBox.checked = true; + } else if (type === "FeetHipsChestAndShoulders") { + feetBox.checked = true; + hipBox.checked = true; + chestBox.checked = true; + shoulderBox.checked = true; + } } diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 515033bf7b..78a20653f4 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -54,6 +54,11 @@ void InputConfiguration::setConfigurationSettings(QJsonObject configurationSetti } QJsonObject InputConfiguration::configurationSettings(QString pluginName) { + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { + if (plugin->getName() == pluginName) { + return plugin->configurationSettings(); + } + } return QJsonObject(); } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 87bd8ac1a5..d1087c5cc0 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -123,6 +123,7 @@ bool ViveControllerManager::isSupported() const { void ViveControllerManager::setConfigurationSettings(const QJsonObject configurationSettings) { if (isSupported()) { _inputDevice->configureCalibrationSettings(configurationSettings); + qDebug() << "sending back information"; } } From 73e628461e4189f8ffb4b5a607de9cf70feb1a05 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 9 Jun 2017 00:44:05 +0100 Subject: [PATCH 011/157] confiration update status --- .../qml/hifi/tablet/InputConfiguration.qml | 43 ++++++++++--------- .../qml/hifi/tablet/OpenVrConfiguration.qml | 23 +++++++--- .../src/plugins/InputConfiguration.cpp | 3 +- .../plugins/src/plugins/InputConfiguration.h | 5 ++- plugins/openvr/src/ViveControllerManager.cpp | 13 ++++-- plugins/openvr/src/ViveControllerManager.h | 2 + 6 files changed, 57 insertions(+), 32 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index b26134c7fd..d556247b9d 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -72,7 +72,6 @@ Rectangle { anchors.left: sourceGlyph.right anchors.leftMargin: 10 anchors.topMargin: 30 - anchors.verticalCenter: sourceGlyph.horizontalCenter } Row { @@ -96,21 +95,6 @@ Rectangle { loader.source = InputConfiguration.configurationLayout(box.currentText); } } - - HifiControls.CheckBox { - onClicked: { - if (checked) { - box.model = InputConfiguration.activeInputPlugins(); - loader.source = ""; - loader.source = InputConfiguration.configurationLayout(box.currentText); - } else { - box.model = InputConfiguration.inputPlugins(); - loader.source = ""; - loader.source = InputConfiguration.configurationLayout(box.currentText); - } - } - } - } @@ -146,7 +130,6 @@ Rectangle { anchors.left: sliderGlyph.right anchors.leftMargin: 10 anchors.topMargin: 30 - anchors.verticalCenter: sliderGlyph.horizontalCenter } Loader { @@ -160,15 +143,35 @@ Rectangle { anchors.topMargin: 10 anchors.bottom: inputConfiguration.bottom - + source: InputConfiguration.configurationLayout(box.currentText); onLoaded: { if (loader.item.hasOwnProperty("pluginName")) { loader.item.pluginName = box.currentText + + if (loader.item.hasOwnProperty("displayInformation")) { + loader.item.displayInformation(); + } } } } - + function inputPlugins() { - return InputConfiguration.inputPlugins(); + return InputConfiguration.activeInputPlugins(); + } + + function initialize() { + loader.source = ""; + loader.source = InputConfiguration.configurationLayout(box.currentText); + } + + Timer { + id: timer + repeat: false + interval: 300 + onTriggered: initialize() + } + + Component.onCompleted: { + timer.start(); } } diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 3679ffe919..958e115bb0 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -23,6 +23,7 @@ Rectangle { property int leftMargin: 75 property string pluginName: "" + property var displayInformation: openVrConfiguration.displayConfiguration() readonly property bool feetChecked: feetBox.checked readonly property bool hipsChecked: hipBox.checked @@ -353,7 +354,6 @@ Rectangle { size: 36 color: hifi.colors.white - anchors.horizontalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 30 @@ -379,6 +379,10 @@ Rectangle { } } + Component.onCompleted: { + InputConfiguration.calibrationStatus.connect(calibrationStatus); + } + HifiControls.SpinBox { id: timeToCalibrate @@ -391,34 +395,39 @@ Rectangle { colorScheme: hifi.colorSchemes.dark } - Component.onCompleted: { - var settings = InputConfiguration.configurationSettings(pluginName); + function calibrationStatus(status) { + console.log("getting calibration status"); + } + function displayConfiguration() { + var settings = InputConfiguration.configurationSettings(pluginName); var configurationType = settings["trackerConfiguration"]; displayTrackerConfiguration(configurationType); var HmdHead = settings["HMDHead"]; var viveController = settings["handController"]; - - console.log(HmdHead); - console.log(viveController); + if (HmdHead) { headBox.checked = true; + headPuckBox.checked = false; } else { headPuckBox.checked = true; + headBox.checked = false; } if (viveController) { handBox.checked = true; + handPuckBox.checked = false; } else { handPuckBox.checked = true; + handBox.checked = false; } } function displayTrackerConfiguration(type) { - + console.log(type); if (type === "Feet") { feetBox.checked = true; } else if (type === "FeetAndHips") { diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 78a20653f4..3414350bf1 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -70,5 +70,6 @@ void InputConfiguration::calibratePlugin(QString pluginName) { } } -void InputConfiguration::calibrated() { +void InputConfiguration::calibrated(const QJsonObject& status) { + emit calibrationStatus(status); } diff --git a/libraries/plugins/src/plugins/InputConfiguration.h b/libraries/plugins/src/plugins/InputConfiguration.h index 2171afca34..fddf858c64 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.h +++ b/libraries/plugins/src/plugins/InputConfiguration.h @@ -28,7 +28,10 @@ public: Q_INVOKABLE void setConfigurationSettings(QJsonObject configurationSettings, QString pluginName); Q_INVOKABLE void calibratePlugin(QString pluginName); Q_INVOKABLE QJsonObject configurationSettings(QString pluginName); - void calibrated(); + void calibrated(const QJsonObject& status); + +signals: + void calibrationStatus(const QJsonObject& status); }; #endif diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index d1087c5cc0..e7a8e87ef3 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -30,7 +30,7 @@ #include #include - +#include #include @@ -123,7 +123,6 @@ bool ViveControllerManager::isSupported() const { void ViveControllerManager::setConfigurationSettings(const QJsonObject configurationSettings) { if (isSupported()) { _inputDevice->configureCalibrationSettings(configurationSettings); - qDebug() << "sending back information"; } } @@ -325,12 +324,18 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso QJsonObject ViveControllerManager::InputDevice::configurationSettings() { Locker locker(_lock); QJsonObject configurationSettings; - configurationSettings["trackerConfiguration"] = configToString(_config); + configurationSettings["trackerConfiguration"] = configToString(_preferedConfig); configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD) ? true : false; configurationSettings["handController"] = (_handConfig == HandConfig::HandController) ? true : false; return configurationSettings; } +void ViveControllerManager::InputDevice::emitCalibrationStatus() { + auto inputConfiguration = DependencyManager::get(); + QJsonObject status = QJsonObject(); + inputConfiguration->calibrated(status); +} + void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) { uint32_t poseIndex = controller::TRACKED_OBJECT_00 + deviceIndex; printDeviceTrackingResultChange(deviceIndex); @@ -463,6 +468,7 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr return; } _calibrated = true; + emitCalibrationStatus(); qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful"; } @@ -860,6 +866,7 @@ QString ViveControllerManager::InputDevice::configToString(Config config) { } void ViveControllerManager::InputDevice::setConfigFromString(const QString& value) { + qDebug() << "------------> setConfigFromString" << value; if (value == "Auto") { _preferedConfig = Config::Auto; } else if (value == "Feet") { diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 257baf9fb5..5547c29213 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -100,6 +100,8 @@ private: int firstShoulderIndex, int secondShoulderIndex); void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); + void emitCalibrationStatus(); + class FilteredStick { public: From ef1be931dc4f5983ed6bd22f55c520473261c4c7 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Sat, 10 Jun 2017 00:50:32 +0100 Subject: [PATCH 012/157] preparing to clean code --- .../qml/hifi/tablet/InputConfiguration.qml | 2 +- .../qml/hifi/tablet/OpenVrConfiguration.qml | 167 +++++++++++++++++- .../src/plugins/InputConfiguration.cpp | 1 + libraries/plugins/src/plugins/InputPlugin.h | 2 +- plugins/openvr/src/ViveControllerManager.cpp | 45 ++++- plugins/openvr/src/ViveControllerManager.h | 7 +- 6 files changed, 210 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index d556247b9d..e97c5a9841 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -156,7 +156,7 @@ Rectangle { } function inputPlugins() { - return InputConfiguration.activeInputPlugins(); + return InputConfiguration.inputPlugins(); } function initialize() { diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 958e115bb0..58abc4252e 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -22,6 +22,7 @@ Rectangle { anchors.fill: parent property int leftMargin: 75 + property int countDown: 0 property string pluginName: "" property var displayInformation: openVrConfiguration.displayConfiguration() @@ -36,6 +37,16 @@ Rectangle { HifiConstants { id: hifi } + MouseArea { + id: mouseArea + + anchors.fill: parent + propagateComposedEvents: true + onPressed: { + parent.forceActiveFocus() + mouse.accepted = false; + } + } color: hifi.colors.baseGray RalewayBold { @@ -374,13 +385,43 @@ Rectangle { anchors.fill: parent onClicked: { - InputCalibration.calibratePlugin(pluginName); + console.log("calibration button pressed..."); + openVrConfiguration.countDown = timeToCalibrate.value; + numberAnimation.start(); + calibrationTimer.start(); + info.visible = true; + info.showCountDown = true; } } } + Timer { + id: calibrationTimer + repeat: false + interval: 20 + onTriggered: { + InputConfiguration.calibratePlugin(pluginName) + info.visible = false; + info.showCountDown = false; + console.log("calibration started"); + } + } + + Timer { + id: displayTimer + repeat: false + interval: 3000 + onTriggered: { + info.showCountDown = false; + info.calibrationFailed = false + info.calibrationSucceed = false; + info.showCalibrationStatus = false; + info.visible = false; + } + } + Component.onCompleted: { - InputConfiguration.calibrationStatus.connect(calibrationStatus); + InputConfiguration.calibrationStatus.connect(calibrationStatusInfo); } HifiControls.SpinBox { @@ -393,10 +434,63 @@ Rectangle { label: "Time til calibration ( in seconds )" colorScheme: hifi.colorSchemes.dark + + onEditingFinished: { + calibrationTimer.interval = value * 1000; + openVrConfiguration.countDown = value; + numberAnimation.duration = calibrationTimer.interval; + } + } + + NumberAnimation { + id: numberAnimation + target: openVrConfiguration + property: "countDown" + to: 0 } - function calibrationStatus(status) { - console.log("getting calibration status"); + function calibrationStatusInfo(status) { + if (status["calibrated"]) { + info.visible = true; + info.showCalibrationStatus = true; + info.calibrationSucceed = true; + } else if (!status["calibrated"]) { + var uncalibrated = status["success"]; + if (uncalibrated) { + } else { + info.visible = true; + info.showCalibrationStatus = true; + info.calibrationFailed = true; + } + } + displayTimer.start(); + } + + + function trackersForConfiguration() { + var pucksNeeded = 0; + + if (headPuckBox.checked) { + pucksNeeded++; + } + + if (feetBox.checked) { + pucksNeeded++; + } + + if (hipBox.checked) { + pucksNeeded++; + } + + if (chestBox.checked) { + pucksNeeded++; + } + + if (shoulderBox.checked) { + pucksNeeded++; + } + + return pucksNeeded; } function displayConfiguration() { @@ -426,8 +520,70 @@ Rectangle { } + Rectangle { + id: info + property bool showCountDown: false + property bool showCalibrationStatus: false + property bool calibrationFailed: false + property bool calibrationSucceed: false + + visible: false + color: hifi.colors.baseGray + anchors.top: openVrConfiguration.top + anchors.bottom: bottomSeperator.bottom + anchors.left: openVrConfiguration.left + anchors.right: openVrConfiguration.right + + Item { + id: countDownContainer + visible: info.showCountDown + anchors.centerIn: parent + RalewayBold { + id: countDownText + + text: openVrConfiguration.countDown + size: 92 + + color: hifi.colors.blueHighlight + + anchors.centerIn: parent + } + } + + Item { + id: calibrationStatus + visible: info.showCalibrationStatus + anchors.centerIn: parent + Item { + id: successInfo + visible: info.calibrationSucceed + anchors.centerIn: parent + RalewayBold { + id: successText + text: "Calibration Successful" + size: 42 + color: hifi.colors.greenHighlight + anchors.centerIn: parent + } + } + + Item { + id: failedInfo + visible: info.calibrationFailed + anchors.fill: parent + RalewayBold { + id: failedText + text: "Calibration Failed" + size: 42 + color: hifi.colors.redAccent + anchors.centerIn: parent + } + } + } + } + + function displayTrackerConfiguration(type) { - console.log(type); if (type === "Feet") { feetBox.checked = true; } else if (type === "FeetAndHips") { @@ -449,7 +605,6 @@ Rectangle { } } - function composeConfigurationSettings() { var trackerConfiguration = ""; var overrideHead = false; diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 3414350bf1..3482810448 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -71,5 +71,6 @@ void InputConfiguration::calibratePlugin(QString pluginName) { } void InputConfiguration::calibrated(const QJsonObject& status) { + qDebug() << "-----------> emitting configuration status <------------"; emit calibrationStatus(status); } diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index e73a047efa..3c5bd433f2 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -29,6 +29,6 @@ public: virtual void setConfigurationSettings(const QJsonObject configurationSettings) { } virtual QJsonObject configurationSettings() { return QJsonObject(); } virtual QString configurationLayout() { return QString(); } - virtual bool calibrate() { return false; } + virtual void calibrate() {} virtual bool configurable() { return false; } }; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index e7a8e87ef3..a7e7b4ae32 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -272,6 +272,14 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle } _trackedControllers = numTrackedControllers; + calibrateFromHandController(inputCalibrationData); + calibrateFromUI(inputCalibrationData); + + updateCalibratedLimbs(); + _lastSimPoseData = _nextSimPoseData; +} + +void ViveControllerManager::InputDevice::calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData) { if (checkForCalibrationEvent()) { quint64 currentTime = usecTimestampNow(); if (!_timeTilCalibrationSet) { @@ -287,9 +295,14 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle _triggersPressedHandled = false; _timeTilCalibrationSet = false; } +} - updateCalibratedLimbs(); - _lastSimPoseData = _nextSimPoseData; +void ViveControllerManager::InputDevice::calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData) { + if (_calibrate) { + calibrateOrUncalibrate(inputCalibrationData); + _calibrate = false; + qDebug() << "------------> calibrateFromUI <-------------"; + } } void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJsonObject configurationSettings) { @@ -321,6 +334,12 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso } } +void ViveControllerManager::InputDevice::calibrateNextFrame() { + Locker locker(_lock); + _calibrate = true; + qDebug() << "---------> calibrateNextFrame <----------"; +} + QJsonObject ViveControllerManager::InputDevice::configurationSettings() { Locker locker(_lock); QJsonObject configurationSettings; @@ -330,9 +349,23 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() { return configurationSettings; } -void ViveControllerManager::InputDevice::emitCalibrationStatus() { +void ViveControllerManager::InputDevice::emitCalibrationStatus(const bool success) { auto inputConfiguration = DependencyManager::get(); QJsonObject status = QJsonObject(); + + if (_calibrated && success) { + status["calibrated"] = _calibrated; + status["configuration"] = configToString(_preferedConfig); + } else if (!_calibrated && !success) { + status["calibrated"] = _calibrated; + status["success"] = success; + } else if (!_calibrated && success) { + status["calibrated"] = _calibrated; + status["success"] = success; + status["configuration"] = configToString(_preferedConfig); + status["puckCount"] = (int)_validTrackedObjects.size(); + } + inputConfiguration->calibrated(status); } @@ -381,6 +414,7 @@ void ViveControllerManager::InputDevice::calibrateOrUncalibrate(const controller calibrate(inputCalibration); } else { uncalibrate(); + emitCalibrationStatus(true); } } @@ -410,6 +444,7 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr if (_config != Config::Auto && puckCount < MIN_PUCK_COUNT) { qDebug() << "Puck Calibration: Failed: Could not meet the minimal # of pucks"; uncalibrate(); + emitCalibrationStatus(false); return; } else if (_config == Config::Auto){ if (puckCount == MIN_PUCK_COUNT) { @@ -424,6 +459,7 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr } else { qDebug() << "Puck Calibration: Auto Config Failed: Could not meet the minimal # of pucks"; uncalibrate(); + emitCalibrationStatus(false); return; } } @@ -465,10 +501,11 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr } else { qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks"; uncalibrate(); + emitCalibrationStatus(false); return; } _calibrated = true; - emitCalibrationStatus(); + emitCalibrationStatus(true); qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful"; } diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 5547c29213..1ec7d129c3 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -46,6 +46,7 @@ public: QString configurationLayout() override; void setConfigurationSettings(const QJsonObject configurationSettings) override; QJsonObject configurationSettings() override; + void calibrate() override { _inputDevice->calibrateNextFrame(); } bool activate() override; void deactivate() override; @@ -99,8 +100,10 @@ private: void calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, int firstShoulderIndex, int secondShoulderIndex); void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); - - void emitCalibrationStatus(); + void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData); + void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData); + void emitCalibrationStatus(const bool success); + void calibrateNextFrame(); class FilteredStick { From f6ef1443c8d7b3d96c0f7085c17e248b813b97fc Mon Sep 17 00:00:00 2001 From: druiz17 Date: Sun, 11 Jun 2017 12:08:45 -0700 Subject: [PATCH 013/157] some more clean up --- .../qml/hifi/tablet/InputConfiguration.qml | 36 ++++++++++++++++--- .../qml/hifi/tablet/OpenVrConfiguration.qml | 2 -- .../src/plugins/InputConfiguration.cpp | 1 - plugins/openvr/src/ViveControllerManager.cpp | 3 -- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index e97c5a9841..b89df4fa3e 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -89,12 +89,24 @@ Rectangle { editable: true colorScheme: hifi.colorSchemes.dark model: inputPlugins() + label: "" onCurrentIndexChanged: { - loader.source = "" - loader.source = InputConfiguration.configurationLayout(box.currentText); + changeSource(); } } + + HifiControls.CheckBox { + id: checkBox + colorScheme: hifi.colorSchemes.dark + text: "show all input plugins" + + onClicked: { + console.log("clicked"); + inputPlugins(); + changeSource(); + } + } } @@ -156,12 +168,26 @@ Rectangle { } function inputPlugins() { - return InputConfiguration.inputPlugins(); + if (checkBox.checked) { + return InputConfiguration.inputPlugins(); + } else { + return InputConfiguration.activeInputPlugins(); + } } function initialize() { - loader.source = ""; - loader.source = InputConfiguration.configurationLayout(box.currentText); + chanageSource(); + } + + function changeSource() { + loader.source = ""; + var source = InputConfiguration.configurationLayout(box.currentText); + loader.source = "OpenVrConfiguration.qml"; + if (source === "") { + box.label = "(not configurable)"; + } else { + box.label = ""; + } } Timer { diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 58abc4252e..e00ee17228 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -385,7 +385,6 @@ Rectangle { anchors.fill: parent onClicked: { - console.log("calibration button pressed..."); openVrConfiguration.countDown = timeToCalibrate.value; numberAnimation.start(); calibrationTimer.start(); @@ -403,7 +402,6 @@ Rectangle { InputConfiguration.calibratePlugin(pluginName) info.visible = false; info.showCountDown = false; - console.log("calibration started"); } } diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 3482810448..3414350bf1 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -71,6 +71,5 @@ void InputConfiguration::calibratePlugin(QString pluginName) { } void InputConfiguration::calibrated(const QJsonObject& status) { - qDebug() << "-----------> emitting configuration status <------------"; emit calibrationStatus(status); } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index a7e7b4ae32..cb789c724d 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -301,7 +301,6 @@ void ViveControllerManager::InputDevice::calibrateFromUI(const controller::Input if (_calibrate) { calibrateOrUncalibrate(inputCalibrationData); _calibrate = false; - qDebug() << "------------> calibrateFromUI <-------------"; } } @@ -337,7 +336,6 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso void ViveControllerManager::InputDevice::calibrateNextFrame() { Locker locker(_lock); _calibrate = true; - qDebug() << "---------> calibrateNextFrame <----------"; } QJsonObject ViveControllerManager::InputDevice::configurationSettings() { @@ -903,7 +901,6 @@ QString ViveControllerManager::InputDevice::configToString(Config config) { } void ViveControllerManager::InputDevice::setConfigFromString(const QString& value) { - qDebug() << "------------> setConfigFromString" << value; if (value == "Auto") { _preferedConfig = Config::Auto; } else if (value == "Feet") { From 45bb3237231a92962faa90cd40cb0a4cdd6a8e9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 00:19:04 -0700 Subject: [PATCH 014/157] experimental support for mirrored audio packets to other mixers --- assignment-client/src/audio/AudioMixer.cpp | 19 +++++++++++ assignment-client/src/audio/AudioMixer.h | 1 + .../src/audio/AudioMixerClientData.cpp | 32 +++++++++++++++++++ .../src/audio/AudioMixerClientData.h | 2 ++ libraries/networking/src/LimitedNodeList.h | 10 ++++++ libraries/networking/src/NLPacket.h | 1 + libraries/networking/src/Node.h | 5 +++ .../networking/src/udt/PacketHeaders.cpp | 4 ++- libraries/networking/src/udt/PacketHeaders.h | 7 +++- 9 files changed, 79 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index bb03a6ec93..87f51ea73c 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -92,6 +92,14 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket"); packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); + packetReceiver.registerListenerForTypes({ + PacketType::MirroredMicrophoneAudioNoEcho, + PacketType::MirroredMicrophoneAudioWithEcho, + PacketType::MirroredInjectAudio, + PacketType::MirroredSilentAudioFrame }, + this, "queueMirroredAudioPacket" + ); + connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); } @@ -103,6 +111,17 @@ void AudioMixer::queueAudioPacket(QSharedPointer message, Share getOrCreateClientData(node.data())->queuePacket(message, node); } +void AudioMixer::queueMirroredAudioPacket(QSharedPointer message) { + // make sure we have a mirrored node for the original sender of the packet + auto nodeList = DependencyManager::get(); + + auto node = nodeList->addOrUpdateNode(message->getSourceID(), NodeType::Agent, + message->getSenderSockAddr(), message->getSenderSockAddr()); + node->setIsMirror(true); + + getOrCreateClientData(node.data())->queuePacket(message, node); +} + void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer message, SharedNodePointer sendingNode) { auto nodeList = DependencyManager::get(); diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 18e754016e..b7eebe6aa1 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -63,6 +63,7 @@ private slots: void handleKillAvatarPacket(QSharedPointer packet, SharedNodePointer sendingNode); void queueAudioPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void queueMirroredAudioPacket(QSharedPointer packet); void removeHRTFsForFinishedInjector(const QUuid& streamID); void start(); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index d5e06504a6..135047f3a5 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -71,6 +71,9 @@ void AudioMixerClientData::processPackets() { case PacketType::SilentAudioFrame: { QMutexLocker lock(&getMutex()); parseData(*packet); + + potentiallyMirrorPacket(*packet); + break; } case PacketType::NegotiateAudioFormat: @@ -97,6 +100,35 @@ void AudioMixerClientData::processPackets() { assert(_packetQueue.empty()); } +void AudioMixerClientData::potentiallyMirrorPacket(ReceivedMessage& message) { + auto nodeList = DependencyManager::get(); + if (!nodeList->getMirrorSocket().isNull()) { + PacketType mirroredType; + + if (message.getType() == PacketType::MicrophoneAudioNoEcho) { + mirroredType = PacketType::MirroredMicrophoneAudioNoEcho; + } else if (message.getType() == PacketType::MicrophoneAudioWithEcho) { + mirroredType = PacketType::MirroredMicrophoneAudioNoEcho; + } else if (message.getType() == PacketType::InjectAudio) { + mirroredType = PacketType::MirroredInjectAudio; + } else if (message.getType() == PacketType::SilentAudioFrame) { + mirroredType = PacketType::MirroredSilentAudioFrame; + } else { + return; + } + + // construct an NLPacket to send to the mirror that has the contents of the received packet + std::unique_ptr messageData { new char[message.getSize()] }; + memcpy(messageData.get(), message.getMessage().data(), message.getSize()); + auto packet = NLPacket::fromReceivedPacket(std::move(messageData), message.getSize(), + message.getSenderSockAddr()); + + packet->setType(mirroredType); + + nodeList->sendPacket(std::move(packet), nodeList->getMirrorSocket()); + } +} + void AudioMixerClientData::negotiateAudioFormat(ReceivedMessage& message, const SharedNodePointer& node) { quint8 numberOfCodecs; message.readPrimitive(&numberOfCodecs); diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 8d76cda2f1..4207362ed3 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -124,6 +124,8 @@ private: QReadWriteLock _streamsLock; AudioStreamMap _audioStreams; // microphone stream from avatar is stored under key of null UUID + void potentiallyMirrorPacket(ReceivedMessage& packet); + using IgnoreZone = AABox; class IgnoreZoneMemo { public: diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 554386f786..16d7f20f99 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -278,6 +278,12 @@ public: void sendFakedHandshakeRequestToNode(SharedNodePointer node); #endif + void setMirrorSocket(const HifiSockAddr& mirrorSocket) { _mirrorSocket = mirrorSocket; } + const HifiSockAddr& getMirrorSocket() { return _mirrorSocket; } + + void setMasterSocket(const HifiSockAddr& masterSocket) { _masterSocket = masterSocket; } + const HifiSockAddr& getMasterSocket() { return _masterSocket; } + public slots: void reset(); void eraseAllNodes(); @@ -386,6 +392,10 @@ protected: } } + + HifiSockAddr _mirrorSocket; + HifiSockAddr _masterSocket; + private slots: void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp); void possiblyTimeoutSTUNAddressLookup(); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 33de262dfb..f9056bbfaa 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -42,6 +42,7 @@ public: static std::unique_ptr fromReceivedPacket(std::unique_ptr data, qint64 size, const HifiSockAddr& senderSockAddr); + static std::unique_ptr fromBase(std::unique_ptr packet); // Provided for convenience, try to limit use diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 1092fcc7fa..dd05961678 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -80,6 +80,9 @@ public: bool isIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled; } + bool isMirror() const { return _isMirror; } + void setIsMirror(bool isMirror) { _isMirror = isMirror; } + private: // privatize copy and assignment operator to disallow Node copying Node(const Node &otherNode); @@ -98,6 +101,8 @@ private: mutable QReadWriteLock _ignoredNodeIDSetLock; std::atomic_bool _ignoreRadiusEnabled; + + bool _isMirror { false }; }; Q_DECLARE_METATYPE(Node*) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 9d970fa318..e29bfd0d78 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -39,7 +39,9 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat << PacketType::ICEServerHeartbeatACK << PacketType::ICEPing << PacketType::ICEPingReply << PacketType::ICEServerHeartbeatDenied << PacketType::AssignmentClientStatus << PacketType::StopNode - << PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement; + << PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement + << PacketType::MirroredMicrophoneAudioNoEcho << PacketType::MirroredMicrophoneAudioWithEcho + << PacketType::MirroredInjectAudio << PacketType::MirroredSilentAudioFrame; PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 2cc3a2c42e..f2a13dc449 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -115,7 +115,12 @@ public: AdjustAvatarSorting, OctreeFileReplacement, CollisionEventChanges, - LAST_PACKET_TYPE = CollisionEventChanges + MirroredMicrophoneAudioNoEcho, + MirroredMicrophoneAudioWithEcho, + MirroredInjectAudio, + MirroredSilentAudioFrame, + LAST_PACKET_TYPE = MirroredSilentAudioFrame, + }; }; From f726c5bc3a466971b2f2fba20488bd53e500dd48 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 01:16:51 -0700 Subject: [PATCH 015/157] handle mirrored packets in AudioMixerClientData --- assignment-client/src/audio/AudioMixer.cpp | 8 ++++++-- .../src/audio/AudioMixerClientData.cpp | 17 +++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 87f51ea73c..9b095d3aa7 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -55,7 +55,8 @@ QVector AudioMixer::_zoneSettings; QVector AudioMixer::_zoneReverbSettings; AudioMixer::AudioMixer(ReceivedMessage& message) : - ThreadedAssignment(message) { + ThreadedAssignment(message) +{ // Always clear settings first // This prevents previous assignment settings from sticking around @@ -101,6 +102,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : ); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); + } void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { @@ -115,7 +117,9 @@ void AudioMixer::queueMirroredAudioPacket(QSharedPointer messag // make sure we have a mirrored node for the original sender of the packet auto nodeList = DependencyManager::get(); - auto node = nodeList->addOrUpdateNode(message->getSourceID(), NodeType::Agent, + QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + + auto node = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, message->getSenderSockAddr(), message->getSenderSockAddr()); node->setIsMirror(true); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 135047f3a5..7c747a3417 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -118,12 +118,9 @@ void AudioMixerClientData::potentiallyMirrorPacket(ReceivedMessage& message) { } // construct an NLPacket to send to the mirror that has the contents of the received packet - std::unique_ptr messageData { new char[message.getSize()] }; - memcpy(messageData.get(), message.getMessage().data(), message.getSize()); - auto packet = NLPacket::fromReceivedPacket(std::move(messageData), message.getSize(), - message.getSenderSockAddr()); - - packet->setType(mirroredType); + auto packet = NLPacket::create(mirroredType, message.getSize() + NUM_BYTES_RFC4122_UUID); + packet->write(message.getSourceID().toRfc4122()); + packet->write(message.getMessage()); nodeList->sendPacket(std::move(packet), nodeList->getMirrorSocket()); } @@ -220,8 +217,11 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { bool isMicStream = false; if (packetType == PacketType::MicrophoneAudioWithEcho + || packetType == PacketType::MirroredMicrophoneAudioWithEcho || packetType == PacketType::MicrophoneAudioNoEcho - || packetType == PacketType::SilentAudioFrame) { + || packetType == PacketType::MirroredMicrophoneAudioNoEcho + || packetType == PacketType::SilentAudioFrame + || packetType == PacketType::MirroredSilentAudioFrame) { QWriteLocker writeLocker { &_streamsLock }; @@ -256,7 +256,8 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { writeLocker.unlock(); isMicStream = true; - } else if (packetType == PacketType::InjectAudio) { + } else if (packetType == PacketType::InjectAudio + || packetType == PacketType::MirroredInjectAudio) { // this is injected audio // grab the stream identifier for this injected audio message.seek(sizeof(quint16)); From 281793c4c0e8c08e4916dbad4d53a3875be1b629 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 01:46:12 -0700 Subject: [PATCH 016/157] update last heard timestamp for mirrored nodes --- assignment-client/src/audio/AudioMixer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9b095d3aa7..55335c1017 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -102,7 +102,6 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : ); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); - } void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { @@ -122,6 +121,7 @@ void AudioMixer::queueMirroredAudioPacket(QSharedPointer messag auto node = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, message->getSenderSockAddr(), message->getSenderSockAddr()); node->setIsMirror(true); + node->setLastHeardMicrostamp(usecTimestampNow()); getOrCreateClientData(node.data())->queuePacket(message, node); } From 0ee0082052a8f87d1a124b03f5a61740fe639356 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 02:05:40 -0700 Subject: [PATCH 017/157] handle new packet types in AudioMixerClientData::processPackets --- assignment-client/src/audio/AudioMixerClientData.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 7c747a3417..616d6252d8 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -68,7 +68,11 @@ void AudioMixerClientData::processPackets() { case PacketType::MicrophoneAudioWithEcho: case PacketType::InjectAudio: case PacketType::AudioStreamStats: - case PacketType::SilentAudioFrame: { + case PacketType::SilentAudioFrame: + case PacketType::MirroredMicrophoneAudioNoEcho: + case PacketType::MirroredMicrophoneAudioWithEcho: + case PacketType::MirroredInjectAudio: + case PacketType::MirroredSilentAudioFrame: { QMutexLocker lock(&getMutex()); parseData(*packet); From e629881665ff614ca4503e8bbfd9c849e74b0a0a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 02:18:27 -0700 Subject: [PATCH 018/157] mirror audio format negotiation --- assignment-client/src/audio/AudioMixerClientData.cpp | 4 ++++ libraries/networking/src/udt/PacketHeaders.h | 1 + 2 files changed, 5 insertions(+) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 616d6252d8..ec235600e2 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -81,7 +81,9 @@ void AudioMixerClientData::processPackets() { break; } case PacketType::NegotiateAudioFormat: + case PacketType::MirroredNegotiateAudioFormat: negotiateAudioFormat(*packet, node); + potentiallyMirrorPacket(*packet); break; case PacketType::RequestsDomainListData: parseRequestsDomainListData(*packet); @@ -117,6 +119,8 @@ void AudioMixerClientData::potentiallyMirrorPacket(ReceivedMessage& message) { mirroredType = PacketType::MirroredInjectAudio; } else if (message.getType() == PacketType::SilentAudioFrame) { mirroredType = PacketType::MirroredSilentAudioFrame; + } else if (message.getType() == PacketType::NegotiateAudioFormat) { + mirroredType = PacketType::MirroredNegotiateAudioFormat; } else { return; } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index f2a13dc449..52b0662c2b 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -115,6 +115,7 @@ public: AdjustAvatarSorting, OctreeFileReplacement, CollisionEventChanges, + MirroredNegotiateAudioFormat, MirroredMicrophoneAudioNoEcho, MirroredMicrophoneAudioWithEcho, MirroredInjectAudio, From b5c26b596e05c5001d7697667d48debd1b9e6f56 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 02:39:54 -0700 Subject: [PATCH 019/157] seek past source UUID in mirrored packets --- assignment-client/src/audio/AudioMixerClientData.cpp | 7 +++++++ libraries/networking/src/udt/PacketHeaders.cpp | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index ec235600e2..b876db55b8 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -303,6 +303,13 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { // seek to the beginning of the packet so that the next reader is in the right spot message.seek(0); + if (packetType == PacketType::MirroredMicrophoneAudioWithEcho + || packetType == PacketType::MirroredMicrophoneAudioNoEcho + || packetType == PacketType::MirroredSilentAudioFrame + || packetType == PacketType::MirroredInjectAudio) { + message.seek(NUM_BYTES_RFC4122_UUID); + } + // check the overflow count before we parse data auto overflowBefore = matchingStream->getOverflowCount(); auto parseResult = matchingStream->parseData(message); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index e29bfd0d78..cdc78ee639 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -41,7 +41,8 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::ICEServerHeartbeatDenied << PacketType::AssignmentClientStatus << PacketType::StopNode << PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement << PacketType::MirroredMicrophoneAudioNoEcho << PacketType::MirroredMicrophoneAudioWithEcho - << PacketType::MirroredInjectAudio << PacketType::MirroredSilentAudioFrame; + << PacketType::MirroredInjectAudio << PacketType::MirroredSilentAudioFrame + << PacketType::MirroredNegotiateAudioFormat; PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { From a085a55107e14c9dece091a7811e2bffe4e3a627 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 02:41:15 -0700 Subject: [PATCH 020/157] register a listener for audio format negotiation --- assignment-client/src/audio/AudioMixer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 55335c1017..0dd52584e0 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -97,7 +97,9 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketType::MirroredMicrophoneAudioNoEcho, PacketType::MirroredMicrophoneAudioWithEcho, PacketType::MirroredInjectAudio, - PacketType::MirroredSilentAudioFrame }, + PacketType::MirroredSilentAudioFrame, + PacketType::MirroredNegotiateAudioFormat + }, this, "queueMirroredAudioPacket" ); From 1b13cd6d45aee1d13d3be1f37941eabca1efabcc Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 12 Jun 2017 17:31:02 +0100 Subject: [PATCH 021/157] saving work --- .../qml/hifi/tablet/InputConfiguration.qml | 4 +- interface/src/Application.cpp | 2 +- interface/src/ui/overlays/Web3DOverlay.cpp | 44 +++++++++---------- .../src/plugins/InputConfiguration.cpp | 1 + 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index b89df4fa3e..e62576b6cf 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -176,13 +176,13 @@ Rectangle { } function initialize() { - chanageSource(); + changeSource(); } function changeSource() { loader.source = ""; var source = InputConfiguration.configurationLayout(box.currentText); - loader.source = "OpenVrConfiguration.qml"; + loader.source = source; if (source === "") { box.label = "(not configurable)"; } else { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 531847ce7f..7d56022e1d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -508,6 +508,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -528,7 +529,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED } }); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(true, qApp, qApp); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 6f1d266597..7585aafc9b 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -183,28 +183,28 @@ void Web3DOverlay::loadSourceURL() { if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") { auto tabletScriptingInterface = DependencyManager::get(); auto flags = tabletScriptingInterface->getFlags(); - - _webSurface->getRootContext()->setContextProperty("offscreenFlags", flags); - _webSurface->getRootContext()->setContextProperty("AddressManager", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("Account", AccountScriptingInterface::getInstance()); - _webSurface->getRootContext()->setContextProperty("AudioStats", DependencyManager::get()->getStats().data()); - _webSurface->getRootContext()->setContextProperty("HMD", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("fileDialogHelper", new FileDialogHelper()); - _webSurface->getRootContext()->setContextProperty("MyAvatar", DependencyManager::get()->getMyAvatar().get()); - _webSurface->getRootContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("Tablet", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("Assets", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("LODManager", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("OctreeStats", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("DCModel", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance()); - _webSurface->getRootContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); - _webSurface->getRootContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); - _webSurface->getRootContext()->setContextProperty("AvatarList", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance()); - _webSurface->getRootContext()->setContextProperty("InputConfiguration", DependencyManager::get().data()); - _webSurface->getRootContext()->setContextProperty("pathToFonts", "../../"); - + + _webSurface->getSurfaceContext()->setContextProperty("offscreenFlags", flags); + _webSurface->getSurfaceContext()->setContextProperty("AddressManager", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("Account", AccountScriptingInterface::getInstance()); + _webSurface->getSurfaceContext()->setContextProperty("AudioStats", DependencyManager::get()->getStats().data()); + _webSurface->getSurfaceContext()->setContextProperty("HMD", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper()); + _webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get()->getMyAvatar().get()); + _webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("DCModel", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("AudioDevice", AudioDeviceScriptingInterface::getInstance()); + _webSurface->getSurfaceContext()->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); + _webSurface->getSurfaceContext()->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance()); + _webSurface->getSurfaceContext()->setContextProperty("AvatarList", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("DialogsManager", DialogsManagerScriptingInterface::getInstance()); + _webSurface->getSurfaceContext()->setContextProperty("InputConfiguration", DependencyManager::get().data()); + + _webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../"); tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data()); // mark the TabletProxy object as cpp ownership. diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 3414350bf1..f1ff93f361 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -65,6 +65,7 @@ QJsonObject InputConfiguration::configurationSettings(QString pluginName) { void InputConfiguration::calibratePlugin(QString pluginName) { for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->getName() == pluginName) { + qDebug() << "calibrating plauin " << pluginName; plugin->calibrate(); } } From 0b847488d7529c6b4e6994bcce88e55474f3e299 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jun 2017 10:54:22 -0700 Subject: [PATCH 022/157] Fix comment --- libraries/networking/src/ReceivedPacketProcessor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index 4e4a3d1d11..5b54d4f309 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -65,7 +65,7 @@ protected: /// Implements generic processing behavior for this thread. virtual bool process() override; - /// Determines the timeout of the wait when there are no packets to process. Default value means no timeout + /// Determines the timeout of the wait when there are no packets to process. Default value is 100ms to allow for regular event processing. virtual unsigned long getMaxWait() const { return MAX_WAIT_TIME; } /// Override to do work before the packets processing loop. Default does nothing. From 8ebf1db9a88e764ed77a8a9588fe794230076a18 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 10:58:34 -0700 Subject: [PATCH 023/157] switch to replicator/replicant and add new node types --- assignment-client/src/audio/AudioMixer.cpp | 14 +++--- assignment-client/src/audio/AudioMixer.h | 2 +- .../src/audio/AudioMixerClientData.cpp | 44 +++++++++---------- .../src/audio/AudioMixerClientData.h | 2 +- libraries/networking/src/LimitedNodeList.h | 4 -- libraries/networking/src/NodeType.h | 2 + .../networking/src/udt/PacketHeaders.cpp | 6 +-- libraries/networking/src/udt/PacketHeaders.h | 12 ++--- 8 files changed, 42 insertions(+), 44 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 0dd52584e0..8f8a6ff2c0 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -94,11 +94,11 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket"); packetReceiver.registerListenerForTypes({ - PacketType::MirroredMicrophoneAudioNoEcho, - PacketType::MirroredMicrophoneAudioWithEcho, - PacketType::MirroredInjectAudio, - PacketType::MirroredSilentAudioFrame, - PacketType::MirroredNegotiateAudioFormat + PacketType::ReplicatedMicrophoneAudioNoEcho, + PacketType::ReplicatedMicrophoneAudioWithEcho, + PacketType::ReplicatedInjectAudio, + PacketType::ReplicatedSilentAudioFrame, + PacketType::ReplicatedNegotiateAudioFormat }, this, "queueMirroredAudioPacket" ); @@ -114,8 +114,8 @@ void AudioMixer::queueAudioPacket(QSharedPointer message, Share getOrCreateClientData(node.data())->queuePacket(message, node); } -void AudioMixer::queueMirroredAudioPacket(QSharedPointer message) { - // make sure we have a mirrored node for the original sender of the packet +void AudioMixer::queueReplicatedAudioPacket(QSharedPointer message) { + // make sure we have a replicated node for the original sender of the packet auto nodeList = DependencyManager::get(); QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index b7eebe6aa1..e542d82a6a 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -63,7 +63,7 @@ private slots: void handleKillAvatarPacket(QSharedPointer packet, SharedNodePointer sendingNode); void queueAudioPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void queueMirroredAudioPacket(QSharedPointer packet); + void queueReplicatedAudioPacket(QSharedPointer packet); void removeHRTFsForFinishedInjector(const QUuid& streamID); void start(); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index b876db55b8..70c9b615d8 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -69,21 +69,21 @@ void AudioMixerClientData::processPackets() { case PacketType::InjectAudio: case PacketType::AudioStreamStats: case PacketType::SilentAudioFrame: - case PacketType::MirroredMicrophoneAudioNoEcho: - case PacketType::MirroredMicrophoneAudioWithEcho: - case PacketType::MirroredInjectAudio: - case PacketType::MirroredSilentAudioFrame: { + case PacketType::ReplicatedMicrophoneAudioNoEcho: + case PacketType::ReplicatedMicrophoneAudioWithEcho: + case PacketType::ReplicatedInjectAudio: + case PacketType::ReplicatedSilentAudioFrame: { QMutexLocker lock(&getMutex()); parseData(*packet); - potentiallyMirrorPacket(*packet); + replicatePacket(*packet); break; } case PacketType::NegotiateAudioFormat: - case PacketType::MirroredNegotiateAudioFormat: + case PacketType::ReplicatedNegotiateAudioFormat: negotiateAudioFormat(*packet, node); - potentiallyMirrorPacket(*packet); + replicatePacket(*packet); break; case PacketType::RequestsDomainListData: parseRequestsDomainListData(*packet); @@ -106,26 +106,26 @@ void AudioMixerClientData::processPackets() { assert(_packetQueue.empty()); } -void AudioMixerClientData::potentiallyMirrorPacket(ReceivedMessage& message) { +void AudioMixerClientData::replicatePacket(ReceivedMessage& message) { auto nodeList = DependencyManager::get(); if (!nodeList->getMirrorSocket().isNull()) { PacketType mirroredType; if (message.getType() == PacketType::MicrophoneAudioNoEcho) { - mirroredType = PacketType::MirroredMicrophoneAudioNoEcho; + mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; } else if (message.getType() == PacketType::MicrophoneAudioWithEcho) { - mirroredType = PacketType::MirroredMicrophoneAudioNoEcho; + mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; } else if (message.getType() == PacketType::InjectAudio) { - mirroredType = PacketType::MirroredInjectAudio; + mirroredType = PacketType::ReplicatedInjectAudio; } else if (message.getType() == PacketType::SilentAudioFrame) { - mirroredType = PacketType::MirroredSilentAudioFrame; + mirroredType = PacketType::ReplicatedSilentAudioFrame; } else if (message.getType() == PacketType::NegotiateAudioFormat) { - mirroredType = PacketType::MirroredNegotiateAudioFormat; + mirroredType = PacketType::ReplicatedNegotiateAudioFormat; } else { return; } - // construct an NLPacket to send to the mirror that has the contents of the received packet + // construct an NLPacket to send to the replicant that has the contents of the received packet auto packet = NLPacket::create(mirroredType, message.getSize() + NUM_BYTES_RFC4122_UUID); packet->write(message.getSourceID().toRfc4122()); packet->write(message.getMessage()); @@ -225,11 +225,11 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { bool isMicStream = false; if (packetType == PacketType::MicrophoneAudioWithEcho - || packetType == PacketType::MirroredMicrophoneAudioWithEcho + || packetType == PacketType::ReplicatedMicrophoneAudioWithEcho || packetType == PacketType::MicrophoneAudioNoEcho - || packetType == PacketType::MirroredMicrophoneAudioNoEcho + || packetType == PacketType::ReplicatedMicrophoneAudioNoEcho || packetType == PacketType::SilentAudioFrame - || packetType == PacketType::MirroredSilentAudioFrame) { + || packetType == PacketType::ReplicatedSilentAudioFrame) { QWriteLocker writeLocker { &_streamsLock }; @@ -265,7 +265,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { isMicStream = true; } else if (packetType == PacketType::InjectAudio - || packetType == PacketType::MirroredInjectAudio) { + || packetType == PacketType::ReplicatedInjectAudio) { // this is injected audio // grab the stream identifier for this injected audio message.seek(sizeof(quint16)); @@ -303,10 +303,10 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { // seek to the beginning of the packet so that the next reader is in the right spot message.seek(0); - if (packetType == PacketType::MirroredMicrophoneAudioWithEcho - || packetType == PacketType::MirroredMicrophoneAudioNoEcho - || packetType == PacketType::MirroredSilentAudioFrame - || packetType == PacketType::MirroredInjectAudio) { + if (packetType == PacketType::ReplicatedMicrophoneAudioWithEcho + || packetType == PacketType::ReplicatedMicrophoneAudioNoEcho + || packetType == PacketType::ReplicatedSilentAudioFrame + || packetType == PacketType::ReplicatedInjectAudio) { message.seek(NUM_BYTES_RFC4122_UUID); } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 4207362ed3..5ab55dd48e 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -124,7 +124,7 @@ private: QReadWriteLock _streamsLock; AudioStreamMap _audioStreams; // microphone stream from avatar is stored under key of null UUID - void potentiallyMirrorPacket(ReceivedMessage& packet); + void replicatePacket(ReceivedMessage& packet); using IgnoreZone = AABox; class IgnoreZoneMemo { diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 16d7f20f99..72fc652733 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -281,9 +281,6 @@ public: void setMirrorSocket(const HifiSockAddr& mirrorSocket) { _mirrorSocket = mirrorSocket; } const HifiSockAddr& getMirrorSocket() { return _mirrorSocket; } - void setMasterSocket(const HifiSockAddr& masterSocket) { _masterSocket = masterSocket; } - const HifiSockAddr& getMasterSocket() { return _masterSocket; } - public slots: void reset(); void eraseAllNodes(); @@ -394,7 +391,6 @@ protected: HifiSockAddr _mirrorSocket; - HifiSockAddr _masterSocket; private slots: void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp); diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index 5ae7a835b6..7324dcaf14 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -25,6 +25,8 @@ namespace NodeType { const NodeType_t AssetServer = 'A'; const NodeType_t MessagesMixer = 'm'; const NodeType_t EntityScriptServer = 'S'; + const NodeType_t ReplicantAudioMixer = 'a'; + const NodeType_t ReplicantAvatarMixer = 'w'; const NodeType_t Unassigned = 1; void init(); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index cdc78ee639..ebc8e80e45 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -40,9 +40,9 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::ICEServerHeartbeatACK << PacketType::ICEPing << PacketType::ICEPingReply << PacketType::ICEServerHeartbeatDenied << PacketType::AssignmentClientStatus << PacketType::StopNode << PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement - << PacketType::MirroredMicrophoneAudioNoEcho << PacketType::MirroredMicrophoneAudioWithEcho - << PacketType::MirroredInjectAudio << PacketType::MirroredSilentAudioFrame - << PacketType::MirroredNegotiateAudioFormat; + << PacketType::ReplicatedMicrophoneAudioNoEcho << PacketType::ReplicatedMicrophoneAudioWithEcho + << PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame + << PacketType::ReplicatedNegotiateAudioFormat; PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 52b0662c2b..3ace60d502 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -115,12 +115,12 @@ public: AdjustAvatarSorting, OctreeFileReplacement, CollisionEventChanges, - MirroredNegotiateAudioFormat, - MirroredMicrophoneAudioNoEcho, - MirroredMicrophoneAudioWithEcho, - MirroredInjectAudio, - MirroredSilentAudioFrame, - LAST_PACKET_TYPE = MirroredSilentAudioFrame, + ReplicatedNegotiateAudioFormat, + ReplicatedMicrophoneAudioNoEcho, + ReplicatedMicrophoneAudioWithEcho, + ReplicatedInjectAudio, + ReplicatedSilentAudioFrame, + LAST_PACKET_TYPE = ReplicatedSilentAudioFrame, }; }; From 2ce924377aedbd4e466c9c19b03643f977c200ca Mon Sep 17 00:00:00 2001 From: seefo Date: Mon, 12 Jun 2017 11:56:38 -0700 Subject: [PATCH 024/157] Added initial settings for replication --- .../resources/describe-settings.json | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index a8c6dd84e7..b3ab6f935d 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1318,6 +1318,43 @@ "advanced": true } ] + }, + { + "name": "replication", + "label": "Replication", + "settings": [ + { + "name": "users", + "label": "Replicated Users", + "type": "table", + "can_add_new_rows": true, + "help": "Users that are replicated", + "numbered": false, + "columns": [ + { + "name": "user", + "label": "User", + "can_set": true + } + ] + }, + { + "name": "replicants", + "label": "Replicants", + "type": "table", + "can_add_new_rows": true, + "help": "Nodes or mirrors that are to replicate the domain", + "numbered": false, + "columns": [ + { + "address": "Address", + "port": "Port", + "mixer_type": "Mixer Type", + "can_set": true + } + ] + } + ] } ] } From ff2800e8d587fabc566cde169226ad0d1bc7ca54 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 11:49:48 -0700 Subject: [PATCH 025/157] Add isReplicant to Node --- domain-server/src/DomainServer.cpp | 5 +++++ libraries/networking/src/Node.cpp | 2 ++ libraries/networking/src/Node.h | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d637a20454..c9005c42e4 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2211,6 +2211,11 @@ void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& } void DomainServer::nodeAdded(SharedNodePointer node) { + // TODO Check to see if node is in list of replicant nodes + if (node->getType() == NodeType::Agent) { + node->setIsReplicant(true); + } + // we don't use updateNodeWithData, so add the DomainServerNodeData to the node here node->setLinkedData(std::unique_ptr { new DomainServerNodeData() }); } diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 60227eeaa1..baad621cd6 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -135,6 +135,7 @@ QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._publicSocket; out << node._localSocket; out << node._permissions; + out << node._isReplicant; return out; } @@ -144,6 +145,7 @@ QDataStream& operator>>(QDataStream& in, Node& node) { in >> node._publicSocket; in >> node._localSocket; in >> node._permissions; + in >> node._isReplicant; return in; } diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index f7afbdd864..2c8270071c 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -48,6 +48,9 @@ public: char getType() const { return _type; } void setType(char type); + bool isReplicant() const { return _isReplicant; } + void setIsReplicant(bool isReplicant) { _isReplicant = isReplicant; } + const QUuid& getConnectionSecret() const { return _connectionSecret; } void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; } @@ -89,6 +92,7 @@ private: Node& operator=(Node otherNode); NodeType_t _type; + bool _isReplicant { false }; QUuid _connectionSecret; std::unique_ptr _linkedData; From 2ff065f75164fdbe1d833103622ef93051dda6c7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 12:11:16 -0700 Subject: [PATCH 026/157] Add isReplicant to node list packet processing --- libraries/networking/src/LimitedNodeList.cpp | 4 +++- libraries/networking/src/LimitedNodeList.h | 2 +- libraries/networking/src/Node.cpp | 5 +++-- libraries/networking/src/Node.h | 4 ++-- libraries/networking/src/NodeList.cpp | 5 +++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index f9baff0daf..43b1602483 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -569,6 +569,7 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) { SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions, + bool isReplicant, const QUuid& connectionSecret) { QReadLocker readLocker(&_nodeMutex); NodeHash::const_iterator it = _nodeHash.find(uuid); @@ -580,11 +581,12 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t matchingNode->setLocalSocket(localSocket); matchingNode->setPermissions(permissions); matchingNode->setConnectionSecret(connectionSecret); + matchingNode->setIsReplicant(isReplicant); return matchingNode; } else { // we didn't have this node, so add them - Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, connectionSecret); + Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, isReplicant, connectionSecret, this); if (nodeType == NodeType::AudioMixer) { LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 72fc652733..4bc9134a73 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -146,7 +146,7 @@ public: SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions = DEFAULT_AGENT_PERMISSIONS, - const QUuid& connectionSecret = QUuid()); + bool isReplicant = false, const QUuid& connectionSecret = QUuid()); static bool parseSTUNResponse(udt::BasePacket* packet, QHostAddress& newPublicAddress, uint16_t& newPublicPort); bool hasCompletedInitialSTUN() const { return _hasCompletedInitialSTUN; } diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index baad621cd6..8972f68d2a 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -51,11 +51,12 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { } Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, - const HifiSockAddr& localSocket, const NodePermissions& permissions, const QUuid& connectionSecret, - QObject* parent) : + const HifiSockAddr& localSocket, const NodePermissions& permissions, bool isReplicant, + const QUuid& connectionSecret, QObject* parent) : NetworkPeer(uuid, publicSocket, localSocket, parent), _type(type), _connectionSecret(connectionSecret), + _isReplicant(isReplicant), _pingMs(-1), // "Uninitialized" _clockSkewUsec(0), _mutex(), diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 2c8270071c..8a2129f6f1 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -39,8 +39,8 @@ class Node : public NetworkPeer { public: Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, - const NodePermissions& permissions, const QUuid& connectionSecret = QUuid(), - QObject* parent = nullptr); + const NodePermissions& permissions, bool isReplicant, const QUuid& connectionSecret = QUuid(), + QObject* parent = 0); bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; } bool operator!=(const Node& otherNode) const { return !(*this == otherNode); } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 2aa30b84aa..6710f3ffa3 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -654,8 +654,9 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { QUuid nodeUUID, connectionUUID; HifiSockAddr nodePublicSocket, nodeLocalSocket; NodePermissions permissions; + bool isReplicant; - packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions; + packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions >> isReplicant; // if the public socket address is 0 then it's reachable at the same IP // as the domain server @@ -666,7 +667,7 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { packetStream >> connectionUUID; SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, - nodeLocalSocket, permissions, connectionUUID); + nodeLocalSocket, permissions, isReplicant, connectionUUID); } void NodeList::sendAssignment(Assignment& assignment) { From 84e1a6f89388d797492fea97b8f966156a48a394 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 13:02:54 -0700 Subject: [PATCH 027/157] Rename isReplicant to isReplicated --- domain-server/src/DomainServer.cpp | 4 ++-- libraries/networking/src/LimitedNodeList.cpp | 6 +++--- libraries/networking/src/LimitedNodeList.h | 2 +- libraries/networking/src/Node.cpp | 8 ++++---- libraries/networking/src/Node.h | 8 ++++---- libraries/networking/src/NodeList.cpp | 8 +++++--- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index c9005c42e4..de53898057 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2211,9 +2211,9 @@ void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& } void DomainServer::nodeAdded(SharedNodePointer node) { - // TODO Check to see if node is in list of replicant nodes + // TODO Check to see if node is in list of replicated nodes if (node->getType() == NodeType::Agent) { - node->setIsReplicant(true); + node->setIsReplicated(true); } // we don't use updateNodeWithData, so add the DomainServerNodeData to the node here diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 43b1602483..7aa17ebf04 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -569,7 +569,7 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) { SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions, - bool isReplicant, + bool isReplicated, const QUuid& connectionSecret) { QReadLocker readLocker(&_nodeMutex); NodeHash::const_iterator it = _nodeHash.find(uuid); @@ -581,12 +581,12 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t matchingNode->setLocalSocket(localSocket); matchingNode->setPermissions(permissions); matchingNode->setConnectionSecret(connectionSecret); - matchingNode->setIsReplicant(isReplicant); + matchingNode->setIsReplicated(isReplicated); return matchingNode; } else { // we didn't have this node, so add them - Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, isReplicant, connectionSecret, this); + Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, isReplicated, connectionSecret, this); if (nodeType == NodeType::AudioMixer) { LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 4bc9134a73..1ace6b2e23 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -146,7 +146,7 @@ public: SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions = DEFAULT_AGENT_PERMISSIONS, - bool isReplicant = false, const QUuid& connectionSecret = QUuid()); + bool isReplicated = false, const QUuid& connectionSecret = QUuid()); static bool parseSTUNResponse(udt::BasePacket* packet, QHostAddress& newPublicAddress, uint16_t& newPublicPort); bool hasCompletedInitialSTUN() const { return _hasCompletedInitialSTUN; } diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 8972f68d2a..49f032b823 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -51,12 +51,12 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { } Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, - const HifiSockAddr& localSocket, const NodePermissions& permissions, bool isReplicant, + const HifiSockAddr& localSocket, const NodePermissions& permissions, bool isReplicated, const QUuid& connectionSecret, QObject* parent) : NetworkPeer(uuid, publicSocket, localSocket, parent), _type(type), _connectionSecret(connectionSecret), - _isReplicant(isReplicant), + _isReplicated(isReplicated), _pingMs(-1), // "Uninitialized" _clockSkewUsec(0), _mutex(), @@ -136,7 +136,7 @@ QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._publicSocket; out << node._localSocket; out << node._permissions; - out << node._isReplicant; + out << node._isReplicated; return out; } @@ -146,7 +146,7 @@ QDataStream& operator>>(QDataStream& in, Node& node) { in >> node._publicSocket; in >> node._localSocket; in >> node._permissions; - in >> node._isReplicant; + in >> node._isReplicated; return in; } diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 8a2129f6f1..73c8538304 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -39,7 +39,7 @@ class Node : public NetworkPeer { public: Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, - const NodePermissions& permissions, bool isReplicant, const QUuid& connectionSecret = QUuid(), + const NodePermissions& permissions, bool isReplicated, const QUuid& connectionSecret = QUuid(), QObject* parent = 0); bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; } @@ -48,8 +48,8 @@ public: char getType() const { return _type; } void setType(char type); - bool isReplicant() const { return _isReplicant; } - void setIsReplicant(bool isReplicant) { _isReplicant = isReplicant; } + bool isReplicated() const { return _isReplicated; } + void setIsReplicated(bool isReplicated) { _isReplicated = isReplicated; } const QUuid& getConnectionSecret() const { return _connectionSecret; } void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; } @@ -92,7 +92,7 @@ private: Node& operator=(Node otherNode); NodeType_t _type; - bool _isReplicant { false }; + bool _isReplicated { false }; QUuid _connectionSecret; std::unique_ptr _linkedData; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 6710f3ffa3..c38a9470b1 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -654,9 +654,11 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { QUuid nodeUUID, connectionUUID; HifiSockAddr nodePublicSocket, nodeLocalSocket; NodePermissions permissions; - bool isReplicant; + bool isReplicated; - packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions >> isReplicant; + packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions >> isReplicated; + + qDebug() << "Node: " << nodeUUID << nodeType << isReplicated; // if the public socket address is 0 then it's reachable at the same IP // as the domain server @@ -667,7 +669,7 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { packetStream >> connectionUUID; SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, - nodeLocalSocket, permissions, isReplicant, connectionUUID); + nodeLocalSocket, permissions, isReplicated, connectionUUID); } void NodeList::sendAssignment(Assignment& assignment) { From bbe675ab72018ea4c1fc1da5d61ff00c344a6cc0 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 12 Jun 2017 22:01:41 +0100 Subject: [PATCH 028/157] making final changes --- .../qml/hifi/tablet/InputConfiguration.qml | 52 +++++------ .../qml/hifi/tablet/OpenVrConfiguration.qml | 86 +++++++++++-------- .../src/plugins/InputConfiguration.cpp | 51 +++++++++-- .../plugins/src/plugins/InputConfiguration.h | 1 - plugins/openvr/src/ViveControllerManager.cpp | 3 +- 5 files changed, 124 insertions(+), 69 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml index e62576b6cf..10181480f0 100644 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/InputConfiguration.qml @@ -89,24 +89,24 @@ Rectangle { editable: true colorScheme: hifi.colorSchemes.dark model: inputPlugins() - label: "" - + label: "" + onCurrentIndexChanged: { - changeSource(); + changeSource(); } } - HifiControls.CheckBox { - id: checkBox - colorScheme: hifi.colorSchemes.dark - text: "show all input plugins" + HifiControls.CheckBox { + id: checkBox + colorScheme: hifi.colorSchemes.dark + text: "show all input plugins" - onClicked: { - console.log("clicked"); - inputPlugins(); - changeSource(); - } - } + onClicked: { + console.log("clicked"); + inputPlugins(); + changeSource(); + } + } } @@ -166,13 +166,13 @@ Rectangle { } } } - + function inputPlugins() { - if (checkBox.checked) { + if (checkBox.checked) { return InputConfiguration.inputPlugins(); - } else { - return InputConfiguration.activeInputPlugins(); - } + } else { + return InputConfiguration.activeInputPlugins(); + } } function initialize() { @@ -180,14 +180,14 @@ Rectangle { } function changeSource() { - loader.source = ""; - var source = InputConfiguration.configurationLayout(box.currentText); - loader.source = source; - if (source === "") { - box.label = "(not configurable)"; - } else { - box.label = ""; - } + loader.source = ""; + var source = InputConfiguration.configurationLayout(box.currentText); + loader.source = source; + if (source === "") { + box.label = "(not configurable)"; + } else { + box.label = ""; + } } Timer { diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index e00ee17228..51bf3f60cd 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -84,13 +84,13 @@ Rectangle { composeConfigurationSettings(); } } - + RalewayBold { size: 12 text: "Vive HMD" color: hifi.colors.lightGrayText } - + HifiControls.CheckBox { id: headPuckBox width: 15 @@ -116,10 +116,10 @@ Rectangle { RalewayBold { id: hands - + text: "Hands:" size: 12 - + color: "white" anchors.top: headConfig.bottom @@ -135,7 +135,7 @@ Rectangle { anchors.left: openVrConfiguration.left anchors.leftMargin: leftMargin + 20 spacing: 10 - + HifiControls.CheckBox { id: handBox width: 15 @@ -151,13 +151,13 @@ Rectangle { composeConfigurationSettings(); } } - + RalewayBold { size: 12 text: "Controllers" color: hifi.colors.lightGrayText } - + HifiControls.CheckBox { id: handPuckBox width: 12 @@ -173,7 +173,7 @@ Rectangle { composeConfigurationSettings(); } } - + RalewayBold { size: 12 text: "Trackers" @@ -183,10 +183,10 @@ Rectangle { RalewayBold { id: additional - + text: "Additional Trackers" size: 12 - + color: hifi.colors.white anchors.top: handConfig.bottom @@ -202,7 +202,7 @@ Rectangle { anchors.left: openVrConfiguration.left anchors.leftMargin: leftMargin + 20 spacing: 10 - + HifiControls.CheckBox { id: feetBox width: 15 @@ -216,7 +216,7 @@ Rectangle { composeConfigurationSettings(); } } - + RalewayBold { size: 12 text: "Feet" @@ -231,7 +231,7 @@ Rectangle { anchors.left: openVrConfiguration.left anchors.leftMargin: leftMargin + 20 spacing: 10 - + HifiControls.CheckBox { id: hipBox width: 15 @@ -249,7 +249,7 @@ Rectangle { composeConfigurationSettings(); } } - + RalewayBold { size: 12 text: "Hips" @@ -271,7 +271,7 @@ Rectangle { anchors.left: openVrConfiguration.left anchors.leftMargin: leftMargin + 20 spacing: 10 - + HifiControls.CheckBox { id: chestBox width: 15 @@ -286,7 +286,7 @@ Rectangle { composeConfigurationSettings(); } } - + RalewayBold { size: 12 text: "Chest" @@ -308,7 +308,7 @@ Rectangle { anchors.left: openVrConfiguration.left anchors.leftMargin: leftMargin + 20 spacing: 10 - + HifiControls.CheckBox { id: shoulderBox width: 15 @@ -323,7 +323,7 @@ Rectangle { composeConfigurationSettings(); } } - + RalewayBold { size: 12 text: "Shoulders" @@ -336,7 +336,7 @@ Rectangle { color: hifi.colors.lightGray } } - + Separator { id: bottomSeperator width: parent.width @@ -367,9 +367,9 @@ Rectangle { anchors.left: parent.left anchors.leftMargin: 30 - + } - + RalewayRegular { id: calibrate text: "CALIBRATE" @@ -413,6 +413,7 @@ Rectangle { info.showCountDown = false; info.calibrationFailed = false info.calibrationSucceed = false; + info.calibrationSucceed = false; info.showCalibrationStatus = false; info.visible = false; } @@ -439,7 +440,7 @@ Rectangle { numberAnimation.duration = calibrationTimer.interval; } } - + NumberAnimation { id: numberAnimation target: openVrConfiguration @@ -455,6 +456,9 @@ Rectangle { } else if (!status["calibrated"]) { var uncalibrated = status["success"]; if (uncalibrated) { + info.visible = true; + info.showCalibrationStatus = true; + info.uncalibrationSucceed = true; } else { info.visible = true; info.showCalibrationStatus = true; @@ -496,10 +500,10 @@ Rectangle { var configurationType = settings["trackerConfiguration"]; displayTrackerConfiguration(configurationType); - + var HmdHead = settings["HMDHead"]; var viveController = settings["handController"]; - + if (HmdHead) { headBox.checked = true; headPuckBox.checked = false; @@ -524,7 +528,8 @@ Rectangle { property bool showCalibrationStatus: false property bool calibrationFailed: false property bool calibrationSucceed: false - + property bool uncalibrationSucceed: false + visible: false color: hifi.colors.baseGray anchors.top: openVrConfiguration.top @@ -538,12 +543,12 @@ Rectangle { anchors.centerIn: parent RalewayBold { id: countDownText - + text: openVrConfiguration.countDown size: 92 - + color: hifi.colors.blueHighlight - + anchors.centerIn: parent } } @@ -576,11 +581,24 @@ Rectangle { color: hifi.colors.redAccent anchors.centerIn: parent } - } + } + + Item { + id: uncalibrateInfo + visible: info.uncalibrationSucceed + anchors.centerIn: parent + RalewayBold { + id: uncalibrateText + text: "Uncalibration Successful" + size: 42 + color: hifi.colors.greenHighlight + anchors.centerIn: parent + } + } } } - - + + function displayTrackerConfiguration(type) { if (type === "Feet") { feetBox.checked = true; @@ -631,8 +649,8 @@ Rectangle { } else if (handPuck) { overrideHandController = true; } - - + + var settingsObject = { "trackerConfiguration": trackerConfiguration, "overrideHead": overrideHead, @@ -640,6 +658,6 @@ Rectangle { } InputConfiguration.setConfigurationSettings(settingsObject, pluginName); - + } } diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index f1ff93f361..d20678b972 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -8,6 +8,9 @@ #include "InputConfiguration.h" + +#include + #include "DisplayPlugin.h" #include "InputPlugin.h" #include "PluginManager.h" @@ -16,6 +19,13 @@ InputConfiguration::InputConfiguration() { } QStringList InputConfiguration::inputPlugins() { + if (QThread::currentThread() != thread()) { + QStringList result; + QMetaObject::invokeMethod(this, "inputPlugins", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QStringList, result)); + return result; + } + QStringList inputPlugins; for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { inputPlugins << QString(plugin->getName()); @@ -25,6 +35,13 @@ QStringList InputConfiguration::inputPlugins() { QStringList InputConfiguration::activeInputPlugins() { + if (QThread::currentThread() != thread()) { + QStringList result; + QMetaObject::invokeMethod(this, "activeInputPlugins", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QStringList, result)); + return result; + } + QStringList activePlugins; for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->configurable()) { @@ -35,8 +52,15 @@ QStringList InputConfiguration::activeInputPlugins() { } QString InputConfiguration::configurationLayout(QString pluginName) { - QString sourcePath; + if (QThread::currentThread() != thread()) { + QString result; + QMetaObject::invokeMethod(this, "configurationLayout", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QString, result), + Q_ARG(QString, pluginName)); + return result; + } + QString sourcePath; for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->getName() == pluginName) { return plugin->configurationLayout(); @@ -46,6 +70,13 @@ QString InputConfiguration::configurationLayout(QString pluginName) { } void InputConfiguration::setConfigurationSettings(QJsonObject configurationSettings, QString pluginName) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setConfigurationSettings", Qt::BlockingQueuedConnection, + Q_ARG(QJsonObject, configurationSettings), + Q_ARG(QString, pluginName)); + return; + } + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->getName() == pluginName) { plugin->setConfigurationSettings(configurationSettings); @@ -54,6 +85,14 @@ void InputConfiguration::setConfigurationSettings(QJsonObject configurationSetti } QJsonObject InputConfiguration::configurationSettings(QString pluginName) { + if (QThread::currentThread() != thread()) { + QJsonObject result; + QMetaObject::invokeMethod(this, "configurationSettings", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QJsonObject, result), + Q_ARG(QString, pluginName)); + return result; + } + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->getName() == pluginName) { return plugin->configurationSettings(); @@ -63,14 +102,14 @@ QJsonObject InputConfiguration::configurationSettings(QString pluginName) { } void InputConfiguration::calibratePlugin(QString pluginName) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "calibratePlugin", Qt::BlockingQueuedConnection); + return; + } + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->getName() == pluginName) { - qDebug() << "calibrating plauin " << pluginName; plugin->calibrate(); } } } - -void InputConfiguration::calibrated(const QJsonObject& status) { - emit calibrationStatus(status); -} diff --git a/libraries/plugins/src/plugins/InputConfiguration.h b/libraries/plugins/src/plugins/InputConfiguration.h index fddf858c64..abf0c89ab4 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.h +++ b/libraries/plugins/src/plugins/InputConfiguration.h @@ -28,7 +28,6 @@ public: Q_INVOKABLE void setConfigurationSettings(QJsonObject configurationSettings, QString pluginName); Q_INVOKABLE void calibratePlugin(QString pluginName); Q_INVOKABLE QJsonObject configurationSettings(QString pluginName); - void calibrated(const QJsonObject& status); signals: void calibrationStatus(const QJsonObject& status); diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 07436c194b..9e723d2a10 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -314,7 +314,6 @@ void ViveControllerManager::InputDevice::calibrateFromUI(const controller::Input void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJsonObject configurationSettings) { Locker locker(_lock); - if (!configurationSettings.empty()) { auto iter = configurationSettings.begin(); auto end = configurationSettings.end(); @@ -372,7 +371,7 @@ void ViveControllerManager::InputDevice::emitCalibrationStatus(const bool succes status["puckCount"] = (int)_validTrackedObjects.size(); } - inputConfiguration->calibrated(status); + emit inputConfiguration->calibrationStatus(status); //inputConfiguration->calibrated(status); } void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) { From 89b0e31edca001430e6d5cf2f467122fccd94c61 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 12 Jun 2017 22:21:46 +0100 Subject: [PATCH 029/157] update calibrate button glyph --- interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 51bf3f60cd..52c18ddff8 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -361,7 +361,7 @@ Rectangle { HiFiGlyphs { id: calibrationGlyph - text: hifi.glyphs.sliders + text: hifi.glyphs.avatar1 size: 36 color: hifi.colors.white From 3142842d5d8a60a6863a35349f7ea410fba94e03 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 14:51:08 -0700 Subject: [PATCH 030/157] Fix Node initialization warnings --- libraries/networking/src/Node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 73c8538304..2ae0ab82e9 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -92,7 +92,6 @@ private: Node& operator=(Node otherNode); NodeType_t _type; - bool _isReplicated { false }; QUuid _connectionSecret; std::unique_ptr _linkedData; @@ -101,6 +100,7 @@ private: QMutex _mutex; MovingPercentile _clockSkewMovingPercentile; NodePermissions _permissions; + bool _isReplicated { false }; tbb::concurrent_unordered_set _ignoredNodeIDSet; mutable QReadWriteLock _ignoredNodeIDSetLock; From 4851d3b56409bef465365a552858ea8746992ade Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 14:52:02 -0700 Subject: [PATCH 031/157] Remove superfluous node log --- libraries/networking/src/NodeList.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index c38a9470b1..9b7a7c91dd 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -658,8 +658,6 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions >> isReplicated; - qDebug() << "Node: " << nodeUUID << nodeType << isReplicated; - // if the public socket address is 0 then it's reachable at the same IP // as the domain server if (nodePublicSocket.getAddress().isNull()) { From 3b3465ea05e76dc9accf09b02bff54937ff44cef Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 14:59:45 -0700 Subject: [PATCH 032/157] Add isUpstream to Node --- assignment-client/src/audio/AudioMixerSlave.cpp | 4 ++++ libraries/networking/src/Node.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index d01d961e33..2d800c3561 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -74,6 +74,10 @@ void AudioMixerSlave::mix(const SharedNodePointer& node) { return; } + if (node->isUpstream()) { + return; + } + // check that the stream is valid auto avatarStream = data->getAvatarAudioStream(); if (avatarStream == nullptr) { diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 2ae0ab82e9..6d74cf4a26 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -51,6 +51,9 @@ public: bool isReplicated() const { return _isReplicated; } void setIsReplicated(bool isReplicated) { _isReplicated = isReplicated; } + bool isUpstream() const { return _isUpstream; } + void setIsUpstream(bool isUpstream) { _isUpstream = isUpstream; } + const QUuid& getConnectionSecret() const { return _connectionSecret; } void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; } @@ -101,6 +104,7 @@ private: MovingPercentile _clockSkewMovingPercentile; NodePermissions _permissions; bool _isReplicated { false }; + bool _isUpstream { false }; tbb::concurrent_unordered_set _ignoredNodeIDSet; mutable QReadWriteLock _ignoredNodeIDSetLock; From efdd3060b0cd16c998447770828970c48d42731c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 15:00:03 -0700 Subject: [PATCH 033/157] Set isUpstream when receiving a replicated audio packet --- assignment-client/src/audio/AudioMixer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8f8a6ff2c0..1246617540 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -122,6 +122,7 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess auto node = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, message->getSenderSockAddr(), message->getSenderSockAddr()); + node->setIsUpstream(true); node->setIsMirror(true); node->setLastHeardMicrostamp(usecTimestampNow()); From eb2a41744826a84718cb7769a07fa4d612f8e8bf Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 15:24:14 -0700 Subject: [PATCH 034/157] Add parent back to Node ctor --- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/Node.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 7aa17ebf04..7b0b2d5bc5 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -586,7 +586,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t return matchingNode; } else { // we didn't have this node, so add them - Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, isReplicated, connectionSecret, this); + Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, isReplicated, connectionSecret); if (nodeType == NodeType::AudioMixer) { LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer); diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 6d74cf4a26..9082deb55b 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -40,7 +40,7 @@ public: Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions, bool isReplicated, const QUuid& connectionSecret = QUuid(), - QObject* parent = 0); + QObject* parent = nullptr); bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; } bool operator!=(const Node& otherNode) const { return !(*this == otherNode); } From a1d3c0dc7b86b82bf25c2bfa23de40b3674c032a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 15:27:24 -0700 Subject: [PATCH 035/157] Fix initialization ordering error in Node --- libraries/networking/src/Node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 9082deb55b..11f88b0f52 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -98,12 +98,12 @@ private: QUuid _connectionSecret; std::unique_ptr _linkedData; + bool _isReplicated { false }; int _pingMs; qint64 _clockSkewUsec; QMutex _mutex; MovingPercentile _clockSkewMovingPercentile; NodePermissions _permissions; - bool _isReplicated { false }; bool _isUpstream { false }; tbb::concurrent_unordered_set _ignoredNodeIDSet; mutable QReadWriteLock _ignoredNodeIDSetLock; From 6635187da36253048be2c086352ee82a87bc602d Mon Sep 17 00:00:00 2001 From: seefo Date: Mon, 12 Jun 2017 13:41:54 -0700 Subject: [PATCH 036/157] Changed domain server settings --- .../resources/describe-settings.json | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index b3ab6f935d..0143414db8 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1328,7 +1328,7 @@ "label": "Replicated Users", "type": "table", "can_add_new_rows": true, - "help": "Users that are replicated", + "help": "Users that are replicated to downstream servers", "numbered": false, "columns": [ { @@ -1339,17 +1339,28 @@ ] }, { - "name": "replicants", - "label": "Replicants", + "name": "downstream_servers", + "label": "Downstream Servers", + "assignment-types": [0,1], "type": "table", "can_add_new_rows": true, - "help": "Nodes or mirrors that are to replicate the domain", + "help": "Downstream servers that are relayed data for replicated users", "numbered": false, "columns": [ { - "address": "Address", - "port": "Port", - "mixer_type": "Mixer Type", + "name": "address", + "label": "Address", + "can_set": true + }, + { + "name": "port", + "label": "Port", + "can_set": true + }, + { + "name": "server_type", + "label": "Server Type", + "placeholder": "Audio Mixer", "can_set": true } ] From c7b3b79a235c5ea7fd2f1f2c03da5c6abde2a4dd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 11:13:43 -0700 Subject: [PATCH 037/157] use replicant nodes for audio packet replication --- .../src/audio/AudioMixerClientData.cpp | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 70c9b615d8..f28e8dfa0b 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -108,30 +108,34 @@ void AudioMixerClientData::processPackets() { void AudioMixerClientData::replicatePacket(ReceivedMessage& message) { auto nodeList = DependencyManager::get(); - if (!nodeList->getMirrorSocket().isNull()) { - PacketType mirroredType; - if (message.getType() == PacketType::MicrophoneAudioNoEcho) { - mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; - } else if (message.getType() == PacketType::MicrophoneAudioWithEcho) { - mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; - } else if (message.getType() == PacketType::InjectAudio) { - mirroredType = PacketType::ReplicatedInjectAudio; - } else if (message.getType() == PacketType::SilentAudioFrame) { - mirroredType = PacketType::ReplicatedSilentAudioFrame; - } else if (message.getType() == PacketType::NegotiateAudioFormat) { - mirroredType = PacketType::ReplicatedNegotiateAudioFormat; - } else { - return; - } + PacketType mirroredType; - // construct an NLPacket to send to the replicant that has the contents of the received packet - auto packet = NLPacket::create(mirroredType, message.getSize() + NUM_BYTES_RFC4122_UUID); - packet->write(message.getSourceID().toRfc4122()); - packet->write(message.getMessage()); - - nodeList->sendPacket(std::move(packet), nodeList->getMirrorSocket()); + if (message.getType() == PacketType::MicrophoneAudioNoEcho) { + mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; + } else if (message.getType() == PacketType::MicrophoneAudioWithEcho) { + mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; + } else if (message.getType() == PacketType::InjectAudio) { + mirroredType = PacketType::ReplicatedInjectAudio; + } else if (message.getType() == PacketType::SilentAudioFrame) { + mirroredType = PacketType::ReplicatedSilentAudioFrame; + } else if (message.getType() == PacketType::NegotiateAudioFormat) { + mirroredType = PacketType::ReplicatedNegotiateAudioFormat; + } else { + return; } + + // construct an NLPacket to send to the replicant that has the contents of the received packet + auto packet = NLPacket::create(mirroredType, message.getSize() + NUM_BYTES_RFC4122_UUID); + packet->write(message.getSourceID().toRfc4122()); + packet->write(message.getMessage()); + + // enumerate the replicant audio mixers and send them the replicated version of this packet + nodeList->eachMatchingNode([&](const SharedNodePointer& node)->bool { + return node->getType() == NodeType::ReplicantAudioMixer; + }, [&](const SharedNodePointer& node) { + nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); + }); } void AudioMixerClientData::negotiateAudioFormat(ReceivedMessage& message, const SharedNodePointer& node) { From d5b466e3ae36eec5ef4b2621e27d92b18ee5c3b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 11:31:35 -0700 Subject: [PATCH 038/157] fix replicant handling slot, add node strings for replicants --- assignment-client/src/audio/AudioMixer.cpp | 3 ++- libraries/networking/src/LimitedNodeList.cpp | 3 ++- libraries/networking/src/Node.cpp | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 1246617540..0927e02655 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -100,10 +100,11 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketType::ReplicatedSilentAudioFrame, PacketType::ReplicatedNegotiateAudioFormat }, - this, "queueMirroredAudioPacket" + this, "queueReplicatedAudioPacket" ); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); + } void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 7b0b2d5bc5..afb0dce8af 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -744,7 +744,8 @@ void LimitedNodeList::removeSilentNodes() { SharedNodePointer node = it->second; node->getMutex().lock(); - if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) { + if (node->getType() != NodeType::ReplicantAudioMixer && node->getType() != NodeType::ReplicantAvatarMixer + && (usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) { // call the NodeHash erase to get rid of this node it = _nodeHash.unsafe_erase(it); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 49f032b823..a023e488c4 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -42,6 +42,8 @@ void NodeType::init() { TypeNameHash.insert(NodeType::MessagesMixer, "Messages Mixer"); TypeNameHash.insert(NodeType::AssetServer, "Asset Server"); TypeNameHash.insert(NodeType::EntityScriptServer, "Entity Script Server"); + TypeNameHash.insert(NodeType::ReplicantAudioMixer, "Replicant Audio Mixer"); + TypeNameHash.insert(NodeType::ReplicantAvatarMixer, "Replicant Avatar Mixer"); TypeNameHash.insert(NodeType::Unassigned, "Unassigned"); } From 2929573cb09f46018121d3815f1ea16f5f864b78 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 11:42:46 -0700 Subject: [PATCH 039/157] do not punch to replicant nodes --- libraries/networking/src/NodeList.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 9b7a7c91dd..5e06ad2b5c 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -712,14 +712,18 @@ void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { } void NodeList::startNodeHolePunch(const SharedNodePointer& node) { - // connect to the correct signal on this node so we know when to ping it - connect(node.data(), &Node::pingTimerTimeout, this, &NodeList::handleNodePingTimeout); - // start the ping timer for this node - node->startPingTimer(); + // we don't hole punch to replicants, since it is assumed that we have a direct line to them + if (node->getType() != NodeType::ReplicantAudioMixer && node->getType() != NodeType::ReplicantAvatarMixer) { + // connect to the correct signal on this node so we know when to ping it + connect(node.data(), &Node::pingTimerTimeout, this, &NodeList::handleNodePingTimeout); - // ping this node immediately - pingPunchForInactiveNode(node); + // start the ping timer for this node + node->startPingTimer(); + + // ping this node immediately + pingPunchForInactiveNode(node); + } } void NodeList::handleNodePingTimeout() { @@ -1121,4 +1125,4 @@ void NodeList::setRequestsDomainListData(bool isRequesting) { void NodeList::startThread() { moveToNewNamedThread(this, "NodeList Thread", QThread::TimeCriticalPriority); -} \ No newline at end of file +} From fe668b1bb11d6ad49784abf4c90f7df00448c442 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 12:14:59 -0700 Subject: [PATCH 040/157] make codec negotiation stateless for replicated agents --- assignment-client/src/audio/AudioMixer.cpp | 9 +++-- .../src/audio/AudioMixerClientData.cpp | 33 ++++++++++++++++--- .../src/audio/AudioMixerClientData.h | 2 ++ libraries/networking/src/Node.cpp | 1 + libraries/networking/src/Node.h | 5 --- libraries/networking/src/NodeType.h | 1 + .../networking/src/udt/PacketHeaders.cpp | 3 +- libraries/networking/src/udt/PacketHeaders.h | 1 - 8 files changed, 38 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 0927e02655..d997c3504b 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -97,8 +97,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketType::ReplicatedMicrophoneAudioNoEcho, PacketType::ReplicatedMicrophoneAudioWithEcho, PacketType::ReplicatedInjectAudio, - PacketType::ReplicatedSilentAudioFrame, - PacketType::ReplicatedNegotiateAudioFormat + PacketType::ReplicatedSilentAudioFrame }, this, "queueReplicatedAudioPacket" ); @@ -121,10 +120,10 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - auto node = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, - message->getSenderSockAddr(), message->getSenderSockAddr()); + auto node = nodeList->addOrUpdateNode(nodeID, NodeType::ReplicatedAgent, + message->getSenderSockAddr(), message->getSenderSockAddr(), + DEFAULT_AGENT_PERMISSIONS, true); node->setIsUpstream(true); - node->setIsMirror(true); node->setLastHeardMicrostamp(usecTimestampNow()); getOrCreateClientData(node.data())->queuePacket(message, node); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index f28e8dfa0b..8ee7f9f383 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -73,6 +73,11 @@ void AudioMixerClientData::processPackets() { case PacketType::ReplicatedMicrophoneAudioWithEcho: case PacketType::ReplicatedInjectAudio: case PacketType::ReplicatedSilentAudioFrame: { + + if (node->getType() == NodeType::ReplicatedAgent && !_codec) { + setupCodecForReplicatedAgent(packet); + } + QMutexLocker lock(&getMutex()); parseData(*packet); @@ -81,9 +86,7 @@ void AudioMixerClientData::processPackets() { break; } case PacketType::NegotiateAudioFormat: - case PacketType::ReplicatedNegotiateAudioFormat: negotiateAudioFormat(*packet, node); - replicatePacket(*packet); break; case PacketType::RequestsDomainListData: parseRequestsDomainListData(*packet); @@ -119,15 +122,20 @@ void AudioMixerClientData::replicatePacket(ReceivedMessage& message) { mirroredType = PacketType::ReplicatedInjectAudio; } else if (message.getType() == PacketType::SilentAudioFrame) { mirroredType = PacketType::ReplicatedSilentAudioFrame; - } else if (message.getType() == PacketType::NegotiateAudioFormat) { - mirroredType = PacketType::ReplicatedNegotiateAudioFormat; } else { return; } // construct an NLPacket to send to the replicant that has the contents of the received packet auto packet = NLPacket::create(mirroredType, message.getSize() + NUM_BYTES_RFC4122_UUID); + + // since this packet will be non-sourced, we add the replicated node's ID here packet->write(message.getSourceID().toRfc4122()); + + // we won't negotiate an audio format with the replicant, because we aren't a listener + // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs + packet->writeString(_selectedCodecName); + packet->write(message.getMessage()); // enumerate the replicant audio mixers and send them the replicated version of this packet @@ -311,7 +319,12 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { || packetType == PacketType::ReplicatedMicrophoneAudioNoEcho || packetType == PacketType::ReplicatedSilentAudioFrame || packetType == PacketType::ReplicatedInjectAudio) { + + // skip past source ID for the replicated packet message.seek(NUM_BYTES_RFC4122_UUID); + + // skip past the codec string + message.readString(); } // check the overflow count before we parse data @@ -660,3 +673,15 @@ bool AudioMixerClientData::shouldIgnore(const SharedNodePointer self, const Shar return shouldIgnore; } + +void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointer message) { + // first pull the codec string from the packet + + // read the string for the codec + auto codecString = message->readString(); + + qDebug() << "Manually setting codec for replicated agent" << codecString; + + const std::pair codec = AudioMixer::negotiateCodec({ codecString }); + setupCodec(codec.second, codec.first); +} diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 5ab55dd48e..72761e64f2 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -108,6 +108,8 @@ public: bool getRequestsDomainListData() { return _requestsDomainListData; } void setRequestsDomainListData(bool requesting) { _requestsDomainListData = requesting; } + void setupCodecForReplicatedAgent(QSharedPointer message); + signals: void injectorStreamFinished(const QUuid& streamIdentifier); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index a023e488c4..a6b6bc18b2 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -44,6 +44,7 @@ void NodeType::init() { TypeNameHash.insert(NodeType::EntityScriptServer, "Entity Script Server"); TypeNameHash.insert(NodeType::ReplicantAudioMixer, "Replicant Audio Mixer"); TypeNameHash.insert(NodeType::ReplicantAvatarMixer, "Replicant Avatar Mixer"); + TypeNameHash.insert(NodeType::ReplicatedAgent, "Replicated Agent"); TypeNameHash.insert(NodeType::Unassigned, "Unassigned"); } diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 11f88b0f52..c905c9d551 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -86,9 +86,6 @@ public: bool isIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled; } - bool isMirror() const { return _isMirror; } - void setIsMirror(bool isMirror) { _isMirror = isMirror; } - private: // privatize copy and assignment operator to disallow Node copying Node(const Node &otherNode); @@ -109,8 +106,6 @@ private: mutable QReadWriteLock _ignoredNodeIDSetLock; std::atomic_bool _ignoreRadiusEnabled; - - bool _isMirror { false }; }; Q_DECLARE_METATYPE(Node*) diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index 7324dcaf14..7c327e08f7 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -27,6 +27,7 @@ namespace NodeType { const NodeType_t EntityScriptServer = 'S'; const NodeType_t ReplicantAudioMixer = 'a'; const NodeType_t ReplicantAvatarMixer = 'w'; + const NodeType_t ReplicatedAgent = 'z'; const NodeType_t Unassigned = 1; void init(); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index ebc8e80e45..f2f0062861 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -41,8 +41,7 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::ICEServerHeartbeatDenied << PacketType::AssignmentClientStatus << PacketType::StopNode << PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement << PacketType::ReplicatedMicrophoneAudioNoEcho << PacketType::ReplicatedMicrophoneAudioWithEcho - << PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame - << PacketType::ReplicatedNegotiateAudioFormat; + << PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame; PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3ace60d502..448ae812ff 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -115,7 +115,6 @@ public: AdjustAvatarSorting, OctreeFileReplacement, CollisionEventChanges, - ReplicatedNegotiateAudioFormat, ReplicatedMicrophoneAudioNoEcho, ReplicatedMicrophoneAudioWithEcho, ReplicatedInjectAudio, From a4aa9689a6098fcf8a445f03ed878189897f56a2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 12:51:18 -0700 Subject: [PATCH 041/157] don't construct a packet of exact size for replicated audio packets --- assignment-client/src/audio/AudioMixer.cpp | 1 - assignment-client/src/audio/AudioMixerClientData.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d997c3504b..2f2b424948 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -103,7 +103,6 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : ); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); - } void AudioMixer::queueAudioPacket(QSharedPointer message, SharedNodePointer node) { diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 8ee7f9f383..6ef795f57b 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -127,7 +127,7 @@ void AudioMixerClientData::replicatePacket(ReceivedMessage& message) { } // construct an NLPacket to send to the replicant that has the contents of the received packet - auto packet = NLPacket::create(mirroredType, message.getSize() + NUM_BYTES_RFC4122_UUID); + auto packet = NLPacket::create(mirroredType); // since this packet will be non-sourced, we add the replicated node's ID here packet->write(message.getSourceID().toRfc4122()); From 88af8b584252996a218014f82a946c8e61e34709 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 12:56:15 -0700 Subject: [PATCH 042/157] use new downstream/upstream nomeclature --- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/audio/AudioMixerClientData.cpp | 4 ++-- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/Node.cpp | 5 ++--- libraries/networking/src/NodeList.cpp | 2 +- libraries/networking/src/NodeType.h | 5 ++--- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 2f2b424948..9fb0a96382 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -119,7 +119,7 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - auto node = nodeList->addOrUpdateNode(nodeID, NodeType::ReplicatedAgent, + auto node = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, message->getSenderSockAddr(), message->getSenderSockAddr(), DEFAULT_AGENT_PERMISSIONS, true); node->setIsUpstream(true); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 6ef795f57b..b95ca5b616 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -74,7 +74,7 @@ void AudioMixerClientData::processPackets() { case PacketType::ReplicatedInjectAudio: case PacketType::ReplicatedSilentAudioFrame: { - if (node->getType() == NodeType::ReplicatedAgent && !_codec) { + if (node->isUpstream() && !_codec) { setupCodecForReplicatedAgent(packet); } @@ -140,7 +140,7 @@ void AudioMixerClientData::replicatePacket(ReceivedMessage& message) { // enumerate the replicant audio mixers and send them the replicated version of this packet nodeList->eachMatchingNode([&](const SharedNodePointer& node)->bool { - return node->getType() == NodeType::ReplicantAudioMixer; + return node->getType() == NodeType::DownstreamAudioMixer; }, [&](const SharedNodePointer& node) { nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); }); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index afb0dce8af..7ca991667e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -744,7 +744,7 @@ void LimitedNodeList::removeSilentNodes() { SharedNodePointer node = it->second; node->getMutex().lock(); - if (node->getType() != NodeType::ReplicantAudioMixer && node->getType() != NodeType::ReplicantAvatarMixer + if (node->getType() != NodeType::DownstreamAudioMixer && node->getType() != NodeType::DownstreamAvatarMixer && (usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) { // call the NodeHash erase to get rid of this node it = _nodeHash.unsafe_erase(it); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index a6b6bc18b2..9331487db9 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -42,9 +42,8 @@ void NodeType::init() { TypeNameHash.insert(NodeType::MessagesMixer, "Messages Mixer"); TypeNameHash.insert(NodeType::AssetServer, "Asset Server"); TypeNameHash.insert(NodeType::EntityScriptServer, "Entity Script Server"); - TypeNameHash.insert(NodeType::ReplicantAudioMixer, "Replicant Audio Mixer"); - TypeNameHash.insert(NodeType::ReplicantAvatarMixer, "Replicant Avatar Mixer"); - TypeNameHash.insert(NodeType::ReplicatedAgent, "Replicated Agent"); + TypeNameHash.insert(NodeType::DownstreamAudioMixer, "Downstream Audio Mixer"); + TypeNameHash.insert(NodeType::DownstreamAvatarMixer, "Downstream Avatar Mixer"); TypeNameHash.insert(NodeType::Unassigned, "Unassigned"); } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 5e06ad2b5c..ddd2137422 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -714,7 +714,7 @@ void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { void NodeList::startNodeHolePunch(const SharedNodePointer& node) { // we don't hole punch to replicants, since it is assumed that we have a direct line to them - if (node->getType() != NodeType::ReplicantAudioMixer && node->getType() != NodeType::ReplicantAvatarMixer) { + if (node->getType() != NodeType::DownstreamAudioMixer && node->getType() != NodeType::DownstreamAvatarMixer) { // connect to the correct signal on this node so we know when to ping it connect(node.data(), &Node::pingTimerTimeout, this, &NodeList::handleNodePingTimeout); diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index 7c327e08f7..7f0d5f0636 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -25,9 +25,8 @@ namespace NodeType { const NodeType_t AssetServer = 'A'; const NodeType_t MessagesMixer = 'm'; const NodeType_t EntityScriptServer = 'S'; - const NodeType_t ReplicantAudioMixer = 'a'; - const NodeType_t ReplicantAvatarMixer = 'w'; - const NodeType_t ReplicatedAgent = 'z'; + const NodeType_t DownstreamAudioMixer = 'a'; + const NodeType_t DownstreamAvatarMixer = 'w'; const NodeType_t Unassigned = 1; void init(); From 91c25d4270646862b186d34b464eff76d17cd00e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 13:15:02 -0700 Subject: [PATCH 043/157] don't continously set codec for upstream agent --- assignment-client/src/audio/AudioMixerClientData.cpp | 7 +++++-- assignment-client/src/audio/AudioMixerClientData.h | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index b95ca5b616..082ac364be 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -74,7 +74,7 @@ void AudioMixerClientData::processPackets() { case PacketType::ReplicatedInjectAudio: case PacketType::ReplicatedSilentAudioFrame: { - if (node->isUpstream() && !_codec) { + if (node->isUpstream() && !_hasSetupCodecForUpstreamNode) { setupCodecForReplicatedAgent(packet); } @@ -261,7 +261,8 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { avatarAudioStream->setupCodec(_codec, _selectedCodecName, AudioConstants::MONO); qDebug() << "creating new AvatarAudioStream... codec:" << _selectedCodecName; - connect(avatarAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioMixerClientData::handleMismatchAudioFormat); + connect(avatarAudioStream, &InboundAudioStream::mismatchedAudioCodec, + this, &AudioMixerClientData::handleMismatchAudioFormat); auto emplaced = _audioStreams.emplace( QUuid(), @@ -684,4 +685,6 @@ void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointer codec = AudioMixer::negotiateCodec({ codecString }); setupCodec(codec.second, codec.first); + + _hasSetupCodecForUpstreamNode = true; } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 72761e64f2..0f9e4c4c18 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -185,6 +185,8 @@ private: bool _shouldMuteClient { false }; bool _requestsDomainListData { false }; + + bool _hasSetupCodecForUpstreamNode { false }; }; #endif // hifi_AudioMixerClientData_h From 7ed9483467083190f715e8b348b1017f3cef563e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 13:57:55 -0700 Subject: [PATCH 044/157] use blocking queued for addOrUpdateNode because of parenting --- assignment-client/src/audio/AudioMixer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9fb0a96382..1e93d0515c 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -119,13 +119,13 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - auto node = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, - message->getSenderSockAddr(), message->getSenderSockAddr(), - DEFAULT_AGENT_PERMISSIONS, true); - node->setIsUpstream(true); - node->setLastHeardMicrostamp(usecTimestampNow()); + auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, + message->getSenderSockAddr(), message->getSenderSockAddr(), + DEFAULT_AGENT_PERMISSIONS, true); + replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); + replicatedNode->setIsUpstream(true); - getOrCreateClientData(node.data())->queuePacket(message, node); + getOrCreateClientData(replicatedNode.data())->queuePacket(message, replicatedNode); } void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer message, SharedNodePointer sendingNode) { From 1868971cfc4c66f40993676c7793ef5c69fc2667 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 14:46:53 -0700 Subject: [PATCH 045/157] fix debug for manual codec in upstream agents --- assignment-client/src/audio/AudioMixerClientData.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 082ac364be..44c51c4ae2 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -681,7 +681,8 @@ void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointerreadString(); - qDebug() << "Manually setting codec for replicated agent" << codecString; + qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID()) + << "-" << codecString; const std::pair codec = AudioMixer::negotiateCodec({ codecString }); setupCodec(codec.second, codec.first); From 03a8d7b8c849547ed7f3be7dc5ecef4437da5d46 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 14:56:28 -0700 Subject: [PATCH 046/157] only replicate packets for agents being replicated --- .../src/audio/AudioMixerClientData.cpp | 77 +++++++++++-------- .../src/audio/AudioMixerClientData.h | 2 +- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 44c51c4ae2..359c7e1b9e 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -80,8 +80,8 @@ void AudioMixerClientData::processPackets() { QMutexLocker lock(&getMutex()); parseData(*packet); - - replicatePacket(*packet); + + optionallyReplicatePacket(*packet, *node); break; } @@ -109,41 +109,52 @@ void AudioMixerClientData::processPackets() { assert(_packetQueue.empty()); } -void AudioMixerClientData::replicatePacket(ReceivedMessage& message) { - auto nodeList = DependencyManager::get(); +void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, const Node& node) { - PacketType mirroredType; + // first, make sure that this is a packet from a node we are supposed to replicate + if (node.isReplicated()) { + auto nodeList = DependencyManager::get(); - if (message.getType() == PacketType::MicrophoneAudioNoEcho) { - mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; - } else if (message.getType() == PacketType::MicrophoneAudioWithEcho) { - mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; - } else if (message.getType() == PacketType::InjectAudio) { - mirroredType = PacketType::ReplicatedInjectAudio; - } else if (message.getType() == PacketType::SilentAudioFrame) { - mirroredType = PacketType::ReplicatedSilentAudioFrame; - } else { - return; + // now make sure it's a packet type that we want to replicate + PacketType mirroredType; + + if (message.getType() == PacketType::MicrophoneAudioNoEcho) { + mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; + } else if (message.getType() == PacketType::MicrophoneAudioWithEcho) { + mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; + } else if (message.getType() == PacketType::InjectAudio) { + mirroredType = PacketType::ReplicatedInjectAudio; + } else if (message.getType() == PacketType::SilentAudioFrame) { + mirroredType = PacketType::ReplicatedSilentAudioFrame; + } else { + return; + } + + std::unique_ptr packet; + + // enumerate the replicant audio mixers and send them the replicated version of this packet + nodeList->eachMatchingNode([&](const SharedNodePointer& node)->bool { + return node->getType() == NodeType::DownstreamAudioMixer; + }, [&](const SharedNodePointer& node) { + // construct the packet only once, if we have any downstream audio mixers to send to + if (!packet) { + // construct an NLPacket to send to the replicant that has the contents of the received packet + packet = NLPacket::create(mirroredType); + + // since this packet will be non-sourced, we add the replicated node's ID here + packet->write(message.getSourceID().toRfc4122()); + + // we won't negotiate an audio format with the replicant, because we aren't a listener + // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs + packet->writeString(_selectedCodecName); + + packet->write(message.getMessage()); + } + + nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); + }); } - // construct an NLPacket to send to the replicant that has the contents of the received packet - auto packet = NLPacket::create(mirroredType); - - // since this packet will be non-sourced, we add the replicated node's ID here - packet->write(message.getSourceID().toRfc4122()); - - // we won't negotiate an audio format with the replicant, because we aren't a listener - // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs - packet->writeString(_selectedCodecName); - - packet->write(message.getMessage()); - - // enumerate the replicant audio mixers and send them the replicated version of this packet - nodeList->eachMatchingNode([&](const SharedNodePointer& node)->bool { - return node->getType() == NodeType::DownstreamAudioMixer; - }, [&](const SharedNodePointer& node) { - nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); - }); } void AudioMixerClientData::negotiateAudioFormat(ReceivedMessage& message, const SharedNodePointer& node) { diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 0f9e4c4c18..b397ab0b8e 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -126,7 +126,7 @@ private: QReadWriteLock _streamsLock; AudioStreamMap _audioStreams; // microphone stream from avatar is stored under key of null UUID - void replicatePacket(ReceivedMessage& packet); + void optionallyReplicatePacket(ReceivedMessage& packet, const Node& node); using IgnoreZone = AABox; class IgnoreZoneMemo { From 4042e0494644cd443ce8c2adca02df0ee3cf6c9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 15:32:09 -0700 Subject: [PATCH 047/157] add isDownstream for cleaner conditionals --- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/Node.cpp | 4 ++++ libraries/networking/src/NodeList.cpp | 2 +- libraries/networking/src/NodeType.h | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 7ca991667e..09300cd919 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -744,7 +744,7 @@ void LimitedNodeList::removeSilentNodes() { SharedNodePointer node = it->second; node->getMutex().lock(); - if (node->getType() != NodeType::DownstreamAudioMixer && node->getType() != NodeType::DownstreamAvatarMixer + if (!NodeType::isDownstream(node->getType()) && (usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) { // call the NodeHash erase to get rid of this node it = _nodeHash.unsafe_erase(it); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 9331487db9..26e75f36f5 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -52,6 +52,10 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { return matchedTypeName != TypeNameHash.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME; } +bool NodeType::isDownstream(NodeType_t nodeType) { + return nodeType == NodeType::DownstreamAudioMixer || nodeType == NodeType::DownstreamAvatarMixer; +} + Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions, bool isReplicated, const QUuid& connectionSecret, QObject* parent) : diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index ddd2137422..38d8c79251 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -714,7 +714,7 @@ void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { void NodeList::startNodeHolePunch(const SharedNodePointer& node) { // we don't hole punch to replicants, since it is assumed that we have a direct line to them - if (node->getType() != NodeType::DownstreamAudioMixer && node->getType() != NodeType::DownstreamAvatarMixer) { + if (!NodeType::isDownstream(node->getType())) { // connect to the correct signal on this node so we know when to ping it connect(node.data(), &Node::pingTimerTimeout, this, &NodeList::handleNodePingTimeout); diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index 7f0d5f0636..ef0aa78357 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -31,6 +31,7 @@ namespace NodeType { void init(); const QString& getNodeTypeName(NodeType_t nodeType); + bool isDownstream(NodeType_t nodeType); } typedef QSet NodeSet; From 9fa97d611a7b89c775fe3713cf6b0c3b8fac4098 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 15:36:46 -0700 Subject: [PATCH 048/157] remove invoked addOrUpdate and move node to node list thread --- assignment-client/src/audio/AudioMixer.cpp | 5 +++++ libraries/networking/src/LimitedNodeList.cpp | 3 +++ 2 files changed, 8 insertions(+) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 1e93d0515c..b4e06863db 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -120,8 +120,13 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, +<<<<<<< HEAD message->getSenderSockAddr(), message->getSenderSockAddr(), DEFAULT_AGENT_PERMISSIONS, true); +======= + message->getSenderSockAddr(), message->getSenderSockAddr()); + +>>>>>>> remove invoked addOrUpdate and move node to node list thread replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); replicatedNode->setIsUpstream(true); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 09300cd919..0494efc7b4 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -588,6 +588,9 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t // we didn't have this node, so add them Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, isReplicated, connectionSecret); + // move the newly constructed node to the LNL thread + newNode->moveToThread(thread()); + if (nodeType == NodeType::AudioMixer) { LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer); } From 4539d615d73df45c174c8dea5733ecc5ed751ca8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 15:41:34 -0700 Subject: [PATCH 049/157] add downstream server settings handling to ThreadedAssignment --- assignment-client/src/audio/AudioMixer.cpp | 9 ++--- libraries/networking/src/Node.cpp | 11 ++++++ libraries/networking/src/Node.h | 1 + libraries/networking/src/NodeType.h | 2 ++ .../networking/src/ThreadedAssignment.cpp | 35 +++++++++++++++++++ libraries/networking/src/ThreadedAssignment.h | 2 ++ 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index b4e06863db..f8c2cf86e8 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -120,13 +120,8 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, -<<<<<<< HEAD message->getSenderSockAddr(), message->getSenderSockAddr(), DEFAULT_AGENT_PERMISSIONS, true); -======= - message->getSenderSockAddr(), message->getSenderSockAddr()); - ->>>>>>> remove invoked addOrUpdate and move node to node list thread replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); replicatedNode->setIsUpstream(true); @@ -536,7 +531,7 @@ void AudioMixer::clearDomainSettings() { _zoneReverbSettings.clear(); } -void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { +void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { qDebug() << "AVX2 Support:" << (cpuSupportsAVX2() ? "enabled" : "disabled"); if (settingsObject.contains(AUDIO_THREADING_GROUP_KEY)) { @@ -754,6 +749,8 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { } } } + + parseDownstreamServers(settingsObject, NodeType::AudioMixer); } AudioMixer::Timer::Timing::Timing(uint64_t& sum) : _sum(sum) { diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 26e75f36f5..3435843814 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -56,6 +56,17 @@ bool NodeType::isDownstream(NodeType_t nodeType) { return nodeType == NodeType::DownstreamAudioMixer || nodeType == NodeType::DownstreamAvatarMixer; } +NodeType_t NodeType::downstreamType(NodeType_t primaryType) { + switch (primaryType) { + case AudioMixer: + return DownstreamAudioMixer; + case AvatarMixer: + return DownstreamAvatarMixer; + default: + return Unassigned; + } +} + Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions, bool isReplicated, const QUuid& connectionSecret, QObject* parent) : diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index c905c9d551..fd2cf6b65b 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -37,6 +37,7 @@ class Node : public NetworkPeer { Q_OBJECT public: + Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const NodePermissions& permissions, bool isReplicated, const QUuid& connectionSecret = QUuid(), diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index ef0aa78357..12e74603ef 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -30,8 +30,10 @@ namespace NodeType { const NodeType_t Unassigned = 1; void init(); + const QString& getNodeTypeName(NodeType_t nodeType); bool isDownstream(NodeType_t nodeType); + NodeType_t downstreamType(NodeType_t primaryType); } typedef QSet NodeSet; diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 9db540cae2..12dc59beed 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include #include @@ -132,3 +133,37 @@ void ThreadedAssignment::domainSettingsRequestFailed() { qCDebug(networking) << "Failed to retreive settings object from domain-server. Bailing on assignment."; setFinished(true); } + +void ThreadedAssignment::parseDownstreamServers(const QJsonObject& settingsObject, NodeType_t nodeType) { + static const QString REPLICATION_GROUP_KEY = "replication"; + static const QString DOWNSTREAM_SERVERS_SETTING_KEY = "downstream_servers"; + if (settingsObject.contains(REPLICATION_GROUP_KEY)) { + const QJsonObject replicationObject = settingsObject[REPLICATION_GROUP_KEY].toObject(); + + const QJsonArray downstreamServers = replicationObject[DOWNSTREAM_SERVERS_SETTING_KEY].toArray(); + + auto nodeList = DependencyManager::get(); + + foreach(const QJsonValue& downstreamServerValue, downstreamServers) { + const QJsonArray downstreamServer = downstreamServerValue.toArray(); + + // make sure we have the number of values we need + if (downstreamServer.size() >= 3) { + // make sure this is a downstream server that matches our type + if (downstreamServer[2].toString() == NodeType::getNodeTypeName(nodeType)) { + // read the address and port and construct a HifiSockAddr from them + HifiSockAddr downstreamServerAddr { + downstreamServer[0].toString(), + static_cast(downstreamServer[1].toInt()) + }; + + // manually add the downstream node to our node list + nodeList->addOrUpdateNode(QUuid::createUuid(), NodeType::downstreamType(nodeType), + downstreamServerAddr, downstreamServerAddr); + + } + } + + } + } +} diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index e9832a2a91..f96755a776 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -40,6 +40,8 @@ signals: protected: void commonInit(const QString& targetName, NodeType_t nodeType); + void parseDownstreamServers(const QJsonObject& settingsObject, NodeType_t nodeType); + bool _isFinished; QTimer _domainServerTimer; QTimer _statsTimer; From 4688fe4c394fb7c734a28cda3e68b65391010a3f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 15:54:09 -0700 Subject: [PATCH 050/157] fix comment for change from replicant to downstream --- assignment-client/src/audio/AudioMixerClientData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 359c7e1b9e..de7bdbc780 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -132,7 +132,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c std::unique_ptr packet; - // enumerate the replicant audio mixers and send them the replicated version of this packet + // enumerate the downstream audio mixers and send them the replicated version of this packet nodeList->eachMatchingNode([&](const SharedNodePointer& node)->bool { return node->getType() == NodeType::DownstreamAudioMixer; }, [&](const SharedNodePointer& node) { From 880157695a708671b44cccd3e32df09f9cd0079a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 16:18:15 -0700 Subject: [PATCH 051/157] do not attempt to hole punch an upstream node --- libraries/networking/src/NodeList.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 38d8c79251..06548499e8 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -713,8 +713,10 @@ void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { void NodeList::startNodeHolePunch(const SharedNodePointer& node) { - // we don't hole punch to replicants, since it is assumed that we have a direct line to them - if (!NodeType::isDownstream(node->getType())) { + // we don't hole punch to downstream servers, since it is assumed that we have a direct line to them + // we also don't hole punch to relayed upstream nodes, since we do not communicate directly with them + + if (!NodeType::isDownstream(node->getType()) && !node->isUpstream()) { // connect to the correct signal on this node so we know when to ping it connect(node.data(), &Node::pingTimerTimeout, this, &NodeList::handleNodePingTimeout); From 63c8273a4164cb8c57fc408ee0027abcb0537655 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 16:23:57 -0700 Subject: [PATCH 052/157] do not send keep alive pings to upstream nodes --- libraries/networking/src/NodeList.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 06548499e8..73c405e3aa 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -768,8 +768,10 @@ void NodeList::stopKeepalivePingTimer() { } void NodeList::sendKeepAlivePings() { + // send keep-alive ping packets to nodes of types we care about that are not relayed to us from an upstream node + eachMatchingNode([this](const SharedNodePointer& node)->bool { - return _nodeTypesOfInterest.contains(node->getType()); + return !node->isUpstream() && _nodeTypesOfInterest.contains(node->getType()); }, [&](const SharedNodePointer& node) { sendPacket(constructPingPacket(), *node); }); From f9f9aeac0116b43617a4d5527abefea767bdca29 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 13 Jun 2017 00:29:45 +0100 Subject: [PATCH 053/157] saving work --- plugins/openvr/src/ViveControllerManager.cpp | 105 +++++++++---------- plugins/openvr/src/ViveControllerManager.h | 11 +- 2 files changed, 55 insertions(+), 61 deletions(-) diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 9e723d2a10..23b8e72963 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -222,7 +222,7 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) { - _configStringMap[Config::Auto] = QString("Auto"); + _configStringMap[Config::None] = QString("None"); _configStringMap[Config::Feet] = QString("Feet"); _configStringMap[Config::FeetAndHips] = QString("FeetAndHips"); _configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest"); @@ -425,49 +425,17 @@ void ViveControllerManager::InputDevice::calibrateOrUncalibrate(const controller void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibrationData& inputCalibration) { qDebug() << "Puck Calibration: Starting..."; - // convert the hmd head from sensor space to avatar space - glm::mat4 hmdSensorFlippedMat = inputCalibration.hmdSensorMat * Matrices::Y_180; - glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat; - glm::mat4 hmdAvatarMat = sensorToAvatarMat * hmdSensorFlippedMat; - // cancel the roll and pitch for the hmd head - glm::quat hmdRotation = cancelOutRollAndPitch(glmExtractRotation(hmdAvatarMat)); - glm::vec3 hmdTranslation = extractTranslation(hmdAvatarMat); - glm::mat4 currentHmd = createMatFromQuatAndPos(hmdRotation, hmdTranslation); - - // calculate the offset from the centerOfEye to defaultHeadMat - glm::mat4 defaultHeadOffset = glm::inverse(inputCalibration.defaultCenterEyeMat) * inputCalibration.defaultHeadMat; - - glm::mat4 currentHead = currentHmd * defaultHeadOffset; - - // calculate the defaultToRefrenceXform - glm::mat4 defaultToReferenceMat = currentHead * glm::inverse(inputCalibration.defaultHeadMat); + glm::mat4 defaultToReferenceMat = glm::mat4(); + if (_headConfig == HeadConfig::HMD) { + defaultToReferenceMat = calculateDefaultToReferenceForHmd(inputCalibration); + } else if (_headConfig == HeadConfig::Puck) { + defaultToReferenceMat = calculateDefaultToReferenceForHeadPuck(inputCalibration); + } int puckCount = (int)_validTrackedObjects.size(); qDebug() << "Puck Calibration: " << puckCount << " pucks found for calibration"; _config = _preferedConfig; - if (_config != Config::Auto && puckCount < MIN_PUCK_COUNT) { - qDebug() << "Puck Calibration: Failed: Could not meet the minimal # of pucks"; - uncalibrate(); - emitCalibrationStatus(false); - return; - } else if (_config == Config::Auto){ - if (puckCount == MIN_PUCK_COUNT) { - _config = Config::Feet; - qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration"; - } else if (puckCount == MIN_FEET_AND_HIPS) { - _config = Config::FeetAndHips; - qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration"; - } else if (puckCount >= MIN_FEET_HIPS_CHEST) { - _config = Config::FeetHipsAndChest; - qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration"; - } else { - qDebug() << "Puck Calibration: Auto Config Failed: Could not meet the minimal # of pucks"; - uncalibrate(); - emitCalibrationStatus(false); - return; - } - } std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition); @@ -487,21 +455,19 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr int secondShoulderIndex = 4; calibrateShoulders(defaultToReferenceMat, inputCalibration, firstShoulderIndex, secondShoulderIndex); } else if (_config == Config::FeetHipsAndHead && puckCount == MIN_FEET_HIPS_HEAD) { - glm::mat4 headPuckDefaultToReferenceMat = recalculateDefaultToReferenceForHeadPuck(inputCalibration); - glm::vec3 headXAxis = getReferenceHeadXAxis(headPuckDefaultToReferenceMat, inputCalibration.defaultHeadMat); - glm::vec3 headPosition = getReferenceHeadPosition(headPuckDefaultToReferenceMat, inputCalibration.defaultHeadMat); - calibrateFeet(headPuckDefaultToReferenceMat, inputCalibration, headXAxis, headPosition); - calibrateHips(headPuckDefaultToReferenceMat, inputCalibration); - calibrateHead(headPuckDefaultToReferenceMat, inputCalibration); + glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); + glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); + calibrateFeet(defaultToReferenceMat, inputCalibration, headXAxis, headPosition); + calibrateHips(defaultToReferenceMat, inputCalibration); + calibrateHead(defaultToReferenceMat, inputCalibration); _overrideHead = true; } else if (_config == Config::FeetHipsChestAndHead && puckCount == MIN_FEET_HIPS_CHEST_HEAD) { - glm::mat4 headPuckDefaultToReferenceMat = recalculateDefaultToReferenceForHeadPuck(inputCalibration); - glm::vec3 headXAxis = getReferenceHeadXAxis(headPuckDefaultToReferenceMat, inputCalibration.defaultHeadMat); - glm::vec3 headPosition = getReferenceHeadPosition(headPuckDefaultToReferenceMat, inputCalibration.defaultHeadMat); - calibrateFeet(headPuckDefaultToReferenceMat, inputCalibration, headXAxis, headPosition); - calibrateHips(headPuckDefaultToReferenceMat, inputCalibration); - calibrateChest(headPuckDefaultToReferenceMat, inputCalibration); - calibrateHead(headPuckDefaultToReferenceMat, inputCalibration); + glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); + glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); + calibrateFeet(defaultToReferenceMat, inputCalibration, headXAxis, headPosition); + calibrateHips(defaultToReferenceMat, inputCalibration); + calibrateChest(defaultToReferenceMat, inputCalibration); + calibrateHead(defaultToReferenceMat, inputCalibration); _overrideHead = true; } else { qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks"; @@ -515,7 +481,7 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr } void ViveControllerManager::InputDevice::uncalibrate() { - _config = Config::Auto; + _config = Config::None; _pucksOffset.clear(); _jointToPuckMap.clear(); _calibrated = false; @@ -597,8 +563,29 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u } } } +glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHmd(const controller::InputCalibrationData& inputCalibration) { + // convert the hmd head from sensor space to avatar space + glm::mat4 hmdSensorFlippedMat = inputCalibration.hmdSensorMat * Matrices::Y_180; + glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat; + glm::mat4 hmdAvatarMat = sensorToAvatarMat * hmdSensorFlippedMat; -glm::mat4 ViveControllerManager::InputDevice::recalculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration) { + // cancel the roll and pitch for the hmd head + glm::quat hmdRotation = cancelOutRollAndPitch(glmExtractRotation(hmdAvatarMat)); + glm::vec3 hmdTranslation = extractTranslation(hmdAvatarMat); + glm::mat4 currentHmd = createMatFromQuatAndPos(hmdRotation, hmdTranslation); + + // calculate the offset from the centerOfEye to defaultHeadMat + glm::mat4 defaultHeadOffset = glm::inverse(inputCalibration.defaultCenterEyeMat) * inputCalibration.defaultHeadMat; + + glm::mat4 currentHead = currentHmd * defaultHeadOffset; + + // calculate the defaultToRefrenceXform + glm::mat4 defaultToReferenceMat = currentHead * glm::inverse(inputCalibration.defaultHeadMat); + + return defaultToReferenceMat; +} + +glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration) { glm::mat4 avatarToSensorMat = glm::inverse(inputCalibration.sensorToWorldMat) * inputCalibration.avatarMat; glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat; size_t headPuckIndex = _validTrackedObjects.size() - 1; @@ -847,6 +834,10 @@ void ViveControllerManager::InputDevice::calibrateHips(glm::mat4& defaultToRefer _pucksOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second); } + +void ViveControllerManager::InputDevice::calibrateHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, int firstHandIndex, int secondHandIndex) { +} + void ViveControllerManager::InputDevice::calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { _jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first; _pucksOffset[_validTrackedObjects[CHEST].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[CHEST].second); @@ -889,7 +880,7 @@ void ViveControllerManager::InputDevice::loadSettings() { Settings settings; settings.beginGroup("PUCK_CONFIG"); { - _preferedConfig = (Config)settings.value("configuration", QVariant((int)Config::Auto)).toInt(); + _preferedConfig = (Config)settings.value("configuration", QVariant((int)Config::None)).toInt(); } settings.endGroup(); } @@ -908,8 +899,8 @@ QString ViveControllerManager::InputDevice::configToString(Config config) { } void ViveControllerManager::InputDevice::setConfigFromString(const QString& value) { - if (value == "Auto") { - _preferedConfig = Config::Auto; + if (value == "None") { + _preferedConfig = Config::None; } else if (value == "Feet") { _preferedConfig = Config::Feet; } else if (value == "FeetAndHips") { diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 1bb662efbc..ea29d974e9 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -78,7 +78,8 @@ private: void configureCalibrationSettings(const QJsonObject configurationSettings); QJsonObject configurationSettings(); controller::Pose addOffsetToPuckPose(int joint) const; - glm::mat4 recalculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration); + glm::mat4 calculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration); + glm::mat4 calculateDefaultToReferenceForHmd(const controller::InputCalibrationData& inputCalibration); void updateCalibratedLimbs(); bool checkForCalibrationEvent(); void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand); @@ -102,6 +103,8 @@ private: void calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, int firstShoulderIndex, int secondShoulderIndex); + void calibrateHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, + int firstHandIndex, int secondHandIndex); void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData); void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData); @@ -133,7 +136,7 @@ private: glm::vec2 _stick { 0.0f, 0.0f }; }; enum class Config { - Auto, + None, Feet, FeetAndHips, FeetHipsAndChest, @@ -152,8 +155,8 @@ private: Pucks }; - Config _config { Config::Auto }; - Config _preferedConfig { Config::Auto }; + Config _config { Config::None }; + Config _preferedConfig { Config::None }; HeadConfig _headConfig { HeadConfig::HMD }; HandConfig _handConfig { HandConfig::HandController }; FilteredStick _filteredLeftStick; From e125e1f608230c3129530b77127ab50127dde49f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 13 Jun 2017 00:37:32 +0100 Subject: [PATCH 054/157] fix issue that caused jenkin to fail buiuling code --- plugins/hifiKinect/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hifiKinect/CMakeLists.txt b/plugins/hifiKinect/CMakeLists.txt index fc4c2f6f7c..a7088eb3b4 100644 --- a/plugins/hifiKinect/CMakeLists.txt +++ b/plugins/hifiKinect/CMakeLists.txt @@ -11,7 +11,7 @@ if (WIN32) if (KINECT_FOUND) set(TARGET_NAME hifiKinect) setup_hifi_plugin(Script Qml Widgets) - link_hifi_libraries(shared controllers ui plugins input-plugins) + link_hifi_libraries(shared controllers ui plugins input-plugins display-plugins) # need to setup appropriate externals... target_kinect() From 682fa247450fe00bcd8130c3531433fee5916ad0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 16:51:25 -0700 Subject: [PATCH 055/157] fix downstream server parsing from settings --- .../networking/src/ThreadedAssignment.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 12dc59beed..5aeb076c11 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -145,25 +145,25 @@ void ThreadedAssignment::parseDownstreamServers(const QJsonObject& settingsObjec auto nodeList = DependencyManager::get(); foreach(const QJsonValue& downstreamServerValue, downstreamServers) { - const QJsonArray downstreamServer = downstreamServerValue.toArray(); + const QJsonObject downstreamServer = downstreamServerValue.toObject(); - // make sure we have the number of values we need - if (downstreamServer.size() >= 3) { - // make sure this is a downstream server that matches our type - if (downstreamServer[2].toString() == NodeType::getNodeTypeName(nodeType)) { - // read the address and port and construct a HifiSockAddr from them - HifiSockAddr downstreamServerAddr { - downstreamServer[0].toString(), - static_cast(downstreamServer[1].toInt()) - }; + static const QString DOWNSTREAM_SERVER_ADDRESS = "address"; + static const QString DOWNSTREAM_SERVER_PORT = "port"; + static const QString DOWNSTREAM_SERVER_TYPE = "server_type"; - // manually add the downstream node to our node list - nodeList->addOrUpdateNode(QUuid::createUuid(), NodeType::downstreamType(nodeType), - downstreamServerAddr, downstreamServerAddr); + // make sure we have the settings we need for this downstream server + if (downstreamServer.contains(DOWNSTREAM_SERVER_ADDRESS) && downstreamServer.contains(DOWNSTREAM_SERVER_PORT) + && downstreamServer[DOWNSTREAM_SERVER_TYPE].toString() == NodeType::getNodeTypeName(nodeType)) { + // read the address and port and construct a HifiSockAddr from them + HifiSockAddr downstreamServerAddr { + downstreamServer[DOWNSTREAM_SERVER_ADDRESS].toString(), + (quint16) downstreamServer[DOWNSTREAM_SERVER_PORT].toString().toInt() + }; - } + // manually add the downstream node to our node list + nodeList->addOrUpdateNode(QUuid::createUuid(), NodeType::downstreamType(nodeType), + downstreamServerAddr, downstreamServerAddr); } - } } } From 30d2e9fd237f7833efd63c78f0b4a766c36fc158 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 17:51:54 -0700 Subject: [PATCH 056/157] add unsafeEachNode to iterate nodes when read lock held elsewhere --- .../src/audio/AudioMixerClientData.cpp | 31 ++++++++++--------- libraries/networking/src/LimitedNodeList.h | 10 ++++++ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index de7bdbc780..c51f240b54 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -113,6 +113,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c // first, make sure that this is a packet from a node we are supposed to replicate if (node.isReplicated()) { + auto nodeList = DependencyManager::get(); // now make sure it's a packet type that we want to replicate @@ -133,25 +134,25 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c std::unique_ptr packet; // enumerate the downstream audio mixers and send them the replicated version of this packet - nodeList->eachMatchingNode([&](const SharedNodePointer& node)->bool { - return node->getType() == NodeType::DownstreamAudioMixer; - }, [&](const SharedNodePointer& node) { - // construct the packet only once, if we have any downstream audio mixers to send to - if (!packet) { - // construct an NLPacket to send to the replicant that has the contents of the received packet - packet = NLPacket::create(mirroredType); + nodeList->unsafeEachNode([&](const SharedNodePointer& node) { + if (node->getType() == NodeType::DownstreamAudioMixer) { + // construct the packet only once, if we have any downstream audio mixers to send to + if (!packet) { + // construct an NLPacket to send to the replicant that has the contents of the received packet + packet = NLPacket::create(mirroredType); - // since this packet will be non-sourced, we add the replicated node's ID here - packet->write(message.getSourceID().toRfc4122()); + // since this packet will be non-sourced, we add the replicated node's ID here + packet->write(message.getSourceID().toRfc4122()); - // we won't negotiate an audio format with the replicant, because we aren't a listener - // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs - packet->writeString(_selectedCodecName); + // we won't negotiate an audio format with the replicant, because we aren't a listener + // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs + packet->writeString(_selectedCodecName); + + packet->write(message.getMessage()); + } - packet->write(message.getMessage()); + nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); } - - nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); }); } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 1ace6b2e23..5e2c88ed94 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -257,6 +257,16 @@ public: return SharedNodePointer(); } + // This is unsafe because it does not take a lock + // Must only be called when you know that a read lock on the node mutex is held + // and will be held for the duration of your iteration + template + void unsafeEachNode(NodeLambda functor) { + for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) { + functor(it->second); + } + } + void putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort); bool getLocalServerPortFromSharedMemory(const QString key, quint16& localPort); From ab3a0ddba2b7c9a8ee04a5163dcbd63255dd3a48 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 12 Jun 2017 19:49:02 -0700 Subject: [PATCH 057/157] don't emit codec mismatch upstream, handle replicated silent frames --- libraries/audio/src/InboundAudioStream.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 88ec7e7bc0..65cccf1fe0 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -147,7 +147,8 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { } case SequenceNumberStats::OnTime: { // Packet is on time; parse its data to the ringbuffer - if (message.getType() == PacketType::SilentAudioFrame) { + if (message.getType() == PacketType::SilentAudioFrame + || message.getType() == PacketType::ReplicatedSilentAudioFrame) { // If we recieved a SilentAudioFrame from our sender, we might want to drop // some of the samples in order to catch up to our desired jitter buffer size. writeDroppableSilentFrames(networkFrames); @@ -168,7 +169,10 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { // inform others of the mismatch auto sendingNode = DependencyManager::get()->nodeWithUUID(message.getSourceID()); - emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket); + if (sendingNode) { + emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket); + } + } } break; From aa9574fc5a0316e0ca06e86d65cac0539ccdcd07 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 09:46:12 -0700 Subject: [PATCH 058/157] add re-replication support to audio mixer --- .../src/audio/AudioMixerClientData.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index c51f240b54..d0e749563a 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -119,6 +119,23 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c // now make sure it's a packet type that we want to replicate PacketType mirroredType; + switch (message.getType()) { + case PacketType::MicrophoneAudioNoEcho: + case PacketType::ReplicatedMicrophoneAudioNoEcho: + mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; + case PacketType::MicrophoneAudioWithEcho: + case PacketType::ReplicatedMicrophoneAudioWithEcho: + mirroredType = PacketType::ReplicatedMicrophoneAudioWithEcho; + case PacketType::InjectAudio: + case PacketType::ReplicatedInjectAudio: + mirroredType = PacketType::ReplicatedInjectAudio; + case PacketType::SilentAudioFrame: + case PacketType::ReplicatedSilentAudioFrame: + mirroredType = PacketType::ReplicatedSilentAudioFrame; + default: + return; + } + if (message.getType() == PacketType::MicrophoneAudioNoEcho) { mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; } else if (message.getType() == PacketType::MicrophoneAudioWithEcho) { @@ -142,7 +159,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c packet = NLPacket::create(mirroredType); // since this packet will be non-sourced, we add the replicated node's ID here - packet->write(message.getSourceID().toRfc4122()); + packet->write(node->getUUID().toRfc4122()); // we won't negotiate an audio format with the replicant, because we aren't a listener // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs From eca35ce01300d0b55a010bf529a5e66211274bda Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 11:18:59 -0700 Subject: [PATCH 059/157] fix double check for packet types --- .../src/audio/AudioMixerClientData.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index d0e749563a..e7b45b2d4e 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -123,31 +123,23 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c case PacketType::MicrophoneAudioNoEcho: case PacketType::ReplicatedMicrophoneAudioNoEcho: mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; + break; case PacketType::MicrophoneAudioWithEcho: case PacketType::ReplicatedMicrophoneAudioWithEcho: mirroredType = PacketType::ReplicatedMicrophoneAudioWithEcho; + break; case PacketType::InjectAudio: case PacketType::ReplicatedInjectAudio: mirroredType = PacketType::ReplicatedInjectAudio; + break; case PacketType::SilentAudioFrame: case PacketType::ReplicatedSilentAudioFrame: mirroredType = PacketType::ReplicatedSilentAudioFrame; + break; default: return; } - if (message.getType() == PacketType::MicrophoneAudioNoEcho) { - mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; - } else if (message.getType() == PacketType::MicrophoneAudioWithEcho) { - mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; - } else if (message.getType() == PacketType::InjectAudio) { - mirroredType = PacketType::ReplicatedInjectAudio; - } else if (message.getType() == PacketType::SilentAudioFrame) { - mirroredType = PacketType::ReplicatedSilentAudioFrame; - } else { - return; - } - std::unique_ptr packet; // enumerate the downstream audio mixers and send them the replicated version of this packet From c1bbb2a084d4f4aa11764ee1f8b4471d85c8e3bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 11:24:05 -0700 Subject: [PATCH 060/157] fix incorrect UUID in replicated packets --- assignment-client/src/audio/AudioMixerClientData.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index e7b45b2d4e..3942c3177b 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -143,15 +143,15 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c std::unique_ptr packet; // enumerate the downstream audio mixers and send them the replicated version of this packet - nodeList->unsafeEachNode([&](const SharedNodePointer& node) { - if (node->getType() == NodeType::DownstreamAudioMixer) { + nodeList->unsafeEachNode([&](const SharedNodePointer& downstreamNode) { + if (downstreamNode->getType() == NodeType::DownstreamAudioMixer) { // construct the packet only once, if we have any downstream audio mixers to send to if (!packet) { // construct an NLPacket to send to the replicant that has the contents of the received packet packet = NLPacket::create(mirroredType); // since this packet will be non-sourced, we add the replicated node's ID here - packet->write(node->getUUID().toRfc4122()); + packet->write(node.getUUID().toRfc4122()); // we won't negotiate an audio format with the replicant, because we aren't a listener // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs @@ -160,7 +160,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c packet->write(message.getMessage()); } - nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); + nodeList->sendUnreliablePacket(*packet, downstreamNode->getPublicSocket()); } }); } From a877bf44fb5098e952de91f21975dddc7ad0cd1f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 13 Jun 2017 11:26:40 -0700 Subject: [PATCH 061/157] CR --- assignment-client/src/octree/OctreeInboundPacketProcessor.cpp | 2 +- assignment-client/src/octree/OctreeInboundPacketProcessor.h | 2 +- libraries/networking/src/ReceivedPacketProcessor.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index d2fef4dfbd..04409b3b21 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -47,7 +47,7 @@ void OctreeInboundPacketProcessor::resetStats() { _singleSenderStats.clear(); } -unsigned long OctreeInboundPacketProcessor::getMaxWait() const { +uint32_t OctreeInboundPacketProcessor::getMaxWait() const { // calculate time until next sendNackPackets() quint64 nextNackTime = _lastNackTime + TOO_LONG_SINCE_LAST_NACK; quint64 now = usecTimestampNow(); diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 4611fcada0..a7fa297d24 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -80,7 +80,7 @@ protected: virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode) override; - virtual unsigned long getMaxWait() const override; + virtual uint32_t getMaxWait() const override; virtual void preProcess() override; virtual void midProcess() override; diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index 5b54d4f309..f71abce1f1 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -20,7 +20,7 @@ class ReceivedPacketProcessor : public GenericThread { Q_OBJECT public: - static const unsigned long MAX_WAIT_TIME { 100 }; + static const uint64_t MAX_WAIT_TIME { 100 }; // Max wait time in ms ReceivedPacketProcessor(); @@ -66,7 +66,7 @@ protected: virtual bool process() override; /// Determines the timeout of the wait when there are no packets to process. Default value is 100ms to allow for regular event processing. - virtual unsigned long getMaxWait() const { return MAX_WAIT_TIME; } + virtual uint32_t getMaxWait() const { return MAX_WAIT_TIME; } /// Override to do work before the packets processing loop. Default does nothing. virtual void preProcess() { } From 3f3cc89b8d0a9408fc94fc2f0bb4e7ba978eae44 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 11:58:08 -0700 Subject: [PATCH 062/157] fix for header of re-replicated packets --- .../src/audio/AudioMixerClientData.cpp | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 3942c3177b..848dc969d8 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -109,6 +109,13 @@ void AudioMixerClientData::processPackets() { assert(_packetQueue.empty()); } +bool isReplicatedPacket(PacketType packetType) { + return packetType == PacketType::ReplicatedMicrophoneAudioNoEcho + || packetType == PacketType::ReplicatedMicrophoneAudioWithEcho + || packetType == PacketType::ReplicatedInjectAudio + || packetType == PacketType::ReplicatedSilentAudioFrame; +} + void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, const Node& node) { // first, make sure that this is a packet from a node we are supposed to replicate @@ -126,7 +133,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c break; case PacketType::MicrophoneAudioWithEcho: case PacketType::ReplicatedMicrophoneAudioWithEcho: - mirroredType = PacketType::ReplicatedMicrophoneAudioWithEcho; + mirroredType = PacketType::ReplicatedMicrophoneAudioWithEcho; break; case PacketType::InjectAudio: case PacketType::ReplicatedInjectAudio: @@ -150,12 +157,14 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c // construct an NLPacket to send to the replicant that has the contents of the received packet packet = NLPacket::create(mirroredType); - // since this packet will be non-sourced, we add the replicated node's ID here - packet->write(node.getUUID().toRfc4122()); + if (!isReplicatedPacket(message.getType())) { + // since this packet will be non-sourced, we add the replicated node's ID here + packet->write(node.getUUID().toRfc4122()); - // we won't negotiate an audio format with the replicant, because we aren't a listener - // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs - packet->writeString(_selectedCodecName); + // we won't negotiate an audio format with the replicant, because we aren't a listener + // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs + packet->writeString(_selectedCodecName); + } packet->write(message.getMessage()); } From ef9a211f6ee6d0f529e4ca19bcfbb408652375a9 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 13 Jun 2017 21:15:16 +0100 Subject: [PATCH 063/157] adding hand punck --- .../qml/hifi/tablet/OpenVrConfiguration.qml | 2 + plugins/openvr/src/ViveControllerManager.cpp | 172 +++++++++++++++--- plugins/openvr/src/ViveControllerManager.h | 9 +- 3 files changed, 157 insertions(+), 26 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 52c18ddff8..23af4fd93d 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -636,6 +636,8 @@ Rectangle { trackerConfiguration = "FeetAndHips"; } else if (feetChecked) { trackerConfiguration = "Feet"; + } else { + trackerConfiguration = "None"; } if (headPuck) { diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 23b8e72963..43f815c068 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -47,6 +47,7 @@ static const char* MENU_PARENT = "Avatar"; static const char* MENU_NAME = "Vive Controllers"; static const char* MENU_PATH = "Avatar" ">" "Vive Controllers"; static const char* RENDER_CONTROLLERS = "Render Hand Controllers"; +static const int MIN_HEAD = 1; static const int MIN_PUCK_COUNT = 2; static const int MIN_FEET_AND_HIPS = 3; static const int MIN_FEET_HIPS_CHEST = 4; @@ -84,7 +85,7 @@ static bool sortPucksXPosition(PuckPosePair firstPuck, PuckPosePair secondPuck) return (firstPuck.second.translation.x < secondPuck.second.translation.x); } -static bool determineFeetOrdering(const controller::Pose& poseA, const controller::Pose& poseB, glm::vec3 axis, glm::vec3 axisOrigin) { +static bool determineLimbOrdering(const controller::Pose& poseA, const controller::Pose& poseB, glm::vec3 axis, glm::vec3 axisOrigin) { glm::vec3 poseAPosition = poseA.getTranslation(); glm::vec3 poseBPosition = poseB.getTranslation(); @@ -222,13 +223,11 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) { - _configStringMap[Config::None] = QString("None"); - _configStringMap[Config::Feet] = QString("Feet"); - _configStringMap[Config::FeetAndHips] = QString("FeetAndHips"); - _configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest"); + _configStringMap[Config::None] = QString("None"); + _configStringMap[Config::Feet] = QString("Feet"); + _configStringMap[Config::FeetAndHips] = QString("FeetAndHips"); + _configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest"); _configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders"); - _configStringMap[Config::FeetHipsChestAndHead] = QString("FeetHipsChestAndHead"); - _configStringMap[Config::FeetHipsAndHead] = QString("FeetHipsAndHead"); if (openVrSupported()) { createPreferences(); @@ -436,31 +435,95 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr int puckCount = (int)_validTrackedObjects.size(); qDebug() << "Puck Calibration: " << puckCount << " pucks found for calibration"; _config = _preferedConfig; + + bool headConfigured = configureHead(defaultToReferenceMat, inputCalibration); + bool handsConfigured = configureHands(defaultToReferenceMat, inputCalibration); + bool bodyConfigured = configureBody(defaultToReferenceMat, inputCalibration); + if (!headConfigured || !handsConfigured || !bodyConfigured) { + uncalibrate(); + emitCalibrationStatus(false); + } else { + _calibrated = true; + emitCalibrationStatus(true); + qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful"; + } +} + +bool ViveControllerManager::InputDevice::configureHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { + std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksXPosition); + int puckCount = (int)_validTrackedObjects.size(); + if (_handConfig == HandConfig::Pucks && puckCount >= MIN_PUCK_COUNT) { + glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); + glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); + size_t FIRST_INDEX = 0; + size_t LAST_INDEX = _validTrackedObjects.size() -1; + auto& firstHand = _validTrackedObjects[FIRST_INDEX]; + auto& secondHand = _validTrackedObjects[LAST_INDEX]; + controller::Pose& firstHandPose = firstHand.second; + controller::Pose& secondHandPose = secondHand.second; + + if (determineLimbOrdering(firstHandPose, secondHandPose, headXAxis, headPosition)) { + calibrateLeftHand(defaultToReferenceMat, inputCalibration, firstHand); + calibrateRightHand(defaultToReferenceMat, inputCalibration, secondHand); + _overrideHands = true; + } else { + calibrateLeftHand(defaultToReferenceMat, inputCalibration, secondHand); + calibrateRightHand(defaultToReferenceMat, inputCalibration, firstHand); + _overrideHands = true; + } + } else if (_handConfig == HandConfig::HandController) { + _overrideHands = false; + return true; + } + return false; +} + +bool ViveControllerManager::InputDevice::configureHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition); + int puckCount = (int)_validTrackedObjects.size(); + if (_headConfig == HeadConfig::Puck && puckCount >= MIN_HEAD) { + calibrateHead(defaultToReferenceMat, inputCalibration); + _validTrackedObjects.erase(_validTrackedObjects.end()); + _overrideHead = true; + return true; + } else if (_headConfig == HeadConfig::HMD) { + return true; + } + return false; +} - if (_config == Config::Feet) { +bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { + int puckCount = (int)_validTrackedObjects.size(); + if (_config == Config::None) { + return true; + } else if (_config == Config::Feet && puckCount >= MIN_PUCK_COUNT) { calibrateFeet(defaultToReferenceMat, inputCalibration); + return true; } else if (_config == Config::FeetAndHips && puckCount >= MIN_FEET_AND_HIPS) { calibrateFeet(defaultToReferenceMat, inputCalibration); calibrateHips(defaultToReferenceMat, inputCalibration); + return true; } else if (_config == Config::FeetHipsAndChest && puckCount >= MIN_FEET_HIPS_CHEST) { calibrateFeet(defaultToReferenceMat, inputCalibration); calibrateHips(defaultToReferenceMat, inputCalibration); calibrateChest(defaultToReferenceMat, inputCalibration); + return true; } else if (_config == Config::FeetHipsAndShoulders && puckCount >= MIN_FEET_HIPS_SHOULDERS) { calibrateFeet(defaultToReferenceMat, inputCalibration); calibrateHips(defaultToReferenceMat, inputCalibration); int firstShoulderIndex = 3; int secondShoulderIndex = 4; calibrateShoulders(defaultToReferenceMat, inputCalibration, firstShoulderIndex, secondShoulderIndex); - } else if (_config == Config::FeetHipsAndHead && puckCount == MIN_FEET_HIPS_HEAD) { + return true; + } /*else if (_config == Config::FeetHipsAndHead && puckCount == MIN_FEET_HIPS_HEAD) { glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); calibrateFeet(defaultToReferenceMat, inputCalibration, headXAxis, headPosition); calibrateHips(defaultToReferenceMat, inputCalibration); calibrateHead(defaultToReferenceMat, inputCalibration); _overrideHead = true; + return true; } else if (_config == Config::FeetHipsChestAndHead && puckCount == MIN_FEET_HIPS_CHEST_HEAD) { glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); @@ -469,15 +532,12 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr calibrateChest(defaultToReferenceMat, inputCalibration); calibrateHead(defaultToReferenceMat, inputCalibration); _overrideHead = true; - } else { - qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks"; - uncalibrate(); - emitCalibrationStatus(false); - return; - } - _calibrated = true; - emitCalibrationStatus(true); - qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful"; + return true; + }*/ + qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks"; + uncalibrate(); + emitCalibrationStatus(false); + return false; } void ViveControllerManager::InputDevice::uncalibrate() { @@ -486,6 +546,7 @@ void ViveControllerManager::InputDevice::uncalibrate() { _jointToPuckMap.clear(); _calibrated = false; _overrideHead = false; + _overrideHands = false; } void ViveControllerManager::InputDevice::updateCalibratedLimbs() { @@ -499,6 +560,11 @@ void ViveControllerManager::InputDevice::updateCalibratedLimbs() { if (_overrideHead) { _poseStateMap[controller::HEAD] = addOffsetToPuckPose(controller::HEAD); } + + if (_overrideHands) { + _poseStateMap[controller::LEFT_HAND] = addOffsetToPuckPose(controller::LEFT_HAND); + _poseStateMap[controller::RIGHT_HAND] = addOffsetToPuckPose(controller::RIGHT_HAND); + } } controller::Pose ViveControllerManager::InputDevice::addOffsetToPuckPose(int joint) const { @@ -809,6 +875,70 @@ void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToRefer } } +void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) { + glm::mat4 avatarToSensorMat = glm::inverse(inputCalibration.sensorToWorldMat) * inputCalibration.avatarMat; + glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat; + controller::Pose& handPose = handPair.second; + glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()) * Matrices::Y_180; + glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat); + glm::vec3 handPoseZAxis = glmExtractRotation(handPoseAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f); + glm::vec3 avatarHandYAxis = glm::vec3(1.0f, 0.0f, 0.0f); + + const float EPSILON = 1.0e-4f; + if (fabsf(fabsf(glm::dot(glm::normalize(avatarHandYAxis), glm::normalize(handPoseZAxis))) - 1.0f) < EPSILON) { + handPoseZAxis = glm::vec3(0.0f, 0.0f, 1.0f); + } + + glm::vec3 yPrime = avatarHandYAxis; + glm::vec3 xPrime = glm::normalize(glm::cross(avatarHandYAxis, handPoseZAxis)); + glm::vec3 zPrime = glm::normalize(glm::cross(xPrime, yPrime)); + + glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f), + glm::vec4(zPrime, 0.0f), glm::vec4(handPoseTranslation, 1.0f)); + + glm::mat4 handPoseOffset = glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + + glm::mat4 finalHandMat = newHandMat * handPoseOffset; + + controller::Pose finalPose(extractTranslation(finalHandMat), glmExtractRotation(finalHandMat)); + + _jointToPuckMap[controller::LEFT_HAND] = handPair.first; + _pucksOffset[handPair.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftHand, finalPose); +} + +void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) { + glm::mat4 avatarToSensorMat = glm::inverse(inputCalibration.sensorToWorldMat) * inputCalibration.avatarMat; + glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat; + controller::Pose& handPose = handPair.second; + glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()) * Matrices::Y_180; + glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat); + glm::vec3 handPoseZAxis = glmExtractRotation(handPoseAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f); + glm::vec3 avatarHandYAxis = glm::vec3(-1.0f, 0.0f, 0.0f); + + const float EPSILON = 1.0e-4f; + if (fabsf(fabsf(glm::dot(glm::normalize(avatarHandYAxis), glm::normalize(handPoseZAxis))) - 1.0f) < EPSILON) { + handPoseZAxis = glm::vec3(0.0f, 0.0f, 1.0f); + } + + glm::vec3 yPrime = avatarHandYAxis; + glm::vec3 xPrime = glm::normalize(glm::cross(avatarHandYAxis, handPoseZAxis)); + glm::vec3 zPrime = glm::normalize(glm::cross(xPrime, yPrime)); + + glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f), + glm::vec4(zPrime, 0.0f), glm::vec4(handPoseTranslation, 1.0f)); + + glm::mat4 handPoseOffset = glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), + glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + + glm::mat4 finalHandMat = newHandMat * handPoseOffset; + + controller::Pose finalPose(extractTranslation(finalHandMat), glmExtractRotation(finalHandMat)); + + _jointToPuckMap[controller::RIGHT_HAND] = handPair.first; + _pucksOffset[handPair.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftHand, finalPose); +} + void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, glm::vec3 headXAxis, glm::vec3 headPosition) { auto& firstFoot = _validTrackedObjects[FIRST_FOOT]; @@ -816,7 +946,7 @@ void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToRefer controller::Pose& firstFootPose = firstFoot.second; controller::Pose& secondFootPose = secondFoot.second; - if (determineFeetOrdering(firstFootPose, secondFootPose, headXAxis, headPosition)) { + if (determineLimbOrdering(firstFootPose, secondFootPose, headXAxis, headPosition)) { _jointToPuckMap[controller::LEFT_FOOT] = firstFoot.first; _pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, firstFootPose); _jointToPuckMap[controller::RIGHT_FOOT] = secondFoot.first; @@ -909,10 +1039,6 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu _preferedConfig = Config::FeetHipsAndChest; } else if (value == "FeetHipsAndShoulders") { _preferedConfig = Config::FeetHipsAndShoulders; - } else if (value == "FeetHipsChestAndHead") { - _preferedConfig = Config::FeetHipsChestAndHead; - } else if (value == "FeetHipsAndHead") { - _preferedConfig = Config::FeetHipsAndHead; } } diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index ea29d974e9..f3b37495cb 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -96,11 +96,15 @@ private: void setConfigFromString(const QString& value); void loadSettings(); void saveSettings() const; + bool configureHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); + bool configureHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); + bool configureBody(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); + void calibrateLeftHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair); + void calibrateRightHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair); void calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); void calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, glm::vec3 headXAxis, glm::vec3 headPosition); void calibrateHips(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); void calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); - void calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, int firstShoulderIndex, int secondShoulderIndex); void calibrateHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, @@ -141,8 +145,7 @@ private: FeetAndHips, FeetHipsAndChest, FeetHipsAndShoulders, - FeetHipsChestAndHead, - FeetHipsAndHead, + FeetHipsChestAndShoulders, }; enum class HeadConfig { From aa23986618fd27a19350f9c0290c80cc38ab220b Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 14 Jun 2017 00:46:55 +0100 Subject: [PATCH 064/157] finxing rotation problem --- plugins/openvr/src/ViveControllerManager.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 43f815c068..41b0ab0989 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -467,10 +467,12 @@ bool ViveControllerManager::InputDevice::configureHands(glm::mat4& defaultToRefe calibrateLeftHand(defaultToReferenceMat, inputCalibration, firstHand); calibrateRightHand(defaultToReferenceMat, inputCalibration, secondHand); _overrideHands = true; + return true; } else { calibrateLeftHand(defaultToReferenceMat, inputCalibration, secondHand); calibrateRightHand(defaultToReferenceMat, inputCalibration, firstHand); _overrideHands = true; + return true; } } else if (_handConfig == HandConfig::HandController) { _overrideHands = false; @@ -879,7 +881,7 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToR glm::mat4 avatarToSensorMat = glm::inverse(inputCalibration.sensorToWorldMat) * inputCalibration.avatarMat; glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat; controller::Pose& handPose = handPair.second; - glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()) * Matrices::Y_180; + glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()); glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat); glm::vec3 handPoseZAxis = glmExtractRotation(handPoseAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f); glm::vec3 avatarHandYAxis = glm::vec3(1.0f, 0.0f, 0.0f); @@ -888,7 +890,7 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToR if (fabsf(fabsf(glm::dot(glm::normalize(avatarHandYAxis), glm::normalize(handPoseZAxis))) - 1.0f) < EPSILON) { handPoseZAxis = glm::vec3(0.0f, 0.0f, 1.0f); } - + glm::vec3 yPrime = avatarHandYAxis; glm::vec3 xPrime = glm::normalize(glm::cross(avatarHandYAxis, handPoseZAxis)); glm::vec3 zPrime = glm::normalize(glm::cross(xPrime, yPrime)); @@ -911,7 +913,7 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo glm::mat4 avatarToSensorMat = glm::inverse(inputCalibration.sensorToWorldMat) * inputCalibration.avatarMat; glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat; controller::Pose& handPose = handPair.second; - glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()) * Matrices::Y_180; + glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()); glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat); glm::vec3 handPoseZAxis = glmExtractRotation(handPoseAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f); glm::vec3 avatarHandYAxis = glm::vec3(-1.0f, 0.0f, 0.0f); @@ -920,7 +922,7 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo if (fabsf(fabsf(glm::dot(glm::normalize(avatarHandYAxis), glm::normalize(handPoseZAxis))) - 1.0f) < EPSILON) { handPoseZAxis = glm::vec3(0.0f, 0.0f, 1.0f); } - + glm::vec3 yPrime = avatarHandYAxis; glm::vec3 xPrime = glm::normalize(glm::cross(avatarHandYAxis, handPoseZAxis)); glm::vec3 zPrime = glm::normalize(glm::cross(xPrime, yPrime)); @@ -929,14 +931,14 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo glm::vec4(zPrime, 0.0f), glm::vec4(handPoseTranslation, 1.0f)); glm::mat4 handPoseOffset = glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), - glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); + glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), glm::vec4(0.0f, 0.0508f, 0.0f, 1.0f)); glm::mat4 finalHandMat = newHandMat * handPoseOffset; controller::Pose finalPose(extractTranslation(finalHandMat), glmExtractRotation(finalHandMat)); _jointToPuckMap[controller::RIGHT_HAND] = handPair.first; - _pucksOffset[handPair.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftHand, finalPose); + _pucksOffset[handPair.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightHand, finalPose); } From ea56c568a76b60cea5b181ee3549cdfc60af9089 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 12 Jun 2017 16:55:37 -0700 Subject: [PATCH 065/157] Add support for replicating by username --- domain-server/src/DomainServer.cpp | 31 +++++++++++++++++-- domain-server/src/DomainServer.h | 6 ++++ .../src/DomainServerSettingsManager.cpp | 10 +++--- .../src/DomainServerSettingsManager.h | 1 + libraries/networking/src/Node.h | 1 + 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index de53898057..afe9b7ca50 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -117,6 +117,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : // if permissions are updated, relay the changes to the Node datastructures connect(&_settingsManager, &DomainServerSettingsManager::updateNodePermissions, &_gatekeeper, &DomainGatekeeper::updateNodePermissions); + connect(&_settingsManager, &DomainServerSettingsManager::settingsUpdated, + this, &DomainServer::updateReplicatedNodes); setupGroupCacheRefresh(); @@ -2210,9 +2212,34 @@ void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& _unfulfilledAssignments.enqueue(assignment); } +void DomainServer::updateReplicatedNodes() { + static const QString REPLICATION_SETTINGS_KEY = "replication"; + _replicatedUsernames.clear(); + auto settings = _settingsManager.getSettingsMap(); + if (settings.contains(REPLICATION_SETTINGS_KEY)) { + auto replicationSettings = settings.value(REPLICATION_SETTINGS_KEY).toJsonObject(); + auto usersSettings = replicationSettings.value("users").toArray(); + for (auto& username : usersSettings) { + _replicatedUsernames.push_back(username.toString()); + } + } + + auto nodeList = DependencyManager::get(); + nodeList->eachNode([&](const SharedNodePointer& otherNode) { + if (shouldReplicateNode(*otherNode)) { + otherNode->setIsReplicated(true); + } + }); +} + +bool DomainServer::shouldReplicateNode(const Node& node) { + QString verifiedUsername = node.getPermissions().getVerifiedUserName(); + auto it = find(_replicatedUsernames.cbegin(), _replicatedUsernames.cend(), verifiedUsername); + return it != _replicatedUsernames.end() && node.getType() == NodeType::Agent; +}; + void DomainServer::nodeAdded(SharedNodePointer node) { - // TODO Check to see if node is in list of replicated nodes - if (node->getType() == NodeType::Agent) { + if (shouldReplicateNode(*node)) { node->setIsReplicated(true); } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 63b82cb37d..3538f85f68 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -102,6 +102,8 @@ private slots: void handleOctreeFileReplacement(QByteArray octreeFile); + void updateReplicatedNodes(); + signals: void iceServerChanged(); void userConnected(); @@ -161,12 +163,16 @@ private: QJsonObject jsonForSocket(const HifiSockAddr& socket); QJsonObject jsonObjectForNode(const SharedNodePointer& node); + bool DomainServer::shouldReplicateNode(const Node& node); + void setupGroupCacheRefresh(); QString pathForRedirect(QString path = QString()) const; SubnetList _acSubnetWhitelist; + std::vector _replicatedUsernames; + DomainGatekeeper _gatekeeper; HTTPManager _httpManager; diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index d6b57b450a..3d256bd2b9 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -991,6 +991,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection unpackPermissions(); apiRefreshGroupInformation(); emit updateNodePermissions(); + emit settingsUpdated(); } return true; @@ -1196,13 +1197,14 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject) { static const QString SECURITY_ROOT_KEY = "security"; static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist"; + static const QString REPLICATION_KEY = "replication"; auto& settingsVariant = _configMap.getConfig(); bool needRestart = false; // Iterate on the setting groups foreach(const QString& rootKey, postedObject.keys()) { - QJsonValue rootValue = postedObject[rootKey]; + const QJsonValue& rootValue = postedObject[rootKey]; if (!settingsVariant.contains(rootKey)) { // we don't have a map below this key yet, so set it up now @@ -1247,7 +1249,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ if (!matchingDescriptionObject.isEmpty()) { updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject); - if (rootKey != SECURITY_ROOT_KEY) { + if (rootKey != SECURITY_ROOT_KEY && rootKey != REPLICATION_KEY) { needRestart = true; } } else { @@ -1261,9 +1263,9 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ // if we matched the setting then update the value if (!matchingDescriptionObject.isEmpty()) { - QJsonValue settingValue = rootValue.toObject()[settingKey]; + const QJsonValue& settingValue = rootValue.toObject()[settingKey]; updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject); - if (rootKey != SECURITY_ROOT_KEY || settingKey == AC_SUBNET_WHITELIST_KEY) { + if ((rootKey != SECURITY_ROOT_KEY && rootKey != REPLICATION_KEY) || settingKey == AC_SUBNET_WHITELIST_KEY) { needRestart = true; } } else { diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index d56a786d4b..4c7d8dfbc9 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -108,6 +108,7 @@ public: signals: void updateNodePermissions(); + void settingsUpdated(); public slots: void apiGetGroupIDJSONCallback(QNetworkReply& requestReply); diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index fd2cf6b65b..33c9e2c205 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -105,6 +105,7 @@ private: bool _isUpstream { false }; tbb::concurrent_unordered_set _ignoredNodeIDSet; mutable QReadWriteLock _ignoredNodeIDSetLock; + std::vector _replicatedUsernames { }; std::atomic_bool _ignoreRadiusEnabled; }; From 2e23230e82f53c76180e838b3a17bcaa9241f91f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jun 2017 08:36:33 -0700 Subject: [PATCH 066/157] Remove DomainServer qualification inside header --- domain-server/src/DomainServer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 3538f85f68..92df7a88e0 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -163,7 +163,7 @@ private: QJsonObject jsonForSocket(const HifiSockAddr& socket); QJsonObject jsonObjectForNode(const SharedNodePointer& node); - bool DomainServer::shouldReplicateNode(const Node& node); + bool shouldReplicateNode(const Node& node); void setupGroupCacheRefresh(); From 029e6de2a0720946e82986f3c58ee43330a88a6a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jun 2017 10:22:59 -0700 Subject: [PATCH 067/157] Fix replicated users not being checked after username verified --- domain-server/src/DomainServer.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index afe9b7ca50..65f85215cb 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -131,6 +131,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : setupNodeListAndAssignments(); + updateReplicatedNodes(); + if (_type != NonMetaverse) { // if we have a metaverse domain, we'll use an access token for API calls resetAccountManagerAccessToken(); @@ -960,6 +962,11 @@ void DomainServer::handleConnectedNode(SharedNodePointer newNode) { emit userConnected(); } + if (shouldReplicateNode(*newNode)) { + qDebug() << "Setting node to replicated: " << newNode->getUUID(); + newNode->setIsReplicated(true); + } + // send out this node to our other connected nodes broadcastNewNode(newNode); } @@ -2217,16 +2224,19 @@ void DomainServer::updateReplicatedNodes() { _replicatedUsernames.clear(); auto settings = _settingsManager.getSettingsMap(); if (settings.contains(REPLICATION_SETTINGS_KEY)) { - auto replicationSettings = settings.value(REPLICATION_SETTINGS_KEY).toJsonObject(); - auto usersSettings = replicationSettings.value("users").toArray(); - for (auto& username : usersSettings) { - _replicatedUsernames.push_back(username.toString()); + auto replicationSettings = settings.value(REPLICATION_SETTINGS_KEY).toMap(); + if (replicationSettings.contains("users")) { + auto usersSettings = replicationSettings.value("users").toList(); + for (auto& username : usersSettings) { + _replicatedUsernames.push_back(username.toString()); + } } } auto nodeList = DependencyManager::get(); nodeList->eachNode([&](const SharedNodePointer& otherNode) { if (shouldReplicateNode(*otherNode)) { + qDebug() << "Setting node to replicated: " << otherNode->getUUID(); otherNode->setIsReplicated(true); } }); @@ -2234,15 +2244,12 @@ void DomainServer::updateReplicatedNodes() { bool DomainServer::shouldReplicateNode(const Node& node) { QString verifiedUsername = node.getPermissions().getVerifiedUserName(); + qDebug() << "Verified username: " << verifiedUsername; auto it = find(_replicatedUsernames.cbegin(), _replicatedUsernames.cend(), verifiedUsername); return it != _replicatedUsernames.end() && node.getType() == NodeType::Agent; }; void DomainServer::nodeAdded(SharedNodePointer node) { - if (shouldReplicateNode(*node)) { - node->setIsReplicated(true); - } - // we don't use updateNodeWithData, so add the DomainServerNodeData to the node here node->setLinkedData(std::unique_ptr { new DomainServerNodeData() }); } From d0e8612a65c7d2cf0ab8cc88c4859e21a56a611e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jun 2017 15:25:22 -0700 Subject: [PATCH 068/157] First pass at AvatarMixer replication --- assignment-client/src/avatars/AvatarMixer.cpp | 75 +++++++++++++++++++ assignment-client/src/avatars/AvatarMixer.h | 3 + .../src/avatars/AvatarMixerClientData.cpp | 4 + libraries/networking/src/LimitedNodeList.cpp | 4 + .../networking/src/udt/PacketHeaders.cpp | 5 +- libraries/networking/src/udt/PacketHeaders.h | 5 +- 6 files changed, 93 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 870149f1bc..f499a787cb 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -54,15 +54,79 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket"); packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket"); + packetReceiver.registerListenerForTypes({ + PacketType::ReplicatedAvatarIdentity, + PacketType::ReplicatedAvatarData, + PacketType::ReplicatedKillAvatar + }, this, "handleReplicatedPackets"); + auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &AvatarMixer::handlePacketVersionMismatch); } +void AvatarMixer::handleReplicatedPackets(QSharedPointer message) { + auto nodeList = DependencyManager::get(); + auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + + auto replicatedNode = nodeList->nodeWithUUID(nodeID); + if (!replicatedNode) { + QMetaObject::invokeMethod(nodeList.data(), "addOrUpdateNode", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(SharedNodePointer, replicatedNode), + Q_ARG(QUuid, nodeID), Q_ARG(NodeType_t, NodeType::Agent), + Q_ARG(HifiSockAddr, message->getSenderSockAddr()), + Q_ARG(HifiSockAddr, message->getSenderSockAddr())); + } + + replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); + replicatedNode->setIsUpstream(true); + + switch (message->getType()) { + case PacketType::AvatarData: + queueIncomingPacket(message, replicatedNode); + break; + case PacketType::AvatarIdentity: + handleAvatarIdentityPacket(message, replicatedNode); + break; + case PacketType::KillAvatar: + handleKillAvatarPacket(message); + break + } + +} + +void AvatarMixer::replicatePacket(ReceivedMessage& message) { + PacketType replicatedType; + if (message.getType() == PacketType::AvatarData) { + replicatedType = PacketType::ReplicatedAvatarData; + } else if (message.getType() == PacketType::AvatarIdentity) { + replicatedType = PacketType::ReplicatedAvatarIdentity; + } else if (message.getType() == PacketType::KillAvatar) { + replicatedType = PacketType::ReplicatedKillAvatar; + } else { + Q_UNREACHABLE(); + return; + } + + auto nodeList = DependencyManager::get(); + nodeList->eachMatchingNode([&](const SharedNodePointer& node) { + return node->getType() == NodeType::ReplicantAvatarMixer; + }, [&](const SharedNodePointer& node) { + // construct an NLPacket to send to the replicant that has the contents of the received packet + auto packet = NLPacket::create(replicatedType, message.getSize() + NUM_BYTES_RFC4122_UUID); + packet->write(message.getSourceID().toRfc4122()); + packet->write(message.getMessage()); + + nodeList->sendPacket(std::move(packet), *node); + }); +} + void AvatarMixer::queueIncomingPacket(QSharedPointer message, SharedNodePointer node) { auto start = usecTimestampNow(); getOrCreateClientData(node)->queuePacket(message, node); auto end = usecTimestampNow(); _queueIncomingPacketElapsedTime += (end - start); + + replicatePacket(*message); } @@ -397,6 +461,13 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes if (nodeData != nullptr) { AvatarData& avatar = nodeData->getAvatar(); + auto data = message->getMessage(); + + if (message->getType() == PacketType::ReplicatedAvatarData) { + data = data.mid(NUM_BYTES_RFC4122_UUID); + } + + // parse the identity packet and update the change timestamp if appropriate AvatarData::Identity identity; AvatarData::parseAvatarIdentityPacket(message->getMessage(), identity); @@ -414,6 +485,8 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes } auto end = usecTimestampNow(); _handleAvatarIdentityPacketElapsedTime += (end - start); + + replicatePacket(*message); } void AvatarMixer::handleKillAvatarPacket(QSharedPointer message) { @@ -421,6 +494,8 @@ void AvatarMixer::handleKillAvatarPacket(QSharedPointer message DependencyManager::get()->processKillNode(*message); auto end = usecTimestampNow(); _handleKillAvatarPacketElapsedTime += (end - start); + + replicatePacket(*message); } void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 1925ec1ebd..ecbed4dca7 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -46,6 +46,7 @@ private slots: void handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode); void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleRequestsDomainListDataPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleReplicatedPackets(QSharedPointer message); void domainSettingsRequestComplete(); void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID); void start(); @@ -61,6 +62,8 @@ private: void manageDisplayName(const SharedNodePointer& node); + void replicatePacket(ReceivedMessage& message); + p_high_resolution_clock::time_point _lastFrameTimestamp; // FIXME - new throttling - use these values somehow diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 4d80bc7d17..41717adeb5 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -62,6 +62,10 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message) { // pull the sequence number from the data first uint16_t sequenceNumber; + if (message.getType() == PacketType::ReplicatedAvatarData) { + message.seek(NUM_BYTES_RFC4122_UUID); + } + message.readPrimitive(&sequenceNumber); if (sequenceNumber < _lastReceivedSequenceNumber && _lastReceivedSequenceNumber != UINT16_MAX) { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0494efc7b4..f28a972720 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -549,6 +549,10 @@ bool LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { } void LimitedNodeList::processKillNode(ReceivedMessage& message) { + if (message.getType() == PacketType::ReplicatedAvatarData) { + message.seek(NUM_BYTES_RFC4122_UUID); + } + // read the node id QUuid nodeUUID = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index f2f0062861..9f213d29ff 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -41,7 +41,8 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::ICEServerHeartbeatDenied << PacketType::AssignmentClientStatus << PacketType::StopNode << PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement << PacketType::ReplicatedMicrophoneAudioNoEcho << PacketType::ReplicatedMicrophoneAudioWithEcho - << PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame; + << PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame + << PacketType::ReplicatedAvatarIdentity << PacketType::ReplicatedAvatarData << PacketType::ReplicatedKillAvatar; PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { @@ -121,7 +122,7 @@ static void ensureProtocolVersionsSignature() { std::call_once(once, [&] { QByteArray buffer; QDataStream stream(&buffer, QIODevice::WriteOnly); - uint8_t numberOfProtocols = static_cast(PacketType::LAST_PACKET_TYPE) + 1; + uint8_t numberOfProtocols = static_cast(PacketType::NUM_PACKET_TYPE); stream << numberOfProtocols; for (uint8_t packetType = 0; packetType < numberOfProtocols; packetType++) { uint8_t packetTypeVersion = static_cast(versionForPacketType(static_cast(packetType))); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 448ae812ff..137108ef75 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -119,8 +119,11 @@ public: ReplicatedMicrophoneAudioWithEcho, ReplicatedInjectAudio, ReplicatedSilentAudioFrame, - LAST_PACKET_TYPE = ReplicatedSilentAudioFrame, + ReplicatedAvatarIdentity, + ReplicatedAvatarData, + ReplicatedKillAvatar, + NUM_PACKET_TYPE }; }; From a0d107c72c961eb1c5d275cc391afdb08da55237 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jun 2017 15:45:12 -0700 Subject: [PATCH 069/157] Only replicate replicated nodes --- assignment-client/src/avatars/AvatarMixer.cpp | 69 +++++++++++-------- assignment-client/src/avatars/AvatarMixer.h | 4 +- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index f499a787cb..2b074f71e6 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -88,36 +88,47 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag handleAvatarIdentityPacket(message, replicatedNode); break; case PacketType::KillAvatar: - handleKillAvatarPacket(message); - break + handleKillAvatarPacket(message, replicatedNode); + break; + default: + // Do nothing + break; } } -void AvatarMixer::replicatePacket(ReceivedMessage& message) { - PacketType replicatedType; - if (message.getType() == PacketType::AvatarData) { - replicatedType = PacketType::ReplicatedAvatarData; - } else if (message.getType() == PacketType::AvatarIdentity) { - replicatedType = PacketType::ReplicatedAvatarIdentity; - } else if (message.getType() == PacketType::KillAvatar) { - replicatedType = PacketType::ReplicatedKillAvatar; - } else { - Q_UNREACHABLE(); - return; +void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node& node) { + // first, make sure that this is a packet from a node we are supposed to replicate + if (node.isReplicated()) { + // now make sure it's a packet type that we want to replicate + PacketType replicatedType; + switch (message.getType()) { + case PacketType::AvatarData: + replicatedType = PacketType::ReplicatedAvatarData; + break; + case PacketType::AvatarIdentity: + replicatedType = PacketType::ReplicatedAvatarIdentity; + break; + case PacketType::KillAvatar: + replicatedType = PacketType::ReplicatedKillAvatar; + break; + default: + Q_UNREACHABLE(); + return; + } + + auto nodeList = DependencyManager::get(); + nodeList->eachMatchingNode([&](const SharedNodePointer& node) { + return node->getType() == NodeType::ReplicantAvatarMixer; + }, [&](const SharedNodePointer& node) { + // construct an NLPacket to send to the replicant that has the contents of the received packet + auto packet = NLPacket::create(replicatedType, message.getSize() + NUM_BYTES_RFC4122_UUID); + packet->write(message.getSourceID().toRfc4122()); + packet->write(message.getMessage()); + + nodeList->sendPacket(std::move(packet), *node); + }); } - - auto nodeList = DependencyManager::get(); - nodeList->eachMatchingNode([&](const SharedNodePointer& node) { - return node->getType() == NodeType::ReplicantAvatarMixer; - }, [&](const SharedNodePointer& node) { - // construct an NLPacket to send to the replicant that has the contents of the received packet - auto packet = NLPacket::create(replicatedType, message.getSize() + NUM_BYTES_RFC4122_UUID); - packet->write(message.getSourceID().toRfc4122()); - packet->write(message.getMessage()); - - nodeList->sendPacket(std::move(packet), *node); - }); } void AvatarMixer::queueIncomingPacket(QSharedPointer message, SharedNodePointer node) { @@ -126,7 +137,7 @@ void AvatarMixer::queueIncomingPacket(QSharedPointer message, S auto end = usecTimestampNow(); _queueIncomingPacketElapsedTime += (end - start); - replicatePacket(*message); + optionallyReplicatePacket(*message, *node); } @@ -486,16 +497,16 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes auto end = usecTimestampNow(); _handleAvatarIdentityPacketElapsedTime += (end - start); - replicatePacket(*message); + optionallyReplicatePacket(*message, *senderNode); } -void AvatarMixer::handleKillAvatarPacket(QSharedPointer message) { +void AvatarMixer::handleKillAvatarPacket(QSharedPointer message, SharedNodePointer node) { auto start = usecTimestampNow(); DependencyManager::get()->processKillNode(*message); auto end = usecTimestampNow(); _handleKillAvatarPacketElapsedTime += (end - start); - replicatePacket(*message); + optionallyReplicatePacket(*message, *node); } void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index ecbed4dca7..17a6db3b08 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -42,7 +42,7 @@ private slots: void handleAdjustAvatarSorting(QSharedPointer message, SharedNodePointer senderNode); void handleViewFrustumPacket(QSharedPointer message, SharedNodePointer senderNode); void handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode); - void handleKillAvatarPacket(QSharedPointer message); + void handleKillAvatarPacket(QSharedPointer message, SharedNodePointer senderNode); void handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode); void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleRequestsDomainListDataPacket(QSharedPointer message, SharedNodePointer senderNode); @@ -62,7 +62,7 @@ private: void manageDisplayName(const SharedNodePointer& node); - void replicatePacket(ReceivedMessage& message); + void optionallyReplicatePacket(ReceivedMessage& message, const Node& node); p_high_resolution_clock::time_point _lastFrameTimestamp; From b4ce9fb4fcb732980fcce9d1d806aed1b8ba33ca Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jun 2017 16:12:13 -0700 Subject: [PATCH 070/157] Remove blocking call + reduce packet construction --- assignment-client/src/avatars/AvatarMixer.cpp | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 2b074f71e6..75b3d23563 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -68,14 +68,8 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag auto nodeList = DependencyManager::get(); auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - auto replicatedNode = nodeList->nodeWithUUID(nodeID); - if (!replicatedNode) { - QMetaObject::invokeMethod(nodeList.data(), "addOrUpdateNode", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(SharedNodePointer, replicatedNode), - Q_ARG(QUuid, nodeID), Q_ARG(NodeType_t, NodeType::Agent), - Q_ARG(HifiSockAddr, message->getSenderSockAddr()), - Q_ARG(HifiSockAddr, message->getSenderSockAddr())); - } + auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, + message->getSenderSockAddr(), message->getSenderSockAddr()) replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); replicatedNode->setIsUpstream(true); @@ -117,16 +111,20 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node return; } + std::unique_ptr packet; + auto nodeList = DependencyManager::get(); nodeList->eachMatchingNode([&](const SharedNodePointer& node) { return node->getType() == NodeType::ReplicantAvatarMixer; }, [&](const SharedNodePointer& node) { - // construct an NLPacket to send to the replicant that has the contents of the received packet - auto packet = NLPacket::create(replicatedType, message.getSize() + NUM_BYTES_RFC4122_UUID); - packet->write(message.getSourceID().toRfc4122()); - packet->write(message.getMessage()); + if (!packet) { + // construct an NLPacket to send to the replicant that has the contents of the received packet + packet = NLPacket::create(replicatedType, message.getSize() + NUM_BYTES_RFC4122_UUID); + packet->write(message.getSourceID().toRfc4122()); + packet->write(message.getMessage()); + } - nodeList->sendPacket(std::move(packet), *node); + nodeList->sendUnreliablePacket(*packet, *node); }); } } From 9aebf68664ca4d1598e2c0df815f4bb3357497a2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jun 2017 16:32:54 -0700 Subject: [PATCH 071/157] Parse replicant from domain settings --- assignment-client/src/avatars/AvatarMixer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 75b3d23563..aae447be60 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -69,7 +69,8 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, - message->getSenderSockAddr(), message->getSenderSockAddr()) + message->getSenderSockAddr(), message->getSenderSockAddr(), + DEFAULT_AGENT_PERMISSIONS, true); replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); replicatedNode->setIsUpstream(true); @@ -115,7 +116,7 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node auto nodeList = DependencyManager::get(); nodeList->eachMatchingNode([&](const SharedNodePointer& node) { - return node->getType() == NodeType::ReplicantAvatarMixer; + return node->getType() == NodeType::DownstreamAvatarMixer; }, [&](const SharedNodePointer& node) { if (!packet) { // construct an NLPacket to send to the replicant that has the contents of the received packet @@ -848,4 +849,6 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) { qCDebug(avatars) << "This domain requires a minimum avatar scale of" << _domainMinimumScale << "and a maximum avatar scale of" << _domainMaximumScale; + + parseDownstreamServers(domainSettings, NodeType::AvatarMixer); } From 5e3479560354cbfb374bcbdf94516af8a5a7bb68 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Jun 2017 18:38:23 -0700 Subject: [PATCH 072/157] Fix packet types filtering --- assignment-client/src/avatars/AvatarMixer.cpp | 9 ++++----- assignment-client/src/avatars/AvatarMixerClientData.cpp | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index aae447be60..ab51e00e74 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -76,13 +76,13 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag replicatedNode->setIsUpstream(true); switch (message->getType()) { - case PacketType::AvatarData: + case PacketType::ReplicatedAvatarData: queueIncomingPacket(message, replicatedNode); break; - case PacketType::AvatarIdentity: + case PacketType::ReplicatedAvatarIdentity: handleAvatarIdentityPacket(message, replicatedNode); break; - case PacketType::KillAvatar: + case PacketType::ReplicatedKillAvatar: handleKillAvatarPacket(message, replicatedNode); break; default: @@ -108,7 +108,6 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node replicatedType = PacketType::ReplicatedKillAvatar; break; default: - Q_UNREACHABLE(); return; } @@ -125,7 +124,7 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node packet->write(message.getMessage()); } - nodeList->sendUnreliablePacket(*packet, *node); + nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); }); } } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 41717adeb5..3c9edcd4a5 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -45,6 +45,7 @@ int AvatarMixerClientData::processPackets() { switch (packet->getType()) { case PacketType::AvatarData: + case PacketType::ReplicatedAvatarData: parseData(*packet); break; default: From 44a63ca27ebac8663b0009738e1f89b84e90f8a1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 10:44:28 -0700 Subject: [PATCH 073/157] handle node killed and remove double IDs in kill packets --- assignment-client/src/avatars/AvatarMixer.cpp | 48 ++++++++++++++++--- libraries/networking/src/LimitedNodeList.cpp | 2 +- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index ab51e00e74..17cdf8b7d6 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -119,8 +119,18 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node }, [&](const SharedNodePointer& node) { if (!packet) { // construct an NLPacket to send to the replicant that has the contents of the received packet - packet = NLPacket::create(replicatedType, message.getSize() + NUM_BYTES_RFC4122_UUID); - packet->write(message.getSourceID().toRfc4122()); + auto packetSize = message.getSize(); + + if (replicatedType != PacketType::ReplicatedKillAvatar) { + packetSize += NUM_BYTES_RFC4122_UUID; + } + + packet = NLPacket::create(replicatedType, packetSize); + + if (replicatedType != PacketType::ReplicatedKillAvatar) { + packet->write(message.getSourceID().toRfc4122()); + } + packet->write(message.getMessage()); } @@ -352,13 +362,38 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { } } + std::unique_ptr killPacket; + std::unique_ptr replicatedKillPacket; + // this was an avatar we were sending to other people // send a kill packet for it to our other nodes - auto killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason)); - killPacket->write(killedNode->getUUID().toRfc4122()); - killPacket->writePrimitive(KillAvatarReason::AvatarDisconnected); + nodeList->eachMatchingNode([&](const SharedNodePointer& node) { + // we relay avatar kill packets to agents that are not upstream + // and downstream avatar mixers, if the node that was just killed was being replicated + return (node->getType() == NodeType::Agent && !node->isUpstream()) + || (killedNode->isReplicated() && node->getType() == NodeType::DownstreamAvatarMixer); + }, [&](const SharedNodePointer& node) { + if (node->getType() == NodeType::Agent) { + if (!killPacket) { + killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason)); + killPacket->write(killedNode->getUUID().toRfc4122()); + killPacket->writePrimitive(KillAvatarReason::AvatarDisconnected); + } + + nodeList->sendUnreliablePacket(*killPacket, *node); + } else { + // send a replicated kill packet to the downstream avatar mixer + if (!replicatedKillPacket) { + replicatedKillPacket = NLPacket::create(PacketType::ReplicatedKillAvatar, + NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason)); + replicatedKillPacket->write(killedNode->getUUID().toRfc4122()); + replicatedKillPacket->writePrimitive(KillAvatarReason::AvatarDisconnected); + } + + nodeList->sendUnreliablePacket(*replicatedKillPacket, node->getPublicSocket()); + } + }); - nodeList->broadcastToNodes(std::move(killPacket), NodeSet() << NodeType::Agent); // we also want to remove sequence number data for this avatar on our other avatars // so invoke the appropriate method on the AvatarMixerClientData for other avatars @@ -756,7 +791,6 @@ void AvatarMixer::run() { connect(&domainHandler, &DomainHandler::settingsReceiveFail, this, &AvatarMixer::domainSettingsRequestFailed); ThreadedAssignment::commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer); - } AvatarMixerClientData* AvatarMixer::getOrCreateClientData(SharedNodePointer node) { diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index f28a972720..b39c86e6e3 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -550,7 +550,7 @@ bool LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { void LimitedNodeList::processKillNode(ReceivedMessage& message) { if (message.getType() == PacketType::ReplicatedAvatarData) { - message.seek(NUM_BYTES_RFC4122_UUID); + message.seek(0); } // read the node id From 8ce6590f0b807f24bac9f920879499866f47348c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 10:56:47 -0700 Subject: [PATCH 074/157] remove ReplicatedAvatarData and immediate replication of identity --- assignment-client/src/avatars/AvatarMixer.cpp | 48 +++---------------- libraries/networking/src/LimitedNodeList.cpp | 4 -- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 - 4 files changed, 8 insertions(+), 47 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 17cdf8b7d6..34fcc3c0ed 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -56,7 +56,6 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : packetReceiver.registerListenerForTypes({ PacketType::ReplicatedAvatarIdentity, - PacketType::ReplicatedAvatarData, PacketType::ReplicatedKillAvatar }, this, "handleReplicatedPackets"); @@ -76,13 +75,13 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag replicatedNode->setIsUpstream(true); switch (message->getType()) { - case PacketType::ReplicatedAvatarData: - queueIncomingPacket(message, replicatedNode); - break; case PacketType::ReplicatedAvatarIdentity: handleAvatarIdentityPacket(message, replicatedNode); break; case PacketType::ReplicatedKillAvatar: + // seek back in the message so the kill packet handler can start by reading the source ID + message->seek(0); + handleKillAvatarPacket(message, replicatedNode); break; default: @@ -94,22 +93,9 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node& node) { // first, make sure that this is a packet from a node we are supposed to replicate - if (node.isReplicated()) { - // now make sure it's a packet type that we want to replicate - PacketType replicatedType; - switch (message.getType()) { - case PacketType::AvatarData: - replicatedType = PacketType::ReplicatedAvatarData; - break; - case PacketType::AvatarIdentity: - replicatedType = PacketType::ReplicatedAvatarIdentity; - break; - case PacketType::KillAvatar: - replicatedType = PacketType::ReplicatedKillAvatar; - break; - default: - return; - } + if (node.isReplicated() + && (message.getType() == PacketType::KillAvatar || message.getType() == PacketType::ReplicatedKillAvatar)) { + PacketType replicatedType = PacketType::ReplicatedKillAvatar; std::unique_ptr packet; @@ -119,18 +105,7 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node }, [&](const SharedNodePointer& node) { if (!packet) { // construct an NLPacket to send to the replicant that has the contents of the received packet - auto packetSize = message.getSize(); - - if (replicatedType != PacketType::ReplicatedKillAvatar) { - packetSize += NUM_BYTES_RFC4122_UUID; - } - - packet = NLPacket::create(replicatedType, packetSize); - - if (replicatedType != PacketType::ReplicatedKillAvatar) { - packet->write(message.getSourceID().toRfc4122()); - } - + packet = NLPacket::create(replicatedType, message.getSize()); packet->write(message.getMessage()); } @@ -144,8 +119,6 @@ void AvatarMixer::queueIncomingPacket(QSharedPointer message, S getOrCreateClientData(node)->queuePacket(message, node); auto end = usecTimestampNow(); _queueIncomingPacketElapsedTime += (end - start); - - optionallyReplicatePacket(*message, *node); } @@ -505,13 +478,6 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer mes if (nodeData != nullptr) { AvatarData& avatar = nodeData->getAvatar(); - auto data = message->getMessage(); - - if (message->getType() == PacketType::ReplicatedAvatarData) { - data = data.mid(NUM_BYTES_RFC4122_UUID); - } - - // parse the identity packet and update the change timestamp if appropriate AvatarData::Identity identity; AvatarData::parseAvatarIdentityPacket(message->getMessage(), identity); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index b39c86e6e3..0494efc7b4 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -549,10 +549,6 @@ bool LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { } void LimitedNodeList::processKillNode(ReceivedMessage& message) { - if (message.getType() == PacketType::ReplicatedAvatarData) { - message.seek(0); - } - // read the node id QUuid nodeUUID = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 9f213d29ff..ad30a184ca 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -42,7 +42,7 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement << PacketType::ReplicatedMicrophoneAudioNoEcho << PacketType::ReplicatedMicrophoneAudioWithEcho << PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame - << PacketType::ReplicatedAvatarIdentity << PacketType::ReplicatedAvatarData << PacketType::ReplicatedKillAvatar; + << PacketType::ReplicatedAvatarIdentity << PacketType::ReplicatedKillAvatar; PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 137108ef75..b7d55c3266 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -120,7 +120,6 @@ public: ReplicatedInjectAudio, ReplicatedSilentAudioFrame, ReplicatedAvatarIdentity, - ReplicatedAvatarData, ReplicatedKillAvatar, NUM_PACKET_TYPE From a8ea8724d39e42e143c4944aba71c1af43138c1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 12:39:47 -0700 Subject: [PATCH 075/157] split broadcast of avatar data for agent and downstream mixer --- .../src/avatars/AvatarMixerSlave.cpp | 631 +++++++++--------- .../src/avatars/AvatarMixerSlave.h | 3 + 2 files changed, 325 insertions(+), 309 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 2ad8bb58ed..7732058f2d 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -81,6 +81,20 @@ static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45; void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { quint64 start = usecTimestampNow(); + if (node->getLinkedData()) { + if (node->getType() == NodeType::Agent && node->getActiveSocket() && !node->isUpstream()) { + broadcastAvatarDataToAgent(node); + } else if (node->getType() == NodeType::DownstreamAvatarMixer) { + broadcastAvatarDataToDownstreamMixer(node); + } + } + + quint64 end = usecTimestampNow(); + _stats.jobElapsedTime += (end - start); +} + +void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) { + auto nodeList = DependencyManager::get(); // setup for distributed random floating point values @@ -88,331 +102,330 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { std::mt19937 generator(randomDevice()); std::uniform_real_distribution distribution; - if (node->getLinkedData() && (node->getType() == NodeType::Agent) && node->getActiveSocket()) { - _stats.nodesBroadcastedTo++; + _stats.nodesBroadcastedTo++; - AvatarMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); + AvatarMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); - nodeData->resetInViewStats(); + nodeData->resetInViewStats(); - const AvatarData& avatar = nodeData->getAvatar(); - glm::vec3 myPosition = avatar.getClientGlobalPosition(); + const AvatarData& avatar = nodeData->getAvatar(); + glm::vec3 myPosition = avatar.getClientGlobalPosition(); - // reset the internal state for correct random number distribution - distribution.reset(); + // reset the internal state for correct random number distribution + distribution.reset(); - // reset the number of sent avatars - nodeData->resetNumAvatarsSentLastFrame(); + // reset the number of sent avatars + nodeData->resetNumAvatarsSentLastFrame(); - // keep a counter of the number of considered avatars - int numOtherAvatars = 0; + // keep a counter of the number of considered avatars + int numOtherAvatars = 0; - // keep track of outbound data rate specifically for avatar data - int numAvatarDataBytes = 0; - int identityBytesSent = 0; + // keep track of outbound data rate specifically for avatar data + int numAvatarDataBytes = 0; + int identityBytesSent = 0; - // max number of avatarBytes per frame - auto maxAvatarBytesPerFrame = (_maxKbpsPerNode * BYTES_PER_KILOBIT) / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND; + // max number of avatarBytes per frame + auto maxAvatarBytesPerFrame = (_maxKbpsPerNode * BYTES_PER_KILOBIT) / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND; - // FIXME - find a way to not send the sessionID for every avatar - int minimumBytesPerAvatar = AvatarDataPacket::AVATAR_HAS_FLAGS_SIZE + NUM_BYTES_RFC4122_UUID; + // FIXME - find a way to not send the sessionID for every avatar + int minimumBytesPerAvatar = AvatarDataPacket::AVATAR_HAS_FLAGS_SIZE + NUM_BYTES_RFC4122_UUID; - int overBudgetAvatars = 0; + int overBudgetAvatars = 0; - // keep track of the number of other avatars held back in this frame - int numAvatarsHeldBack = 0; + // keep track of the number of other avatars held back in this frame + int numAvatarsHeldBack = 0; - // keep track of the number of other avatar frames skipped - int numAvatarsWithSkippedFrames = 0; + // keep track of the number of other avatar frames skipped + int numAvatarsWithSkippedFrames = 0; - // When this is true, the AvatarMixer will send Avatar data to a client - // about avatars they've ignored or that are out of view - bool PALIsOpen = nodeData->getRequestsDomainListData(); + // When this is true, the AvatarMixer will send Avatar data to a client + // about avatars they've ignored or that are out of view + bool PALIsOpen = nodeData->getRequestsDomainListData(); - // When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them - bool getsAnyIgnored = PALIsOpen && node->getCanKick(); + // When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them + bool getsAnyIgnored = PALIsOpen && node->getCanKick(); - if (PALIsOpen) { - // Increase minimumBytesPerAvatar if the PAL is open - minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) + - sizeof(AvatarDataPacket::AudioLoudness); - } - - // setup a PacketList for the avatarPackets - auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData); - - // Define the minimum bubble size - static const glm::vec3 minBubbleSize = glm::vec3(0.3f, 1.3f, 0.3f); - // Define the scale of the box for the current node - glm::vec3 nodeBoxScale = (nodeData->getPosition() - nodeData->getGlobalBoundingBoxCorner()) * 2.0f; - // Set up the bounding box for the current node - AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale); - // Clamp the size of the bounding box to a minimum scale - if (glm::any(glm::lessThan(nodeBoxScale, minBubbleSize))) { - nodeBox.setScaleStayCentered(minBubbleSize); - } - // Quadruple the scale of both bounding boxes - nodeBox.embiggen(4.0f); - - - // setup list of AvatarData as well as maps to map betweeen the AvatarData and the original nodes - // for calling the AvatarData::sortAvatars() function and getting our sorted list of client nodes - QList avatarList; - std::unordered_map avatarDataToNodes; - - std::for_each(_begin, _end, [&](const SharedNodePointer& otherNode) { - const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); - - // theoretically it's possible for a Node to be in the NodeList (and therefore end up here), - // but not have yet sent data that's linked to the node. Check for that case and don't - // consider those nodes. - if (otherNodeData) { - AvatarSharedPointer otherAvatar = otherNodeData->getAvatarSharedPointer(); - avatarList << otherAvatar; - avatarDataToNodes[otherAvatar] = otherNode; - } - }); - - AvatarSharedPointer thisAvatar = nodeData->getAvatarSharedPointer(); - ViewFrustum cameraView = nodeData->getViewFrustom(); - std::priority_queue sortedAvatars; - AvatarData::sortAvatars(avatarList, cameraView, sortedAvatars, - - [&](AvatarSharedPointer avatar)->uint64_t{ - auto avatarNode = avatarDataToNodes[avatar]; - assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map - return nodeData->getLastBroadcastTime(avatarNode->getUUID()); - }, - - [&](AvatarSharedPointer avatar)->float{ - glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner()); - return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z)); - }, - - [&](AvatarSharedPointer avatar)->bool{ - if (avatar == thisAvatar) { - return true; // ignore ourselves... - } - - bool shouldIgnore = false; - - // We will also ignore other nodes for a couple of different reasons: - // 1) ignore bubbles and ignore specific node - // 2) the node hasn't really updated it's frame data recently, this can - // happen if for example the avatar is connected on a desktop and sending - // updates at ~30hz. So every 3 frames we skip a frame. - auto avatarNode = avatarDataToNodes[avatar]; - - assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map - - const AvatarMixerClientData* avatarNodeData = reinterpret_cast(avatarNode->getLinkedData()); - assert(avatarNodeData); // we can't have gotten here without avatarNode having valid data - quint64 startIgnoreCalculation = usecTimestampNow(); - - // make sure we have data for this avatar, that it isn't the same node, - // and isn't an avatar that the viewing node has ignored - // or that has ignored the viewing node - if (!avatarNode->getLinkedData() - || avatarNode->getUUID() == node->getUUID() - || (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen) - || (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) { - shouldIgnore = true; - } else { - - // Check to see if the space bubble is enabled - // Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored - if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) { - - // Define the scale of the box for the current other node - glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f; - // Set up the bounding box for the current other node - AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale); - // Clamp the size of the bounding box to a minimum scale - if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) { - otherNodeBox.setScaleStayCentered(minBubbleSize); - } - // Quadruple the scale of both bounding boxes - otherNodeBox.embiggen(4.0f); - - // Perform the collision check between the two bounding boxes - if (nodeBox.touches(otherNodeBox)) { - nodeData->ignoreOther(node, avatarNode); - shouldIgnore = !getsAnyIgnored; - } - } - // Not close enough to ignore - if (!shouldIgnore) { - nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID()); - } - } - quint64 endIgnoreCalculation = usecTimestampNow(); - _stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation); - - if (!shouldIgnore) { - AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID()); - AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber(); - - // FIXME - This code does appear to be working. But it seems brittle. - // It supports determining if the frame of data for this "other" - // avatar has already been sent to the reciever. This has been - // verified to work on a desktop display that renders at 60hz and - // therefore sends to mixer at 30hz. Each second you'd expect to - // have 15 (45hz-30hz) duplicate frames. In this case, the stat - // avg_other_av_skips_per_second does report 15. - // - // make sure we haven't already sent this data from this sender to this receiver - // or that somehow we haven't sent - if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { - ++numAvatarsHeldBack; - shouldIgnore = true; - } else if (lastSeqFromSender - lastSeqToReceiver > 1) { - // this is a skip - we still send the packet but capture the presence of the skip so we see it happening - ++numAvatarsWithSkippedFrames; - } - } - return shouldIgnore; - }); - - // loop through our sorted avatars and allocate our bandwidth to them accordingly - int avatarRank = 0; - - // this is overly conservative, because it includes some avatars we might not consider - int remainingAvatars = (int)sortedAvatars.size(); - - while (!sortedAvatars.empty()) { - AvatarPriority sortData = sortedAvatars.top(); - sortedAvatars.pop(); - const auto& avatarData = sortData.avatar; - avatarRank++; - remainingAvatars--; - - auto otherNode = avatarDataToNodes[avatarData]; - assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map - - // NOTE: Here's where we determine if we are over budget and drop to bare minimum data - int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars; - bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame; - - quint64 startAvatarDataPacking = usecTimestampNow(); - - ++numOtherAvatars; - - const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); - - // If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO - // the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A. - if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) { - identityBytesSent += sendIdentityPacket(otherNodeData, node); - } - - const AvatarData* otherAvatar = otherNodeData->getConstAvatarData(); - glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition(); - - // determine if avatar is in view, to determine how much data to include... - glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f; - AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale); - bool isInView = nodeData->otherAvatarInView(otherNodeBox); - - // start a new segment in the PacketList for this avatar - avatarPacketList->startSegment(); - - AvatarData::AvatarDataDetail detail; - - if (overBudget) { - overBudgetAvatars++; - _stats.overBudgetAvatars++; - detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData; - } else if (!isInView) { - detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData; - nodeData->incrementAvatarOutOfView(); - } else { - detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO - ? AvatarData::SendAllData : AvatarData::CullSmallData; - nodeData->incrementAvatarInView(); - } - - bool includeThisAvatar = true; - auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID()); - QVector& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID()); - bool distanceAdjust = true; - glm::vec3 viewerPosition = myPosition; - AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray - bool dropFaceTracking = false; - - quint64 start = usecTimestampNow(); - QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, - hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); - quint64 end = usecTimestampNow(); - _stats.toByteArrayElapsedTime += (end - start); - - static const int MAX_ALLOWED_AVATAR_DATA = (1400 - NUM_BYTES_RFC4122_UUID); - if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { - qCWarning(avatars) << "otherAvatar.toByteArray() resulted in very large buffer:" << bytes.size() << "... attempt to drop facial data"; - - dropFaceTracking = true; // first try dropping the facial data - bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, - hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); - - if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { - qCWarning(avatars) << "otherAvatar.toByteArray() without facial data resulted in very large buffer:" << bytes.size() << "... reduce to MinimumData"; - bytes = otherAvatar->toByteArray(AvatarData::MinimumData, lastEncodeForOther, lastSentJointsForOther, - hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); - } - - if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { - qCWarning(avatars) << "otherAvatar.toByteArray() MinimumData resulted in very large buffer:" << bytes.size() << "... FAIL!!"; - includeThisAvatar = false; - } - } - - if (includeThisAvatar) { - numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122()); - numAvatarDataBytes += avatarPacketList->write(bytes); - - if (detail != AvatarData::NoData) { - _stats.numOthersIncluded++; - - // increment the number of avatars sent to this reciever - nodeData->incrementNumAvatarsSentLastFrame(); - - // set the last sent sequence number for this sender on the receiver - nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), - otherNodeData->getLastReceivedSequenceNumber()); - - // remember the last time we sent details about this other node to the receiver - nodeData->setLastBroadcastTime(otherNode->getUUID(), start); - } - } - - avatarPacketList->endSegment(); - - quint64 endAvatarDataPacking = usecTimestampNow(); - _stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking); - }; - - quint64 startPacketSending = usecTimestampNow(); - - // close the current packet so that we're always sending something - avatarPacketList->closeCurrentPacket(true); - - _stats.numPacketsSent += (int)avatarPacketList->getNumPackets(); - _stats.numBytesSent += numAvatarDataBytes; - - // send the avatar data PacketList - nodeList->sendPacketList(std::move(avatarPacketList), *node); - - // record the bytes sent for other avatar data in the AvatarMixerClientData - nodeData->recordSentAvatarData(numAvatarDataBytes); - - // record the number of avatars held back this frame - nodeData->recordNumOtherAvatarStarves(numAvatarsHeldBack); - nodeData->recordNumOtherAvatarSkips(numAvatarsWithSkippedFrames); - - quint64 endPacketSending = usecTimestampNow(); - _stats.packetSendingElapsedTime += (endPacketSending - startPacketSending); + if (PALIsOpen) { + // Increase minimumBytesPerAvatar if the PAL is open + minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) + + sizeof(AvatarDataPacket::AudioLoudness); } - quint64 end = usecTimestampNow(); - _stats.jobElapsedTime += (end - start); + // setup a PacketList for the avatarPackets + auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData); + + // Define the minimum bubble size + static const glm::vec3 minBubbleSize = glm::vec3(0.3f, 1.3f, 0.3f); + // Define the scale of the box for the current node + glm::vec3 nodeBoxScale = (nodeData->getPosition() - nodeData->getGlobalBoundingBoxCorner()) * 2.0f; + // Set up the bounding box for the current node + AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale); + // Clamp the size of the bounding box to a minimum scale + if (glm::any(glm::lessThan(nodeBoxScale, minBubbleSize))) { + nodeBox.setScaleStayCentered(minBubbleSize); + } + // Quadruple the scale of both bounding boxes + nodeBox.embiggen(4.0f); + + + // setup list of AvatarData as well as maps to map betweeen the AvatarData and the original nodes + // for calling the AvatarData::sortAvatars() function and getting our sorted list of client nodes + QList avatarList; + std::unordered_map avatarDataToNodes; + + std::for_each(_begin, _end, [&](const SharedNodePointer& otherNode) { + const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); + + // theoretically it's possible for a Node to be in the NodeList (and therefore end up here), + // but not have yet sent data that's linked to the node. Check for that case and don't + // consider those nodes. + if (otherNodeData) { + AvatarSharedPointer otherAvatar = otherNodeData->getAvatarSharedPointer(); + avatarList << otherAvatar; + avatarDataToNodes[otherAvatar] = otherNode; + } + }); + + AvatarSharedPointer thisAvatar = nodeData->getAvatarSharedPointer(); + ViewFrustum cameraView = nodeData->getViewFrustom(); + std::priority_queue sortedAvatars; + AvatarData::sortAvatars(avatarList, cameraView, sortedAvatars, + + [&](AvatarSharedPointer avatar)->uint64_t{ + auto avatarNode = avatarDataToNodes[avatar]; + assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map + return nodeData->getLastBroadcastTime(avatarNode->getUUID()); + }, + + [&](AvatarSharedPointer avatar)->float{ + glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner()); + return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z)); + }, + + [&](AvatarSharedPointer avatar)->bool{ + if (avatar == thisAvatar) { + return true; // ignore ourselves... + } + + bool shouldIgnore = false; + + // We will also ignore other nodes for a couple of different reasons: + // 1) ignore bubbles and ignore specific node + // 2) the node hasn't really updated it's frame data recently, this can + // happen if for example the avatar is connected on a desktop and sending + // updates at ~30hz. So every 3 frames we skip a frame. + auto avatarNode = avatarDataToNodes[avatar]; + + assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map + + const AvatarMixerClientData* avatarNodeData = reinterpret_cast(avatarNode->getLinkedData()); + assert(avatarNodeData); // we can't have gotten here without avatarNode having valid data + quint64 startIgnoreCalculation = usecTimestampNow(); + + // make sure we have data for this avatar, that it isn't the same node, + // and isn't an avatar that the viewing node has ignored + // or that has ignored the viewing node + if (!avatarNode->getLinkedData() + || avatarNode->getUUID() == node->getUUID() + || (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen) + || (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) { + shouldIgnore = true; + } else { + + // Check to see if the space bubble is enabled + // Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored + if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) { + + // Define the scale of the box for the current other node + glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f; + // Set up the bounding box for the current other node + AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale); + // Clamp the size of the bounding box to a minimum scale + if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) { + otherNodeBox.setScaleStayCentered(minBubbleSize); + } + // Quadruple the scale of both bounding boxes + otherNodeBox.embiggen(4.0f); + + // Perform the collision check between the two bounding boxes + if (nodeBox.touches(otherNodeBox)) { + nodeData->ignoreOther(node, avatarNode); + shouldIgnore = !getsAnyIgnored; + } + } + // Not close enough to ignore + if (!shouldIgnore) { + nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID()); + } + } + quint64 endIgnoreCalculation = usecTimestampNow(); + _stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation); + + if (!shouldIgnore) { + AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID()); + AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber(); + + // FIXME - This code does appear to be working. But it seems brittle. + // It supports determining if the frame of data for this "other" + // avatar has already been sent to the reciever. This has been + // verified to work on a desktop display that renders at 60hz and + // therefore sends to mixer at 30hz. Each second you'd expect to + // have 15 (45hz-30hz) duplicate frames. In this case, the stat + // avg_other_av_skips_per_second does report 15. + // + // make sure we haven't already sent this data from this sender to this receiver + // or that somehow we haven't sent + if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { + ++numAvatarsHeldBack; + shouldIgnore = true; + } else if (lastSeqFromSender - lastSeqToReceiver > 1) { + // this is a skip - we still send the packet but capture the presence of the skip so we see it happening + ++numAvatarsWithSkippedFrames; + } + } + return shouldIgnore; + }); + + // loop through our sorted avatars and allocate our bandwidth to them accordingly + int avatarRank = 0; + + // this is overly conservative, because it includes some avatars we might not consider + int remainingAvatars = (int)sortedAvatars.size(); + + while (!sortedAvatars.empty()) { + AvatarPriority sortData = sortedAvatars.top(); + sortedAvatars.pop(); + const auto& avatarData = sortData.avatar; + avatarRank++; + remainingAvatars--; + + auto otherNode = avatarDataToNodes[avatarData]; + assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map + + // NOTE: Here's where we determine if we are over budget and drop to bare minimum data + int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars; + bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame; + + quint64 startAvatarDataPacking = usecTimestampNow(); + + ++numOtherAvatars; + + const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); + + // If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO + // the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A. + if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) { + identityBytesSent += sendIdentityPacket(otherNodeData, node); + } + + const AvatarData* otherAvatar = otherNodeData->getConstAvatarData(); + glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition(); + + // determine if avatar is in view, to determine how much data to include... + glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f; + AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale); + bool isInView = nodeData->otherAvatarInView(otherNodeBox); + + // start a new segment in the PacketList for this avatar + avatarPacketList->startSegment(); + + AvatarData::AvatarDataDetail detail; + + if (overBudget) { + overBudgetAvatars++; + _stats.overBudgetAvatars++; + detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData; + } else if (!isInView) { + detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData; + nodeData->incrementAvatarOutOfView(); + } else { + detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO + ? AvatarData::SendAllData : AvatarData::CullSmallData; + nodeData->incrementAvatarInView(); + } + + bool includeThisAvatar = true; + auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID()); + QVector& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID()); + bool distanceAdjust = true; + glm::vec3 viewerPosition = myPosition; + AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray + bool dropFaceTracking = false; + + quint64 start = usecTimestampNow(); + QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, + hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); + quint64 end = usecTimestampNow(); + _stats.toByteArrayElapsedTime += (end - start); + + static const int MAX_ALLOWED_AVATAR_DATA = (1400 - NUM_BYTES_RFC4122_UUID); + if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { + qCWarning(avatars) << "otherAvatar.toByteArray() resulted in very large buffer:" << bytes.size() << "... attempt to drop facial data"; + + dropFaceTracking = true; // first try dropping the facial data + bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, + hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); + + if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { + qCWarning(avatars) << "otherAvatar.toByteArray() without facial data resulted in very large buffer:" << bytes.size() << "... reduce to MinimumData"; + bytes = otherAvatar->toByteArray(AvatarData::MinimumData, lastEncodeForOther, lastSentJointsForOther, + hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); + } + + if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { + qCWarning(avatars) << "otherAvatar.toByteArray() MinimumData resulted in very large buffer:" << bytes.size() << "... FAIL!!"; + includeThisAvatar = false; + } + } + + if (includeThisAvatar) { + numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122()); + numAvatarDataBytes += avatarPacketList->write(bytes); + + if (detail != AvatarData::NoData) { + _stats.numOthersIncluded++; + + // increment the number of avatars sent to this reciever + nodeData->incrementNumAvatarsSentLastFrame(); + + // set the last sent sequence number for this sender on the receiver + nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), + otherNodeData->getLastReceivedSequenceNumber()); + + // remember the last time we sent details about this other node to the receiver + nodeData->setLastBroadcastTime(otherNode->getUUID(), start); + } + } + + avatarPacketList->endSegment(); + + quint64 endAvatarDataPacking = usecTimestampNow(); + _stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking); + }; + + quint64 startPacketSending = usecTimestampNow(); + + // close the current packet so that we're always sending something + avatarPacketList->closeCurrentPacket(true); + + _stats.numPacketsSent += (int)avatarPacketList->getNumPackets(); + _stats.numBytesSent += numAvatarDataBytes; + + // send the avatar data PacketList + nodeList->sendPacketList(std::move(avatarPacketList), *node); + + // record the bytes sent for other avatar data in the AvatarMixerClientData + nodeData->recordSentAvatarData(numAvatarDataBytes); + + // record the number of avatars held back this frame + nodeData->recordNumOtherAvatarStarves(numAvatarsHeldBack); + nodeData->recordNumOtherAvatarSkips(numAvatarsWithSkippedFrames); + + quint64 endPacketSending = usecTimestampNow(); + _stats.packetSendingElapsedTime += (endPacketSending - startPacketSending); +} + +void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node) { + } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.h b/assignment-client/src/avatars/AvatarMixerSlave.h index 04141d9d72..c11ac3291c 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.h +++ b/assignment-client/src/avatars/AvatarMixerSlave.h @@ -93,6 +93,9 @@ public: private: int sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode); + void broadcastAvatarDataToAgent(const SharedNodePointer& node); + void broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node); + // frame state ConstIter _begin; ConstIter _end; From 98abb237832821810eb0d7759d4f3ecdb679a207 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 12:41:39 -0700 Subject: [PATCH 076/157] remove ReplicatedAvatarData handling --- assignment-client/src/avatars/AvatarMixerClientData.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 3c9edcd4a5..4d80bc7d17 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -45,7 +45,6 @@ int AvatarMixerClientData::processPackets() { switch (packet->getType()) { case PacketType::AvatarData: - case PacketType::ReplicatedAvatarData: parseData(*packet); break; default: @@ -63,10 +62,6 @@ int AvatarMixerClientData::parseData(ReceivedMessage& message) { // pull the sequence number from the data first uint16_t sequenceNumber; - if (message.getType() == PacketType::ReplicatedAvatarData) { - message.seek(NUM_BYTES_RFC4122_UUID); - } - message.readPrimitive(&sequenceNumber); if (sequenceNumber < _lastReceivedSequenceNumber && _lastReceivedSequenceNumber != UINT16_MAX) { From dc94f83591cc135b9281708dc08c03ce04938e71 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 13:42:19 -0700 Subject: [PATCH 077/157] build out bulk avatar data replication --- .../src/avatars/AvatarMixerSlave.cpp | 454 +++++++++++------- libraries/networking/src/NLPacketList.h | 2 + .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 2 +- libraries/networking/src/udt/PacketList.cpp | 4 +- libraries/networking/src/udt/PacketList.h | 5 +- 6 files changed, 278 insertions(+), 191 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 7732058f2d..802ea442c3 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -81,12 +81,10 @@ static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45; void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { quint64 start = usecTimestampNow(); - if (node->getLinkedData()) { - if (node->getType() == NodeType::Agent && node->getActiveSocket() && !node->isUpstream()) { - broadcastAvatarDataToAgent(node); - } else if (node->getType() == NodeType::DownstreamAvatarMixer) { - broadcastAvatarDataToDownstreamMixer(node); - } + if (node->getType() == NodeType::Agent && node->getLinkedData() && node->getActiveSocket() && !node->isUpstream()) { + broadcastAvatarDataToAgent(node); + } else if (node->getType() == NodeType::DownstreamAvatarMixer) { + broadcastAvatarDataToDownstreamMixer(node); } quint64 end = usecTimestampNow(); @@ -174,12 +172,11 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) std::unordered_map avatarDataToNodes; std::for_each(_begin, _end, [&](const SharedNodePointer& otherNode) { - const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); + // make sure this is an agent that we have avatar data for before considering it for inclusion + if (otherNode->getType() == NodeType::Agent + && otherNode->getLinkedData()) { + const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); - // theoretically it's possible for a Node to be in the NodeList (and therefore end up here), - // but not have yet sent data that's linked to the node. Check for that case and don't - // consider those nodes. - if (otherNodeData) { AvatarSharedPointer otherAvatar = otherNodeData->getAvatarSharedPointer(); avatarList << otherAvatar; avatarDataToNodes[otherAvatar] = otherNode; @@ -190,217 +187,216 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) ViewFrustum cameraView = nodeData->getViewFrustom(); std::priority_queue sortedAvatars; AvatarData::sortAvatars(avatarList, cameraView, sortedAvatars, + [&](AvatarSharedPointer avatar)->uint64_t{ + auto avatarNode = avatarDataToNodes[avatar]; + assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map + return nodeData->getLastBroadcastTime(avatarNode->getUUID()); + }, - [&](AvatarSharedPointer avatar)->uint64_t{ - auto avatarNode = avatarDataToNodes[avatar]; - assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map - return nodeData->getLastBroadcastTime(avatarNode->getUUID()); - }, + [&](AvatarSharedPointer avatar)->float{ + glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner()); + return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z)); + }, - [&](AvatarSharedPointer avatar)->float{ - glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner()); - return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z)); - }, + [&](AvatarSharedPointer avatar)->bool{ + if (avatar == thisAvatar) { + return true; // ignore ourselves... + } - [&](AvatarSharedPointer avatar)->bool{ - if (avatar == thisAvatar) { - return true; // ignore ourselves... - } + bool shouldIgnore = false; - bool shouldIgnore = false; + // We will also ignore other nodes for a couple of different reasons: + // 1) ignore bubbles and ignore specific node + // 2) the node hasn't really updated it's frame data recently, this can + // happen if for example the avatar is connected on a desktop and sending + // updates at ~30hz. So every 3 frames we skip a frame. + auto avatarNode = avatarDataToNodes[avatar]; - // We will also ignore other nodes for a couple of different reasons: - // 1) ignore bubbles and ignore specific node - // 2) the node hasn't really updated it's frame data recently, this can - // happen if for example the avatar is connected on a desktop and sending - // updates at ~30hz. So every 3 frames we skip a frame. - auto avatarNode = avatarDataToNodes[avatar]; + assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map - assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map + const AvatarMixerClientData* avatarNodeData = reinterpret_cast(avatarNode->getLinkedData()); + assert(avatarNodeData); // we can't have gotten here without avatarNode having valid data + quint64 startIgnoreCalculation = usecTimestampNow(); - const AvatarMixerClientData* avatarNodeData = reinterpret_cast(avatarNode->getLinkedData()); - assert(avatarNodeData); // we can't have gotten here without avatarNode having valid data - quint64 startIgnoreCalculation = usecTimestampNow(); + // make sure we have data for this avatar, that it isn't the same node, + // and isn't an avatar that the viewing node has ignored + // or that has ignored the viewing node + if (!avatarNode->getLinkedData() + || avatarNode->getUUID() == node->getUUID() + || (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen) + || (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) { + shouldIgnore = true; + } else { - // make sure we have data for this avatar, that it isn't the same node, - // and isn't an avatar that the viewing node has ignored - // or that has ignored the viewing node - if (!avatarNode->getLinkedData() - || avatarNode->getUUID() == node->getUUID() - || (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen) - || (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) { - shouldIgnore = true; - } else { + // Check to see if the space bubble is enabled + // Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored + if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) { - // Check to see if the space bubble is enabled - // Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored - if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) { + // Define the scale of the box for the current other node + glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f; + // Set up the bounding box for the current other node + AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale); + // Clamp the size of the bounding box to a minimum scale + if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) { + otherNodeBox.setScaleStayCentered(minBubbleSize); + } + // Quadruple the scale of both bounding boxes + otherNodeBox.embiggen(4.0f); - // Define the scale of the box for the current other node - glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f; - // Set up the bounding box for the current other node - AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale); - // Clamp the size of the bounding box to a minimum scale - if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) { - otherNodeBox.setScaleStayCentered(minBubbleSize); - } - // Quadruple the scale of both bounding boxes - otherNodeBox.embiggen(4.0f); + // Perform the collision check between the two bounding boxes + if (nodeBox.touches(otherNodeBox)) { + nodeData->ignoreOther(node, avatarNode); + shouldIgnore = !getsAnyIgnored; + } + } + // Not close enough to ignore + if (!shouldIgnore) { + nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID()); + } + } + quint64 endIgnoreCalculation = usecTimestampNow(); + _stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation); - // Perform the collision check between the two bounding boxes - if (nodeBox.touches(otherNodeBox)) { - nodeData->ignoreOther(node, avatarNode); - shouldIgnore = !getsAnyIgnored; - } - } - // Not close enough to ignore - if (!shouldIgnore) { - nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID()); - } - } - quint64 endIgnoreCalculation = usecTimestampNow(); - _stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation); + if (!shouldIgnore) { + AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID()); + AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber(); - if (!shouldIgnore) { - AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID()); - AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber(); + // FIXME - This code does appear to be working. But it seems brittle. + // It supports determining if the frame of data for this "other" + // avatar has already been sent to the reciever. This has been + // verified to work on a desktop display that renders at 60hz and + // therefore sends to mixer at 30hz. Each second you'd expect to + // have 15 (45hz-30hz) duplicate frames. In this case, the stat + // avg_other_av_skips_per_second does report 15. + // + // make sure we haven't already sent this data from this sender to this receiver + // or that somehow we haven't sent + if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { + ++numAvatarsHeldBack; + shouldIgnore = true; + } else if (lastSeqFromSender - lastSeqToReceiver > 1) { + // this is a skip - we still send the packet but capture the presence of the skip so we see it happening + ++numAvatarsWithSkippedFrames; + } + } + return shouldIgnore; + }); - // FIXME - This code does appear to be working. But it seems brittle. - // It supports determining if the frame of data for this "other" - // avatar has already been sent to the reciever. This has been - // verified to work on a desktop display that renders at 60hz and - // therefore sends to mixer at 30hz. Each second you'd expect to - // have 15 (45hz-30hz) duplicate frames. In this case, the stat - // avg_other_av_skips_per_second does report 15. - // - // make sure we haven't already sent this data from this sender to this receiver - // or that somehow we haven't sent - if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { - ++numAvatarsHeldBack; - shouldIgnore = true; - } else if (lastSeqFromSender - lastSeqToReceiver > 1) { - // this is a skip - we still send the packet but capture the presence of the skip so we see it happening - ++numAvatarsWithSkippedFrames; - } - } - return shouldIgnore; - }); + // loop through our sorted avatars and allocate our bandwidth to them accordingly + int avatarRank = 0; - // loop through our sorted avatars and allocate our bandwidth to them accordingly - int avatarRank = 0; + // this is overly conservative, because it includes some avatars we might not consider + int remainingAvatars = (int)sortedAvatars.size(); - // this is overly conservative, because it includes some avatars we might not consider - int remainingAvatars = (int)sortedAvatars.size(); + while (!sortedAvatars.empty()) { + AvatarPriority sortData = sortedAvatars.top(); + sortedAvatars.pop(); + const auto& avatarData = sortData.avatar; + avatarRank++; + remainingAvatars--; - while (!sortedAvatars.empty()) { - AvatarPriority sortData = sortedAvatars.top(); - sortedAvatars.pop(); - const auto& avatarData = sortData.avatar; - avatarRank++; - remainingAvatars--; + auto otherNode = avatarDataToNodes[avatarData]; + assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map - auto otherNode = avatarDataToNodes[avatarData]; - assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map + // NOTE: Here's where we determine if we are over budget and drop to bare minimum data + int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars; + bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame; - // NOTE: Here's where we determine if we are over budget and drop to bare minimum data - int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars; - bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame; + quint64 startAvatarDataPacking = usecTimestampNow(); - quint64 startAvatarDataPacking = usecTimestampNow(); + ++numOtherAvatars; - ++numOtherAvatars; + const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); - const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); + // If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO + // the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A. + if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) { + identityBytesSent += sendIdentityPacket(otherNodeData, node); + } - // If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO - // the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A. - if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) { - identityBytesSent += sendIdentityPacket(otherNodeData, node); - } + const AvatarData* otherAvatar = otherNodeData->getConstAvatarData(); + glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition(); - const AvatarData* otherAvatar = otherNodeData->getConstAvatarData(); - glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition(); + // determine if avatar is in view, to determine how much data to include... + glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f; + AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale); + bool isInView = nodeData->otherAvatarInView(otherNodeBox); - // determine if avatar is in view, to determine how much data to include... - glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f; - AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale); - bool isInView = nodeData->otherAvatarInView(otherNodeBox); + // start a new segment in the PacketList for this avatar + avatarPacketList->startSegment(); - // start a new segment in the PacketList for this avatar - avatarPacketList->startSegment(); + AvatarData::AvatarDataDetail detail; - AvatarData::AvatarDataDetail detail; + if (overBudget) { + overBudgetAvatars++; + _stats.overBudgetAvatars++; + detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData; + } else if (!isInView) { + detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData; + nodeData->incrementAvatarOutOfView(); + } else { + detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO + ? AvatarData::SendAllData : AvatarData::CullSmallData; + nodeData->incrementAvatarInView(); + } - if (overBudget) { - overBudgetAvatars++; - _stats.overBudgetAvatars++; - detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData; - } else if (!isInView) { - detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData; - nodeData->incrementAvatarOutOfView(); - } else { - detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO - ? AvatarData::SendAllData : AvatarData::CullSmallData; - nodeData->incrementAvatarInView(); - } + bool includeThisAvatar = true; + auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID()); + QVector& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID()); + bool distanceAdjust = true; + glm::vec3 viewerPosition = myPosition; + AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray + bool dropFaceTracking = false; - bool includeThisAvatar = true; - auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID()); - QVector& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID()); - bool distanceAdjust = true; - glm::vec3 viewerPosition = myPosition; - AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray - bool dropFaceTracking = false; - - quint64 start = usecTimestampNow(); - QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, - hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); - quint64 end = usecTimestampNow(); - _stats.toByteArrayElapsedTime += (end - start); - - static const int MAX_ALLOWED_AVATAR_DATA = (1400 - NUM_BYTES_RFC4122_UUID); - if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { - qCWarning(avatars) << "otherAvatar.toByteArray() resulted in very large buffer:" << bytes.size() << "... attempt to drop facial data"; - - dropFaceTracking = true; // first try dropping the facial data - bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, - hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); + quint64 start = usecTimestampNow(); + QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, + hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); + quint64 end = usecTimestampNow(); + _stats.toByteArrayElapsedTime += (end - start); + static const int MAX_ALLOWED_AVATAR_DATA = (1400 - NUM_BYTES_RFC4122_UUID); if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { - qCWarning(avatars) << "otherAvatar.toByteArray() without facial data resulted in very large buffer:" << bytes.size() << "... reduce to MinimumData"; - bytes = otherAvatar->toByteArray(AvatarData::MinimumData, lastEncodeForOther, lastSentJointsForOther, + qCWarning(avatars) << "otherAvatar.toByteArray() resulted in very large buffer:" << bytes.size() << "... attempt to drop facial data"; + + dropFaceTracking = true; // first try dropping the facial data + bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther, hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); + + if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { + qCWarning(avatars) << "otherAvatar.toByteArray() without facial data resulted in very large buffer:" << bytes.size() << "... reduce to MinimumData"; + bytes = otherAvatar->toByteArray(AvatarData::MinimumData, lastEncodeForOther, lastSentJointsForOther, + hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition, &lastSentJointsForOther); + } + + if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { + qCWarning(avatars) << "otherAvatar.toByteArray() MinimumData resulted in very large buffer:" << bytes.size() << "... FAIL!!"; + includeThisAvatar = false; + } } - if (bytes.size() > MAX_ALLOWED_AVATAR_DATA) { - qCWarning(avatars) << "otherAvatar.toByteArray() MinimumData resulted in very large buffer:" << bytes.size() << "... FAIL!!"; - includeThisAvatar = false; + if (includeThisAvatar) { + numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122()); + numAvatarDataBytes += avatarPacketList->write(bytes); + + if (detail != AvatarData::NoData) { + _stats.numOthersIncluded++; + + // increment the number of avatars sent to this reciever + nodeData->incrementNumAvatarsSentLastFrame(); + + // set the last sent sequence number for this sender on the receiver + nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), + otherNodeData->getLastReceivedSequenceNumber()); + + // remember the last time we sent details about this other node to the receiver + nodeData->setLastBroadcastTime(otherNode->getUUID(), start); + } } - } - if (includeThisAvatar) { - numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122()); - numAvatarDataBytes += avatarPacketList->write(bytes); + avatarPacketList->endSegment(); - if (detail != AvatarData::NoData) { - _stats.numOthersIncluded++; - - // increment the number of avatars sent to this reciever - nodeData->incrementNumAvatarsSentLastFrame(); - - // set the last sent sequence number for this sender on the receiver - nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), - otherNodeData->getLastReceivedSequenceNumber()); - - // remember the last time we sent details about this other node to the receiver - nodeData->setLastBroadcastTime(otherNode->getUUID(), start); - } - } - - avatarPacketList->endSegment(); - - quint64 endAvatarDataPacking = usecTimestampNow(); - _stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking); + quint64 endAvatarDataPacking = usecTimestampNow(); + _stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking); }; quint64 startPacketSending = usecTimestampNow(); @@ -426,6 +422,92 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) } void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node) { + _stats.nodesBroadcastedTo++; + // setup a PacketList for the replicated bulk avatar data + auto avatarPacketList = NLPacketList::create(PacketType::ReplicatedBulkAvatarData); + + int numAvatarDataBytes = 0; + + std::for_each(_begin, _end, [&](const SharedNodePointer& agentNode) { + // collect agents that we have avatar data for + if (agentNode->getType() == NodeType::Agent && agentNode->getLinkedData()) { + const AvatarMixerClientData* agentNodeData = reinterpret_cast(agentNode->getLinkedData()); + + AvatarSharedPointer otherAvatar = agentNodeData->getAvatarSharedPointer(); + + quint64 startAvatarDataPacking = usecTimestampNow(); + + // we cannot send a downstream avatar mixer any updates that expect them to have previous state for this avatar + // since we have no idea if they're online and receiving our packets + + // so we always send a full update for this avatar + quint64 start = usecTimestampNow(); + AvatarDataPacket::HasFlags flagsOut; + QByteArray avatarByteArray = otherAvatar->toByteArray(AvatarData::SendAllData, 0, {}, + flagsOut, false, false, + glm::vec3(0), nullptr); + quint64 end = usecTimestampNow(); + _stats.toByteArrayElapsedTime += (end - start); + + // figure out how large our avatar byte array can be to fit in the packet list + // given that we need it and the avatar UUID and the size of the byte array (16 bit) + // to fit in a segment of the packet list + auto maxAvatarByteArraySize = avatarPacketList->getMaxSegmentSize(); + maxAvatarByteArraySize -= NUM_BYTES_RFC4122_UUID; + maxAvatarByteArraySize -= sizeof(quint16); + + if (avatarByteArray.size() > maxAvatarByteArraySize) { + qCWarning(avatars) << "Replicated avatar data too large for" << otherAvatar->getSessionUUID() + << "-" << avatarByteArray.size() << "bytes"; + + avatarByteArray = otherAvatar->toByteArray(AvatarData::SendAllData, 0, {}, + flagsOut, true, false, + glm::vec3(0), nullptr); + + if (avatarByteArray.size() > maxAvatarByteArraySize) { + qCWarning(avatars) << "Replicated avatar data without facial data still too large for" + << otherAvatar->getSessionUUID() << "-" << avatarByteArray.size() << "bytes"; + + avatarByteArray = otherAvatar->toByteArray(AvatarData::MinimumData, 0, {}, + flagsOut, true, false, + glm::vec3(0), nullptr); + } + } + + if (avatarByteArray.size() <= maxAvatarByteArraySize) { + // start a new segment in the packet list for this avatar + avatarPacketList->startSegment(); + + numAvatarDataBytes += avatarPacketList->write(agentNode->getUUID().toRfc4122()); + numAvatarDataBytes += avatarPacketList->writePrimitive((quint16) avatarByteArray.size()); + numAvatarDataBytes += avatarPacketList->write(avatarByteArray); + + avatarPacketList->endSegment(); + + } else { + qCWarning(avatars) << "Could not fit minimum data avatar for" << otherAvatar->getSessionUUID() + << "to packet list -" << avatarByteArray.size() << "bytes"; + } + + quint64 endAvatarDataPacking = usecTimestampNow(); + _stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking); + } + }); + + quint64 startPacketSending = usecTimestampNow(); + + // close the current packet so that we're always sending something + avatarPacketList->closeCurrentPacket(true); + + _stats.numPacketsSent += (int)avatarPacketList->getNumPackets(); + _stats.numBytesSent += numAvatarDataBytes; + + // send the replicated bulk avatar data + auto nodeList = DependencyManager::get(); + nodeList->sendPacketList(std::move(avatarPacketList), node->getPublicSocket()); + + quint64 endPacketSending = usecTimestampNow(); + _stats.packetSendingElapsedTime += (endPacketSending - startPacketSending); } diff --git a/libraries/networking/src/NLPacketList.h b/libraries/networking/src/NLPacketList.h index 48ce5ef81a..910d39f71b 100644 --- a/libraries/networking/src/NLPacketList.h +++ b/libraries/networking/src/NLPacketList.h @@ -23,6 +23,8 @@ public: PacketVersion getVersion() const { return _packetVersion; } const QUuid& getSourceID() const { return _sourceID; } + + qint64 getMaxSegmentSize() const override { return NLPacket::maxPayloadSize(_packetType, _isOrdered); } private: NLPacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index ad30a184ca..fc6251566e 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -42,7 +42,7 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::DomainServerRemovedNode << PacketType::UsernameFromIDReply << PacketType::OctreeFileReplacement << PacketType::ReplicatedMicrophoneAudioNoEcho << PacketType::ReplicatedMicrophoneAudioWithEcho << PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame - << PacketType::ReplicatedAvatarIdentity << PacketType::ReplicatedKillAvatar; + << PacketType::ReplicatedAvatarIdentity << PacketType::ReplicatedKillAvatar << PacketType::ReplicatedBulkAvatarData; PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index b7d55c3266..9b37a7d76d 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -121,7 +121,7 @@ public: ReplicatedSilentAudioFrame, ReplicatedAvatarIdentity, ReplicatedKillAvatar, - + ReplicatedBulkAvatarData, NUM_PACKET_TYPE }; }; diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 8651f9eed4..d69ff39197 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -36,8 +36,8 @@ std::unique_ptr PacketList::fromReceivedPackets(std::list> _packets; + + bool _isOrdered = false; private: friend class ::LimitedNodeList; @@ -93,7 +97,6 @@ private: Packet::MessageNumber _messageNumber; bool _isReliable = false; - bool _isOrdered = false; std::unique_ptr _currentPacket; From 01263d9435424dc5a93d6a3f21458ea0b0f978ce Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 15:29:12 -0700 Subject: [PATCH 078/157] only send identity packets directly to agents not upstream --- assignment-client/src/avatars/AvatarMixer.cpp | 14 ++++++++------ .../src/avatars/AvatarMixerSlave.cpp | 18 +++++++++++------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 34fcc3c0ed..4b032496b1 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -126,12 +126,14 @@ AvatarMixer::~AvatarMixer() { } void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { - QByteArray individualData = nodeData->getAvatar().identityByteArray(); - individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); - auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); - identityPackets->write(individualData); - DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); - ++_sumIdentityPackets; + if (destinationNode->getType() == NodeType::DownstreamAvatarMixer || !destinationNode->isUpstream()) { + QByteArray individualData = nodeData->getAvatar().identityByteArray(); + individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); + auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); + identityPackets->write(individualData); + DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); + ++_sumIdentityPackets; + } } std::chrono::microseconds AvatarMixer::timeFrame(p_high_resolution_clock::time_point& timestamp) { diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 802ea442c3..581052cab3 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -67,13 +67,17 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) { int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { - QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); - individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious - auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); - identityPackets->write(individualData); - DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); - _stats.numIdentityPackets++; - return individualData.size(); + if (destinationNode->getType() == NodeType::DownstreamAvatarMixer || !destinationNode->isUpstream()) { + QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); + individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious + auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); + identityPackets->write(individualData); + DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); + _stats.numIdentityPackets++; + return individualData.size(); + } else { + return -1; + } } static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45; From 6c5947d319a809cad6c20b8185316b3693a103ba Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jun 2017 14:43:59 -0700 Subject: [PATCH 079/157] Add periodic sending of avatar identity data to downstream nodes --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 581052cab3..17fadd8284 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -425,9 +425,13 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) _stats.packetSendingElapsedTime += (endPacketSending - startPacketSending); } +uint64_t REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US = 5 * 1000 * 1000; + void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node) { _stats.nodesBroadcastedTo++; + AvatarMixerClientData* nodeData = reinterpret_cast(node->getLinkedData()); + // setup a PacketList for the replicated bulk avatar data auto avatarPacketList = NLPacketList::create(PacketType::ReplicatedBulkAvatarData); @@ -438,6 +442,13 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin if (agentNode->getType() == NodeType::Agent && agentNode->getLinkedData()) { const AvatarMixerClientData* agentNodeData = reinterpret_cast(agentNode->getLinkedData()); + auto now = usecTimestampNow(); + auto lastBroadcastTime = nodeData->getLastBroadcastTime(agentNode->getUUID()); + if (lastBroadcastTime <= agentNodeData->getIdentityChangeTimestamp() + || (now - lastBroadcastTime) >= REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US) { + sendIdentityPacket(agentNodeData, node); + } + AvatarSharedPointer otherAvatar = agentNodeData->getAvatarSharedPointer(); quint64 startAvatarDataPacking = usecTimestampNow(); From 52150ad97152bb28851cd60bd3c3cc5bfb4ebffb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jun 2017 15:29:25 -0700 Subject: [PATCH 080/157] Add node data to downstream avatar mixers --- assignment-client/src/avatars/AvatarMixer.cpp | 6 +++++- libraries/networking/src/ThreadedAssignment.cpp | 7 ++++--- libraries/networking/src/ThreadedAssignment.h | 5 ++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 4b032496b1..582c39b124 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -851,5 +851,9 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) { << "and a maximum avatar scale of" << _domainMaximumScale; - parseDownstreamServers(domainSettings, NodeType::AvatarMixer); + parseDownstreamServers(domainSettings, NodeType::AvatarMixer, [](Node& node) { + if (!node.getLinkedData()) { + node.setLinkedData(std::unique_ptr { new AvatarMixerClientData(node.getUUID()) }); + } + }); } diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 5aeb076c11..24573e0ffc 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -134,7 +134,7 @@ void ThreadedAssignment::domainSettingsRequestFailed() { setFinished(true); } -void ThreadedAssignment::parseDownstreamServers(const QJsonObject& settingsObject, NodeType_t nodeType) { +void ThreadedAssignment::parseDownstreamServers(const QJsonObject& settingsObject, NodeType_t nodeType, DownstreamNodeFoundCallback callback) { static const QString REPLICATION_GROUP_KEY = "replication"; static const QString DOWNSTREAM_SERVERS_SETTING_KEY = "downstream_servers"; if (settingsObject.contains(REPLICATION_GROUP_KEY)) { @@ -161,8 +161,9 @@ void ThreadedAssignment::parseDownstreamServers(const QJsonObject& settingsObjec }; // manually add the downstream node to our node list - nodeList->addOrUpdateNode(QUuid::createUuid(), NodeType::downstreamType(nodeType), - downstreamServerAddr, downstreamServerAddr); + auto node = nodeList->addOrUpdateNode(QUuid::createUuid(), NodeType::downstreamType(nodeType), + downstreamServerAddr, downstreamServerAddr); + callback(*node); } } } diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index f96755a776..0cc7b2f40c 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -18,6 +18,8 @@ #include "Assignment.h" +using DownstreamNodeFoundCallback = std::function; + class ThreadedAssignment : public Assignment { Q_OBJECT public: @@ -40,7 +42,8 @@ signals: protected: void commonInit(const QString& targetName, NodeType_t nodeType); - void parseDownstreamServers(const QJsonObject& settingsObject, NodeType_t nodeType); + void parseDownstreamServers(const QJsonObject& settingsObject, NodeType_t nodeType, + DownstreamNodeFoundCallback callback = [](Node& downstreamNode) {}); bool _isFinished; QTimer _domainServerTimer; From da3cd59a968fb8816655d91aa9da08a26fb3d433 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jun 2017 15:29:55 -0700 Subject: [PATCH 081/157] Fix avatar mixer not setting last broadcast time for downstream nodes --- .../src/avatars/AvatarMixerSlave.cpp | 15 ++++++++------- libraries/networking/src/LimitedNodeList.cpp | 6 ++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 17fadd8284..fe28c96340 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -442,13 +442,6 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin if (agentNode->getType() == NodeType::Agent && agentNode->getLinkedData()) { const AvatarMixerClientData* agentNodeData = reinterpret_cast(agentNode->getLinkedData()); - auto now = usecTimestampNow(); - auto lastBroadcastTime = nodeData->getLastBroadcastTime(agentNode->getUUID()); - if (lastBroadcastTime <= agentNodeData->getIdentityChangeTimestamp() - || (now - lastBroadcastTime) >= REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US) { - sendIdentityPacket(agentNodeData, node); - } - AvatarSharedPointer otherAvatar = agentNodeData->getAvatarSharedPointer(); quint64 startAvatarDataPacking = usecTimestampNow(); @@ -465,6 +458,14 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin quint64 end = usecTimestampNow(); _stats.toByteArrayElapsedTime += (end - start); + auto lastBroadcastTime = nodeData->getLastBroadcastTime(agentNode->getUUID()); + if (lastBroadcastTime <= agentNodeData->getIdentityChangeTimestamp() + || (start - lastBroadcastTime) >= REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US) { + qDebug() << "Sending identity packet for " << agentNode->getUUID() << " to " << node->getUUID(); + sendIdentityPacket(agentNodeData, node); + nodeData->setLastBroadcastTime(agentNode->getUUID(), start); + } + // figure out how large our avatar byte array can be to fit in the packet list // given that we need it and the avatar UUID and the size of the byte array (16 bit) // to fit in a segment of the packet list diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0494efc7b4..9c0754cf26 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -446,7 +446,8 @@ qint64 LimitedNodeList::sendPacketList(std::unique_ptr packetList, return _nodeSocket.writePacketList(std::move(packetList), *activeSocket); } else { - qCDebug(networking) << "LimitedNodeList::sendPacketList called without active socket for node. Not sending."; + qCDebug(networking) << "LimitedNodeList::sendPacketList called without active socket for node " + << destinationNode.getUUID() << ". Not sending."; return ERROR_SENDING_PACKET_BYTES; } } @@ -454,7 +455,8 @@ qint64 LimitedNodeList::sendPacketList(std::unique_ptr packetList, qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const Node& destinationNode, const HifiSockAddr& overridenSockAddr) { if (overridenSockAddr.isNull() && !destinationNode.getActiveSocket()) { - qCDebug(networking) << "LimitedNodeList::sendPacket called without active socket for node. Not sending."; + qCDebug(networking) << "LimitedNodeList::sendPacket called without active socket for node" + << destinationNode.getUUID() << ". Not sending."; return ERROR_SENDING_PACKET_BYTES; } From 76f1a7445e5c4cc7dfb9454d5d6f5d6d3f2ebc00 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 15:32:07 -0700 Subject: [PATCH 082/157] handle replicated bulk avatar data packets --- assignment-client/src/avatars/AvatarMixer.cpp | 37 +++++++++++++++++++ assignment-client/src/avatars/AvatarMixer.h | 1 + .../src/avatars/AvatarMixerSlave.cpp | 18 ++++----- libraries/networking/src/ReceivedMessage.cpp | 14 +++++++ libraries/networking/src/ReceivedMessage.h | 2 + 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 582c39b124..5aaf633ed9 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -59,6 +59,8 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : PacketType::ReplicatedKillAvatar }, this, "handleReplicatedPackets"); + packetReceiver.registerListener(PacketType::ReplicatedBulkAvatarData, this, "handleReplicatedBulkAvatarPacket"); + auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &AvatarMixer::handlePacketVersionMismatch); } @@ -91,6 +93,41 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag } +void AvatarMixer::handleReplicatedBulkAvatarPacket(QSharedPointer message) { + auto nodeList = DependencyManager::get(); + + while (message->getBytesLeftToRead()) { + // first, grab the node ID for this replicated avatar + auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + + // make sure we have an upstream replicated node that matches + auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, + message->getSenderSockAddr(), message->getSenderSockAddr(), + DEFAULT_AGENT_PERMISSIONS, true); + + replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); + replicatedNode->setIsUpstream(true); + + // grab the size of the avatar byte array so we know how much to read + quint16 avatarByteArraySize; + message->readPrimitive(&avatarByteArraySize); + + // read the avatar byte array + auto avatarByteArray = message->read(avatarByteArraySize); + + // construct a "fake" avatar data received message from the byte array and packet list information + auto replicatedMessage = QSharedPointer::create(avatarByteArray, PacketType::AvatarData, + versionForPacketType(PacketType::AvatarData), + message->getSenderSockAddr(), nodeID); + + // queue up the replicated avatar data with the client data for the replicated node + auto start = usecTimestampNow(); + getOrCreateClientData(replicatedNode)->queuePacket(replicatedMessage, replicatedNode); + auto end = usecTimestampNow(); + _queueIncomingPacketElapsedTime += (end - start); + } +} + void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node& node) { // first, make sure that this is a packet from a node we are supposed to replicate if (node.isReplicated() diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 17a6db3b08..e0d073a281 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -47,6 +47,7 @@ private slots: void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleRequestsDomainListDataPacket(QSharedPointer message, SharedNodePointer senderNode); void handleReplicatedPackets(QSharedPointer message); + void handleReplicatedBulkAvatarPacket(QSharedPointer message); void domainSettingsRequestComplete(); void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID); void start(); diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index fe28c96340..a536eaabd3 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -452,9 +452,11 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin // so we always send a full update for this avatar quint64 start = usecTimestampNow(); AvatarDataPacket::HasFlags flagsOut; - QByteArray avatarByteArray = otherAvatar->toByteArray(AvatarData::SendAllData, 0, {}, - flagsOut, false, false, - glm::vec3(0), nullptr); + + QVector emptyLastJointSendData { otherAvatar->getJointCount() }; + + QByteArray avatarByteArray = otherAvatar->toByteArray(AvatarData::SendAllData, 0, emptyLastJointSendData, + flagsOut, false, false, glm::vec3(0), nullptr); quint64 end = usecTimestampNow(); _stats.toByteArrayElapsedTime += (end - start); @@ -477,17 +479,15 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin qCWarning(avatars) << "Replicated avatar data too large for" << otherAvatar->getSessionUUID() << "-" << avatarByteArray.size() << "bytes"; - avatarByteArray = otherAvatar->toByteArray(AvatarData::SendAllData, 0, {}, - flagsOut, true, false, - glm::vec3(0), nullptr); + avatarByteArray = otherAvatar->toByteArray(AvatarData::SendAllData, 0, emptyLastJointSendData, + flagsOut, true, false, glm::vec3(0), nullptr); if (avatarByteArray.size() > maxAvatarByteArraySize) { qCWarning(avatars) << "Replicated avatar data without facial data still too large for" << otherAvatar->getSessionUUID() << "-" << avatarByteArray.size() << "bytes"; - avatarByteArray = otherAvatar->toByteArray(AvatarData::MinimumData, 0, {}, - flagsOut, true, false, - glm::vec3(0), nullptr); + avatarByteArray = otherAvatar->toByteArray(AvatarData::MinimumData, 0, emptyLastJointSendData, + flagsOut, true, false, glm::vec3(0), nullptr); } } diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index 2c5a11334b..6ca249fb22 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -42,6 +42,20 @@ ReceivedMessage::ReceivedMessage(NLPacket& packet) { } +ReceivedMessage::ReceivedMessage(QByteArray byteArray, PacketType packetType, PacketVersion packetVersion, + const HifiSockAddr& senderSockAddr, QUuid sourceID) : + _data(byteArray), + _headData(_data.mid(0, HEAD_DATA_SIZE)), + _numPackets(1), + _sourceID(sourceID), + _packetType(packetType), + _packetVersion(packetVersion), + _senderSockAddr(senderSockAddr), + _isComplete(true) +{ + +} + void ReceivedMessage::setFailed() { _failed = true; _isComplete = true; diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index 3acb7163e7..ae51e7592a 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -24,6 +24,8 @@ class ReceivedMessage : public QObject { public: ReceivedMessage(const NLPacketList& packetList); ReceivedMessage(NLPacket& packet); + ReceivedMessage(QByteArray byteArray, PacketType packetType, PacketVersion packetVersion, + const HifiSockAddr& senderSockAddr, QUuid sourceID = QUuid()); QByteArray getMessage() const { return _data; } const char* getRawMessage() const { return _data.constData(); } From 50f46dafa6fa2bdc463b97f5732588d78eb5b259 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 15:38:15 -0700 Subject: [PATCH 083/157] add a sequence number to replicated avatar data --- .../src/avatars/AvatarMixerSlave.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index a536eaabd3..8a3ec2dc5a 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -475,6 +475,9 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin maxAvatarByteArraySize -= NUM_BYTES_RFC4122_UUID; maxAvatarByteArraySize -= sizeof(quint16); + auto sequenceNumberSize = sizeof(agentNodeData->getLastReceivedSequenceNumber()); + maxAvatarByteArraySize -= sequenceNumberSize; + if (avatarByteArray.size() > maxAvatarByteArraySize) { qCWarning(avatars) << "Replicated avatar data too large for" << otherAvatar->getSessionUUID() << "-" << avatarByteArray.size() << "bytes"; @@ -492,11 +495,21 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin } if (avatarByteArray.size() <= maxAvatarByteArraySize) { + // increment the number of avatars sent to this reciever + nodeData->incrementNumAvatarsSentLastFrame(); + + // set the last sent sequence number for this sender on the receiver + nodeData->setLastBroadcastSequenceNumber(agentNode->getUUID(), + agentNodeData->getLastReceivedSequenceNumber()); + // start a new segment in the packet list for this avatar avatarPacketList->startSegment(); + // write the node's UUID, the size of the replicated avatar data, + // the sequence number of the replicated avatar data, and the replicated avatar data numAvatarDataBytes += avatarPacketList->write(agentNode->getUUID().toRfc4122()); - numAvatarDataBytes += avatarPacketList->writePrimitive((quint16) avatarByteArray.size()); + numAvatarDataBytes += avatarPacketList->writePrimitive((quint16) (avatarByteArray.size() + sequenceNumberSize)); + numAvatarDataBytes += avatarPacketList->writePrimitive(agentNodeData->getLastReceivedSequenceNumber()); numAvatarDataBytes += avatarPacketList->write(avatarByteArray); avatarPacketList->endSegment(); From 9085a0896a308f0e197b4a1fd8f05881ade83061 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 15:46:14 -0700 Subject: [PATCH 084/157] manually activate sockets for downstream servers --- assignment-client/src/audio/AudioMixerClientData.cpp | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 4 ++-- libraries/networking/src/ThreadedAssignment.cpp | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 848dc969d8..e976e4176d 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -169,7 +169,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c packet->write(message.getMessage()); } - nodeList->sendUnreliablePacket(*packet, downstreamNode->getPublicSocket()); + nodeList->sendUnreliablePacket(*packet, *downstreamNode); } }); } diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 5aaf633ed9..57c48ee6d4 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -146,7 +146,7 @@ void AvatarMixer::optionallyReplicatePacket(ReceivedMessage& message, const Node packet->write(message.getMessage()); } - nodeList->sendUnreliablePacket(*packet, node->getPublicSocket()); + nodeList->sendUnreliablePacket(*packet, *node); }); } } @@ -402,7 +402,7 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { replicatedKillPacket->writePrimitive(KillAvatarReason::AvatarDisconnected); } - nodeList->sendUnreliablePacket(*replicatedKillPacket, node->getPublicSocket()); + nodeList->sendUnreliablePacket(*replicatedKillPacket, *node); } }); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 24573e0ffc..3e679f643a 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -163,6 +163,10 @@ void ThreadedAssignment::parseDownstreamServers(const QJsonObject& settingsObjec // manually add the downstream node to our node list auto node = nodeList->addOrUpdateNode(QUuid::createUuid(), NodeType::downstreamType(nodeType), downstreamServerAddr, downstreamServerAddr); + + // manually activate the public socket for the downstream node + node->activatePublicSocket(); + callback(*node); } } From 8f7a3595f58f58560c668fc44f78340e89b85e25 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 15:49:03 -0700 Subject: [PATCH 085/157] only send display name changes back to directly connected agents --- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 57c48ee6d4..988ddfed4c 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -163,7 +163,7 @@ AvatarMixer::~AvatarMixer() { } void AvatarMixer::sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { - if (destinationNode->getType() == NodeType::DownstreamAvatarMixer || !destinationNode->isUpstream()) { + if (destinationNode->getType() == NodeType::Agent && !destinationNode->isUpstream()) { QByteArray individualData = nodeData->getAvatar().identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); From 0708daa6ccfeb401ef53601eeaabfa3894448004 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jun 2017 16:10:08 -0700 Subject: [PATCH 086/157] Add separate sendReplicatedIdentityPacket --- assignment-client/src/avatars/AvatarMixer.cpp | 6 +++--- .../src/avatars/AvatarMixerSlave.cpp | 21 +++++++++++++++---- .../src/avatars/AvatarMixerSlave.h | 1 + 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 988ddfed4c..c88108fb36 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -76,14 +76,14 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); replicatedNode->setIsUpstream(true); + // seek back in the message so the packet handler can start by reading the source ID + message->seek(0); + switch (message->getType()) { case PacketType::ReplicatedAvatarIdentity: handleAvatarIdentityPacket(message, replicatedNode); break; case PacketType::ReplicatedKillAvatar: - // seek back in the message so the kill packet handler can start by reading the source ID - message->seek(0); - handleKillAvatarPacket(message, replicatedNode); break; default: diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 8a3ec2dc5a..55975a790d 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -65,18 +65,31 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) { _stats.processIncomingPacketsElapsedTime += (end - start); } - int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { if (destinationNode->getType() == NodeType::DownstreamAvatarMixer || !destinationNode->isUpstream()) { QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious - auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); + auto identityPackets = NLPacketList::create(PacketType::ReplicatedAvatarIdentity, QByteArray(), true, true); identityPackets->write(individualData); DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); _stats.numIdentityPackets++; return individualData.size(); } else { - return -1; + return 0; + } +} + +int AvatarMixerSlave::sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { + if (destinationNode->getType() == NodeType::DownstreamAvatarMixer || !destinationNode->isUpstream()) { + QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); + individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious + auto identityPackets = NLPacketList::create(PacketType::ReplicatedAvatarIdentity, QByteArray(), true, true); + identityPackets->write(individualData); + DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); + _stats.numIdentityPackets++; + return individualData.size(); + } else { + return 0; } } @@ -464,7 +477,7 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin if (lastBroadcastTime <= agentNodeData->getIdentityChangeTimestamp() || (start - lastBroadcastTime) >= REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US) { qDebug() << "Sending identity packet for " << agentNode->getUUID() << " to " << node->getUUID(); - sendIdentityPacket(agentNodeData, node); + sendReplicatedIdentityPacket(agentNodeData, node); nodeData->setLastBroadcastTime(agentNode->getUUID(), start); } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.h b/assignment-client/src/avatars/AvatarMixerSlave.h index c11ac3291c..509a8ec94b 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.h +++ b/assignment-client/src/avatars/AvatarMixerSlave.h @@ -92,6 +92,7 @@ public: private: int sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode); + int sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode); void broadcastAvatarDataToAgent(const SharedNodePointer& node); void broadcastAvatarDataToDownstreamMixer(const SharedNodePointer& node); From a476a5b82ea740ff34fa5f144acd4ad38d0b05a4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 13 Jun 2017 16:42:38 -0700 Subject: [PATCH 087/157] Change ReplicatedAvatarIdentity packet to be an unreliable packet --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 55975a790d..b6e76e2b57 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -69,7 +69,7 @@ int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, if (destinationNode->getType() == NodeType::DownstreamAvatarMixer || !destinationNode->isUpstream()) { QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious - auto identityPackets = NLPacketList::create(PacketType::ReplicatedAvatarIdentity, QByteArray(), true, true); + auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); identityPackets->write(individualData); DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); _stats.numIdentityPackets++; @@ -83,9 +83,9 @@ int AvatarMixerSlave::sendReplicatedIdentityPacket(const AvatarMixerClientData* if (destinationNode->getType() == NodeType::DownstreamAvatarMixer || !destinationNode->isUpstream()) { QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious - auto identityPackets = NLPacketList::create(PacketType::ReplicatedAvatarIdentity, QByteArray(), true, true); - identityPackets->write(individualData); - DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); + auto identityPacket = NLPacket::create(PacketType::ReplicatedAvatarIdentity); + identityPacket->write(individualData); + DependencyManager::get()->sendUnreliablePacket(*identityPacket, *destinationNode); _stats.numIdentityPackets++; return individualData.size(); } else { From 29842c67cc1705ae6d0446675426cf31ac0e1fc5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 13 Jun 2017 18:04:59 -0700 Subject: [PATCH 088/157] use received message faking for cleaner replication in audio --- assignment-client/src/audio/AudioMixer.cpp | 21 +++++++++++++++- .../src/audio/AudioMixerClientData.cpp | 24 +++++-------------- libraries/audio/src/InboundAudioStream.cpp | 12 +++++++++- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f8c2cf86e8..e397254441 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -125,7 +125,26 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); replicatedNode->setIsUpstream(true); - getOrCreateClientData(replicatedNode.data())->queuePacket(message, replicatedNode); + // construct a "fake" avatar data received message from the byte array and packet list information + auto audioData = message->getMessage().mid(NUM_BYTES_RFC4122_UUID); + + PacketType rewrittenType; + + if (message->getType() == PacketType::ReplicatedMicrophoneAudioNoEcho) { + rewrittenType = PacketType::MicrophoneAudioNoEcho; + } else if (message->getType() == PacketType::ReplicatedMicrophoneAudioWithEcho) { + rewrittenType = PacketType::MicrophoneAudioWithEcho; + } else if (message->getType() == PacketType::ReplicatedInjectAudio) { + rewrittenType = PacketType::InjectAudio; + } else if (message->getType() == PacketType::ReplicatedSilentAudioFrame) { + rewrittenType = PacketType::SilentAudioFrame; + } + + auto replicatedMessage = QSharedPointer::create(audioData, rewrittenType, + versionForPacketType(rewrittenType), + message->getSenderSockAddr(), nodeID); + + getOrCreateClientData(replicatedNode.data())->queuePacket(replicatedMessage, replicatedNode); } void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer message, SharedNodePointer sendingNode) { diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index e976e4176d..d4d098133d 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -160,10 +160,6 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c if (!isReplicatedPacket(message.getType())) { // since this packet will be non-sourced, we add the replicated node's ID here packet->write(node.getUUID().toRfc4122()); - - // we won't negotiate an audio format with the replicant, because we aren't a listener - // so pack the codec string here so that it can statelessly setup a decoder for this string when it needs - packet->writeString(_selectedCodecName); } packet->write(message.getMessage()); @@ -312,6 +308,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { // this is injected audio // grab the stream identifier for this injected audio message.seek(sizeof(quint16)); + QUuid streamIdentifier = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); bool isStereo; @@ -346,18 +343,6 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { // seek to the beginning of the packet so that the next reader is in the right spot message.seek(0); - if (packetType == PacketType::ReplicatedMicrophoneAudioWithEcho - || packetType == PacketType::ReplicatedMicrophoneAudioNoEcho - || packetType == PacketType::ReplicatedSilentAudioFrame - || packetType == PacketType::ReplicatedInjectAudio) { - - // skip past source ID for the replicated packet - message.seek(NUM_BYTES_RFC4122_UUID); - - // skip past the codec string - message.readString(); - } - // check the overflow count before we parse data auto overflowBefore = matchingStream->getOverflowCount(); auto parseResult = matchingStream->parseData(message); @@ -706,9 +691,9 @@ bool AudioMixerClientData::shouldIgnore(const SharedNodePointer self, const Shar } void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointer message) { - // first pull the codec string from the packet + // pull the codec string from the packet + message->seek(sizeof(quint16)); - // read the string for the codec auto codecString = message->readString(); qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID()) @@ -718,4 +703,7 @@ void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointerseek(0); } diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 65cccf1fe0..56353e14e3 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -127,7 +127,17 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { // parse the info after the seq number and before the audio data (the stream properties) int prePropertyPosition = message.getPosition(); int propertyBytes = parseStreamProperties(message.getType(), message.readWithoutCopy(message.getBytesLeftToRead()), networkFrames); - message.seek(prePropertyPosition + propertyBytes); + + if (message.getType() == PacketType::ReplicatedMicrophoneAudioNoEcho + || message.getType() == PacketType::ReplicatedMicrophoneAudioWithEcho + || message.getType() == PacketType::ReplicatedInjectAudio + || message.getType() == PacketType::ReplicatedSilentAudioFrame) { + message.seek(NUM_BYTES_RFC4122_UUID); + message.readString(); + message.read(sizeof(quint16) + prePropertyPosition + propertyBytes); + } else { + message.seek(prePropertyPosition + propertyBytes); + } // handle this packet based on its arrival status. switch (arrivalInfo._status) { From 2f307f418cf737172581196b2a33f80635f2ab0b Mon Sep 17 00:00:00 2001 From: seefo Date: Tue, 13 Jun 2017 15:40:37 -0700 Subject: [PATCH 089/157] Added support for dropdown to tables in domain settings --- .../resources/describe-settings.json | 13 ++++- .../resources/web/settings/js/settings.js | 49 +++++++++++++++++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 0143414db8..e9327d6a66 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1360,8 +1360,19 @@ { "name": "server_type", "label": "Server Type", + "type": "select", "placeholder": "Audio Mixer", - "can_set": true + "can_set": true, + "options": [ + { + "value": "Audio Mixer", + "label": "Audio Mixer" + }, + { + "value": "Avatar Mixer", + "label": "Avatar Mixer" + } + ] } ] } diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 8066223318..2c42699523 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1163,6 +1163,8 @@ function makeTable(setting, keypath, setting_value) { var isNonDeletableRow = !setting.can_add_new_rows; + // console.log(setting); + _.each(setting.columns, function(col) { var colValue, colName; @@ -1183,6 +1185,24 @@ function makeTable(setting, keypath, setting_value) { "" + ""; + } else if (isArray && col.type === "select" ) { + + //console.log("adding row"); + //console.log(col); + //console.log(setting); + + html += + "" + + ""; + html += ""; + + } else if (isArray && col.type === "time" && col.editable) { html += "" + @@ -1281,6 +1301,23 @@ function makeTableHiddenInputs(setting, initialValues, categoryValue) { "" + ""; + } else if (col.type === "select") { + + console.log(col); + console.log(setting); + console.log(categoryValue); + + html += "" + html += ""; + html += ""; + } else { html += " 1 ? "." + key : ""); + if (isCheckbox) { - input.attr("name", setting_name + "[" + row_index + "]" + (num_columns > 1 ? "." + key : "")) + input.attr("name", newName) } else { - input.attr("name", setting_name + "[" + row_index + "]" + (num_columns > 1 ? "." + key : "")) + if(isDropdown) { + $(element).children("select").attr("data-hidden-input", newName); + } + input.attr("name", newName); } } else { // because the name of the setting in question requires the key // setup a hook to change the HTML name of the element whenever the key changes + var colName = $(element).attr("name"); keyInput.on('change', function(){ input.attr("name", setting_name + "." + $(this).val() + "." + colName); From 4080814df8cdc1466673f47941021c601f2edf49 Mon Sep 17 00:00:00 2001 From: seefo Date: Tue, 13 Jun 2017 16:32:51 -0700 Subject: [PATCH 090/157] Cleaned up dropdown support for tables --- .../resources/web/settings/js/settings.js | 41 +++++-------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 2c42699523..3b8da0a849 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1163,8 +1163,6 @@ function makeTable(setting, keypath, setting_value) { var isNonDeletableRow = !setting.can_add_new_rows; - // console.log(setting); - _.each(setting.columns, function(col) { var colValue, colName; @@ -1185,24 +1183,6 @@ function makeTable(setting, keypath, setting_value) { "" + ""; - } else if (isArray && col.type === "select" ) { - - //console.log("adding row"); - //console.log(col); - //console.log(setting); - - html += - "" + - ""; - html += ""; - - } else if (isArray && col.type === "time" && col.editable) { html += "" + @@ -1302,13 +1282,8 @@ function makeTableHiddenInputs(setting, initialValues, categoryValue) { "name='" + col.name + "'" + (defaultValue ? " checked" : "") + "/>" + ""; } else if (col.type === "select") { - - console.log(col); - console.log(setting); - console.log(categoryValue); - html += "" - html += "'" for(var i in col.options) { var option = col.options[i]; @@ -1316,8 +1291,7 @@ function makeTableHiddenInputs(setting, initialValues, categoryValue) { } html += ""; - html += ""; - + html += ""; } else { html += " 1 ? "." + key : ""); - + if (isCheckbox) { input.attr("name", newName) } else { - if(isDropdown) { + if(isDropdown) { $(element).children("select").attr("data-hidden-input", newName); } input.attr("name", newName); @@ -1467,7 +1441,6 @@ function addTableRow(row) { } else { // because the name of the setting in question requires the key // setup a hook to change the HTML name of the element whenever the key changes - var colName = $(element).attr("name"); keyInput.on('change', function(){ input.attr("name", setting_name + "." + $(this).val() + "." + colName); @@ -1478,6 +1451,12 @@ function addTableRow(row) { input.focus(); focusChanged = true; } + + // if we are adding a dropdown, we should go ahead and make its select + // element is visible + if(isDropdown) { + $(element).children("select").attr("style", ""); + } if (isCheckbox) { $(input).find("input").attr("data-changed", "true"); From 2d9e92d1218bfa60184ffc176cff5348b3357864 Mon Sep 17 00:00:00 2001 From: seefo Date: Tue, 13 Jun 2017 18:08:26 -0700 Subject: [PATCH 091/157] Made requested changes to PR10683 --- domain-server/resources/web/settings/js/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 3b8da0a849..d35fbf0027 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1285,7 +1285,7 @@ function makeTableHiddenInputs(setting, initialValues, categoryValue) { html += "" html += "'" for (var i in col.options) { - var option = col.options[i]; + var option = col.options[i]; html += ""; } - html += ""; - html += ""; + html += ""; + html += ""; } else { html += " Date: Wed, 14 Jun 2017 17:20:37 -0700 Subject: [PATCH 125/157] change new Node flag to isForcedNeverSilent --- domain-server/src/DomainServer.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/networking/src/NetworkPeer.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 7907d8679f..be75ad61ee 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2267,7 +2267,7 @@ void DomainServer::updateDownstreamNodes() { // manually add the downstream node to our node list auto node = nodeList->addOrUpdateNode(QUuid::createUuid(), downstreamNodeType, downstreamServerAddr, downstreamServerAddr); - node->setIsForcedAlive(true); + node->setIsForcedNeverSilent(true); qDebug() << "Adding downstream node:" << node->getUUID() << downstreamServerAddr; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 994b5305e6..14a9d0b257 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -749,7 +749,7 @@ void LimitedNodeList::removeSilentNodes() { SharedNodePointer node = it->second; node->getMutex().lock(); - if (!node->isForcedAlive() + if (!node->isForcedNeverSilent() && (usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) { // call the NodeHash erase to get rid of this node it = _nodeHash.unsafe_erase(it); diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index ad7076285f..48dd82ecb7 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -76,8 +76,8 @@ public: float getOutboundBandwidth() const; // in kbps float getInboundBandwidth() const; // in kbps - bool isForcedAlive() const { return _isForcedAlive; } - void setIsForcedAlive(bool isForcedAlive) { _isForcedAlive = isForcedAlive; } + bool isForcedNeverSilent() const { return _isForcedNeverSilent; } + void setIsForcedNeverSilent(bool isForcedNeverSilent) { _isForcedNeverSilent = isForcedNeverSilent; } friend QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer); friend QDataStream& operator>>(QDataStream& in, NetworkPeer& peer); @@ -107,7 +107,7 @@ protected: int _connectionAttempts; - bool _isForcedAlive { false }; + bool _isForcedNeverSilent { false }; }; QDebug operator<<(QDebug debug, const NetworkPeer &peer); From 94abfc2d6b7e6ca58f352e0cab8f501ae55550e1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 15 Jun 2017 11:47:13 -0700 Subject: [PATCH 126/157] nomenclature changes from replication to broadcast --- domain-server/resources/describe-settings.json | 14 +++++++------- domain-server/src/DomainServer.cpp | 6 +++--- domain-server/src/DomainServerSettingsManager.cpp | 7 ++++--- libraries/networking/src/ThreadedAssignment.cpp | 6 +++--- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 020262ca13..10da5b55fc 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1320,15 +1320,15 @@ ] }, { - "name": "replication", - "label": "Replication", + "name": "broadcasting", + "label": "Broadcasting", "settings": [ { "name": "users", - "label": "Replicated Users", + "label": "Broadcasted Users", "type": "table", "can_add_new_rows": true, - "help": "Users that are replicated to downstream servers", + "help": "Users that are broadcasted to downstream servers", "numbered": false, "columns": [ { @@ -1340,11 +1340,11 @@ }, { "name": "downstream_servers", - "label": "Downstream Servers", + "label": "Receiving Servers", "assignment-types": [0,1], "type": "table", "can_add_new_rows": true, - "help": "Downstream servers that are relayed data for replicated users", + "help": "Servers that receive data for broadcasted users", "numbered": false, "columns": [ { @@ -1364,7 +1364,7 @@ "placeholder": "Audio Mixer", "default": "Audio Mixer", "can_set": true, - "options": [ + "options": [ { "value": "Audio Mixer", "label": "Audio Mixer" diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0c0f8a5e55..81f10d83c6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2220,11 +2220,11 @@ void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& } void DomainServer::updateReplicatedNodes() { - static const QString REPLICATION_SETTINGS_KEY = "replication"; + static const QString BROADCASTING_SETTINGS_KEY = "broadcasting"; _replicatedUsernames.clear(); auto settings = _settingsManager.getSettingsMap(); - if (settings.contains(REPLICATION_SETTINGS_KEY)) { - auto replicationSettings = settings.value(REPLICATION_SETTINGS_KEY).toMap(); + if (settings.contains(BROADCASTING_SETTINGS_KEY)) { + auto replicationSettings = settings.value(BROADCASTING_SETTINGS_KEY).toMap(); if (replicationSettings.contains("users")) { auto usersSettings = replicationSettings.value("users").toList(); for (auto& username : usersSettings) { diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 3d256bd2b9..9279648319 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -1197,7 +1197,7 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject) { static const QString SECURITY_ROOT_KEY = "security"; static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist"; - static const QString REPLICATION_KEY = "replication"; + static const QString BROADCASTING_KEY = "broadcasting"; auto& settingsVariant = _configMap.getConfig(); bool needRestart = false; @@ -1249,7 +1249,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ if (!matchingDescriptionObject.isEmpty()) { updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject); - if (rootKey != SECURITY_ROOT_KEY && rootKey != REPLICATION_KEY) { + if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY) { needRestart = true; } } else { @@ -1265,7 +1265,8 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ if (!matchingDescriptionObject.isEmpty()) { const QJsonValue& settingValue = rootValue.toObject()[settingKey]; updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject); - if ((rootKey != SECURITY_ROOT_KEY && rootKey != REPLICATION_KEY) || settingKey == AC_SUBNET_WHITELIST_KEY) { + if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY) + || settingKey == AC_SUBNET_WHITELIST_KEY) { needRestart = true; } } else { diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 3e679f643a..430775a7ac 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -135,10 +135,10 @@ void ThreadedAssignment::domainSettingsRequestFailed() { } void ThreadedAssignment::parseDownstreamServers(const QJsonObject& settingsObject, NodeType_t nodeType, DownstreamNodeFoundCallback callback) { - static const QString REPLICATION_GROUP_KEY = "replication"; + static const QString BROADCASTING_GROUP_KEY = "broadcasting"; static const QString DOWNSTREAM_SERVERS_SETTING_KEY = "downstream_servers"; - if (settingsObject.contains(REPLICATION_GROUP_KEY)) { - const QJsonObject replicationObject = settingsObject[REPLICATION_GROUP_KEY].toObject(); + if (settingsObject.contains(BROADCASTING_GROUP_KEY)) { + const QJsonObject replicationObject = settingsObject[BROADCASTING_GROUP_KEY].toObject(); const QJsonArray downstreamServers = replicationObject[DOWNSTREAM_SERVERS_SETTING_KEY].toArray(); From 6cf4ff1dafe54a9a3c5fae656cdf5c23d51a915f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 15 Jun 2017 13:44:44 -0700 Subject: [PATCH 127/157] remove debug and fix peek of session ID --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 1 - libraries/avatars/src/AvatarHashMap.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 17d222e9e3..4d5e507923 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -479,7 +479,6 @@ void AvatarMixerSlave::broadcastAvatarDataToDownstreamMixer(const SharedNodePoin auto lastBroadcastTime = nodeData->getLastBroadcastTime(agentNode->getUUID()); if (lastBroadcastTime <= agentNodeData->getIdentityChangeTimestamp() || (start - lastBroadcastTime) >= REBROADCAST_IDENTITY_TO_DOWNSTREAM_EVERY_US) { - qDebug() << "Sending identity packet for " << agentNode->getUUID() << " to " << node->getUUID(); sendReplicatedIdentityPacket(agentNodeData, node); nodeData->setLastBroadcastTime(agentNode->getUUID(), start); } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index cfbf2a8806..023bb39201 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -128,7 +128,7 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer message, SharedNodePointer sendingNode) { // peek the avatar UUID from the incoming packet - QUuid identityUUID = message->peek(NUM_BYTES_RFC4122_UUID); + QUuid identityUUID = QUuid::fromRfc4122(message->peek(NUM_BYTES_RFC4122_UUID)); // make sure this isn't for an ignored avatar auto nodeList = DependencyManager::get(); From 8f154321a4727cbfde9d156cf5ab574aaf01b099 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 15 Jun 2017 14:25:10 -0700 Subject: [PATCH 128/157] never process null avatar ID in avatar manager --- libraries/avatars/src/AvatarHashMap.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 023bb39201..06ead63de1 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -130,6 +130,11 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer // peek the avatar UUID from the incoming packet QUuid identityUUID = QUuid::fromRfc4122(message->peek(NUM_BYTES_RFC4122_UUID)); + if (identityUUID.isNull()) { + qCDebug(avatars) << "Refusing to process identity packet for null avatar ID"; + return; + } + // make sure this isn't for an ignored avatar auto nodeList = DependencyManager::get(); static auto EMPTY = QUuid(); From 330a27b3a089bc64db1edd9adc16076fbc068aee Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 15 Jun 2017 14:25:21 -0700 Subject: [PATCH 129/157] Fix removing all downstream nodes in settings not killing nodes --- domain-server/src/DomainServer.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index be75ad61ee..9a69e3077e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2227,11 +2227,12 @@ static const QString REPLICATION_SETTINGS_KEY = "replication"; void DomainServer::updateDownstreamNodes() { auto settings = _settingsManager.getSettingsMap(); if (settings.contains(REPLICATION_SETTINGS_KEY)) { + auto nodeList = DependencyManager::get(); + std::vector downstreamNodesInSettings; auto replicationSettings = settings.value(REPLICATION_SETTINGS_KEY).toMap(); if (replicationSettings.contains("downstream_servers")) { auto serversSettings = replicationSettings.value("downstream_servers").toList(); - auto nodeList = DependencyManager::get(); std::vector knownDownstreamNodes; nodeList->eachNode([&](const SharedNodePointer& otherNode) { if (NodeType::isDownstream(otherNode->getType())) { @@ -2239,8 +2240,6 @@ void DomainServer::updateDownstreamNodes() { } }); - std::vector downstreamNodesInSettings; - for (auto& server : serversSettings) { auto downstreamServer = server.toMap(); @@ -2277,20 +2276,20 @@ void DomainServer::updateDownstreamNodes() { } } - std::vector nodesToKill; - nodeList->eachNode([&](const SharedNodePointer& otherNode) { - if (NodeType::isDownstream(otherNode->getType())) { - bool nodeInSettings = find(downstreamNodesInSettings.cbegin(), downstreamNodesInSettings.cend(), - otherNode->getPublicSocket()) != downstreamNodesInSettings.cend(); - if (!nodeInSettings) { - qDebug() << "Removing downstream node:" << otherNode->getUUID() << otherNode->getPublicSocket(); - nodesToKill.push_back(otherNode); - } + } + std::vector nodesToKill; + nodeList->eachNode([&](const SharedNodePointer& otherNode) { + if (NodeType::isDownstream(otherNode->getType())) { + bool nodeInSettings = find(downstreamNodesInSettings.cbegin(), downstreamNodesInSettings.cend(), + otherNode->getPublicSocket()) != downstreamNodesInSettings.cend(); + if (!nodeInSettings) { + qDebug() << "Removing downstream node:" << otherNode->getUUID() << otherNode->getPublicSocket(); + nodesToKill.push_back(otherNode); } - }); - for (auto& node : nodesToKill) { - handleKillNode(node); } + }); + for (auto& node : nodesToKill) { + handleKillNode(node); } } } From 0565cfa2b7f41a6cf0f0616607b87e9035b9221d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 15 Jun 2017 14:59:12 -0700 Subject: [PATCH 130/157] fix for array additions in DS settings --- .../resources/web/settings/js/settings.js | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 2947983ef9..3196213e4a 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -39,7 +39,8 @@ var Settings = { ACCESS_TOKEN_SELECTOR: '[name="metaverse.access_token"]', PLACES_TABLE_ID: 'places-table', FORM_ID: 'settings-form', - INVALID_ROW_CLASS: 'invalid-input' + INVALID_ROW_CLASS: 'invalid-input', + DATA_ROW_INDEX: 'data-row-index' }; var viewHelpers = { @@ -223,10 +224,10 @@ $(document).ready(function(){ // set focus to the first input in the new row $target.closest('table').find('tr.inputs input:first').focus(); } - + var tableRows = sibling.parent(); var tableBody = tableRows.parent(); - + // if theres no more siblings, we should jump to a new row if (sibling.next().length == 0 && tableRows.nextAll().length == 1) { tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click(); @@ -1005,7 +1006,7 @@ function saveSettings() { var password = formJSON["security"]["http_password"]; var verify_password = formJSON["security"]["verify_http_password"]; - // if they've only emptied out the default password field, we should go ahead and acknowledge + // if they've only emptied out the default password field, we should go ahead and acknowledge // the verify password field if (password != undefined && verify_password == undefined) { verify_password = ""; @@ -1158,8 +1159,9 @@ function makeTable(setting, keypath, setting_value) { } html += ""; + (isCategorized ? ("data-category='" + categoryValue + "'") : "") + " " + + (isArray ? "" : "name='" + keypath + "." + rowIndexOrName + "'") + + (isArray ? Settings.DATA_ROW_INDEX + "='" + (row_num - 1) + "'" : "" ) + ">"; if (setting.numbered === true) { html += "" + row_num + "" @@ -1292,12 +1294,12 @@ function makeTableHiddenInputs(setting, initialValues, categoryValue) { } else if (col.type === "select") { html += "" html += ""; html += ""; } else { @@ -1398,6 +1400,15 @@ function addTableRow(row) { var setting_name = table.attr("name"); row.addClass(Settings.DATA_ROW_CLASS + " " + Settings.NEW_ROW_CLASS); + // if this is an array, add the row index (which is the index of the last row + 1) + // as a data attribute to the row + var row_index = 0; + if (isArray) { + var previous_row_index = parseInt(row.siblings('.' + Settings.DATA_ROW_CLASS + ':last').attr(Settings.DATA_ROW_INDEX), 10); + row_index = previous_row_index + 1; + row.attr(Settings.DATA_ROW_INDEX, row_index); + } + var focusChanged = false; _.each(row.children(), function(element) { @@ -1430,7 +1441,6 @@ function addTableRow(row) { var isDropdown = input.hasClass("table-dropdown"); if (isArray) { - var row_index = row.siblings('.' + Settings.DATA_ROW_CLASS).length var key = $(element).attr('name'); // are there multiple columns or just one? @@ -1438,16 +1448,13 @@ function addTableRow(row) { var num_columns = row.children('.' + Settings.DATA_COL_CLASS).length var newName = setting_name + "[" + row_index + "]" + (num_columns > 1 ? "." + key : ""); - if (isCheckbox) { - input.attr("name", newName) - } else { - if (isDropdown) { - // default values for hidden inputs inside child selects gets cleared so we need to remind it - var selectElement = $(element).children("select"); - selectElement.attr("data-hidden-input", newName); - $(element).children("input").val(selectElement.val()); - } - input.attr("name", newName); + input.attr("name", newName); + + if (isDropdown) { + // default values for hidden inputs inside child selects gets cleared so we need to remind it + var selectElement = $(element).children("select"); + selectElement.attr("data-hidden-input", newName); + $(element).children("input").val(selectElement.val()); } } else { // because the name of the setting in question requires the key @@ -1462,10 +1469,10 @@ function addTableRow(row) { input.focus(); focusChanged = true; } - + // if we are adding a dropdown, we should go ahead and make its select // element is visible - if (isDropdown) { + if (isDropdown) { $(element).children("select").attr("style", ""); } From d7724b90afa7de507fe45f7bf77aad6f7e249fa8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 15 Jun 2017 15:01:03 -0700 Subject: [PATCH 131/157] address code review comments --- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index b5faf71bde..76ce2061c0 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -103,7 +103,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : ); connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled); - connect(nodeList.data(), &NodeList::nodeAdded, this, [this](SharedNodePointer node) { + connect(nodeList.data(), &NodeList::nodeAdded, this, [this](const SharedNodePointer& node) { if (node->getType() == NodeType::DownstreamAudioMixer) { node->activatePublicSocket(); } diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 631145aee4..1ec3ed54c4 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -63,7 +63,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : auto nodeList = DependencyManager::get(); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &AvatarMixer::handlePacketVersionMismatch); - connect(nodeList.data(), &NodeList::nodeAdded, this, [this](SharedNodePointer node) { + connect(nodeList.data(), &NodeList::nodeAdded, this, [this](const SharedNodePointer& node) { if (node->getType() == NodeType::DownstreamAvatarMixer) { getOrCreateClientData(node); node->activatePublicSocket(); From 07102cc98dd476f62f0e24442ea6513b88b0662d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 16 Jun 2017 00:25:27 +0100 Subject: [PATCH 132/157] improving the ui --- .../qml/hifi/tablet/OpenVrConfiguration.qml | 238 +++++++++++++----- plugins/openvr/src/ViveControllerManager.cpp | 145 ++++------- plugins/openvr/src/ViveControllerManager.h | 4 +- 3 files changed, 222 insertions(+), 165 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 23af4fd93d..30685010ec 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -35,8 +35,21 @@ Rectangle { readonly property bool handController: handBox.checked readonly property bool handPuck: handPuckBox.checked + property int state: buttonState.disabled + property var lastConfiguration: null + HifiConstants { id: hifi } + QtObject { + id: buttonState + readonly property int disabled: 0 + readonly property int apply: 1 + readonly property int applyAndCalibrate: 2 + readonly property int calibrate: 3 + + } + + MouseArea { id: mouseArea @@ -66,7 +79,7 @@ Rectangle { anchors.top: head.bottom anchors.topMargin: 5 anchors.left: openVrConfiguration.left - anchors.leftMargin: leftMargin + 20 + anchors.leftMargin: leftMargin + 10 spacing: 10 HifiControls.CheckBox { @@ -81,7 +94,7 @@ Rectangle { } else { checked = true; } - composeConfigurationSettings(); + sendConfigurationSettings(); } } @@ -103,7 +116,7 @@ Rectangle { } else { checked = true; } - composeConfigurationSettings(); + sendConfigurationSettings(); } } @@ -112,8 +125,35 @@ Rectangle { text: "Tracker" color: hifi.colors.lightGrayText } - } + HifiControls.SpinBox { + id: headYOffset + decimals: 4 + width: 110 + label: "Y: offset" + value: -0.0254 + stepSize: 0.0254 + colorScheme: hifi.colorSchemes.dark + + onEditingFinished: { + } + } + + + HifiControls.SpinBox { + id: headZOffset + width: 105 + label: "Z: offset" + value: -0.152 + stepSize: 0.0254 + decimals: 4 + colorScheme: hifi.colorSchemes.dark + + onEditingFinished: { + } + } + } + RalewayBold { id: hands @@ -133,7 +173,7 @@ Rectangle { anchors.top: hands.bottom anchors.topMargin: 5 anchors.left: openVrConfiguration.left - anchors.leftMargin: leftMargin + 20 + anchors.leftMargin: leftMargin + 10 spacing: 10 HifiControls.CheckBox { @@ -148,7 +188,7 @@ Rectangle { } else { checked = true; } - composeConfigurationSettings(); + sendConfigurationSettings(); } } @@ -170,7 +210,7 @@ Rectangle { } else { checked = true; } - composeConfigurationSettings(); + sendConfigurationSettings(); } } @@ -179,6 +219,33 @@ Rectangle { text: "Trackers" color: hifi.colors.lightGrayText } + + HifiControls.SpinBox { + id: handYOffset + decimals: 4 + width: 105 + label: "Y: offset" + value: -0.0508 + stepSize: 0.0254 + colorScheme: hifi.colorSchemes.dark + + onEditingFinished: { + } + } + + + HifiControls.SpinBox { + id: handZOffset + width: 105 + label: "Z: offset" + value: -0.0254 + stepSize: 0.0254 + decimals: 4 + colorScheme: hifi.colorSchemes.dark + + onEditingFinished: { + } + } } RalewayBold { @@ -200,7 +267,7 @@ Rectangle { anchors.top: additional.bottom anchors.topMargin: 15 anchors.left: openVrConfiguration.left - anchors.leftMargin: leftMargin + 20 + anchors.leftMargin: leftMargin + 10 spacing: 10 HifiControls.CheckBox { @@ -213,7 +280,7 @@ Rectangle { if (hipsChecked) { checked = true; } - composeConfigurationSettings(); + sendConfigurationSettings(); } } @@ -229,7 +296,7 @@ Rectangle { anchors.top: feetConfig.bottom anchors.topMargin: 15 anchors.left: openVrConfiguration.left - anchors.leftMargin: leftMargin + 20 + anchors.leftMargin: leftMargin + 10 spacing: 10 HifiControls.CheckBox { @@ -246,7 +313,7 @@ Rectangle { if (chestChecked) { checked = true; } - composeConfigurationSettings(); + sendConfigurationSettings(); } } @@ -269,7 +336,7 @@ Rectangle { anchors.top: hipConfig.bottom anchors.topMargin: 15 anchors.left: openVrConfiguration.left - anchors.leftMargin: leftMargin + 20 + anchors.leftMargin: leftMargin + 10 spacing: 10 HifiControls.CheckBox { @@ -283,7 +350,7 @@ Rectangle { hipBox.checked = true; feetBox.checked = true; } - composeConfigurationSettings(); + sendConfigurationSettings(); } } @@ -306,7 +373,7 @@ Rectangle { anchors.top: chestConfig.bottom anchors.topMargin: 15 anchors.left: openVrConfiguration.left - anchors.leftMargin: leftMargin + 20 + anchors.leftMargin: leftMargin + 10 spacing: 10 HifiControls.CheckBox { @@ -320,7 +387,7 @@ Rectangle { hipBox.checked = true; feetBox.checked = true; } - composeConfigurationSettings(); + sendConfigurationSettings(); } } @@ -345,52 +412,23 @@ Rectangle { } - Rectangle { + HifiControls.Button { + id: calibrationButton - width: 200 - height: 35 - radius: 6 - - color: hifi.colors.blueHighlight - + color: hifi.buttons.blue + text: "Calibrate" + //glyph: hifi.glyphs.avatar1 anchors.top: bottomSeperator.bottom anchors.topMargin: 10 anchors.left: parent.left anchors.leftMargin: leftMargin - - - HiFiGlyphs { - id: calibrationGlyph - text: hifi.glyphs.avatar1 - size: 36 - color: hifi.colors.white - - anchors.left: parent.left - anchors.leftMargin: 30 - - } - - RalewayRegular { - id: calibrate - text: "CALIBRATE" - size: 17 - color: hifi.colors.white - - anchors.left: calibrationGlyph.right - anchors.top: parent.top - anchors.topMargin: 8 - } - - MouseArea { - anchors.fill: parent - - onClicked: { - openVrConfiguration.countDown = timeToCalibrate.value; - numberAnimation.start(); - calibrationTimer.start(); - info.visible = true; - info.showCountDown = true; - } + + onClicked: { + openVrConfiguration.countDown = timeToCalibrate.value; + numberAnimation.start(); + calibrationTimer.start(); + info.visible = true; + info.showCountDown = true; } } @@ -421,16 +459,18 @@ Rectangle { Component.onCompleted: { InputConfiguration.calibrationStatus.connect(calibrationStatusInfo); + lastConfiguration = composeConfigurationSettings(); } HifiControls.SpinBox { id: timeToCalibrate - + width: 70 anchors.top: calibrationButton.bottom anchors.topMargin: 40 anchors.left: parent.left anchors.leftMargin: leftMargin + minimumValue: 3 label: "Time til calibration ( in seconds )" colorScheme: hifi.colorSchemes.dark @@ -590,7 +630,7 @@ Rectangle { RalewayBold { id: uncalibrateText text: "Uncalibration Successful" - size: 42 + size: 37 color: hifi.colors.greenHighlight anchors.centerIn: parent } @@ -621,6 +661,58 @@ Rectangle { } } + function updateButtonState() { + var settings = composeConfigurationSettings(); + var bodySetting = settings["bodyConfiguration"]; + var headSetting = settings["headConfiguration"]; + var headOverride = headSetting["override"]; + var handSetting = settings["handConfiguration"]; + var handOverride = settings["override"]; + + var settingsChanged = false; + + if (lastConfiguration["bodyConfiguration"]["override"] !== bodySetting["override"]) { + settingsChanged = true; + } + + var lastHead = lastConfiguration["headConfiguration"]; + if (lastHead["override"] !== headOverride) { + settingsChanged = true; + } + + var lastHand = lastConfiguration["handConfiguration"]; + if (lastHand["override"] !== handOverride) { + settingsChanged = true; + } + + if (settingsChanged) { + if ((!handOverride) && (!headOverride) && (bodySetting === "Auto")) { + state = buttonState.apply; + } else { + state = buttonState.applyAndCalibrate; + } + } else { + if (state == buttonState.apply) { + state = buttonState.disabled; + } + } + + lastConfiguration = settings; + } + + function updateCalibrationText() { + updateButtonState(); + if (buttonState.disabled == state) { + calibrationButton.text = "Apply"; + } else if (buttonState.apply == state) { + calibrationButton.text = "Apply"; + } else if (buttonState.applyAndCalibrate == state) { + calibrationButton.text = "Apply And Calibrate"; + } else if (buttonState.calibrate == state) { + calibrationButton.text = "Calibrate"; + } + } + function composeConfigurationSettings() { var trackerConfiguration = ""; var overrideHead = false; @@ -631,7 +723,7 @@ Rectangle { } else if (shouldersChecked) { trackerConfiguration = "FeetHipsAndShoulders"; } else if (chestChecked) { - trackerConfiguration = "FeetHipsChest"; + trackerConfiguration = "FeetHipsAndChest"; } else if (hipsChecked) { trackerConfiguration = "FeetAndHips"; } else if (feetChecked) { @@ -652,14 +744,30 @@ Rectangle { overrideHandController = true; } - - var settingsObject = { - "trackerConfiguration": trackerConfiguration, - "overrideHead": overrideHead, - "overrideHandController": overrideHandController + var headObject = { + "override": overrideHead, + "Y": headYOffset.value, + "Z": headZOffset.value } - InputConfiguration.setConfigurationSettings(settingsObject, pluginName); + var handObject = { + "override": overrideHandController, + "Y": handYOffset.value, + "Z": handZOffset.value + } + + var settingsObject = { + "bodyConfiguration": trackerConfiguration, + "headConfiguration": headObject, + "handConfiguration": handObject + } + return settingsObject; + } + + function sendConfigurationSettings() { + var settings = composeConfigurationSettings(); + InputConfiguration.setConfigurationSettings(settings, pluginName); + updateCalibrationText(); } } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 69d5fde5d3..e9915934af 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -47,19 +47,23 @@ static const char* MENU_PARENT = "Avatar"; static const char* MENU_NAME = "Vive Controllers"; static const char* MENU_PATH = "Avatar" ">" "Vive Controllers"; static const char* RENDER_CONTROLLERS = "Render Hand Controllers"; + static const int MIN_HEAD = 1; static const int MIN_PUCK_COUNT = 2; static const int MIN_FEET_AND_HIPS = 3; static const int MIN_FEET_HIPS_CHEST = 4; -static const int MIN_FEET_HIPS_HEAD = 4; static const int MIN_FEET_HIPS_SHOULDERS = 5; -static const int MIN_FEET_HIPS_CHEST_HEAD = 5; +static const int MIN_FEET_HIPS_CHEST_SHOULDERS = 6; + static const int FIRST_FOOT = 0; static const int SECOND_FOOT = 1; static const int HIP = 2; static const int CHEST = 3; + static float HEAD_PUCK_Y_OFFSET = -0.0254f; static float HEAD_PUCK_Z_OFFSET = -0.152f; +static float HAND_PUCK_Y_OFFSET = -0.0508f; +static float HAND_PUCK_Z_OFFSET = 0.0254f; const char* ViveControllerManager::NAME { "OpenVR" }; @@ -117,6 +121,12 @@ static QString deviceTrackingResultToString(vr::ETrackingResult trackingResult) return result; } +void ViveControllerManager::calibrate() { + if (isSupported()) { + _inputDevice->calibrateNextFrame(); + } +} + bool ViveControllerManager::isSupported() const { return openVrSupported(); } @@ -233,7 +243,7 @@ ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : contro _configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders"); if (openVrSupported()) { - createPreferences(); + loadSettings(); } } @@ -340,6 +350,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso iter++; } } + + saveSettings(); } void ViveControllerManager::InputDevice::calibrateNextFrame() { @@ -469,11 +481,15 @@ bool ViveControllerManager::InputDevice::configureHands(glm::mat4& defaultToRefe if (determineLimbOrdering(firstHandPose, secondHandPose, headXAxis, headPosition)) { calibrateLeftHand(defaultToReferenceMat, inputCalibration, firstHand); calibrateRightHand(defaultToReferenceMat, inputCalibration, secondHand); + _validTrackedObjects.erase(_validTrackedObjects.begin()); + _validTrackedObjects.erase(_validTrackedObjects.end() - 1); _overrideHands = true; return true; } else { calibrateLeftHand(defaultToReferenceMat, inputCalibration, secondHand); calibrateRightHand(defaultToReferenceMat, inputCalibration, firstHand); + _validTrackedObjects.erase(_validTrackedObjects.begin()); + _validTrackedObjects.erase(_validTrackedObjects.end() - 1); _overrideHands = true; return true; } @@ -489,7 +505,7 @@ bool ViveControllerManager::InputDevice::configureHead(glm::mat4& defaultToRefer int puckCount = (int)_validTrackedObjects.size(); if (_headConfig == HeadConfig::Puck && puckCount >= MIN_HEAD) { calibrateHead(defaultToReferenceMat, inputCalibration); - _validTrackedObjects.erase(_validTrackedObjects.end()); + _validTrackedObjects.erase(_validTrackedObjects.end() - 1); _overrideHead = true; return true; } else if (_headConfig == HeadConfig::HMD) { @@ -499,7 +515,10 @@ bool ViveControllerManager::InputDevice::configureHead(glm::mat4& defaultToRefer } bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { + std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition); int puckCount = (int)_validTrackedObjects.size(); + glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); + glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); if (_config == Config::None) { return true; } else if (_config == Config::Feet && puckCount >= MIN_PUCK_COUNT) { @@ -521,24 +540,15 @@ bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToRefer int secondShoulderIndex = 4; calibrateShoulders(defaultToReferenceMat, inputCalibration, firstShoulderIndex, secondShoulderIndex); return true; - } /*else if (_config == Config::FeetHipsAndHead && puckCount == MIN_FEET_HIPS_HEAD) { - glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); - glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); - calibrateFeet(defaultToReferenceMat, inputCalibration, headXAxis, headPosition); - calibrateHips(defaultToReferenceMat, inputCalibration); - calibrateHead(defaultToReferenceMat, inputCalibration); - _overrideHead = true; - return true; - } else if (_config == Config::FeetHipsChestAndHead && puckCount == MIN_FEET_HIPS_CHEST_HEAD) { - glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); - glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); - calibrateFeet(defaultToReferenceMat, inputCalibration, headXAxis, headPosition); + } else if (_config == Config::FeetHipsChestAndShoulders && puckCount >= MIN_FEET_HIPS_CHEST_SHOULDERS) { + calibrateFeet(defaultToReferenceMat, inputCalibration); calibrateHips(defaultToReferenceMat, inputCalibration); calibrateChest(defaultToReferenceMat, inputCalibration); - calibrateHead(defaultToReferenceMat, inputCalibration); - _overrideHead = true; + int firstShoulderIndex = 4; + int secondShoulderIndex = 5; + calibrateShoulders(defaultToReferenceMat, inputCalibration, firstShoulderIndex, secondShoulderIndex); return true; - }*/ + } qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks"; uncalibrate(); emitCalibrationStatus(false); @@ -861,25 +871,6 @@ void ViveControllerManager::InputDevice::hapticsHelper(float deltaTime, bool lef } } -void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { - auto& firstFoot = _validTrackedObjects[FIRST_FOOT]; - auto& secondFoot = _validTrackedObjects[SECOND_FOOT]; - controller::Pose& firstFootPose = firstFoot.second; - controller::Pose& secondFootPose = secondFoot.second; - - if (firstFootPose.translation.x < secondFootPose.translation.x) { - _jointToPuckMap[controller::LEFT_FOOT] = firstFoot.first; - _pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, firstFootPose); - _jointToPuckMap[controller::RIGHT_FOOT] = secondFoot.first; - _pucksOffset[secondFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightFoot, secondFootPose); - } else { - _jointToPuckMap[controller::LEFT_FOOT] = secondFoot.first; - _pucksOffset[secondFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, secondFootPose); - _jointToPuckMap[controller::RIGHT_FOOT] = firstFoot.first; - _pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightFoot, firstFootPose); - } -} - void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) { controller::Pose& handPose = handPair.second; glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()); @@ -897,19 +888,19 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToR glm::vec3 yPrime = glm::normalize(glm::cross(zPrime, xPrime)); glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f), - glm::vec4(zPrime, 0.0f), glm::vec4(handPoseTranslation, 1.0f)); + glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - glm::vec3 translationOffset = glm::vec3(0.0f, -0.0508f, 0.0254f); + glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET); glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat); glm::quat finalRotation = glmExtractRotation(newHandMat); glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation; - glm::mat4 offset = createMatFromQuatAndPos(rotationOffset, translationOffset); + glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset); _jointToPuckMap[controller::LEFT_HAND] = handPair.first; - _pucksOffset[handPair.first] = offset; + _pucksOffset[handPair.first] = offsetMat; } void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair) { @@ -929,24 +920,26 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo glm::vec3 yPrime = glm::normalize(glm::cross(zPrime, xPrime)); glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f), - glm::vec4(zPrime, 0.0f), glm::vec4(handPoseTranslation, 1.0f)); + glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - glm::vec3 translationOffset = glm::vec3(0.0f, -0.0508f, 0.0254f); + glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET); glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat); glm::quat finalRotation = glmExtractRotation(newHandMat); glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation; - glm::mat4 offset = createMatFromQuatAndPos(rotationOffset, translationOffset); + glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset); _jointToPuckMap[controller::RIGHT_HAND] = handPair.first; - _pucksOffset[handPair.first] = offset; + _pucksOffset[handPair.first] = offsetMat; } -void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, glm::vec3 headXAxis, glm::vec3 headPosition) { +void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { + glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); + glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); auto& firstFoot = _validTrackedObjects[FIRST_FOOT]; auto& secondFoot = _validTrackedObjects[SECOND_FOOT]; controller::Pose& firstFootPose = firstFoot.second; @@ -1016,7 +1009,9 @@ void ViveControllerManager::InputDevice::loadSettings() { Settings settings; settings.beginGroup("PUCK_CONFIG"); { - _preferedConfig = (Config)settings.value("configuration", QVariant((int)Config::None)).toInt(); + _preferedConfig = (Config)settings.value("body configuration", QVariant((int)Config::None)).toInt(); + _headConfig = (HeadConfig)settings.value("head configuration", QVariant((int)HeadConfig::HMD)).toInt(); + _handConfig = (HandConfig)settings.value("hand configuration", QVariant((int)HandConfig::HandController)).toInt(); } settings.endGroup(); } @@ -1025,7 +1020,9 @@ void ViveControllerManager::InputDevice::saveSettings() const { Settings settings; settings.beginGroup("PUCK_CONFIG"); { - settings.setValue(QString("configuration"), (int)_preferedConfig); + settings.setValue(QString("body configuration"), (int)_preferedConfig); + settings.setValue(QString("head configuration"), (int)_headConfig); + settings.setValue(QString("hand configuration"), (int)_handConfig); } settings.endGroup(); } @@ -1045,54 +1042,8 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu _preferedConfig = Config::FeetHipsAndChest; } else if (value == "FeetHipsAndShoulders") { _preferedConfig = Config::FeetHipsAndShoulders; - } -} - -void ViveControllerManager::InputDevice::createPreferences() { - loadSettings(); - auto preferences = DependencyManager::get(); - static const QString VIVE_PUCKS_CONFIG = "Vive Pucks Configuration"; - - { - static const float MIN_VALUE = -3.0f; - static const float MAX_VALUE = 3.0f; - static const float STEP = 0.01f; - - auto getter = [this]()->float { return HEAD_PUCK_Y_OFFSET; }; - auto setter = [this](const float& value) { HEAD_PUCK_Y_OFFSET = value; }; - - auto preference = new SpinnerPreference(VIVE_PUCKS_CONFIG, "HeadPuckYOffset", getter, setter); - preference->setMin(MIN_VALUE); - preference->setMax(MAX_VALUE); - preference->setDecimals(3); - preference->setStep(STEP); - preferences->addPreference(preference); - } - - { - static const float MIN_VALUE = -3.0f; - static const float MAX_VALUE = 3.0f; - static const float STEP = 0.01f; - - auto getter = [this]()->float { return HEAD_PUCK_Z_OFFSET; }; - auto setter = [this](const float& value) { HEAD_PUCK_Z_OFFSET = value; }; - - auto preference = new SpinnerPreference(VIVE_PUCKS_CONFIG, "HeadPuckXOffset", getter, setter); - preference->setMin(MIN_VALUE); - preference->setMax(MAX_VALUE); - preference->setStep(STEP); - preference->setDecimals(3); - preferences->addPreference(preference); - } - - { - auto getter = [this]()->QString { return _configStringMap[_preferedConfig]; }; - auto setter = [this](const QString& value) { setConfigFromString(value); saveSettings(); }; - auto preference = new ComboBoxPreference(VIVE_PUCKS_CONFIG, "Configuration", getter, setter); - QStringList list = {"Auto", "Feet", "FeetAndHips", "FeetHipsAndChest", "FeetHipsAndShoulders", "FeetHipsAndHead"}; - preference->setItems(list); - preferences->addPreference(preference); - + } else if (value == "FeetHipsChestAndShoulders") { + _preferedConfig = Config::FeetHipsChestAndShoulders; } } diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index f3b37495cb..2e9137c4d9 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -46,7 +46,7 @@ public: QString configurationLayout() override; void setConfigurationSettings(const QJsonObject configurationSettings) override; QJsonObject configurationSettings() override; - void calibrate() override { _inputDevice->calibrateNextFrame(); } + void calibrate() override; bool isHeadController() const override { return true; } bool isHeadControllerMounted() const; @@ -69,7 +69,6 @@ private: QString getDefaultMappingConfig() const override; void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; void focusOutEvent() override; - void createPreferences(); bool triggerHapticPulse(float strength, float duration, controller::Hand hand) override; void hapticsHelper(float deltaTime, bool leftHand); void calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration); @@ -102,7 +101,6 @@ private: void calibrateLeftHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair); void calibrateRightHand(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair); void calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); - void calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, glm::vec3 headXAxis, glm::vec3 headPosition); void calibrateHips(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); void calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); void calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, From 36b49901148c19f03d331133f60cbc7e608d7e83 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 15 Jun 2017 17:19:05 -0700 Subject: [PATCH 133/157] fix for table additions when there is no initial row --- domain-server/resources/web/settings/js/settings.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 3196213e4a..181e5baa21 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -1404,8 +1404,14 @@ function addTableRow(row) { // as a data attribute to the row var row_index = 0; if (isArray) { - var previous_row_index = parseInt(row.siblings('.' + Settings.DATA_ROW_CLASS + ':last').attr(Settings.DATA_ROW_INDEX), 10); - row_index = previous_row_index + 1; + var previous_row = row.siblings('.' + Settings.DATA_ROW_CLASS + ':last'); + + if (previous_row.length > 0) { + row_index = parseInt(previous_row.attr(Settings.DATA_ROW_INDEX), 10) + 1; + } else { + row_index = 0; + } + row.attr(Settings.DATA_ROW_INDEX, row_index); } From c332244f4f7ebe525f0d7ce973c28805f413d45d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 15 Jun 2017 17:34:20 -0700 Subject: [PATCH 134/157] fix race for isUpstream and node hole punch --- assignment-client/src/audio/AudioMixer.cpp | 3 +-- assignment-client/src/avatars/AvatarMixer.cpp | 3 +-- libraries/networking/src/LimitedNodeList.cpp | 12 ++++++++---- libraries/networking/src/LimitedNodeList.h | 5 +++-- libraries/networking/src/Node.cpp | 8 ++------ libraries/networking/src/Node.h | 1 - libraries/networking/src/NodeList.cpp | 2 +- 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 76ce2061c0..d0afc7b0d4 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -126,9 +126,8 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, message->getSenderSockAddr(), message->getSenderSockAddr(), - DEFAULT_AGENT_PERMISSIONS, true); + true, true); replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); - replicatedNode->setIsUpstream(true); // construct a "fake" audio received message from the byte array and packet list information auto audioData = message->getMessage().mid(NUM_BYTES_RFC4122_UUID); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 4998a3b520..c4e59b6324 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -75,10 +75,9 @@ SharedNodePointer addOrUpdateReplicatedNode(const QUuid& nodeID, const HifiSockA auto replicatedNode = DependencyManager::get()->addOrUpdateNode(nodeID, NodeType::Agent, senderSockAddr, senderSockAddr, - DEFAULT_AGENT_PERMISSIONS, true); + true, true); replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); - replicatedNode->setIsUpstream(true); return replicatedNode; } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 14a9d0b257..d2bae28820 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -570,9 +570,8 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node) { SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, - const NodePermissions& permissions, - bool isReplicated, - const QUuid& connectionSecret) { + bool isReplicated, bool isUpstream, + const QUuid& connectionSecret, const NodePermissions& permissions) { QReadLocker readLocker(&_nodeMutex); NodeHash::const_iterator it = _nodeHash.find(uuid); @@ -584,11 +583,16 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t matchingNode->setPermissions(permissions); matchingNode->setConnectionSecret(connectionSecret); matchingNode->setIsReplicated(isReplicated); + matchingNode->setIsUpstream(isUpstream); return matchingNode; } else { // we didn't have this node, so add them - Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, isReplicated, connectionSecret); + Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket); + newNode->setIsReplicated(isReplicated); + newNode->setIsUpstream(isUpstream); + newNode->setConnectionSecret(connectionSecret); + newNode->setPermissions(permissions); // move the newly constructed node to the LNL thread newNode->moveToThread(thread()); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 5e2c88ed94..01e0ef2dc0 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -145,8 +145,9 @@ public: SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, - const NodePermissions& permissions = DEFAULT_AGENT_PERMISSIONS, - bool isReplicated = false, const QUuid& connectionSecret = QUuid()); + bool isReplicated = false, bool isUpstream = false, + const QUuid& connectionSecret = QUuid(), + const NodePermissions& permissions = DEFAULT_AGENT_PERMISSIONS); static bool parseSTUNResponse(udt::BasePacket* packet, QHostAddress& newPublicAddress, uint16_t& newPublicPort); bool hasCompletedInitialSTUN() const { return _hasCompletedInitialSTUN; } diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index f74be8adcd..ea1b6e0eb5 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -73,17 +73,13 @@ NodeType_t NodeType::fromString(QString type) { Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, - const HifiSockAddr& localSocket, const NodePermissions& permissions, bool isReplicated, - const QUuid& connectionSecret, QObject* parent) : + const HifiSockAddr& localSocket, QObject* parent) : NetworkPeer(uuid, publicSocket, localSocket, parent), _type(type), - _connectionSecret(connectionSecret), - _isReplicated(isReplicated), _pingMs(-1), // "Uninitialized" _clockSkewUsec(0), _mutex(), - _clockSkewMovingPercentile(30, 0.8f), // moving 80th percentile of 30 samples - _permissions(permissions) + _clockSkewMovingPercentile(30, 0.8f) // moving 80th percentile of 30 samples { // Update socket's object name setType(_type); diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 33c9e2c205..c20ff5a395 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -40,7 +40,6 @@ public: Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, - const NodePermissions& permissions, bool isReplicated, const QUuid& connectionSecret = QUuid(), QObject* parent = nullptr); bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 179b6e202d..f502cb2a3c 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -667,7 +667,7 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { packetStream >> connectionUUID; SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, - nodeLocalSocket, permissions, isReplicated, connectionUUID); + nodeLocalSocket, isReplicated, false, connectionUUID, permissions); // nodes that are downstream of our own type are kept alive when we hear about them from the domain server if (node->getType() == NodeType::downstreamType(_ownerType)) { From 2015f059c7dddf89b64c81a120699040e7ca11c1 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Sat, 17 Jun 2017 00:37:33 +0100 Subject: [PATCH 135/157] fixed hand calibration --- .../qml/hifi/tablet/OpenVrConfiguration.qml | 2 +- plugins/openvr/src/ViveControllerManager.cpp | 23 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 30685010ec..c0da9e2b6e 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -768,6 +768,6 @@ Rectangle { function sendConfigurationSettings() { var settings = composeConfigurationSettings(); InputConfiguration.setConfigurationSettings(settings, pluginName); - updateCalibrationText(); + //updateCalibrationText(); } } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index e9915934af..44de16a478 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -330,19 +330,22 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso auto iter = configurationSettings.begin(); auto end = configurationSettings.end(); while (iter != end) { - if (iter.key() == "trackerConfiguration") { + if (iter.key() == "bodyConfiguration") { setConfigFromString(iter.value().toString()); - } else if (iter.key() == "overrideHead") { - bool overrideHead = iter.value().toBool(); + } else if (iter.key() == "headConfiguration") { + QJsonObject headObject = iter.value().toObject(); + bool overrideHead = headObject["override"].toBool(); if (overrideHead) { _headConfig = HeadConfig::Puck; } else { _headConfig = HeadConfig::HMD; } - } else if (iter.key() == "overrideHandController") { - bool overrideHands = iter.value().toBool(); + } else if (iter.key() == "handConfiguration") { + QJsonObject handsObject = iter.value().toObject(); + bool overrideHands = handsObject["override"].toBool(); if (overrideHands) { _handConfig = HandConfig::Pucks; + qDebug() << "--------> configure hands <---------"; } else { _handConfig = HandConfig::HandController; } @@ -876,8 +879,7 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToR glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()); glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat); glm::vec3 handPoseZAxis = glmExtractRotation(handPoseAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f); - glm::vec3 avatarHandYAxis = transformVectorFast(glm::inverse(handPoseAvatarMat), glm::vec3(1.0f, 0.0f, 0.0f)); - + glm::vec3 avatarHandYAxis = transformVectorFast(inputCalibration.defaultLeftHand, glm::vec3(0.0f, 1.0f, 0.0f)); const float EPSILON = 1.0e-4f; if (fabsf(fabsf(glm::dot(glm::normalize(avatarHandYAxis), glm::normalize(handPoseZAxis))) - 1.0f) < EPSILON) { handPoseZAxis = glm::vec3(0.0f, 0.0f, 1.0f); @@ -891,7 +893,7 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToR glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET); + glm::vec3 translationOffset = glm::vec3(0.0f, -HAND_PUCK_Y_OFFSET, 0.0f); glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat); glm::quat finalRotation = glmExtractRotation(newHandMat); @@ -908,8 +910,7 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo glm::mat4 handPoseAvatarMat = createMatFromQuatAndPos(handPose.getRotation(), handPose.getTranslation()); glm::vec3 handPoseTranslation = extractTranslation(handPoseAvatarMat); glm::vec3 handPoseZAxis = glmExtractRotation(handPoseAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f); - glm::vec3 avatarHandYAxis = transformVectorFast(glm::inverse(handPoseAvatarMat), glm::vec3(1.0f, 0.0f, 0.0f)); - + glm::vec3 avatarHandYAxis = transformVectorFast(inputCalibration.defaultRightHand, glm::vec3(0.0f, 1.0f, 0.0f)); const float EPSILON = 1.0e-4f; if (fabsf(fabsf(glm::dot(glm::normalize(avatarHandYAxis), glm::normalize(handPoseZAxis))) - 1.0f) < EPSILON) { handPoseZAxis = glm::vec3(0.0f, 0.0f, 1.0f); @@ -924,7 +925,7 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo - glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET); + glm::vec3 translationOffset = glm::vec3(0.0f, 0.0f, 0.0f); glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat); glm::quat finalRotation = glmExtractRotation(newHandMat); From 2933a20a0c52231a1012c3449064c2827fec4aa9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 19 Jun 2017 10:43:45 -0700 Subject: [PATCH 136/157] some cleanup for audio/avatar replicated packet checking --- assignment-client/src/audio/AudioMixer.cpp | 14 ++------- .../src/audio/AudioMixerClientData.cpp | 29 +++++++------------ .../src/audio/AudioMixerClientData.h | 1 - assignment-client/src/avatars/AvatarMixer.cpp | 18 ++++++++++-- .../networking/src/udt/PacketHeaders.cpp | 9 ++++++ libraries/networking/src/udt/PacketHeaders.h | 2 ++ 6 files changed, 39 insertions(+), 34 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d0afc7b0d4..ab4b20b9cc 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -132,18 +132,10 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess // construct a "fake" audio received message from the byte array and packet list information auto audioData = message->getMessage().mid(NUM_BYTES_RFC4122_UUID); - PacketType rewrittenType; + PacketType rewrittenType = REPLICATED_PACKET_MAPPING.key(message->getType()); - if (message->getType() == PacketType::ReplicatedMicrophoneAudioNoEcho) { - rewrittenType = PacketType::MicrophoneAudioNoEcho; - } else if (message->getType() == PacketType::ReplicatedMicrophoneAudioWithEcho) { - rewrittenType = PacketType::MicrophoneAudioWithEcho; - } else if (message->getType() == PacketType::ReplicatedInjectAudio) { - rewrittenType = PacketType::InjectAudio; - } else if (message->getType() == PacketType::ReplicatedSilentAudioFrame) { - rewrittenType = PacketType::SilentAudioFrame; - } else { - return; + if (rewrittenType == PacketType::Unknown) { + qDebug() << "Cannot unwrap replicated packet type not present in REPLICATED_PACKET_WRAPPING"; } auto replicatedMessage = QSharedPointer::create(audioData, rewrittenType, diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 7641000a7a..6e11257c7f 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -124,27 +124,18 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c auto nodeList = DependencyManager::get(); // now make sure it's a packet type that we want to replicate - PacketType mirroredType; - switch (message.getType()) { - case PacketType::MicrophoneAudioNoEcho: - case PacketType::ReplicatedMicrophoneAudioNoEcho: - mirroredType = PacketType::ReplicatedMicrophoneAudioNoEcho; - break; - case PacketType::MicrophoneAudioWithEcho: - case PacketType::ReplicatedMicrophoneAudioWithEcho: - mirroredType = PacketType::ReplicatedMicrophoneAudioWithEcho; - break; - case PacketType::InjectAudio: - case PacketType::ReplicatedInjectAudio: - mirroredType = PacketType::ReplicatedInjectAudio; - break; - case PacketType::SilentAudioFrame: - case PacketType::ReplicatedSilentAudioFrame: - mirroredType = PacketType::ReplicatedSilentAudioFrame; - break; - default: + // first check if it is an original type that we should replicate + PacketType mirroredType = REPLICATED_PACKET_MAPPING.value(message.getType()); + + if (mirroredType == PacketType::Unknown) { + // if it wasn't check if it is a replicated type that we should re-replicate + if (REPLICATED_PACKET_MAPPING.key(message.getType()) != PacketType::Unknown) { + mirroredType = message.getType(); + } else { + qDebug() << "Packet passed to optionallyReplicatePacket was not a replicatable type - returning"; return; + } } std::unique_ptr packet; diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index b397ab0b8e..76a9cd6aa7 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -26,7 +26,6 @@ #include "PositionalAudioStream.h" #include "AvatarAudioStream.h" - class AudioMixerClientData : public NodeData { Q_OBJECT public: diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index c4e59b6324..136d5f2e8e 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -127,9 +127,21 @@ void AvatarMixer::handleReplicatedBulkAvatarPacket(QSharedPointer packet; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 7985df58bf..fb416cac4d 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -44,6 +44,15 @@ const QSet NON_SOURCED_PACKETS = QSet() << PacketType::ReplicatedInjectAudio << PacketType::ReplicatedSilentAudioFrame << PacketType::ReplicatedAvatarIdentity << PacketType::ReplicatedKillAvatar << PacketType::ReplicatedBulkAvatarData; +const QHash REPLICATED_PACKET_MAPPING { + { PacketType::MicrophoneAudioNoEcho, PacketType::ReplicatedMicrophoneAudioNoEcho }, + { PacketType::MicrophoneAudioWithEcho, PacketType::ReplicatedMicrophoneAudioWithEcho }, + { PacketType::InjectAudio, PacketType::ReplicatedInjectAudio }, + { PacketType::SilentAudioFrame, PacketType::ReplicatedSilentAudioFrame }, + { PacketType::AvatarIdentity, PacketType::ReplicatedAvatarIdentity }, + { PacketType::KillAvatar, PacketType::ReplicatedKillAvatar }, +}; + PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { case PacketType::DomainList: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index c080ab8e19..2944c1ce93 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -128,6 +128,8 @@ public: using PacketType = PacketTypeEnum::Value; +extern const QHash REPLICATED_PACKET_MAPPING; + const int NUM_BYTES_MD5_HASH = 16; typedef char PacketVersion; From 734cde33e733de7005fc2e34d99a324f9d58b177 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 19 Jun 2017 21:40:09 +0100 Subject: [PATCH 137/157] better calibrate button --- .../qml/hifi/tablet/OpenVrConfiguration.qml | 170 +++++++++++++++--- plugins/openvr/src/ViveControllerManager.cpp | 3 +- 2 files changed, 148 insertions(+), 25 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index c0da9e2b6e..62203b811d 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -9,6 +9,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 import "../../styles-uit" import "../../controls" import "../../controls-uit" as HifiControls @@ -125,11 +127,20 @@ Rectangle { text: "Tracker" color: hifi.colors.lightGrayText } + } + Row { + id: headOffsets + anchors.top: headConfig.bottom + anchors.topMargin: 5 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 10 + spacing: 10 + visible: headPuckBox.checked HifiControls.SpinBox { id: headYOffset decimals: 4 - width: 110 + width: 112 label: "Y: offset" value: -0.0254 stepSize: 0.0254 @@ -142,7 +153,7 @@ Rectangle { HifiControls.SpinBox { id: headZOffset - width: 105 + width: 112 label: "Z: offset" value: -0.152 stepSize: 0.0254 @@ -153,6 +164,7 @@ Rectangle { } } } + RalewayBold { id: hands @@ -162,8 +174,8 @@ Rectangle { color: "white" - anchors.top: headConfig.bottom - anchors.topMargin: 10 + anchors.top: (headOffsets.visible ? headOffsets.bottom : headConfig.bottom) + anchors.topMargin: (headOffsets.visible ? 22 : 10) anchors.left: parent.left anchors.leftMargin: leftMargin } @@ -219,11 +231,21 @@ Rectangle { text: "Trackers" color: hifi.colors.lightGrayText } + } + Row { + id: handOffset + visible: handPuckBox.checked + anchors.top: handConfig.bottom + anchors.topMargin: 5 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 10 + spacing: 10 + HifiControls.SpinBox { id: handYOffset decimals: 4 - width: 105 + width: 112 label: "Y: offset" value: -0.0508 stepSize: 0.0254 @@ -236,7 +258,7 @@ Rectangle { HifiControls.SpinBox { id: handZOffset - width: 105 + width: 112 label: "Z: offset" value: -0.0254 stepSize: 0.0254 @@ -256,8 +278,8 @@ Rectangle { color: hifi.colors.white - anchors.top: handConfig.bottom - anchors.topMargin: 10 + anchors.top: (handOffset.visible ? handOffset.bottom : handConfig.bottom) + anchors.topMargin: (handOffset.visible ? 22 : 10) anchors.left: parent.left anchors.leftMargin: leftMargin } @@ -412,23 +434,120 @@ Rectangle { } - HifiControls.Button { - + + Rectangle { id: calibrationButton - color: hifi.buttons.blue - text: "Calibrate" - //glyph: hifi.glyphs.avatar1 + property int color: hifi.buttons.blue + property int colorScheme: hifi.colorSchemes.light + property string glyph: hifi.glyphs.avatar1 + property bool enabled: true + property bool pressed: false + property bool hovered: false + property int size: 32 + property string text: "calibrate" + property int padding: 12 + + width: glyphButton.width + calibrationText.width + padding + height: hifi.dimensions.controlLineHeight anchors.top: bottomSeperator.bottom anchors.topMargin: 10 anchors.left: parent.left anchors.leftMargin: leftMargin + + radius: hifi.buttons.radius - onClicked: { - openVrConfiguration.countDown = timeToCalibrate.value; - numberAnimation.start(); - calibrationTimer.start(); - info.visible = true; - info.showCountDown = true; + gradient: Gradient { + GradientStop { + position: 0.2 + color: { + if (!calibrationButton.enabled) { + hifi.buttons.disabledColorStart[calibrationButton.colorScheme] + } else if (calibrationButton.pressed) { + hifi.buttons.pressedColor[calibrationButton.color] + } else if (calibrationButton.hovered) { + hifi.buttons.hoveredColor[calibrationButton.color] + } else { + hifi.buttons.colorStart[calibrationButton.color] + } + } + } + + GradientStop { + position: 1.0 + color: { + if (!calibrationButton.enabled) { + hifi.buttons.disabledColorFinish[calibrationButton.colorScheme] + } else if (calibrationButton.pressed) { + hifi.buttons.pressedColor[calibrationButton.color] + } else if (calibrationButton.hovered) { + hifi.buttons.hoveredColor[calibrationButton.color] + } else { + hifi.buttons.colorFinish[calibrationButton.color] + } + } + } + } + + + + + HiFiGlyphs { + id: glyphButton + color: enabled ? hifi.buttons.textColor[calibrationButton.color] + : hifi.buttons.disabledTextColor[calibrationButton.colorScheme] + text: calibrationButton.glyph + size: calibrationButton.size + + anchors { + top: parent.top + bottom: parent.bottom + bottomMargin: 1 + verticalCenter: parent.horizontalCenter + } + } + + RalewayBold { + id: calibrationText + font.capitalization: Font.AllUppercase + color: enabled ? hifi.buttons.textColor[calibrationButton.color] + : hifi.buttons.disabledTextColor[calibrationButton.colorScheme] + size: hifi.fontSizes.buttonLabel + text: calibrationButton.text + + anchors { + left: glyphButton.right + top: parent.top + topMargin: 7 + } + } + + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onClicked: { + openVrConfiguration.countDown = timeToCalibrate.value; + numberAnimation.start(); + calibrationTimer.start(); + info.visible = true; + info.showCountDown = true; + } + + onPressed: { + calibrationButton.pressed = true; + } + + onReleased: { + calibrationButton.pressed = false; + } + + onEntered: { + calibrationButton.hovered = true; + } + + onExited: { + calibrationButton.hovered = false; + } } } @@ -667,11 +786,11 @@ Rectangle { var headSetting = settings["headConfiguration"]; var headOverride = headSetting["override"]; var handSetting = settings["handConfiguration"]; - var handOverride = settings["override"]; + var handOverride = handSetting["override"]; var settingsChanged = false; - - if (lastConfiguration["bodyConfiguration"]["override"] !== bodySetting["override"]) { + + if (lastConfiguration["bodyConfiguration"] !== bodySetting) { settingsChanged = true; } @@ -686,14 +805,17 @@ Rectangle { } if (settingsChanged) { - if ((!handOverride) && (!headOverride) && (bodySetting === "Auto")) { + if ((!handOverride) && (!headOverride) && (bodySetting === "None")) { state = buttonState.apply; + console.log("apply"); } else { state = buttonState.applyAndCalibrate; + console.log("apply and calibrate"); } } else { if (state == buttonState.apply) { state = buttonState.disabled; + console.log("disable"); } } @@ -768,6 +890,6 @@ Rectangle { function sendConfigurationSettings() { var settings = composeConfigurationSettings(); InputConfiguration.setConfigurationSettings(settings, pluginName); - //updateCalibrationText(); + updateCalibrationText(); } } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 44de16a478..7ffdcb731a 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -345,7 +345,6 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHands = handsObject["override"].toBool(); if (overrideHands) { _handConfig = HandConfig::Pucks; - qDebug() << "--------> configure hands <---------"; } else { _handConfig = HandConfig::HandController; } @@ -354,6 +353,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso } } + qDebug() << configToString(_preferedConfig); + saveSettings(); } From 13dff29bd55781dacfb295b964b90ef46be83cf7 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 20 Jun 2017 01:19:10 +0100 Subject: [PATCH 138/157] adding calibration screen --- .../qml/hifi/tablet/CalibratingScreen.qml | 98 ++++++++ .../qml/hifi/tablet/ControllerSettings.qml | 209 ++++++++++++++++++ .../qml/hifi/tablet/InputConfiguration.qml | 203 ----------------- .../qml/hifi/tablet/OpenVrConfiguration.qml | 136 +++--------- interface/src/Menu.cpp | 2 +- plugins/openvr/src/ViveControllerManager.cpp | 7 +- 6 files changed, 341 insertions(+), 314 deletions(-) create mode 100644 interface/resources/qml/hifi/tablet/CalibratingScreen.qml create mode 100644 interface/resources/qml/hifi/tablet/ControllerSettings.qml delete mode 100644 interface/resources/qml/hifi/tablet/InputConfiguration.qml diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml new file mode 100644 index 0000000000..43c8b22636 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -0,0 +1,98 @@ +// +// Created by Dante Ruiz on 6/1/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +import QtQuick 2.5 + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtGraphicalEffects 1.0 +import QtQuick.Controls.Styles 1.4 +import "../../styles-uit" +import "../../controls" +import "../../controls-uit" as HifiControls + + +Rectangle { + id: info + + + signal canceled() + signal restart() + + HifiConstants { id: hifi } + visible: true + color: hifi.colors.baseGray + + BusyIndicator { + id: busyIndicator + width: 350 + height: 350 + + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + topMargin: 60 + } + running: true + } + + RalewayBold { + id: directions + + anchors { + top: busyIndicator.bottom + topMargin: 100 + horizontalCenter: parent.horizontalCenter + } + + color: hifi.colors.white + size: hifi.fontSizes.rootMenuDisclosure + text: "please stand in a T-Pose during calibration" + } + + Row { + + spacing: 20 + anchors { + top: directions.bottom + topMargin: 30 + horizontalCenter: parent.horizontalCenter + } + + + HifiControls.Button { + width: 120 + height: 30 + color: hifi.buttons.red + text: "RESTART" + + onClicked: { + restart(); + } + } + + HifiControls.Button { + width: 120 + height: 30 + color: hifi.buttons.black + text: "CANCEL" + + onClicked: { + stack.pop(); + canceled(); + } + } + } + + + + function callingFunction() { + console.log("---------> calling function from parent <----------------"); + } +} diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml new file mode 100644 index 0000000000..cc638858e9 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -0,0 +1,209 @@ +// +// Created by Dante Ruiz on 6/1/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtGraphicalEffects 1.0 +import "../../styles-uit" +import "../../controls" +import "../../controls-uit" as HifiControls + +StackView { + id: stack + initialItem: inputConfiguration + Rectangle { + id: inputConfiguration + anchors.fill: parent + + HifiConstants { id: hifi } + + color: hifi.colors.baseGray + + property var pluginSettings: null + + Rectangle { + width: inputConfiguration.width + height: 1 + color: hifi.colors.baseGrayShadow + x: -hifi.dimensions.contentMargin.x + } + + RalewayRegular { + id: header + text: "Controller Settings" + size: 22 + color: "white" + + anchors.top: inputConfiguration.top + anchors.left: inputConfiguration.left + anchors.leftMargin: 20 + anchors.topMargin: 20 + } + + + Separator { + id: headerSeparator + width: inputConfiguration.width + anchors.top: header.bottom + anchors.topMargin: 10 + } + + HiFiGlyphs { + id: sourceGlyph + text: hifi.glyphs.source + size: 36 + color: hifi.colors.blueHighlight + + anchors.top: headerSeparator.bottom + anchors.left: inputConfiguration.left + anchors.leftMargin: 40 + anchors.topMargin: 20 + } + + RalewayRegular { + id: configuration + text: "SELECT DEVICE" + size: 15 + color: hifi.colors.lightGrayText + + + anchors.top: headerSeparator.bottom + anchors.left: sourceGlyph.right + anchors.leftMargin: 10 + anchors.topMargin: 30 + } + + Row { + id: configRow + z: 999 + anchors.top: sourceGlyph.bottom + anchors.topMargin: 20 + anchors.left: sourceGlyph.left + anchors.leftMargin: 40 + spacing: 10 + HifiControls.ComboBox { + id: box + width: 160 + z: 999 + editable: true + colorScheme: hifi.colorSchemes.dark + model: inputPlugins() + label: "" + + onCurrentIndexChanged: { + changeSource(); + } + } + + HifiControls.CheckBox { + id: checkBox + colorScheme: hifi.colorSchemes.dark + text: "show all input plugins" + + onClicked: { + console.log("clicked"); + inputPlugins(); + changeSource(); + } + } + } + + + Separator { + id: configurationSeparator + z: 0 + width: inputConfiguration.width + anchors.top: configRow.bottom + anchors.topMargin: 10 + } + + + HiFiGlyphs { + id: sliderGlyph + text: hifi.glyphs.sliders + size: 36 + color: hifi.colors.blueHighlight + + anchors.top: configurationSeparator.bottom + anchors.left: inputConfiguration.left + anchors.leftMargin: 40 + anchors.topMargin: 20 + } + + RalewayRegular { + id: configurationHeader + text: "CONFIGURATION" + size: 15 + color: hifi.colors.lightGrayText + + + anchors.top: configurationSeparator.bottom + anchors.left: sliderGlyph.right + anchors.leftMargin: 10 + anchors.topMargin: 30 + } + + Loader { + id: loader + asynchronous: false + + width: inputConfiguration.width + anchors.left: inputConfiguration.left + anchors.right: inputConfiguration.right + anchors.top: configurationHeader.bottom + anchors.topMargin: 10 + anchors.bottom: inputConfiguration.bottom + + source: InputConfiguration.configurationLayout(box.currentText); + onLoaded: { + if (loader.item.hasOwnProperty("pluginName")) { + loader.item.pluginName = box.currentText + + if (loader.item.hasOwnProperty("displayInformation")) { + loader.item.displayInformation(); + } + } + } + } + } + + + function inputPlugins() { + if (checkBox.checked) { + return InputConfiguration.inputPlugins(); + } else { + return InputConfiguration.activeInputPlugins(); + } + } + + function initialize() { + changeSource(); + } + + function changeSource() { + loader.source = ""; + var source = InputConfiguration.configurationLayout(box.currentText); + loader.source = source; + if (source === "") { + box.label = "(not configurable)"; + } else { + box.label = ""; + } + } + + Timer { + id: timer + repeat: false + interval: 300 + onTriggered: initialize() + } + + Component.onCompleted: { + timer.start(); + } +} diff --git a/interface/resources/qml/hifi/tablet/InputConfiguration.qml b/interface/resources/qml/hifi/tablet/InputConfiguration.qml deleted file mode 100644 index 10181480f0..0000000000 --- a/interface/resources/qml/hifi/tablet/InputConfiguration.qml +++ /dev/null @@ -1,203 +0,0 @@ -// -// Created by Dante Ruiz on 6/1/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -import QtQuick 2.5 -import QtGraphicalEffects 1.0 -import "../../styles-uit" -import "../../controls" -import "../../controls-uit" as HifiControls - -Rectangle { - id: inputConfiguration - anchors.fill: parent - - HifiConstants { id: hifi } - - color: hifi.colors.baseGray - - property var pluginSettings: null - - Rectangle { - width: inputConfiguration.width - height: 1 - color: hifi.colors.baseGrayShadow - x: -hifi.dimensions.contentMargin.x - } - - RalewayRegular { - id: header - text: "Controller Settings" - size: 22 - color: "white" - - anchors.top: inputConfiguration.top - anchors.left: inputConfiguration.left - anchors.leftMargin: 20 - anchors.topMargin: 20 - } - - - Separator { - id: headerSeparator - width: inputConfiguration.width - anchors.top: header.bottom - anchors.topMargin: 10 - } - - HiFiGlyphs { - id: sourceGlyph - text: hifi.glyphs.source - size: 36 - color: hifi.colors.blueHighlight - - anchors.top: headerSeparator.bottom - anchors.left: inputConfiguration.left - anchors.leftMargin: 40 - anchors.topMargin: 20 - } - - RalewayRegular { - id: configuration - text: "SELECT DEVICE" - size: 15 - color: hifi.colors.lightGrayText - - - anchors.top: headerSeparator.bottom - anchors.left: sourceGlyph.right - anchors.leftMargin: 10 - anchors.topMargin: 30 - } - - Row { - id: configRow - z: 999 - anchors.top: sourceGlyph.bottom - anchors.topMargin: 20 - anchors.left: sourceGlyph.left - anchors.leftMargin: 40 - spacing: 10 - HifiControls.ComboBox { - id: box - width: 160 - z: 999 - editable: true - colorScheme: hifi.colorSchemes.dark - model: inputPlugins() - label: "" - - onCurrentIndexChanged: { - changeSource(); - } - } - - HifiControls.CheckBox { - id: checkBox - colorScheme: hifi.colorSchemes.dark - text: "show all input plugins" - - onClicked: { - console.log("clicked"); - inputPlugins(); - changeSource(); - } - } - } - - - Separator { - id: configurationSeparator - z: 0 - width: inputConfiguration.width - anchors.top: configRow.bottom - anchors.topMargin: 10 - } - - - HiFiGlyphs { - id: sliderGlyph - text: hifi.glyphs.sliders - size: 36 - color: hifi.colors.blueHighlight - - anchors.top: configurationSeparator.bottom - anchors.left: inputConfiguration.left - anchors.leftMargin: 40 - anchors.topMargin: 20 - } - - RalewayRegular { - id: configurationHeader - text: "CONFIGURATION" - size: 15 - color: hifi.colors.lightGrayText - - - anchors.top: configurationSeparator.bottom - anchors.left: sliderGlyph.right - anchors.leftMargin: 10 - anchors.topMargin: 30 - } - - Loader { - id: loader - asynchronous: false - - width: inputConfiguration.width - anchors.left: inputConfiguration.left - anchors.right: inputConfiguration.right - anchors.top: configurationHeader.bottom - anchors.topMargin: 10 - anchors.bottom: inputConfiguration.bottom - - source: InputConfiguration.configurationLayout(box.currentText); - onLoaded: { - if (loader.item.hasOwnProperty("pluginName")) { - loader.item.pluginName = box.currentText - - if (loader.item.hasOwnProperty("displayInformation")) { - loader.item.displayInformation(); - } - } - } - } - - function inputPlugins() { - if (checkBox.checked) { - return InputConfiguration.inputPlugins(); - } else { - return InputConfiguration.activeInputPlugins(); - } - } - - function initialize() { - changeSource(); - } - - function changeSource() { - loader.source = ""; - var source = InputConfiguration.configurationLayout(box.currentText); - loader.source = source; - if (source === "") { - box.label = "(not configurable)"; - } else { - box.label = ""; - } - } - - Timer { - id: timer - repeat: false - interval: 300 - onTriggered: initialize() - } - - Component.onCompleted: { - timer.start(); - } -} diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 62203b811d..7fde6c53eb 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -14,6 +14,7 @@ import QtQuick.Controls.Styles 1.4 import "../../styles-uit" import "../../controls" import "../../controls-uit" as HifiControls +import "." Rectangle { @@ -42,6 +43,7 @@ Rectangle { HifiConstants { id: hifi } + Component { id: screen; CalibratingScreen {} } QtObject { id: buttonState readonly property int disabled: 0 @@ -440,11 +442,11 @@ Rectangle { property int color: hifi.buttons.blue property int colorScheme: hifi.colorSchemes.light property string glyph: hifi.glyphs.avatar1 - property bool enabled: true + property bool enabled: false property bool pressed: false property bool hovered: false property int size: 32 - property string text: "calibrate" + property string text: "apply" property int padding: 12 width: glyphButton.width + calibrationText.width + padding @@ -502,7 +504,6 @@ Rectangle { top: parent.top bottom: parent.bottom bottomMargin: 1 - verticalCenter: parent.horizontalCenter } } @@ -526,11 +527,19 @@ Rectangle { anchors.fill: parent hoverEnabled: true onClicked: { - openVrConfiguration.countDown = timeToCalibrate.value; - numberAnimation.start(); - calibrationTimer.start(); - info.visible = true; - info.showCountDown = true; + if (calibrationButton.enabled) { + calibrationTimer.interval = timeToCalibrate.value * 1000 + openVrConfiguration.countDown = timeToCalibrate.value; + numberAnimation.duration = calibrationTimer.interval + numberAnimation.start(); + calibrationTimer.start(); + var calibratingScreen = screen.createObject(); + stack.push(calibratingScreen); + + calibratingScreen.callingFunction(); + calibratingScreen.canceled.connect(cancelCalibration); + calibratingScreen.restart.connect(restartCalibration); + } } onPressed: { @@ -557,8 +566,6 @@ Rectangle { interval: 20 onTriggered: { InputConfiguration.calibratePlugin(pluginName) - info.visible = false; - info.showCountDown = false; } } @@ -567,12 +574,6 @@ Rectangle { repeat: false interval: 3000 onTriggered: { - info.showCountDown = false; - info.calibrationFailed = false - info.calibrationSucceed = false; - info.calibrationSucceed = false; - info.showCalibrationStatus = false; - info.visible = false; } } @@ -590,6 +591,7 @@ Rectangle { anchors.leftMargin: leftMargin minimumValue: 3 + value: 3 label: "Time til calibration ( in seconds )" colorScheme: hifi.colorSchemes.dark @@ -609,19 +611,12 @@ Rectangle { function calibrationStatusInfo(status) { if (status["calibrated"]) { - info.visible = true; - info.showCalibrationStatus = true; - info.calibrationSucceed = true; } else if (!status["calibrated"]) { var uncalibrated = status["success"]; if (uncalibrated) { - info.visible = true; - info.showCalibrationStatus = true; - info.uncalibrationSucceed = true; + } else { - info.visible = true; - info.showCalibrationStatus = true; - info.calibrationFailed = true; + } } displayTimer.start(); @@ -654,6 +649,14 @@ Rectangle { return pucksNeeded; } + function cancelCalibration() { + console.log("canceling calibration"); + } + + function restartCalibration() { + console.log("restating calibration"); + } + function displayConfiguration() { var settings = InputConfiguration.configurationSettings(pluginName); var configurationType = settings["trackerConfiguration"]; @@ -680,84 +683,6 @@ Rectangle { } } - - Rectangle { - id: info - property bool showCountDown: false - property bool showCalibrationStatus: false - property bool calibrationFailed: false - property bool calibrationSucceed: false - property bool uncalibrationSucceed: false - - visible: false - color: hifi.colors.baseGray - anchors.top: openVrConfiguration.top - anchors.bottom: bottomSeperator.bottom - anchors.left: openVrConfiguration.left - anchors.right: openVrConfiguration.right - - Item { - id: countDownContainer - visible: info.showCountDown - anchors.centerIn: parent - RalewayBold { - id: countDownText - - text: openVrConfiguration.countDown - size: 92 - - color: hifi.colors.blueHighlight - - anchors.centerIn: parent - } - } - - Item { - id: calibrationStatus - visible: info.showCalibrationStatus - anchors.centerIn: parent - Item { - id: successInfo - visible: info.calibrationSucceed - anchors.centerIn: parent - RalewayBold { - id: successText - text: "Calibration Successful" - size: 42 - color: hifi.colors.greenHighlight - anchors.centerIn: parent - } - } - - Item { - id: failedInfo - visible: info.calibrationFailed - anchors.fill: parent - RalewayBold { - id: failedText - text: "Calibration Failed" - size: 42 - color: hifi.colors.redAccent - anchors.centerIn: parent - } - } - - Item { - id: uncalibrateInfo - visible: info.uncalibrationSucceed - anchors.centerIn: parent - RalewayBold { - id: uncalibrateText - text: "Uncalibration Successful" - size: 37 - color: hifi.colors.greenHighlight - anchors.centerIn: parent - } - } - } - } - - function displayTrackerConfiguration(type) { if (type === "Feet") { feetBox.checked = true; @@ -825,12 +750,15 @@ Rectangle { function updateCalibrationText() { updateButtonState(); if (buttonState.disabled == state) { - calibrationButton.text = "Apply"; + calibrationButton.enabled = false; } else if (buttonState.apply == state) { + calibrationButton.enabled = true; calibrationButton.text = "Apply"; } else if (buttonState.applyAndCalibrate == state) { + calibrationButton.enabled = true; calibrationButton.text = "Apply And Calibrate"; } else if (buttonState.calibrate == state) { + calibrationButton.enabled = true; calibrationButton.text = "Calibrate"; } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f5b0a2e407..5b5480dbfc 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -313,7 +313,7 @@ Menu::Menu() { action = addActionToQMenuAndActionHash(settingsMenu, "InputConfiguration"); connect(action, &QAction::triggered, [] { auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); - tablet->loadQMLSource("InputConfiguration.qml"); + tablet->loadQMLSource("ControllerSettings.qml"); }); // Settings > Control with Speech [advanced] diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 7ffdcb731a..f683ee75de 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -1011,9 +1011,6 @@ void ViveControllerManager::InputDevice::loadSettings() { Settings settings; settings.beginGroup("PUCK_CONFIG"); { - _preferedConfig = (Config)settings.value("body configuration", QVariant((int)Config::None)).toInt(); - _headConfig = (HeadConfig)settings.value("head configuration", QVariant((int)HeadConfig::HMD)).toInt(); - _handConfig = (HandConfig)settings.value("hand configuration", QVariant((int)HandConfig::HandController)).toInt(); } settings.endGroup(); } @@ -1022,9 +1019,7 @@ void ViveControllerManager::InputDevice::saveSettings() const { Settings settings; settings.beginGroup("PUCK_CONFIG"); { - settings.setValue(QString("body configuration"), (int)_preferedConfig); - settings.setValue(QString("head configuration"), (int)_headConfig); - settings.setValue(QString("hand configuration"), (int)_handConfig); + } settings.endGroup(); } From 33b89c9d327be0a61d24cc7c1c0fd10d8aa1e16f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 20 Jun 2017 17:26:17 +0100 Subject: [PATCH 139/157] adding glyph and text --- .../qml/hifi/tablet/CalibratingScreen.qml | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml index 43c8b22636..ffd2a80e58 100644 --- a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -24,6 +24,8 @@ Rectangle { signal canceled() signal restart() + + property int count: 3 HifiConstants { id: hifi } visible: true @@ -42,6 +44,47 @@ Rectangle { running: true } + + HiFiGlyphs { + id: image + text: hifi.glyphs.avatar1 + size: 190 + color: hifi.colors.white + + anchors { + top: busyIndicator.top + topMargin: 40 + horizontalCenter: busyIndicator.horizontalCenter + } + } + + RalewayBold { + id: statusText + text: "CALIBRATION STARTING IN" + size: 16 + color: hifi.colors.blueHighlight + + anchors { + top: image.bottom + topMargin: 15 + horizontalCenter: image.horizontalCenter + } + } + + + RalewayBold { + id: countDown + text: info.count + color: hifi.colors.blueHighlight + + anchors { + top: statusText.bottom + topMargin: 12 + horizontalCenter: statusText.horizontalCenter + } + } + + RalewayBold { id: directions @@ -56,6 +99,13 @@ Rectangle { text: "please stand in a T-Pose during calibration" } + NumberAnimation { + id: numberAnimation + target: info + property: count + to: 0 + } + Row { spacing: 20 @@ -89,10 +139,9 @@ Rectangle { } } } - - + function start() { + } function callingFunction() { - console.log("---------> calling function from parent <----------------"); } } From 2c3db0fb91481176a8c69280e2b867c826148c98 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 21 Jun 2017 01:07:12 +0100 Subject: [PATCH 140/157] finished calibration-ui --- .../images/loader-calibrate-blue.png | Bin 0 -> 7935 bytes .../images/loader-calibrate-white.png | Bin 0 -> 7376 bytes .../qml/hifi/tablet/CalibratingScreen.qml | 82 +++++++++++-- .../qml/hifi/tablet/ControllerSettings.qml | 23 ++-- .../qml/hifi/tablet/OpenVrConfiguration.qml | 110 +++++++++++++----- interface/src/Application.cpp | 2 + interface/src/Menu.cpp | 8 +- .../src/plugins/InputConfiguration.cpp | 30 ++++- .../plugins/src/plugins/InputConfiguration.h | 1 + libraries/plugins/src/plugins/InputPlugin.h | 1 + plugins/openvr/src/ViveControllerManager.cpp | 54 ++++----- plugins/openvr/src/ViveControllerManager.h | 3 +- 12 files changed, 234 insertions(+), 80 deletions(-) create mode 100644 interface/resources/images/loader-calibrate-blue.png create mode 100644 interface/resources/images/loader-calibrate-white.png diff --git a/interface/resources/images/loader-calibrate-blue.png b/interface/resources/images/loader-calibrate-blue.png new file mode 100644 index 0000000000000000000000000000000000000000..808f5fa3d217e7ed4558b72aad5c4e633f31be99 GIT binary patch literal 7935 zcmaKRdpy(a|Npf~DhidB6l+SvHir=8q{B2kd0BBSV*#!WQrC2yo97tZ25DzjQn4Bk_!^4jfJiPHI@gC0`(@iRoMiE^^Fhntbec(^u72kEJyp#j&`LuqIq*3#5ggKMg5XrtBj&>HGU zbq#$Db$v~B_}>@82!4co-b??ax#iznv-;-3@<0sny|2L4?p zPZ9x5^$0*~pwxvat>sDxu(kdFyAlZh@eZV%#Q#_C{{#*^6&ip?pTq}}g23(NZ@vKcsi~kcNhZuBp1IwuQQ-u9lgOrp_S^(|=;kNuEIj zJdyHG?D_x3TKsFQ@IVNQqHm5T`v&9BTarlx_-f+%zW+mu*&$0yO+9tZLwdS;|69vi z?D>D!V)n0E&_?hhXyNw$KimC}>7==(aQL6YYXtxA@y8R-8zRUEW21LQS*`%c5ssRh zoT7GqySwpennlLdL<_C;>+Pl1N$(VmQI;5k$A39zz1`d;`l5JCxm=f9<;3J@gu8!N zEHkM*`D(evgTly+y$_VH9BPP^*x&=Cw?|o8y_Of93@^HTH-JF;+%c9F_MxKbHoGP3 zS5wvZugUTLeUowcOhZ02~JZM;w577ytq&0DMvK_^AF#=wt29#--xW zH<;`{3PZc`9e4eFGCn1mnhacHbx1-mdX(ZB=G#9Fk&7-grxz}>rIb=i8Ra>JxZ~ZN zG138fxh&j7B}yJ$E5ENL8YvR~%X!PRUb79$DHv<%veGqOjW_#o4-NRSOw$8gsqB|V z(P|cImum0|cgu zvtB7ByM6UuX}(Hil{FW?dPLVn`Ykt$0DkNX?>v0!?;=gc)fN9+lZo`-#ZS%Ik<=Vq z%h(kSx@Wj$<=C^)w$@@>lw47d|H9jn`jXEjjU_$P&xfYyzk@nrGM+7DxroKX#x~kU z?itZ)BU{JTWbga+OhMkh&4u?PwATg(1g3Qt9}lhL9_9+@A_u=42G8#W__U@A++DqX zqJY!&eWvU>iEgy9hN<*|j-@;Erk#n-XOe1mo+yCuW3iPf2b}F@WN#JgR(_ej%5{`c z6Yzy$UM;lF1p3D6kjyI<^w^b}hHKab?wBBmRuxIjIlVMc@~AxZw%e=|QO_snWjNQ* zNPKt7AQX<9--?77d>%>Ftf4E_4ll6Jg~m+_&0_(tM(H12X9LWhuqR5yq=&J%l5mVK zL<$|AmW#X{u|92Hd#3MYmRE<Y!|QW)NUyh&;Pmw;lpjlOG1}<8ID?w5(%O;c;I;5<`2cFGw+KG3UFey6dpGL)sB>O`0_#Zs7uJpiC_nZ}oD7QL zI#{9@w8>&|-;v?c1WklHhHbyIx7hVt+>T8ai(N+iQu@|4V~<)o7Im>h!yxwl#ja5! zuJYb#QI2?QZdCv}u;aFO?DyCqkL-$6Ng?v9(Q_5ukDBWge>zQ>(XCY6@k6Ro>Tup` zz7tml6(;pSigK$i+9*>+p-M=&dzWK*t0ueFBUVgpuJW7p9)MxnuM?>XC^}dijCPs) zVJ40#f&syfgb%uvop>>uVb97Td2SWTz)S1~8t{=@H_q+q9cYZ3eRX%ZBj8&LDeBx??EgX4N2`HGBAtO$Zs% zZug`0u3g6}YLc89t9;4oNzrrHsgl!MY*gf?MKSF9k9E@q+(x=l=(EoYUKs(Ejrd2u zpu!akP0n;!dQ!`9!MjuGwoF5-jvHuUd+*y=kYFM_J$!Ya9TbFu4F(W>&1 z@}!}bn@4I?FfWSA{lCrWY!2tkJBe5j8Jcd#t*T$7mCxakM`qr z^^;Fp2_>sBhG);9sxMFONKab4^rqxy%0{7#hq*zl8pcerYiTRKK#tMip{pQ0C>}|* zv8rm%c9~6b)#{z2DD>q*-om6vq1O4vrIcjXT*c68(t@~xIHo$1%1xg( zX)~^p(fY`6h=3l~HoEe*{y-~n_S}k`0%Vn7z_d59M>mC{y-uLQQV_yVH}k}I6(t$& z&gmB|99q8aBDuzqu2J|h$#DJC1crO_N6|s?cvd(gdveY-yiN`&`!V;`_0d&kC4D_p zzaUQ+gR%Y%gllzUqN_CK-g&-SnO~HKX%bFycT4SHtBHJtB#0|cbbcRZB_C)73sAo8 z6}y=E;5;`MgE7w8SzM%J8X9`lQhG`cWgvr?@orZd?zBmFdmYIWmf`x(sve`8elwBl z7FVe=BUeye(H`dqcip`?D@IfWaNZ$T?>oDF+kIqXUS7WZYU zuqsM@=egRy-mmX$uke>#pL|wqP&{52A`(FgIXjrqrKVM$CiKehKgNx*UOdH}=(ZFl z^fBPh&|lVzYTP|^C88qS9m5_9d^$A|EWs!eRP|_goBFIyWbgl@X+1r9kKufp0a zEY%^`u@Vtgvu?tj56HDB{TCy*tQU8qabQ(&m@|qgv4uej>4@3&W)4h?axypU=?%P; zw=AE&$7$ngre_}yJ+Q7!o~%gkS{E5EP0~jdU*E)t@Th1ixwdB6r9=~4Z59|xUQ7hl zDED>OsWv9tF6?Tbko9r*sL1XT!A!vf`2$DN@9x;mH{qHRCBd`>+xP2uz1%q_3=QD! zoXib`NG()z{zmPjapG{>s_Ci+s`|&5I+Ou&C%A#;+j1&!)yU^B6JcvJA2d&@6L_Oo z>%annN68|{O8K}9e+iWkPV;t;)XVXu(e40K9j`0h>CFncPl)=PtC$t$mA9DjH2nkIf@AMxG)*cIMOIh;{8nNWV^-C3pj;HZ73QIi=1HBv&Tn58dE+B8 z8cHY%6F`N|3C*p~KO!cyTxa9eSC``*kcuJ%ZWR?GRCQ{uHBp!2K>wU7zpD9oN!C`M zkFC!isTizM)ywf^xrl}>_L=d~YFDGATYpgfHrIWC79F2AkSQH;U5PtnoDOJpjJ-2B_B8 zUr@l%-CB+Jl0G0pASvQNT+Bg#G8W$6C(>0aeJn; zbefqB(_4o`@6U<*)*HMgTi>^}VqM0B3bn~hY20LnrtSa>raw6a0};3!hLEgaTa1-h z=dcSehXH12dkd*n7QDq>c+tqLaOr?f`64qm0H38vkK(C8SH43VHh~+CY%Axh>pOQ~ zgB=_}B!h3L*~*N+1qFGqDe0*85crzbpNddIB2raZ1z@m(EpxsJy2=Lth9=mO$f!E1 z2LY{#bKh&nvG0mw$WUa3FFlAq100 z(8jMuu&{0Rmcob$7zdH15)L!5b!R;`tn`+nNeB~|tc)0^GEPNqP>!F{~RsCHckBM{jT zA5v30uJFg|kmb_%6PYRr?rZWl6T~XgrXk>zCEE>JM9K{pW=R^U9q&?602n-{OXa(M zmkAV{vSu%?!~KpCx}ITYpIn2SsvS2_Rsfiw`bF6x5%Bmr)j%k|Q)+5t4L&Fy2JY){ zDihb@0I3`0B}%|*PQ$Eu24!) zeOK(7&YTH_$~AsnMt`VogBY-v6Vak`TR-Vb)+n?X|1)QK!BjKanE8+^i^i zed<;qMGWGouHTCTnDWv3#b;b*oWHM=hdO>8ru+tu-Kp%IG^ETC2OC&NI$;+l#%jmS zlodg1?2IAq`9TD4g&vf;4YZgBak}1-ck)Fs%o{kisv;rI#p@3{5FoDc^J0}v^D}}Y=brInHhnPf)U*#LQZAI&hUX`TYf;QL1GWc#g zd<|YrOYIlMFm5=qZ6dI{91q_jL*cI0XkHI}KSVHgk)K1CNtFTprhm@vXOA@2j?-?O z+qYlT$E_dH^LkuxO&3AfiXLEt8UMY{sbzD|u5P=^Y}RR*dl2G)1?R<)4h{Cv@_A0% zM+M3GPeGbAs+Ca550VyK^Hf#^uVQETZeL&3ZH$M(b0|52uTK2MPXlgeWj~r`;tV*` zTZTk24#*Flvewj1BguLkV%%*AC}|HxrpaMM69* zl7~8lVWY7+mK=i^O%b@8wJMK=41^LQkOxkB3H^ek1^OIu3<-Ad052_yd3(2K6#(z* zD_>5V-nW$#9KZhw%mnW(q`H~2&pmjkFti?6tMW$Ns88qAx$jct0K8CmpH5_)c+f4p z3#xj#v{`Y&HtmmNZW^exR}r9C?>8~ZO0$l=g8)Ikw^yDmf6vhl;TSem8l|&GoU#iq z1~{2?C9c-Z*^kI*WkUexF|65%Py!aKbEj1V@NE;5MQQr2D8cN*B@jvdIGu_Qxaao0yvLj&6a}_^r0)qi4Y+Wn;5FudWp`Z|0$ftShE!@X;t2V zasUYOEv#ydrG3+>Vgai6TYPnYm|X*>w-r&l@iysT0N4 zg!zdOZcT1qo2eBa+3K54eRI*~{!Nc8*k4H8NPVSRbG}u4(*PX^mFF24wxR_0>IkcS z*++!n!)C?=Uazig9!31_z{O%QG#Ut>}q?Hj8>C$ z))DKB!=m`JtBA>0E~~d*%Hh5ag9xAPY~wkV>dpBH%tT~#h3#q==NUV+V!f!VmL8C~ z+HP`1P;yh7FFxVUPOSE++j0_^i)sbXi5|6d=Pmug5MdvcoQ|Bc?0n;b8d;mu!(5pp z(uRceJ@4-~zJ);)c^8U%G#jVw?pGxaZQ=$H<(e0TVS4mR#fdlAXAH_<8$|ecHF|^U zY4E4-gNcL0J@B&__UOE@!}A^7^^(r0x&0KArrvX(%I>h~eTm!$7$fVnYA!{A>M1 z0|?+3`nFa0r`0`pt3CGfQfAjC;f54Bt@w28tQa;x8R%>PK%iv$Xj|{Ojy*n89u@DV zZHZ_A=TRQFFUDCfN^wKnf+v>#`L_g?gu z!jQi_enhx-<|$+81Kvt3w%O#4aq-M>u<&@-g>y+r8$`QLTAd_vk<1lJ^fmfLbfb-11Lc}+#EE$rMl)4Y0-s=nF z5}J4QW)I&iqGv333S#5{oHsa~wAmnQXo$<(0`}J)M)Nnnn>&Cq>d$|ZShnL&x5m{1 zc~)cV$;39PIqUiCN*l*w$lvoA$>Y zFN%NN<&cSq@5ZPuHA7~G$s^cYP=|WGgpnpN`M_}PyNr8*r7!mG4szrZ8=|R!K4(f( z+=7qW`)k)Z{YHlxb0_FZM*1M^k_OXtyd?DIa%SkmqTj!NAg`Moihh^tZ|t5h7j>ll z=Uf#oAq0*WnZFga;%#aySM@tbtNo?s`_{XfdwF!H(cfh&5s;d#ZWG2n+mz)P7nSC- zV+$19{ewGh$isO%I{0DLofZC`_xw&UkC(ZQ?0go*w6gl$kv(>KhiUj^$!!njADWy@ z$-=YcEko}0>dn7tL67i<@zFZ30)F4A`8=dRcJaL9+hNinMcV7Lv19YI;?ol875;?p z+Z)zz{;>VGbIsF8zw8oM-_R>1WlO3ejO+ATwzu@pI4v-? znUG1VIFWv&{X%`p>j+Zm(_BhCYx~U0maC&v*k|v46r>s5*rj09s@aGikAaNcEe)3p z35T>_@af-@p0o_*BQu{=!wNdO!V6?)AchUoBzhRKKw06_-e_dH6RM1&+V^W@sp*~C zvGi=_(%S%)$8QQQ78Gn+vKq&8Bj|C;dp=3i`ufkE`LgoK0C}0*5!02?H!qSR@o@kd zt$pdMM=UI$`m@BZKKX$XjlM;sxXRv7>bYvL3V)YRRh!B$J%LRgI%bu^!dmB_DSvfF z%eqbSmw$e^z1a+LW%W0RsQ^Q#tFx|GiK3j49=&nJ=$9SPZy zIC=SpG4>)^193Z)c2KK^^(SW+Vy0UL2)2iE^6&JPZep*9bL)%(RTLP|F_1MTdcxL#MpMk;U$l%$7uzh1^?PKGssG|TbENAokt?}per zxib25PD}?=8oMlB=@V+UrdsA&-eP1rvCrzP@(*qqwxrx+l$3CC^$xNH&E1InXg$EAh1V^1{ zLhy8(@B_ZI4|nCj!~3XwyO?Hn-9-!b300!}jPuPgNwXA~fVqC#a&w)YMfC~jCE<&? z7-)0(gsjmUnFXHJa`UTipDrtN5~(iYwvUIrZVIjKZcK-al8lq4;u0mtXZ2pZo%;|J z=GbxSyc0x#;9L*%5NAuTIzddDI?;g2r{C#%Bu~F^uu)=O3y~Vb@8BuM=DJt0~H=FsKH1GP+ zn3J_R_TKeR!Fk(kcG^k(+S|5CwlMWh`>x9nP9k;Oq_)C&w0b|=y=%sh6#CM8|NcUo ztL5L`Sq|+x)0q*L)HUo_|K6{$MuKm_{&~eKKd|&u^s%K~a^X|D=}D<&`J)42tcn?= zVBBZOhA8uXyzD#7j2+M7H5bt{p0~aK`Bt;~Ll+(9#-x1R&lO8$DjlvRv$^!0_s;4u zt`|K_LtzCE($HMLQFH=TnpE{5fz_=xtAf8&czWf`35z%y`LK6T%Z>-0ZaPo%Bv3!b zeepKLG#gu^3&~VzQctfI%iGaKt9!X&iT2Cn?o`S0{_TyyQ~B?Y`c9R6R(&&n{bGI5 z*##@c6$@2oasf8uLIsG233NKuW4vBy4;UJ?w0|lp5MREWCX-sRk8$FSb@m_6*d7mt zeV*b}&v>@miC_hl8CFl#cW?^en}v+Z~W_0l{8&Z&FaOs zyivP^YNliUpyLyt`i2iQ)h&Drc9Na@+~+$2qm4DQL^RHDVuqeVa~tn;N?Kg()!8y9 zJ6zvo)Iay-YxN7n!)LljP1*4*WR5JkF*PNyTJghpZa&M>4lik%0G3vDvYA?J#Nj~{L*L5MZ9lr=w z&XAxrjYOO=Sd`#y5W{YnZaF^$vZIkbs!Pjd56o3<$OXq8wfS+90tD`@*C*}LdzpBJ zyYuaX;ory|7dAzdGX%3%bR@2=%Qg5}I*qGeKkLw2u=0K+Fxzd#FR1w2L}^M2E%z?c zExf2K6K{-ek*6=aF*PF4?ulDYFID=LTdG=-3#^ALbpkp!@GaQigEE@fs%9!jPck(3 zv5xIyoy)V0qSkEkeir4YBsvn7m~pfHJ=^Q6wu5ojR+(5Ocp21O)r5gK|9q-U1dj8O z-pI$ZMox9i;@BA#O^tj%%NpZ{zqS^BZEi^JKA3{Xv5&++<6+0VSW{I<-`NaWeMQG| zw||Y-N*VONUv!&^=LhVQ92vQa&vF%?ch7i11g58H^@$M~x$jg9*X``fm4Q}#hGO;X z$3-GCnwzgBc8`e{a-7C@YM-Dl^r^D#U5O*=OM z03d(#h_x#KKmx#@j5GiMuXPi50sx>wvhgCh5kpCd!LfMYa0u}vUj1lPa2Vbd9~_c& zx(#m%08-k76J8`QCr1p97=;W5F-US$3;h{kHn)Hi9U6GE^W zo`z0nrx+`IIN?ZgEZ!~o*a=*61kNNx!`w{Wl#C%q#YEvr!Rq9w$mlo>8LJ_&i;0fI zfMS$}x&%Usz-s&q%FD@F-HI5CS2si&A#i$ndg{g|NIk=Y2Kt6@b$zs+Aqs7R(nBNA zdKf)4Mjx&I_oZQ`ZWk&85JMsmqt!u+!6%9FB&>$UKPg1T{Ksr`+}~xw z5u;G#;24x15)G#GGuNmXC#U}(8Wr^)bR5YQ|KE83Ps4F1l49^ES9}~XJ{E^}#fNHw zu3|7&vG`yTG4=$J82L{Xox_PFVq7>eM%~IvQZ;pLr(hf*8WieCw49tUN2B9N!O=MU zQERLQIVuK8AcSBJ7+D@RKwIk_FgbWYPtV5K5^ZT{gSIs`urks&I-qCykFGTl7axU> zCjFxu@?Ty3f7JyE0Tu;gjgKWH;6rRanZumpyoM*8)oxa&PxGrjzus4Ksx{^CPM&a6yVGT04faFSyJN&*|~W2Y~wwjZ?!yDz7B*Vd*jiS zlKhgg5}HuPA&fUhe*rImt0Gk4Q)22Xu{k^&zD5{)cH*31{k-#KHQczc_eE?~r%NM= zSKX`MK5NV?rB_cbo)g$OyyFq3KmRuW+a9UMetr0plwbVbGZHk0Cv%@>)%6_Qx zEO@8Qq~O?ym6d)nlP&wh^CWJ_k6n!)Gse zU06!rzq+ftDc@ck&uj9fyReJN-6sg~&tiCOW-t7r`biOlf#jR2%#rZLcdRznAdAE5 zo6QiW!`G%*TTdl-_D5oz+2QsiXypA)8HbtMYoQ>gk?AcBw-YJG^G1*s; zVEQ7q?s(eshQUO{%+pBsXO@9%K%2kaVS>=&!(C_?R^IOQaXEdzLtZFF5H(JMJj*kC z@0Z{mZCF(o^hg+0lyuc07D9!Mb}2osOyznmR+6BRHJ!V8c8(|u(aF&l8$Wqxvq;{gCq~qvMzlaXt_#Y|RmN@b-k8=d(}oN2ki@ z{i$@l5`aUC87m~3bh;;u`jnRzMCXl(qan_0nXWV?zCk-1gJ1b zUDK3}S;MQ9hjdEA3|G&PnJAD{iipegw3qQo<9lxnBEB5BaU0r?)RYuw0eX(h@ z(r=n&_vMDY_$ZkhhV7McW^2DrgnQObc3D0kr4N^;dgx^U99j>F<%fUTgTFSYlW}#} zY`ij8XPtJyjbq~H4MTX(!km*Ag&T{!9rsv>?vhmD{R=miz8>*^yIdL$vBr$=xU4wfCN@Y3(B|vM*Q|8KmX*Y3iN7p{X8X+t9R-TXy3WMKEMBzG zD|3@rt*J#8P$sUw;Cm)=F*-|JUh@wBbQphJydI!FfhPajdE75SaU|D-e#n2m9SlwZ}e+hmr1aSrh|oFWGRAj>Q&*7_H9i$_cn<;>G7%VfHOO1xl#Cu9-SqQWUaKt zUc?&*ZUvNyLekzL6#Swszp_2Ho);~Y0hEc`s%*tK>GN6Q_Ue`HS*1XEK$#d{ z`z1^KImHQaXOo;{&!XofM^d>WcB9{`kzIddOm%KNU29QTCTg%=8n0d4*|WYs&R#l(K6 z_IPvu=qVYBz$xgr(cvkzq-)6Qf9?ASLXzty)#R)+X1Wb}rh_V>#pK@FHvM1pAC*ET zp4~9jlm|HZ&DOjtSt64&#G9oMsbcch9br$O_3TGC4&lW?Ud40cGOOes8WdSIc`k)Ief#C^ju5^_Ec0K`MU>!0~NxTj584ww=;l^ zw|2izL0-u;|IFIp0U|8YdBUvI*t$=@7;Ocp#sxgMl@#s}T+x?anI{S0J7?G37O`o^ zKB$F=acAo(%%kDG=*Bm*GWi<-PJYK;WQtErD~`SxsRrgB-$=G%EDP2HRO2lpK-h^O zN3Ay`zeLS^X)sg^Skt$Gt;iG~G~mp>?Dv6}nErN20?rC60m?)S%qw|4 zcl)7fQ)!C8>C}A`|9WZaA{g$a>B?aQ+Ncu-w%Cp0giczfInJBI04zj|xJM-sL6J2m zunBK9X@e0jO;^?zz6K})r?7K8idg#Z1EZ0L}3bKs8Pi zU0_FgH&;m&lY6_BSf|fcNC&b33(>y&b~R#|Os8u0^BdqZLWIgzm7-T9DT^Ti_JuwM z&Da~#n;Q)r@nx6Vapzj+4IPbv`?~zPBckc5_Mkr@>QSOEo2}AsDKv2PWw8j(PxCP;W;Ra32wX<%d}ZMLreEGhjf^_L&%mndV%zksm6(vH*c5{?IxQ z$=D8@@?)*82+J>XiyGZ?^I*nBSVUfIKxO+cJjHe zri^W%!OQd?XDb%zBaXUY%v&{ZvbnCnkwA9KhJevyBB;fZpl^A@1}?uEj<*MsRhS(t z66YQRAyS&S8G{1gdL#LoEc;Q8oNV4P;17Qhaux#o3J>rXC7--vz> zii^m#1VbHx`%B@9&>3K`^|oB?0HE~_xqe;1D1PyV4j5sI^zIAy!;r0?7@@k|+HRL*fIQ+#q0gd$i^33XvdK$&~q*J6JKKDe^Wpv(zd zleC|2**@^+du>6crnH`M)C8x=h<4asjx12E8{oZ#+)zjWDV3OXpPZtf1JWugOr`k* z=)-@z%Aum>5xe>V=Krb zjiObPv*REw>W5iqbi&;dbGJ()uj)-2hfl~{`Uqt$jfy|T_lRvHJUhqves0J4U;Z*a)2wXGQ z2c-3@Bj6N<&G_-`vIN-Q$JbM;IQ4veEi^+*vFOzt)M7}GGniH3;)nt{SG1mctdbN) zm8?N+FNo{7SF1BaCBs(_TX%3|0Tbn!33_~%pgimr2s#sc8!SW&V?%w0K=rv~-G$BQp4G!{{~XCs z1vvR0=Y_)71rvIsBNm_d{&Tbe`2DJHAh4F(*m8&YDPcJz^C<3RZ{$SspnZ~+S8!RPnWvLv zNe6vE{5~)BDofN&j~MU+b5QH&pU*p1<=+Wza2S$}jmrn@(1hxXkD%ZiU1-MZXeRIB zS+5|ZX|q-ef>4>$JmsZfD9v&X}kiMAnrDGkOf$?##7DFHP8-1jfV(fN zAa(gMG*DI!*{w0eu-_D z((r`k4f<%WSmCgcvxR%=CMynuZT)WP*0n*_AvAw*R+E=F2!4N(s`^vxLfHIS+)XS- z2GHhP|M$}<*vR;@gC;i=Hs$ONDoUm2&5)_=vF|FBFC^ct!h1Yw^K=QUM6yvDW@ zlNL&Zn~gx8%a_M4lnZCF#Gj$GbX+G4OfL}8RFUd^KQ(>o;73`C!0F?$z=wf0{J6@| zL!s4Dlv}6zy1Ke94RRJPqkEmGuyW}^b2%^%8P9&0DKzqD)wKafbmlzbX9 zwCnc+T1FXiO}=$ z`0UugDd`c4U7~q!xmMygLx_dQq;DTq}oxu+UL~YFLIYi6A`@#P1*=kObBe2 zU8nH?Y3^nl5u+mherBVXk{_mq~wbjIeDbo6wyUgEXN zJ~=lopBjF?wp{(&r0h+EF%5e!>bJG@Sv7h+LOwN~f;|*N-{n95@P+35mmJJm6RJ8g z=+?mdRlDy$9Nb>@Ue@xSu6P(S1oXGWp2wdI@=KIm@#Kx>{)zQ5SU>9ZktUv3Iq@66=!Cl0T=I_23(KTE3eRTEcj~UC> zeq_B|x~!Y6X#2fwa!+anWjp3{>BnkE!c<;X-O1STq3K)VQj?S(X18%4tAH>JYazcN zSvq;vIcbkI5WT0Ln6_2jQK=t@Ef?NU;xC^wm(!yW?vZ(Yy=(R*1~uhWb|Uya9Ibcx zqcv=&|NGuMttq=w$M|^f*Kb_deO+zmciAuW*@yb` z1m%VWV~E>RQ~rW5#-af7t*b;!Ak+qv|GGvxz15BY=KIT!YZp78XAu@$9J<_pE+ z3+*SDVt`DRpCHcpa#7OTJs!Djb1v*F867KMZ4PtWv@A88hQy zd`oX(+&hb%IpbegT9%*LFIx4@O1BwbTZH3x>hKwn56$Odg7b>pAm%fbbb|Fp(z|)T zqAdKGc|v-4Fa|VM`a&_Ivi07pmB~ZM6n;MI+=G{A=Hdqn=5A!aTA74D3CoecxJ{cM zT5soiu*~#vd*_$2vvnhU+SO7uO@o)QHNxFIioSVSc3p zTKs_dq>KlVSzO3ieRC5H=>vwR%Z#qytiv7T>PWR1DMx}SJ+oSlK zY=bnPoW-QoJqf{m?WT-uflY#jby#uyzPgC@Mg74t1Qu)EHYsRb z^5BMNWO}@655?#NOg2$u!%8OhFR-I~#eWJ7i|~$w>=Q(jkxz1-gI4bG?`j_Jzwo?- z>;f&wL*6c#_8sf=nh>9n^=_#$IyJJ&kNPEk+mGGlsX7nOC0!(xkX_7HPdzYri;2VD zrxty?BaFX^P)&X@tKv4Sy_;athj)-WUb)+s)7fJWD<^lqy1Ca8!J&N_f9X30pI_LY z{x){4tW>{66w~3;i?IH#JdtI#`sYfL&!DT9@OjBcWz_6IXmqD{RKeJ^i?Fjd@Xb^D zlQdFIigEAl6A?Gd155_PYIW1s^UQlTZ7&bed3b6JrO%=5RJ+iX7hNDyEBGAtrN3|S zN71JK2~S(`_zr==8~4QAa3aQonWNila@#^AXzo!V7AzufuV)^gi+keBuV#lOjk3D% zorBNKd%uaLeXl;b9c0qogY52n`|8H?{oBgD2HQw(>~Oy??;69n^;#=~^=YCnr%Dx5 ztNN?!GG3oPzBbG~Z6=i_syVh0_AqYw(UGy=1E?^k-#V^OI4)}6EHE+Gzi5uDAJufD zFNd3Ct9@U!*;>?em2QUg?db0;<(K*^q!)VJ3g@)JZnBeeJSeY(fh2M&p+xGf+yL#bSx0(An zw2w!_-o%GC#L&~c1cBMKK_RP8d4J#tc{z@^FYv9e-@G4c3NfKm6S&myg_+toKPXK1 z*u{Hhc5xw`Sk=HQgqAmWU=?T3fp-fKcD0k-Isa9^st04~^$Pvr!Xv@k+WcCS&{PeWzd-NRKHAN-s8 z6`a}HMve4fLz(Jm%ur7~+{5}IOa0>ge(LyK_+ ztHif@VdZbSs8^nUx$^v!!hGmqk$}?Ordz)5v+&+FXht8@$E2$|Yi)TVq{zch*&{G~ zFL(c*@~(mQebO8n!&-Mk-QsK?6hL8;GvQ~4hQpB)k#hAVxb#bikF)9}~I0016xpa2SZ l<^lshWI;j9^xC=|K%NI<+4F={C-@)ZQJZ7dk1T`E{STku$6o*d literal 0 HcmV?d00001 diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml index ffd2a80e58..b8935f5463 100644 --- a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -25,23 +25,40 @@ Rectangle { signal canceled() signal restart() - property int count: 3 + property int count: 3 + property string calibratingText: "CALIBRATING..." + property string calibratingCountText: "CALIBRATION STARTING IN" + property string calibrationSuccess: "CALIBRATION COMPLETED" + property string calibrationFailed: "CALIBRATION FAILED" HifiConstants { id: hifi } visible: true color: hifi.colors.baseGray - BusyIndicator { + property string whiteIndicator: "../../../images/loader-calibrate-white.png" + property string blueIndicator: "../../../images/loader-calibrate-blue.png" + + Image { id: busyIndicator width: 350 height: 350 + property bool running: true + anchors { horizontalCenter: parent.horizontalCenter top: parent.top topMargin: 60 } - running: true + visible: busyIndicator.running + source: blueIndicator + NumberAnimation on rotation { + id: busyRotation + running: busyIndicator.running + loops: Animation.Infinite + duration: 1000 + from: 0 ; to: 360 + } } @@ -60,7 +77,7 @@ Rectangle { RalewayBold { id: statusText - text: "CALIBRATION STARTING IN" + text: info.calibratingCountText size: 16 color: hifi.colors.blueHighlight @@ -102,10 +119,27 @@ Rectangle { NumberAnimation { id: numberAnimation target: info - property: count + property: "count" to: 0 } + Timer { + id: timer + + repeat: false + interval: 3000 + onTriggered: { + info.calibrating(); + } + } + + Timer { + id: closeWindow + repeat: false + interval: 3000 + onTriggered: stack.pop(); + } + Row { spacing: 20 @@ -124,6 +158,10 @@ Rectangle { onClicked: { restart(); + numberAnimation.stop(); + info.count = (timer.interval / 1000); + numberAnimation.start(); + timer.restart(); } } @@ -134,14 +172,42 @@ Rectangle { text: "CANCEL" onClicked: { - stack.pop(); canceled(); + stack.pop() } } } - function start() { + function start(interval, countNumber) { + countDown.visible = true; + statusText.color = hifi.colors.blueHighlight; + numberAnimation.duration = interval + info.count = countNumber; + timer.interval = interval; + numberAnimation.start(); + timer.start(); } - function callingFunction() { + + function calibrating() { + countDown.visible = false; + busyIndicator.source = whiteIndicator; + busyRotation.from = 360 + busyRotation.to = 0 + statusText.text = info.calibratingText; + statusText.color = hifi.colors.white + } + + function success() { + busyIndicator.running = false; + statusText.text = info.calibrationSuccess + statusText.color = hifi.colors.greenHighlight + closeWindow.start(); + } + + function failure() { + busyIndicator.running = false; + statusText.text = info.calibrationFailed + statusText.color = hifi.colors.redHighlight + closeWindow.start(); } } diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index cc638858e9..e1ba93a840 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -103,10 +103,9 @@ StackView { HifiControls.CheckBox { id: checkBox colorScheme: hifi.colorSchemes.dark - text: "show all input plugins" + text: "show all input devices" onClicked: { - console.log("clicked"); inputPlugins(); changeSource(); } @@ -162,12 +161,16 @@ StackView { source: InputConfiguration.configurationLayout(box.currentText); onLoaded: { if (loader.item.hasOwnProperty("pluginName")) { - loader.item.pluginName = box.currentText - - if (loader.item.hasOwnProperty("displayInformation")) { - loader.item.displayInformation(); + if (box.currentText === "Vive") { + loader.item.pluginName = "OpenVR"; + } else { + loader.item.pluginName = box.currentText; } } + + if (loader.item.hasOwnProperty("displayInformation")) { + loader.item.displayConfiguration(); + } } } } @@ -187,7 +190,13 @@ StackView { function changeSource() { loader.source = ""; - var source = InputConfiguration.configurationLayout(box.currentText); + var source = ""; + if (box.currentText == "Vive") { + source = InputConfiguration.configurationLayout("OpenVR"); + } else { + source = InputConfiguration.configurationLayout(box.currentText); + } + loader.source = source; if (source === "") { box.label = "(not configurable)"; diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 7fde6c53eb..9c23cf8677 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -27,7 +27,7 @@ Rectangle { property int leftMargin: 75 property int countDown: 0 property string pluginName: "" - property var displayInformation: openVrConfiguration.displayConfiguration() + property var displayInformation: null readonly property bool feetChecked: feetBox.checked readonly property bool hipsChecked: hipBox.checked @@ -144,7 +144,7 @@ Rectangle { decimals: 4 width: 112 label: "Y: offset" - value: -0.0254 + minimumValue: -10 stepSize: 0.0254 colorScheme: hifi.colorSchemes.dark @@ -157,7 +157,7 @@ Rectangle { id: headZOffset width: 112 label: "Z: offset" - value: -0.152 + minimumValue: -10 stepSize: 0.0254 decimals: 4 colorScheme: hifi.colorSchemes.dark @@ -249,7 +249,7 @@ Rectangle { decimals: 4 width: 112 label: "Y: offset" - value: -0.0508 + minimumValue: -10 stepSize: 0.0254 colorScheme: hifi.colorSchemes.dark @@ -262,7 +262,7 @@ Rectangle { id: handZOffset width: 112 label: "Z: offset" - value: -0.0254 + minimumValue: -10 stepSize: 0.0254 decimals: 4 colorScheme: hifi.colorSchemes.dark @@ -528,17 +528,19 @@ Rectangle { hoverEnabled: true onClicked: { if (calibrationButton.enabled) { - calibrationTimer.interval = timeToCalibrate.value * 1000 - openVrConfiguration.countDown = timeToCalibrate.value; - numberAnimation.duration = calibrationTimer.interval - numberAnimation.start(); - calibrationTimer.start(); - var calibratingScreen = screen.createObject(); - stack.push(calibratingScreen); - - calibratingScreen.callingFunction(); - calibratingScreen.canceled.connect(cancelCalibration); - calibratingScreen.restart.connect(restartCalibration); + if (openVrConfiguration.state === buttonState.apply) { + InputConfiguration.uncalibratePlugin(pluginName); + updateCalibrationButton(); + } else { + calibrationTimer.interval = timeToCalibrate.value * 1000 + openVrConfiguration.countDown = timeToCalibrate.value; + var calibratingScreen = screen.createObject(); + stack.push(calibratingScreen); + calibratingScreen.canceled.connect(cancelCalibration); + calibratingScreen.restart.connect(restartCalibration); + calibratingScreen.start(calibrationTimer.interval, timeToCalibrate.value); + calibrationTimer.start(); + } } } @@ -547,7 +549,7 @@ Rectangle { } onReleased: { - calibrationButton.pressed = false; + calibrationButton.pressed = false; } onEntered: { @@ -592,7 +594,6 @@ Rectangle { minimumValue: 3 value: 3 - label: "Time til calibration ( in seconds )" colorScheme: hifi.colorSchemes.dark onEditingFinished: { @@ -602,6 +603,31 @@ Rectangle { } } + RalewayBold { + id: delayTextInfo + size: 10 + text: "Delay Before Calibration Starts" + color: hifi.colors.white + + anchors { + left: timeToCalibrate.right + leftMargin: 20 + verticalCenter: timeToCalibrate.verticalCenter + } + } + + RalewayRegular { + size: 12 + text: "sec" + color: hifi.colors.lightGray + + anchors { + left: delayTextInfo.right + leftMargin: 10 + verticalCenter: delayTextInfo.verticalCenter + } + } + NumberAnimation { id: numberAnimation target: openVrConfiguration @@ -610,16 +636,17 @@ Rectangle { } function calibrationStatusInfo(status) { + var calibrationScreen = stack.currentItem; if (status["calibrated"]) { + calibrationScreen.success(); } else if (!status["calibrated"]) { var uncalibrated = status["success"]; - if (uncalibrated) { - - } else { - + if (!uncalibrated) { + calibrationScreen.failure(); } } - displayTimer.start(); + + updateCalibrationButton(); } @@ -650,11 +677,11 @@ Rectangle { } function cancelCalibration() { - console.log("canceling calibration"); + calibrationTimer.stop(); } function restartCalibration() { - console.log("restating calibration"); + calibrationTimer.restart(); } function displayConfiguration() { @@ -681,6 +708,9 @@ Rectangle { handPuckBox.checked = true; handBox.checked = false; } + + initializeButtonState(); + updateCalibrationText(); } function displayTrackerConfiguration(type) { @@ -732,25 +762,45 @@ Rectangle { if (settingsChanged) { if ((!handOverride) && (!headOverride) && (bodySetting === "None")) { state = buttonState.apply; - console.log("apply"); } else { state = buttonState.applyAndCalibrate; - console.log("apply and calibrate"); } } else { if (state == buttonState.apply) { state = buttonState.disabled; - console.log("disable"); + } else if (state == buttonState.applyAndCalibrate) { + state = buttonState.calibrate; } } lastConfiguration = settings; } - function updateCalibrationText() { + function initializeButtonState() { + var settings = composeConfigurationSettings(); + var bodySetting = settings["bodyConfiguration"]; + var headSetting = settings["headConfiguration"]; + var headOverride = headSetting["override"]; + var handSetting = settings["handConfiguration"]; + var handOverride = handSetting["override"]; + + + if ((!handOverride) && (!headOverride) && (bodySetting === "None")) { + state = buttonState.disabled; + } else { + state = buttonState.calibrate; + } + } + + function updateCalibrationButton() { updateButtonState(); + updateCalibrationText(); + } + + function updateCalibrationText() { if (buttonState.disabled == state) { calibrationButton.enabled = false; + calibrationButton.text = "Apply"; } else if (buttonState.apply == state) { calibrationButton.enabled = true; calibrationButton.text = "Apply"; @@ -818,6 +868,6 @@ Rectangle { function sendConfigurationSettings() { var settings = composeConfigurationSettings(); InputConfiguration.setConfigurationSettings(settings, pluginName); - updateCalibrationText(); + updateCalibrationButton(); } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8505e07181..95e3cec3b5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -109,6 +109,7 @@ #include #include #include +#include #include #include #include @@ -1997,6 +1998,7 @@ void Application::initializeUi() { surfaceContext->setContextProperty("TextureCache", DependencyManager::get().data()); surfaceContext->setContextProperty("ModelCache", DependencyManager::get().data()); surfaceContext->setContextProperty("SoundCache", DependencyManager::get().data()); + surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get().data()); surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance()); surfaceContext->setContextProperty("Tablet", DependencyManager::get().data()); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5b5480dbfc..8c9baa7c43 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -38,6 +38,7 @@ #include "MainWindow.h" #include "render/DrawStatus.h" #include "scripting/MenuScriptingInterface.h" +#include "scripting/HMDScriptingInterface.h" #include "ui/DialogsManager.h" #include "ui/StandAloneJSConsole.h" #include "InterfaceLogging.h" @@ -310,10 +311,15 @@ Menu::Menu() { QString("../../hifi/tablet/TabletLodPreferences.qml"), "LodPreferencesDialog"); }); - action = addActionToQMenuAndActionHash(settingsMenu, "InputConfiguration"); + action = addActionToQMenuAndActionHash(settingsMenu, "Controller Settings"); connect(action, &QAction::triggered, [] { auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); + auto hmd = DependencyManager::get(); tablet->loadQMLSource("ControllerSettings.qml"); + + if (!hmd->getShouldShowTablet()) { + hmd->toggleShouldShowTablet(); + } }); // Settings > Control with Speech [advanced] diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index d20678b972..33948ef70d 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -28,7 +28,12 @@ QStringList InputConfiguration::inputPlugins() { QStringList inputPlugins; for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { - inputPlugins << QString(plugin->getName()); + QString pluginName = plugin->getName(); + if (pluginName == QString("OpenVR")) { + inputPlugins << QString("Vive"); + } else { + inputPlugins << pluginName; + } } return inputPlugins; } @@ -45,7 +50,12 @@ QStringList InputConfiguration::activeInputPlugins() { QStringList activePlugins; for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { if (plugin->configurable()) { - activePlugins << QString(plugin->getName()); + QString pluginName = plugin->getName(); + if (pluginName == QString("OpenVR")) { + activePlugins << QString("Vive"); + } else { + activePlugins << pluginName; + } } } return activePlugins; @@ -113,3 +123,19 @@ void InputConfiguration::calibratePlugin(QString pluginName) { } } } + + +bool InputConfiguration::uncalibratePlugin(QString pluginName) { + if (QThread::currentThread() != thread()) { + bool result; + QMetaObject::invokeMethod(this, "uncalibratePlugin", Qt::BlockingQueuedConnection, + Q_ARG(bool, result)); + return result; + } + + for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { + if (plugin->getName() == pluginName) { + return plugin->uncalibrate(); + } + } +} diff --git a/libraries/plugins/src/plugins/InputConfiguration.h b/libraries/plugins/src/plugins/InputConfiguration.h index abf0c89ab4..27591edc34 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.h +++ b/libraries/plugins/src/plugins/InputConfiguration.h @@ -28,6 +28,7 @@ public: Q_INVOKABLE void setConfigurationSettings(QJsonObject configurationSettings, QString pluginName); Q_INVOKABLE void calibratePlugin(QString pluginName); Q_INVOKABLE QJsonObject configurationSettings(QString pluginName); + Q_INVOKABLE bool uncalibratePlugin(QString pluginName); signals: void calibrationStatus(const QJsonObject& status); diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index 51bff07de9..5d02964c97 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -29,6 +29,7 @@ public: virtual QJsonObject configurationSettings() { return QJsonObject(); } virtual QString configurationLayout() { return QString(); } virtual void calibrate() {} + virtual bool uncalibrate() { return false; } virtual bool configurable() { return false; } virtual bool isHandController() const { return false; } virtual bool isHeadController() const { return false; } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index f683ee75de..3b62a1a927 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -127,6 +127,14 @@ void ViveControllerManager::calibrate() { } } +bool ViveControllerManager::uncalibrate() { + if (isSupported()) { + _inputDevice->uncalibrate(); + return true; + } + return false; +} + bool ViveControllerManager::isSupported() const { return openVrSupported(); } @@ -241,10 +249,6 @@ ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : contro _configStringMap[Config::FeetAndHips] = QString("FeetAndHips"); _configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest"); _configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders"); - - if (openVrSupported()) { - loadSettings(); - } } void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { @@ -319,7 +323,8 @@ void ViveControllerManager::InputDevice::calibrateFromHandController(const contr void ViveControllerManager::InputDevice::calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData) { if (_calibrate) { - calibrateOrUncalibrate(inputCalibrationData); + uncalibrate(); + calibrate(inputCalibrationData); _calibrate = false; } } @@ -337,6 +342,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHead = headObject["override"].toBool(); if (overrideHead) { _headConfig = HeadConfig::Puck; + HEAD_PUCK_Y_OFFSET = (float)headObject["Y"].toDouble(); + HEAD_PUCK_Z_OFFSET = (float)headObject["Z"].toDouble(); } else { _headConfig = HeadConfig::HMD; } @@ -345,6 +352,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHands = handsObject["override"].toBool(); if (overrideHands) { _handConfig = HandConfig::Pucks; + HAND_PUCK_Y_OFFSET = (float)handsObject["Y"].toDouble(); + HAND_PUCK_Z_OFFSET = (float)handsObject["Z"].toDouble(); } else { _handConfig = HandConfig::HandController; } @@ -352,10 +361,6 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso iter++; } } - - qDebug() << configToString(_preferedConfig); - - saveSettings(); } void ViveControllerManager::InputDevice::calibrateNextFrame() { @@ -444,15 +449,22 @@ void ViveControllerManager::InputDevice::calibrateOrUncalibrate(const controller void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibrationData& inputCalibration) { qDebug() << "Puck Calibration: Starting..."; + int puckCount = (int)_validTrackedObjects.size(); + qDebug() << "Puck Calibration: " << puckCount << " pucks found for calibration"; + + if (puckCount == 0) { + uncalibrate(); + emitCalibrationStatus(false); + return; + } + glm::mat4 defaultToReferenceMat = glm::mat4(); if (_headConfig == HeadConfig::HMD) { defaultToReferenceMat = calculateDefaultToReferenceForHmd(inputCalibration); } else if (_headConfig == HeadConfig::Puck) { defaultToReferenceMat = calculateDefaultToReferenceForHeadPuck(inputCalibration); } - - int puckCount = (int)_validTrackedObjects.size(); - qDebug() << "Puck Calibration: " << puckCount << " pucks found for calibration"; + _config = _preferedConfig; bool headConfigured = configureHead(defaultToReferenceMat, inputCalibration); @@ -1006,24 +1018,6 @@ void ViveControllerManager::InputDevice::calibrateHead(glm::mat4& defaultToRefer _pucksOffset[head.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHeadMat, newHead); } - -void ViveControllerManager::InputDevice::loadSettings() { - Settings settings; - settings.beginGroup("PUCK_CONFIG"); - { - } - settings.endGroup(); -} - -void ViveControllerManager::InputDevice::saveSettings() const { - Settings settings; - settings.beginGroup("PUCK_CONFIG"); - { - - } - settings.endGroup(); -} - QString ViveControllerManager::InputDevice::configToString(Config config) { return _configStringMap[config]; } diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 1a4df550d9..4ebe466a04 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -45,6 +45,7 @@ public: void setConfigurationSettings(const QJsonObject configurationSettings) override; QJsonObject configurationSettings() override; void calibrate() override; + bool uncalibrate() override; bool isHeadController() const override { return true; } bool isHeadControllerMounted() const; @@ -91,8 +92,6 @@ private: void partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int xPseudoButton, int yPseudoButton); void printDeviceTrackingResultChange(uint32_t deviceIndex); void setConfigFromString(const QString& value); - void loadSettings(); - void saveSettings() const; bool configureHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); bool configureHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); bool configureBody(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); From 2e329602f7eb7f0ef4b020e7ff19b2a6e814d42f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 21 Jun 2017 01:13:45 +0100 Subject: [PATCH 141/157] minimize diff --- interface/resources/qml/styles-uit/Separator.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/styles-uit/Separator.qml b/interface/resources/qml/styles-uit/Separator.qml index eb3bc33cf7..4134b928a7 100644 --- a/interface/resources/qml/styles-uit/Separator.qml +++ b/interface/resources/qml/styles-uit/Separator.qml @@ -1,3 +1,4 @@ +// // Separator.qml // // Created by Zach Fox on 2017-06-06 From 5e82b13d65ec46f7dc97295c10323748bdb90ceb Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 21 Jun 2017 01:15:17 +0100 Subject: [PATCH 142/157] removed double include --- interface/src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e32cf1232f..04c5ab6d3d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -83,7 +83,6 @@ #include #include #include -#include #include #include #include From 17832b602244e22767a0f2075524dbc83bc5439d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 21 Jun 2017 01:38:05 +0100 Subject: [PATCH 143/157] edited some button behavior --- interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 9c23cf8677..2a951f31ef 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -301,8 +301,10 @@ Rectangle { boxRadius: 7 onClicked: { - if (hipsChecked) { - checked = true; + if (!checked) { + shoulderBox.checked = false; + chestBox.checked = false; + hipBox.checked = false; } sendConfigurationSettings(); } From f369303bfed4abfe5e5bdef9e6f4c921f0d2cef9 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 21 Jun 2017 18:12:31 +0100 Subject: [PATCH 144/157] removed warning --- libraries/plugins/src/plugins/InputConfiguration.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/plugins/src/plugins/InputConfiguration.cpp b/libraries/plugins/src/plugins/InputConfiguration.cpp index 33948ef70d..04b1e3b370 100644 --- a/libraries/plugins/src/plugins/InputConfiguration.cpp +++ b/libraries/plugins/src/plugins/InputConfiguration.cpp @@ -138,4 +138,6 @@ bool InputConfiguration::uncalibratePlugin(QString pluginName) { return plugin->uncalibrate(); } } + + return false; } From 0d9aa8182ec00282e211cf37898f1167c55d497c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 21 Jun 2017 17:10:19 -0400 Subject: [PATCH 145/157] have cmake find fbx library on Linux --- cmake/modules/FindFBX.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindFBX.cmake b/cmake/modules/FindFBX.cmake index 7f6a424aa1..2e84d1ea19 100644 --- a/cmake/modules/FindFBX.cmake +++ b/cmake/modules/FindFBX.cmake @@ -29,6 +29,7 @@ string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*$" "\\1" FBX_VERSION_MINOR "${FBX_VER string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" FBX_VERSION_PATCH "${FBX_VERSION}") set(FBX_MAC_LOCATIONS "/Applications/Autodesk/FBX\ SDK/${FBX_VERSION}") +set(FBX_LINUX_LOCATIONS "/usr/local/lib/gcc4/x64/debug/") if (WIN32) string(REGEX REPLACE "\\\\" "/" WIN_PROGRAM_FILES_X64_DIRECTORY $ENV{ProgramW6432}) @@ -36,7 +37,7 @@ endif() set(FBX_WIN_LOCATIONS "${WIN_PROGRAM_FILES_X64_DIRECTORY}/Autodesk/FBX/FBX SDK/${FBX_VERSION}") -set(FBX_SEARCH_LOCATIONS $ENV{FBX_ROOT} ${FBX_ROOT} ${FBX_MAC_LOCATIONS} ${FBX_WIN_LOCATIONS}) +set(FBX_SEARCH_LOCATIONS $ENV{FBX_ROOT} ${FBX_ROOT} ${FBX_MAC_LOCATIONS} ${FBX_WIN_LOCATIONS} ${FBX_LINUX_LOCATIONS}) function(_fbx_append_debugs _endvar _library) if (${_library} AND ${_library}_DEBUG) @@ -94,6 +95,8 @@ elseif (APPLE) find_library(SYSTEM_CONFIGURATION NAMES SystemConfiguration) _fbx_find_library(FBX_LIBRARY libfbxsdk.a release) _fbx_find_library(FBX_LIBRARY_DEBUG libfbxsdk.a debug) +else () + _fbx_find_library(FBX_LIBRARY libfbxsdk.a release) endif() include(FindPackageHandleStandardArgs) From c4699e00ca2ace25e9bc73f633948eb102aee654 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 21 Jun 2017 23:10:08 +0100 Subject: [PATCH 146/157] added hand offsets --- .../qml/hifi/tablet/CalibratingScreen.qml | 2 +- .../qml/hifi/tablet/OpenVrConfiguration.qml | 4 ++++ plugins/openvr/src/ViveControllerManager.cpp | 17 ++++++----------- plugins/openvr/src/ViveControllerManager.h | 2 -- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml index b8935f5463..338a76989f 100644 --- a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -113,7 +113,7 @@ Rectangle { color: hifi.colors.white size: hifi.fontSizes.rootMenuDisclosure - text: "please stand in a T-Pose during calibration" + text: "Please stand in a T-Pose during calibration" } NumberAnimation { diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 2a951f31ef..52a935ab19 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -149,6 +149,7 @@ Rectangle { colorScheme: hifi.colorSchemes.dark onEditingFinished: { + sendConfigurationSettings(); } } @@ -163,6 +164,7 @@ Rectangle { colorScheme: hifi.colorSchemes.dark onEditingFinished: { + sendConfigurationSettings(); } } } @@ -254,6 +256,7 @@ Rectangle { colorScheme: hifi.colorSchemes.dark onEditingFinished: { + sendConfigurationSettings(); } } @@ -268,6 +271,7 @@ Rectangle { colorScheme: hifi.colorSchemes.dark onEditingFinished: { + sendConfigurationSettings(); } } } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 3b62a1a927..d914cdcfad 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -342,8 +342,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHead = headObject["override"].toBool(); if (overrideHead) { _headConfig = HeadConfig::Puck; - HEAD_PUCK_Y_OFFSET = (float)headObject["Y"].toDouble(); - HEAD_PUCK_Z_OFFSET = (float)headObject["Z"].toDouble(); + HEAD_PUCK_Y_OFFSET = headObject["Y"].toDouble(); + HEAD_PUCK_Z_OFFSET = headObject["Z"].toDouble(); } else { _headConfig = HeadConfig::HMD; } @@ -352,8 +352,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHands = handsObject["override"].toBool(); if (overrideHands) { _handConfig = HandConfig::Pucks; - HAND_PUCK_Y_OFFSET = (float)handsObject["Y"].toDouble(); - HAND_PUCK_Z_OFFSET = (float)handsObject["Z"].toDouble(); + HAND_PUCK_Y_OFFSET = handsObject["Y"].toDouble(); + HAND_PUCK_Z_OFFSET = handsObject["Z"].toDouble(); } else { _handConfig = HandConfig::HandController; } @@ -906,7 +906,7 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToR glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - glm::vec3 translationOffset = glm::vec3(0.0f, -HAND_PUCK_Y_OFFSET, 0.0f); + glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET); glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat); glm::quat finalRotation = glmExtractRotation(newHandMat); @@ -932,13 +932,12 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo glm::vec3 zPrime = handPoseZAxis; glm::vec3 xPrime = glm::normalize(glm::cross(avatarHandYAxis, handPoseZAxis)); glm::vec3 yPrime = glm::normalize(glm::cross(zPrime, xPrime)); - glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f), glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); - glm::vec3 translationOffset = glm::vec3(0.0f, 0.0f, 0.0f); + glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET); glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat); glm::quat finalRotation = glmExtractRotation(newHandMat); @@ -977,10 +976,6 @@ void ViveControllerManager::InputDevice::calibrateHips(glm::mat4& defaultToRefer _pucksOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second); } - -void ViveControllerManager::InputDevice::calibrateHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, int firstHandIndex, int secondHandIndex) { -} - void ViveControllerManager::InputDevice::calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { _jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first; _pucksOffset[_validTrackedObjects[CHEST].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[CHEST].second); diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 4ebe466a04..67a9ff46fd 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -102,8 +102,6 @@ private: void calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); void calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, int firstShoulderIndex, int secondShoulderIndex); - void calibrateHands(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, - int firstHandIndex, int secondHandIndex); void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration); void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData); void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData); From 4a552affe673fa8bba7c71943ddc265d0b235662 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 21 Jun 2017 15:19:03 -0700 Subject: [PATCH 147/157] Fix reload content for baked skyboxes --- libraries/model-networking/src/model-networking/TextureCache.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 674e4dbe3b..ed1715219a 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -821,6 +821,7 @@ void NetworkTexture::refresh() { TextureCache::requestCompleted(_self); } + _ktxResourceState = PENDING_INITIAL_LOAD; Resource::refresh(); } From 781e2f409f0a4da4c2c37ca61467895c76974c8c Mon Sep 17 00:00:00 2001 From: 1P-Cusack <1p-cusack@1stplayable.com> Date: Wed, 21 Jun 2017 18:50:39 -0400 Subject: [PATCH 148/157] Adding support for loading obj.gz files in ModelCache. --- .../src/model-networking/ModelCache.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 623832aaa8..3bb33e0a2a 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -20,6 +20,8 @@ #include +#include + #include "ModelNetworkingLogging.h" #include #include @@ -171,7 +173,9 @@ void GeometryReader::run() { QString urlname = _url.path().toLower(); if (!urlname.isEmpty() && !_url.path().isEmpty() && - (_url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj"))) { + (_url.path().toLower().endsWith(".fbx") || + _url.path().toLower().endsWith(".obj") || + _url.path().toLower().endsWith(".gz"))) { FBXGeometry::Pointer fbxGeometry; if (_url.path().toLower().endsWith(".fbx")) { @@ -181,7 +185,12 @@ void GeometryReader::run() { } } else if (_url.path().toLower().endsWith(".obj")) { fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _combineParts, _url)); - } else { + } else if (_url.path().toLower().endsWith(".gz")) { + QByteArray uncompressedData; + if (gunzip(_data, uncompressedData)){ + fbxGeometry.reset(OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url)); + } + } else { throw QString("unsupported format"); } From 94a33fea9404c944c381f95ef27486d47bdab3a9 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 21 Jun 2017 16:03:05 -0700 Subject: [PATCH 149/157] new switches to override avatarURL --- interface/src/Application.cpp | 38 ++++++++++++++++++++++++------- interface/src/Application.h | 15 ++++++++---- interface/src/avatar/MyAvatar.cpp | 12 ++++++---- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c672f59a50..6838efcd6b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -214,7 +214,7 @@ static QTimer pingTimer; static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; -// For processing on QThreadPool, we target a number of threads after reserving some +// For processing on QThreadPool, we target a number of threads after reserving some // based on how many are being consumed by the application and the display plugin. However, // we will never drop below the 'min' value static const int MIN_PROCESSING_THREAD_POOL_SIZE = 1; @@ -859,6 +859,19 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } ResourceCache::setRequestLimit(concurrentDownloads); + // perhaps override the avatar url. We test later for validity, so + // no need to do so here. If someone specifies both --avatarURL + // and --replaceAvatarURL, the replaceAvatarURL wins. + QString avatarURL = getCmdOption(argc, constArgv, "--avatarURL"); + qDebug() << "XXXXXXXXXXXXXXXXXXXXX" << avatarURL; + _avatarOverrideUrl = QUrl::fromUserInput(avatarURL); + QString replaceURL = getCmdOption(argc, constArgv, "--replaceAvatarURL"); + qDebug() << "YYYYYYYYYYYYYYYYYYYYYY" << replaceURL; + if (!replaceURL.isEmpty()) { + _avatarOverrideUrl = QUrl::fromUserInput(replaceURL); + _saveAvatarOverrideUrl = true; + } + _glWidget = new GLCanvas(); getApplicationCompositor().setRenderingWidget(_glWidget); _window->setCentralWidget(_glWidget); @@ -1248,7 +1261,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Add periodic checks to send user activity data static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000; static int NEARBY_AVATAR_RADIUS_METERS = 10; - + // setup the stats interval depending on if the 1s faster hearbeat was requested static const QString FAST_STATS_ARG = "--fast-heartbeat"; static int SEND_STATS_INTERVAL_MS = arguments().indexOf(FAST_STATS_ARG) != -1 ? 1000 : 10000; @@ -1398,10 +1411,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _autoSwitchDisplayModeSupportedHMDPlugin = nullptr; foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { - if (displayPlugin->isHmd() && + if (displayPlugin->isHmd() && displayPlugin->getSupportsAutoSwitch()) { _autoSwitchDisplayModeSupportedHMDPlugin = displayPlugin; - _autoSwitchDisplayModeSupportedHMDPluginName = + _autoSwitchDisplayModeSupportedHMDPluginName = _autoSwitchDisplayModeSupportedHMDPlugin->getName(); _previousHMDWornStatus = _autoSwitchDisplayModeSupportedHMDPlugin->isDisplayVisible(); @@ -1653,7 +1666,7 @@ void Application::onAboutToQuit() { } getActiveDisplayPlugin()->deactivate(); - if (_autoSwitchDisplayModeSupportedHMDPlugin + if (_autoSwitchDisplayModeSupportedHMDPlugin && _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { _autoSwitchDisplayModeSupportedHMDPlugin->endSession(); } @@ -1722,8 +1735,8 @@ void Application::cleanupBeforeQuit() { // Cleanup all overlays after the scripts, as scripts might add more _overlays.cleanupAllOverlays(); - // The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual - // removal of the items. + // The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual + // removal of the items. // See https://highfidelity.fogbugz.com/f/cases/5328 _main3DScene->processTransactionQueue(); @@ -5217,7 +5230,7 @@ void Application::clearDomainOctreeDetails() { skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT); _recentlyClearedDomain = true; - + DependencyManager::get()->clearUnusedResources(); DependencyManager::get()->clearUnusedResources(); DependencyManager::get()->clearUnusedResources(); @@ -5281,6 +5294,10 @@ void Application::nodeActivated(SharedNodePointer node) { if (node->getType() == NodeType::AvatarMixer) { // new avatar mixer, send off our identity packet on next update loop // Reset skeletonModelUrl if the last server modified our choice. + // Override the avatar url (but not model name) here too. + if (_avatarOverrideUrl.isValid()) { + getMyAvatar()->useFullAvatarURL(_avatarOverrideUrl); + } static const QUrl empty{}; if (getMyAvatar()->getFullAvatarURLFromPreferences() != getMyAvatar()->cannonicalSkeletonModelURL(empty)) { getMyAvatar()->resetFullAvatarURL(); @@ -7035,3 +7052,8 @@ QUuid Application::getTabletFrameID() const { auto HMD = DependencyManager::get(); return HMD->getCurrentTabletFrameID(); } + +void Application::setAvatarOverrideUrl(const QUrl& url, bool save) { + _avatarOverrideUrl = url; + _saveAvatarOverrideUrl = save; +} diff --git a/interface/src/Application.h b/interface/src/Application.h index dadedde7bd..cab42d1e1c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -102,9 +102,9 @@ class Application; #endif #define qApp (static_cast(QCoreApplication::instance())) -class Application : public QApplication, - public AbstractViewStateInterface, - public AbstractScriptingServicesInterface, +class Application : public QApplication, + public AbstractViewStateInterface, + public AbstractScriptingServicesInterface, public AbstractUriHandler, public PluginContainer { Q_OBJECT @@ -294,6 +294,10 @@ public: OverlayID getTabletHomeButtonID() const; QUuid getTabletFrameID() const; // may be an entity or an overlay + void setAvatarOverrideUrl(const QUrl& url, bool save); + QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; } + bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; } + signals: void svoImportRequested(const QString& url); @@ -675,11 +679,14 @@ private: FileScriptingInterface* _fileDownload; AudioInjector* _snapshotSoundInjector { nullptr }; SharedSoundPointer _snapshotSound; - + DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin; QString _autoSwitchDisplayModeSupportedHMDPluginName; bool _previousHMDWornStatus; void startHMDStandBySession(); void endHMDSession(); + + QUrl _avatarOverrideUrl; + bool _saveAvatarOverrideUrl { false }; }; #endif // hifi_Application_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e96f626082..e6c9ac9fb6 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -929,10 +929,14 @@ void MyAvatar::saveData() { settings.setValue("scale", _targetScale); - settings.setValue("fullAvatarURL", + // only save the fullAvatarURL if it has not been overwritten on command line, or it + // has but we want it saved + if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid() ) { + settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ? "" : _fullAvatarURLFromPreferences.toString()); + } settings.setValue("fullAvatarModelName", _fullAvatarModelName); @@ -2430,7 +2434,7 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette // Our head may be embedded, but our center is out and there's room below. See corresponding comment above. return false; // nothing below } - + // See if we have room between entities above and below, but that we are not contained. // First check if the surface above us is the bottom of something, and the surface below us it the top of something. // I.e., we are in a clearing between two objects. @@ -3150,6 +3154,6 @@ void MyAvatar::updateHoldActions(const AnimPose& prePhysicsPose, const AnimPose& } } -const MyHead* MyAvatar::getMyHead() const { - return static_cast(getHead()); +const MyHead* MyAvatar::getMyHead() const { + return static_cast(getHead()); } From 92cbb86e8ba512de713a76b3432b5bea51d79d39 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 21 Jun 2017 16:09:08 -0700 Subject: [PATCH 150/157] remove debugging --- interface/src/Application.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6838efcd6b..932c710df4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -863,10 +863,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // no need to do so here. If someone specifies both --avatarURL // and --replaceAvatarURL, the replaceAvatarURL wins. QString avatarURL = getCmdOption(argc, constArgv, "--avatarURL"); - qDebug() << "XXXXXXXXXXXXXXXXXXXXX" << avatarURL; _avatarOverrideUrl = QUrl::fromUserInput(avatarURL); QString replaceURL = getCmdOption(argc, constArgv, "--replaceAvatarURL"); - qDebug() << "YYYYYYYYYYYYYYYYYYYYYY" << replaceURL; if (!replaceURL.isEmpty()) { _avatarOverrideUrl = QUrl::fromUserInput(replaceURL); _saveAvatarOverrideUrl = true; From aeb3f443f81da91a689bd31e9580761dd3a863b4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 21 Jun 2017 16:14:14 -0700 Subject: [PATCH 151/157] address code review comments --- .../src/audio/AudioMixerClientData.cpp | 3 +-- assignment-client/src/avatars/AvatarMixer.cpp | 6 ++--- assignment-client/src/avatars/AvatarMixer.h | 2 +- .../src/avatars/AvatarMixerSlave.cpp | 4 +-- domain-server/src/DomainServer.cpp | 26 ++++++++++++------- libraries/avatars/src/AvatarData.cpp | 24 ++++++----------- libraries/avatars/src/AvatarData.h | 5 ++-- libraries/networking/src/LimitedNodeList.h | 5 ---- libraries/networking/src/NetworkPeer.h | 5 ++++ 9 files changed, 37 insertions(+), 43 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 6e11257c7f..bf19a02d9a 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -121,8 +121,6 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c // first, make sure that this is a packet from a node we are supposed to replicate if (node.isReplicated()) { - auto nodeList = DependencyManager::get(); - // now make sure it's a packet type that we want to replicate // first check if it is an original type that we should replicate @@ -139,6 +137,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c } std::unique_ptr packet; + auto nodeList = DependencyManager::get(); // enumerate the downstream audio mixers and send them the replicated version of this packet nodeList->unsafeEachNode([&](const SharedNodePointer& downstreamNode) { diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 136d5f2e8e..f1e30f4442 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -57,7 +57,7 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) : packetReceiver.registerListenerForTypes({ PacketType::ReplicatedAvatarIdentity, PacketType::ReplicatedKillAvatar - }, this, "handleReplicatedPackets"); + }, this, "handleReplicatedPacket"); packetReceiver.registerListener(PacketType::ReplicatedBulkAvatarData, this, "handleReplicatedBulkAvatarPacket"); @@ -82,7 +82,7 @@ SharedNodePointer addOrUpdateReplicatedNode(const QUuid& nodeID, const HifiSockA return replicatedNode; } -void AvatarMixer::handleReplicatedPackets(QSharedPointer message) { +void AvatarMixer::handleReplicatedPacket(QSharedPointer message) { auto nodeList = DependencyManager::get(); auto nodeID = QUuid::fromRfc4122(message->peek(NUM_BYTES_RFC4122_UUID)); @@ -96,8 +96,6 @@ void AvatarMixer::handleReplicatedPackets(QSharedPointer messag } void AvatarMixer::handleReplicatedBulkAvatarPacket(QSharedPointer message) { - auto nodeList = DependencyManager::get(); - while (message->getBytesLeftToRead()) { // first, grab the node ID for this replicated avatar auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 42414dab55..58d4487652 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -46,7 +46,7 @@ private slots: void handleNodeIgnoreRequestPacket(QSharedPointer message, SharedNodePointer senderNode); void handleRadiusIgnoreRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleRequestsDomainListDataPacket(QSharedPointer message, SharedNodePointer senderNode); - void handleReplicatedPackets(QSharedPointer message); + void handleReplicatedPacket(QSharedPointer message); void handleReplicatedBulkAvatarPacket(QSharedPointer message); void domainSettingsRequestComplete(); void handlePacketVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID); diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 4d5e507923..8092518454 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -67,7 +67,7 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) { int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { if (destinationNode->getType() == NodeType::Agent && !destinationNode->isUpstream()) { - QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(true); + QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); identityPackets->write(individualData); @@ -81,7 +81,7 @@ int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, int AvatarMixerSlave::sendReplicatedIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { if (destinationNode->getType() == NodeType::DownstreamAvatarMixer) { - QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(true); + QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious auto identityPacket = NLPacket::create(PacketType::ReplicatedAvatarIdentity); identityPacket->write(individualData); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 856a568ca7..1f903ea1bc 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2277,6 +2277,10 @@ void DomainServer::updateDownstreamNodes() { } } + + // enumerate the nodes to determine which are no longer downstream for this domain + // collect them in a vector to separately remove them with handleKillNode (since eachNode has a read lock and + // we cannot recursively take the write lock required by handleKillNode) std::vector nodesToKill; nodeList->eachNode([&](const SharedNodePointer& otherNode) { if (NodeType::isDownstream(otherNode->getType())) { @@ -2288,6 +2292,7 @@ void DomainServer::updateDownstreamNodes() { } } }); + for (auto& node : nodesToKill) { handleKillNode(node); } @@ -2296,12 +2301,11 @@ void DomainServer::updateDownstreamNodes() { void DomainServer::updateReplicatedNodes() { // Make sure we have downstream nodes in our list - // TODO Move this to a different function - _replicatedUsernames.clear(); auto settings = _settingsManager.getSettingsMap(); static const QString REPLICATED_USERS_KEY = "users"; _replicatedUsernames.clear(); + if (settings.contains(BROADCASTING_SETTINGS_KEY)) { auto replicationSettings = settings.value(BROADCASTING_SETTINGS_KEY).toMap(); if (replicationSettings.contains(REPLICATED_USERS_KEY)) { @@ -2319,9 +2323,6 @@ void DomainServer::updateReplicatedNodes() { auto shouldReplicate = shouldReplicateNode(*otherNode); auto isReplicated = otherNode->isReplicated(); if (isReplicated && !shouldReplicate) { - qDebug() << "Setting node to NOT be replicated:" << otherNode->getUUID(); - } else if (!isReplicated && shouldReplicate) { - qDebug() << "Setting node to replicated:" << otherNode->getUUID(); qDebug() << "Setting node to NOT be replicated:" << otherNode->getPermissions().getVerifiedUserName() << otherNode->getUUID(); } else if (!isReplicated && shouldReplicate) { @@ -2334,11 +2335,16 @@ void DomainServer::updateReplicatedNodes() { } bool DomainServer::shouldReplicateNode(const Node& node) { - QString verifiedUsername = node.getPermissions().getVerifiedUserName(); - // Both the verified username and usernames in _replicatedUsernames are lowercase, so - // comparisons here are case-insensitive. - auto it = find(_replicatedUsernames.cbegin(), _replicatedUsernames.cend(), verifiedUsername); - return it != _replicatedUsernames.end() && node.getType() == NodeType::Agent; + if (node.getType() == NodeType::Agent) { + QString verifiedUsername = node.getPermissions().getVerifiedUserName(); + + // Both the verified username and usernames in _replicatedUsernames are lowercase, so + // comparisons here are case-insensitive. + auto it = find(_replicatedUsernames.cbegin(), _replicatedUsernames.cend(), verifiedUsername); + return it != _replicatedUsernames.end(); + } else { + return false; + } }; void DomainServer::nodeAdded(SharedNodePointer node) { diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 6ec2b45c89..eb4a02cb62 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1496,13 +1496,13 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide udt::SequenceNumber incomingSequenceNumber(incomingSequenceNumberType); if (!_hasProcessedFirstIdentity) { - _lastIncomingSequenceNumber = incomingSequenceNumber - 1; + _lastSequenceNumber = incomingSequenceNumber - 1; _hasProcessedFirstIdentity = true; qCDebug(avatars) << "Processing first identity packet for" << avatarSessionID << "-" << (udt::SequenceNumber::Type) incomingSequenceNumber; } - if (incomingSequenceNumber > _lastIncomingSequenceNumber) { + if (incomingSequenceNumber > _lastSequenceNumber) { Identity identity; packetStream >> identity.skeletonModelURL @@ -1512,7 +1512,7 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide >> identity.avatarEntityData; // set the store identity sequence number to match the incoming identity - _lastIncomingSequenceNumber = incomingSequenceNumber; + _lastSequenceNumber = incomingSequenceNumber; if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) { setSkeletonModelURL(identity.skeletonModelURL); @@ -1552,34 +1552,26 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide << "identity.skeletonModelURL:" << identity.skeletonModelURL << "identity.displayName:" << identity.displayName << "identity.sessionDisplayName:" << identity.sessionDisplayName; -#endif - } else { -#ifdef WANT_DEBUG + qCDebug(avatars) << "Refusing to process identity for" << uuidStringWithoutCurlyBraces(avatarSessionID) << "since" - << (udt::SequenceNumber::Type) _lastIncomingSequenceNumber + << (udt::SequenceNumber::Type) _lastSequenceNumber << "is >=" << (udt::SequenceNumber::Type) incomingSequenceNumber; #endif } } -QByteArray AvatarData::identityByteArray(bool shouldForwardIncomingSequenceNumber) const { +QByteArray AvatarData::identityByteArray() const { QByteArray identityData; QDataStream identityStream(&identityData, QIODevice::Append); const QUrl& urlToSend = cannonicalSkeletonModelURL(emptyURL); // depends on _skeletonModelURL - // we use the boolean flag to determine if this is an identity byte array for a mixer to send to an agent - // or an agent to send to a mixer - // when mixers send identity packets to agents, they simply forward along the last incoming sequence number they received // whereas agents send a fresh outgoing sequence number when identity data has changed - udt::SequenceNumber identitySequenceNumber = - shouldForwardIncomingSequenceNumber ? _lastIncomingSequenceNumber : _lastOutgoingSequenceNumber; - _avatarEntitiesLock.withReadLock([&] { identityStream << getSessionUUID() - << (udt::SequenceNumber::Type) identitySequenceNumber + << (udt::SequenceNumber::Type) _lastSequenceNumber << urlToSend << _attachmentData << _displayName @@ -1763,7 +1755,7 @@ void AvatarData::sendIdentityPacket() { if (_identityDataChanged) { // if the identity data has changed, push the sequence number forwards - ++_lastOutgoingSequenceNumber; + ++_lastSequenceNumber; } QByteArray identityData = identityByteArray(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 44d910b571..8d09f936b5 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -539,7 +539,7 @@ public: void processAvatarIdentity(const QByteArray& identityData, bool& identityChanged, bool& displayNameChanged, bool& skeletonModelUrlChanged); - QByteArray identityByteArray(bool shouldForwardIncomingSequenceNumber = false) const; + QByteArray identityByteArray() const; const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; } const QString& getDisplayName() const { return _displayName; } @@ -781,8 +781,7 @@ protected: float _audioAverageLoudness { 0.0f }; bool _identityDataChanged { false }; - udt::SequenceNumber _lastIncomingSequenceNumber { 0 }; - udt::SequenceNumber _lastOutgoingSequenceNumber { 0 }; + udt::SequenceNumber _lastSequenceNumber { 0 }; bool _hasProcessedFirstIdentity { false }; float _density; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 01e0ef2dc0..ab61c71952 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -289,9 +289,6 @@ public: void sendFakedHandshakeRequestToNode(SharedNodePointer node); #endif - void setMirrorSocket(const HifiSockAddr& mirrorSocket) { _mirrorSocket = mirrorSocket; } - const HifiSockAddr& getMirrorSocket() { return _mirrorSocket; } - public slots: void reset(); void eraseAllNodes(); @@ -401,8 +398,6 @@ protected: } - HifiSockAddr _mirrorSocket; - private slots: void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp); void possiblyTimeoutSTUNAddressLookup(); diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index 48dd82ecb7..9842768b37 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -76,6 +76,11 @@ public: float getOutboundBandwidth() const; // in kbps float getInboundBandwidth() const; // in kbps + // Typically the LimitedNodeList removes nodes after they are "silent" + // meaning that we have not received any packets (including simple keepalive pings) from them for a set interval. + // The _isForcedNeverSilent flag tells the LimitedNodeList that a Node should never be killed by removeSilentNodes() + // even if its the timestamp of when it was last heard from has never been updated. + bool isForcedNeverSilent() const { return _isForcedNeverSilent; } void setIsForcedNeverSilent(bool isForcedNeverSilent) { _isForcedNeverSilent = isForcedNeverSilent; } From 95704c1ba5976ff823bf14cab1bef772e9a2510b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 21 Jun 2017 17:58:19 -0700 Subject: [PATCH 152/157] make broadcasting settings advanced --- domain-server/resources/describe-settings.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index fd0e107558..c7dc97f595 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1344,6 +1344,7 @@ "name": "users", "label": "Broadcasted Users", "type": "table", + "advanced": true, "can_add_new_rows": true, "help": "Users that are broadcasted to downstream servers", "numbered": false, @@ -1360,6 +1361,7 @@ "label": "Receiving Servers", "assignment-types": [0,1], "type": "table", + "advanced": true, "can_add_new_rows": true, "help": "Servers that receive data for broadcasted users", "numbered": false, From b1119ff46586d83b5873683f26e48837f0712cb0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 21 Jun 2017 20:10:54 -0700 Subject: [PATCH 153/157] more changes to get oven building on Linux --- tools/oven/CMakeLists.txt | 15 ++++++++++++++- tools/oven/src/Oven.cpp | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/oven/CMakeLists.txt b/tools/oven/CMakeLists.txt index 24c8a9a0e2..f4fca3304c 100644 --- a/tools/oven/CMakeLists.txt +++ b/tools/oven/CMakeLists.txt @@ -4,15 +4,28 @@ setup_hifi_project(Widgets Gui Concurrent) link_hifi_libraries(networking shared image gpu ktx) +setup_memory_debugger() + if (WIN32) package_libraries_for_deployment() endif () +if (UNIX) + find_package(Threads REQUIRED) + if(THREADS_HAVE_PTHREAD_ARG) + target_compile_options(PUBLIC oven "-pthread") + endif() +endif () + # try to find the FBX SDK but fail silently if we don't # because this tool is not built by default find_package(FBX) if (FBX_FOUND) - target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES}) + if (CMAKE_THREAD_LIBS_INIT) + target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES} "${CMAKE_THREAD_LIBS_INIT}") + else () + target_link_libraries(${TARGET_NAME} ${FBX_LIBRARIES}) + endif () target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${FBX_INCLUDE_DIR}) endif () diff --git a/tools/oven/src/Oven.cpp b/tools/oven/src/Oven.cpp index a38aaa2b97..dc763cc82d 100644 --- a/tools/oven/src/Oven.cpp +++ b/tools/oven/src/Oven.cpp @@ -18,7 +18,7 @@ #include "ui/OvenMainWindow.h" #include "Oven.h" -#include "BakerCli.h" +#include "BakerCLI.h" static const QString OUTPUT_FOLDER = "/Users/birarda/code/hifi/lod/test-oven/export"; From 5da01f00743d34c030cbb9dfbd9926616e32eccb Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 22 Jun 2017 07:09:24 -0700 Subject: [PATCH 154/157] updated comments --- interface/src/Application.cpp | 9 ++++++--- interface/src/avatar/MyAvatar.cpp | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 932c710df4..bab6a544d8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -859,11 +859,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } ResourceCache::setRequestLimit(concurrentDownloads); - // perhaps override the avatar url. We test later for validity, so - // no need to do so here. If someone specifies both --avatarURL - // and --replaceAvatarURL, the replaceAvatarURL wins. + // perhaps override the avatar url. Since we will test later for validity + // we don't need to do so here. QString avatarURL = getCmdOption(argc, constArgv, "--avatarURL"); _avatarOverrideUrl = QUrl::fromUserInput(avatarURL); + + // If someone specifies both --avatarURL and --replaceAvatarURL, + // the replaceAvatarURL wins. So only set the _overrideUrl if this + // does have a non-empty string. QString replaceURL = getCmdOption(argc, constArgv, "--replaceAvatarURL"); if (!replaceURL.isEmpty()) { _avatarOverrideUrl = QUrl::fromUserInput(replaceURL); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e6c9ac9fb6..4a0d753695 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -929,8 +929,9 @@ void MyAvatar::saveData() { settings.setValue("scale", _targetScale); - // only save the fullAvatarURL if it has not been overwritten on command line, or it - // has but we want it saved + // only save the fullAvatarURL if it has not been overwritten on command line + // (so the overrideURL is not valid), or it was overridden _and_ we specified + // --replaceAvatarURL (so _saveAvatarOverrideUrl is true) if (qApp->getSaveAvatarOverrideUrl() || !qApp->getAvatarOverrideUrl().isValid() ) { settings.setValue("fullAvatarURL", _fullAvatarURLFromPreferences == AvatarData::defaultFullAvatarModelUrl() ? From f8c30c70e838b1fc3fff849c67a36de74d4991cb Mon Sep 17 00:00:00 2001 From: 1P-Cusack <1p-cusack@1stplayable.com> Date: Thu, 22 Jun 2017 11:21:19 -0400 Subject: [PATCH 155/157] Addressing some feedback. Making the .obj.gz checks more specific and adding an exception if gunzip fails. --- .../model-networking/src/model-networking/ModelCache.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 3bb33e0a2a..704455c981 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -175,7 +175,7 @@ void GeometryReader::run() { if (!urlname.isEmpty() && !_url.path().isEmpty() && (_url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj") || - _url.path().toLower().endsWith(".gz"))) { + _url.path().toLower().endsWith(".obj.gz"))) { FBXGeometry::Pointer fbxGeometry; if (_url.path().toLower().endsWith(".fbx")) { @@ -185,11 +185,14 @@ void GeometryReader::run() { } } else if (_url.path().toLower().endsWith(".obj")) { fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _combineParts, _url)); - } else if (_url.path().toLower().endsWith(".gz")) { + } else if (_url.path().toLower().endsWith(".obj.gz")) { QByteArray uncompressedData; if (gunzip(_data, uncompressedData)){ fbxGeometry.reset(OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url)); + } else { + throw QString("failed to decompress .obj.gz" ); } + } else { throw QString("unsupported format"); } From 42cceb02a4e2344626b118e1fa42db40ea6b01b9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Jun 2017 11:10:43 -0700 Subject: [PATCH 156/157] push sequence number when managing identity data for agent --- assignment-client/src/avatars/AvatarMixer.cpp | 8 +++++++- libraries/avatars/src/AvatarData.cpp | 12 ++++++------ libraries/avatars/src/AvatarData.h | 4 +++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index f1e30f4442..28ede7a77d 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -331,7 +331,13 @@ void AvatarMixer::manageIdentityData(const SharedNodePointer& node) { } } if (sendIdentity) { - sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name or avatar. + + // since this packet includes a change to either the skeleton model URL or the display name + // it needs a new sequence number + nodeData->getAvatar().pushIdentitySequenceNumber(); + + // tell node whose name changed about its new session display name or avatar. + sendIdentityPacket(nodeData, node); } } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index eb4a02cb62..3bcd401e38 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1496,13 +1496,13 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide udt::SequenceNumber incomingSequenceNumber(incomingSequenceNumberType); if (!_hasProcessedFirstIdentity) { - _lastSequenceNumber = incomingSequenceNumber - 1; + _sequenceNumber = incomingSequenceNumber - 1; _hasProcessedFirstIdentity = true; qCDebug(avatars) << "Processing first identity packet for" << avatarSessionID << "-" << (udt::SequenceNumber::Type) incomingSequenceNumber; } - if (incomingSequenceNumber > _lastSequenceNumber) { + if (incomingSequenceNumber > _sequenceNumber) { Identity identity; packetStream >> identity.skeletonModelURL @@ -1512,7 +1512,7 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide >> identity.avatarEntityData; // set the store identity sequence number to match the incoming identity - _lastSequenceNumber = incomingSequenceNumber; + _sequenceNumber = incomingSequenceNumber; if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) { setSkeletonModelURL(identity.skeletonModelURL); @@ -1555,7 +1555,7 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide } else { qCDebug(avatars) << "Refusing to process identity for" << uuidStringWithoutCurlyBraces(avatarSessionID) << "since" - << (udt::SequenceNumber::Type) _lastSequenceNumber + << (udt::SequenceNumber::Type) _sequenceNumber << "is >=" << (udt::SequenceNumber::Type) incomingSequenceNumber; #endif } @@ -1571,7 +1571,7 @@ QByteArray AvatarData::identityByteArray() const { _avatarEntitiesLock.withReadLock([&] { identityStream << getSessionUUID() - << (udt::SequenceNumber::Type) _lastSequenceNumber + << (udt::SequenceNumber::Type) _sequenceNumber << urlToSend << _attachmentData << _displayName @@ -1755,7 +1755,7 @@ void AvatarData::sendIdentityPacket() { if (_identityDataChanged) { // if the identity data has changed, push the sequence number forwards - ++_lastSequenceNumber; + ++_sequenceNumber; } QByteArray identityData = identityByteArray(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8d09f936b5..204ca5d5af 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -625,6 +625,8 @@ public: bool getIdentityDataChanged() const { return _identityDataChanged; } // has the identity data changed since the last time sendIdentityPacket() was called void markIdentityDataChanged() { _identityDataChanged = true; } + void pushIdentitySequenceNumber() { ++_sequenceNumber; }; + float getDensity() const { return _density; } signals: @@ -781,7 +783,7 @@ protected: float _audioAverageLoudness { 0.0f }; bool _identityDataChanged { false }; - udt::SequenceNumber _lastSequenceNumber { 0 }; + udt::SequenceNumber _sequenceNumber { 0 }; bool _hasProcessedFirstIdentity { false }; float _density; From ccbae07170fea16badcbd70a4e83f42afd7a1523 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Jun 2017 11:23:58 -0700 Subject: [PATCH 157/157] rename _sequenceNumber to _lastSequenceNumber --- libraries/avatars/src/AvatarData.cpp | 12 ++++++------ libraries/avatars/src/AvatarData.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 3bcd401e38..4926ca0fdb 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1496,13 +1496,13 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide udt::SequenceNumber incomingSequenceNumber(incomingSequenceNumberType); if (!_hasProcessedFirstIdentity) { - _sequenceNumber = incomingSequenceNumber - 1; + _identitySequenceNumber = incomingSequenceNumber - 1; _hasProcessedFirstIdentity = true; qCDebug(avatars) << "Processing first identity packet for" << avatarSessionID << "-" << (udt::SequenceNumber::Type) incomingSequenceNumber; } - if (incomingSequenceNumber > _sequenceNumber) { + if (incomingSequenceNumber > _identitySequenceNumber) { Identity identity; packetStream >> identity.skeletonModelURL @@ -1512,7 +1512,7 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide >> identity.avatarEntityData; // set the store identity sequence number to match the incoming identity - _sequenceNumber = incomingSequenceNumber; + _identitySequenceNumber = incomingSequenceNumber; if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) { setSkeletonModelURL(identity.skeletonModelURL); @@ -1555,7 +1555,7 @@ void AvatarData::processAvatarIdentity(const QByteArray& identityData, bool& ide } else { qCDebug(avatars) << "Refusing to process identity for" << uuidStringWithoutCurlyBraces(avatarSessionID) << "since" - << (udt::SequenceNumber::Type) _sequenceNumber + << (udt::SequenceNumber::Type) _identitySequenceNumber << "is >=" << (udt::SequenceNumber::Type) incomingSequenceNumber; #endif } @@ -1571,7 +1571,7 @@ QByteArray AvatarData::identityByteArray() const { _avatarEntitiesLock.withReadLock([&] { identityStream << getSessionUUID() - << (udt::SequenceNumber::Type) _sequenceNumber + << (udt::SequenceNumber::Type) _identitySequenceNumber << urlToSend << _attachmentData << _displayName @@ -1755,7 +1755,7 @@ void AvatarData::sendIdentityPacket() { if (_identityDataChanged) { // if the identity data has changed, push the sequence number forwards - ++_sequenceNumber; + ++_identitySequenceNumber; } QByteArray identityData = identityByteArray(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 204ca5d5af..de905277d5 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -625,7 +625,7 @@ public: bool getIdentityDataChanged() const { return _identityDataChanged; } // has the identity data changed since the last time sendIdentityPacket() was called void markIdentityDataChanged() { _identityDataChanged = true; } - void pushIdentitySequenceNumber() { ++_sequenceNumber; }; + void pushIdentitySequenceNumber() { ++_identitySequenceNumber; }; float getDensity() const { return _density; } @@ -783,7 +783,7 @@ protected: float _audioAverageLoudness { 0.0f }; bool _identityDataChanged { false }; - udt::SequenceNumber _sequenceNumber { 0 }; + udt::SequenceNumber _identitySequenceNumber { 0 }; bool _hasProcessedFirstIdentity { false }; float _density;