From 83ec346cc55c59444b5ddc4ea33af052121299d9 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 17 Oct 2018 16:42:29 -0700 Subject: [PATCH 01/25] changed the hand azimuth computation to be in spine2 space. this stops you from having a reversed direction when you sit down with hmd lean off and the hands are behind the origin in the z direction. --- interface/src/avatar/MyAvatar.cpp | 91 +++++++++++++++++++++++-------- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b347963cf1..e7d09b79a2 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -475,16 +475,33 @@ void MyAvatar::update(float deltaTime) { // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { - glm::vec3 handHipAzimuthWorldSpace = transformVectorFast(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); - glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); - glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); - glm::vec3 handHipAzimuthSensorSpace = transformVectorFast(worldToSensorMat, handHipAzimuthWorldSpace); - glm::vec2 normedHandHipAzimuthSensorSpace(0.0f, 1.0f); - if (glm::length(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)) > 0.0f) { - normedHandHipAzimuthSensorSpace = glm::normalize(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)); + int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); + if (!(spine2Index < 0)) { + // use the spine for the azimuth origin. + glm::quat spine2Rot = getAbsoluteJointRotationInObjectFrame(spine2Index); + glm::vec3 handHipAzimuthAvatarSpace = spine2Rot * glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y); + glm::vec3 handHipAzimuthWorldSpace = transformVectorFast(getTransform().getMatrix(), handHipAzimuthAvatarSpace); + glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); + glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); + glm::vec3 handHipAzimuthSensorSpace = transformVectorFast(worldToSensorMat, handHipAzimuthWorldSpace); + glm::vec2 normedHandHipAzimuthSensorSpace(0.0f, 1.0f); + if (glm::length(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)) > 0.0f) { + normedHandHipAzimuthSensorSpace = glm::normalize(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)); + } + glm::vec2 headFacingPlusHandHipAzimuthMix = lerp(normedHandHipAzimuthSensorSpace, _headControllerFacing, PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH); + _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, headFacingPlusHandHipAzimuthMix, tau); + } else { + glm::vec3 handHipAzimuthWorldSpace = transformVectorFast(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); + glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); + glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); + glm::vec3 handHipAzimuthSensorSpace = transformVectorFast(worldToSensorMat, handHipAzimuthWorldSpace); + glm::vec2 normedHandHipAzimuthSensorSpace(0.0f, 1.0f); + if (glm::length(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)) > 0.0f) { + normedHandHipAzimuthSensorSpace = glm::normalize(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)); + } + glm::vec2 headFacingPlusHandHipAzimuthMix = lerp(normedHandHipAzimuthSensorSpace, _headControllerFacing, PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH); + _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, headFacingPlusHandHipAzimuthMix, tau); } - glm::vec2 headFacingPlusHandHipAzimuthMix = lerp(normedHandHipAzimuthSensorSpace, _headControllerFacing, PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH); - _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, headFacingPlusHandHipAzimuthMix, tau); } else { _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau); } @@ -854,6 +871,20 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { glm::vec2 MyAvatar::computeHandAzimuth() const { controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); + + int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); + glm::vec3 spine2Position(0.0f,0.0f,0.0f); + glm::quat spine2Rotation(0.0f, 0.0f, 0.0f, 1.0f); + if (!(spine2Index < 0)) { + // use the spine for the azimuth origin. + spine2Position = getAbsoluteJointTranslationInObjectFrame(spine2Index); + glm::quat spine2Rotation = getAbsoluteJointRotationInObjectFrame(spine2Index); + } + glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - spine2Position; + glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - spine2Position; + glm::vec3 rightHandSpine2Space = glm::inverse(spine2Rotation) * rightHandOffset; + glm::vec3 leftHandSpine2Space = glm::inverse(spine2Rotation) * leftHandOffset; + controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD); const float HALFWAY = 0.50f; glm::vec2 latestHipToHandController = _hipToHandController; @@ -862,23 +893,25 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { // we need the old azimuth reading to prevent flipping the facing direction 180 // in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart. glm::vec2 oldAzimuthReading = _hipToHandController; - if ((glm::length(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)) > 0.0f) && (glm::length(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)) > 0.0f)) { - latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)), glm::normalize(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)), HALFWAY); + if ((glm::length(glm::vec2(rightHandSpine2Space.x, rightHandSpine2Space.z)) > 0.0f) && (glm::length(glm::vec2(leftHandSpine2Space.x, leftHandSpine2Space.z)) > 0.0f)) { + latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandSpine2Space.x, rightHandSpine2Space.z)), glm::normalize(glm::vec2(leftHandSpine2Space.x, leftHandSpine2Space.z)), HALFWAY); } else { - latestHipToHandController = glm::vec2(0.0f, -1.0f); + latestHipToHandController = glm::vec2(0.0f, 1.0f); } glm::vec3 headLookAtAvatarSpace = transformVectorFast(headPoseAvatarSpace.getMatrix(), glm::vec3(0.0f, 0.0f, 1.0f)); - glm::vec2 headAzimuthAvatarSpace = glm::vec2(headLookAtAvatarSpace.x, headLookAtAvatarSpace.z); - if (glm::length(headAzimuthAvatarSpace) > 0.0f) { - headAzimuthAvatarSpace = glm::normalize(headAzimuthAvatarSpace); + glm::vec3 headLookAtSpine2Space = glm::inverse(spine2Rotation) * headLookAtAvatarSpace; + + glm::vec2 headAzimuthSpine2Space = glm::vec2(headLookAtSpine2Space.x, headLookAtSpine2Space.z); + if (glm::length(headAzimuthSpine2Space) > 0.0f) { + headAzimuthSpine2Space = glm::normalize(headAzimuthSpine2Space); } else { - headAzimuthAvatarSpace = -latestHipToHandController; + headAzimuthSpine2Space = -latestHipToHandController; } // check the angular distance from forward and back float cosForwardAngle = glm::dot(latestHipToHandController, oldAzimuthReading); - float cosHeadShoulder = glm::dot(-latestHipToHandController, headAzimuthAvatarSpace); + float cosHeadShoulder = glm::dot(-latestHipToHandController, headAzimuthSpine2Space); // if we are now closer to the 180 flip of the previous chest forward // then we negate our computed latestHipToHandController to keep the chest from flipping. // also check the head to shoulder azimuth difference if we negate. @@ -3392,19 +3425,33 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { } glm::mat4 MyAvatar::getSpine2RotationRigSpace() const { + int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); + glm::quat spine2Rot = Quaternions::IDENTITY; + if (!(spine2Index < 0)) { + // use the spine for the azimuth origin. + spine2Rot = getAbsoluteJointRotationInObjectFrame(spine2Index); + } + glm::vec3 spine2UpAvatarSpace = spine2Rot * glm::vec3(0.0f, 1.0f, 0.0f); + glm::vec3 spine2FwdAvatarSpace = spine2Rot * glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y); // static const glm::quat RIG_CHANGE_OF_BASIS = Quaternions::Y_180; // RIG_CHANGE_OF_BASIS * AVATAR_TO_RIG_ROTATION * inverse(RIG_CHANGE_OF_BASIS) = Quaternions::Y_180; //avatar Space; const glm::quat AVATAR_TO_RIG_ROTATION = Quaternions::Y_180; - glm::vec3 hipToHandRigSpace = AVATAR_TO_RIG_ROTATION * glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y); + glm::vec3 spine2UpRigSpace = AVATAR_TO_RIG_ROTATION * spine2UpAvatarSpace; + glm::vec3 spine2FwdRigSpace = AVATAR_TO_RIG_ROTATION * spine2FwdAvatarSpace; glm::vec3 u, v, w; - if (glm::length(hipToHandRigSpace) > 0.0f) { - hipToHandRigSpace = glm::normalize(hipToHandRigSpace); + if (glm::length(spine2FwdRigSpace) > 0.0f) { + spine2FwdRigSpace = glm::normalize(spine2FwdRigSpace); } else { - hipToHandRigSpace = glm::vec3(0.0f, 0.0f, 1.0f); + spine2FwdRigSpace = glm::vec3(0.0f, 0.0f, 1.0f); } - generateBasisVectors(glm::vec3(0.0f,1.0f,0.0f), hipToHandRigSpace, u, v, w); + if (glm::length(spine2UpRigSpace) > 0.0f) { + spine2UpRigSpace = glm::normalize(spine2UpRigSpace); + } else { + spine2UpRigSpace = glm::vec3(0.0f, 1.0f, 0.0f); + } + generateBasisVectors(spine2UpRigSpace, spine2FwdRigSpace, u, v, w); glm::mat4 spine2RigSpace(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f)); return spine2RigSpace; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 16b765711a..85d6bea018 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1688,7 +1688,7 @@ private: glm::vec2 _headControllerFacingMovingAverage { 0.0f, 0.0f }; // facing vector in xz plane (sensor space) glm::quat _averageHeadRotation { 0.0f, 0.0f, 0.0f, 1.0f }; - glm::vec2 _hipToHandController { 0.0f, -1.0f }; // spine2 facing vector in xz plane (avatar space) + glm::vec2 _hipToHandController { 0.0f, 1.0f }; // spine2 facing vector in xz plane (spine2 space) float _currentStandingHeight { 0.0f }; bool _resetMode { true }; From 8f4fafe4d0480a88d0e19ad4044df32ad69b7433 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 18 Oct 2018 08:44:01 -0700 Subject: [PATCH 02/25] put some smoothing on the spine2 rotation in myskeletonmodel.cpp --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/avatar/MySkeletonModel.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e7d09b79a2..a5bb08658d 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -878,7 +878,7 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { if (!(spine2Index < 0)) { // use the spine for the azimuth origin. spine2Position = getAbsoluteJointTranslationInObjectFrame(spine2Index); - glm::quat spine2Rotation = getAbsoluteJointRotationInObjectFrame(spine2Index); + spine2Rotation = getAbsoluteJointRotationInObjectFrame(spine2Index); } glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - spine2Position; glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - spine2Position; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 3084542472..900d532c88 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -261,7 +261,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { } generateBasisVectors(up, fwd, u, v, w); AnimPose newSpinePose(glm::mat4(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f))); - currentSpine2Pose.rot() = newSpinePose.rot(); + currentSpine2Pose.rot() = safeLerp(currentSpine2Pose.rot(), newSpinePose.rot(), 0.5f); params.primaryControllerPoses[Rig::PrimaryControllerType_Spine2] = currentSpine2Pose; params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; } From 12b03b0e07e3d69d727e44b401cfea953ddcde3f Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 18 Oct 2018 10:52:13 -0700 Subject: [PATCH 03/25] tinkering with lerping the spine2 position in avatar space --- interface/src/avatar/MyAvatar.cpp | 3 ++- interface/src/avatar/MyAvatar.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a5bb08658d..e8d87d30af 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -877,7 +877,8 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { glm::quat spine2Rotation(0.0f, 0.0f, 0.0f, 1.0f); if (!(spine2Index < 0)) { // use the spine for the azimuth origin. - spine2Position = getAbsoluteJointTranslationInObjectFrame(spine2Index); + spine2Position = getAbsoluteJointTranslationInObjectFrame(spine2Index); + _spine2PositionAvatarSpace = _spine2PositionAvatarSpace + ((0.05f) * (spine2Position - _spine2PositionAvatarSpace)); spine2Rotation = getAbsoluteJointRotationInObjectFrame(spine2Index); } glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - spine2Position; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 85d6bea018..f40f7e3023 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1689,6 +1689,7 @@ private: glm::quat _averageHeadRotation { 0.0f, 0.0f, 0.0f, 1.0f }; glm::vec2 _hipToHandController { 0.0f, 1.0f }; // spine2 facing vector in xz plane (spine2 space) + glm::vec3 _spine2PositionAvatarSpace { 0.0f, 0.0f, 0.0f }; float _currentStandingHeight { 0.0f }; bool _resetMode { true }; From 5a8a5bbc55612098b07bb182b84aeb5513785ad4 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 22 Oct 2018 18:18:16 -0300 Subject: [PATCH 04/25] Set AEC enabled by default --- .../fragment/SettingsFragment.java | 20 +++++++++++-------- android/app/src/main/res/xml/settings.xml | 3 ++- libraries/audio-client/src/AudioClient.cpp | 4 ++-- libraries/audio-client/src/AudioClient.h | 1 + 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java index cc23665e72..58b6638531 100644 --- a/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java +++ b/android/app/src/main/java/io/highfidelity/hifiinterface/fragment/SettingsFragment.java @@ -3,8 +3,8 @@ package io.highfidelity.hifiinterface.fragment; import android.content.SharedPreferences; import android.media.audiofx.AcousticEchoCanceler; import android.os.Bundle; -import android.preference.Preference; import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; import android.support.annotation.Nullable; import io.highfidelity.hifiinterface.R; @@ -18,17 +18,23 @@ public class SettingsFragment extends PreferenceFragment implements SharedPrefer private final String HIFI_SETTINGS_AEC_KEY = "aec"; private final String PREFERENCE_KEY_AEC = "aec"; + private final boolean DEFAULT_AEC_ENABLED = true; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); + boolean aecAvailable = AcousticEchoCanceler.isAvailable(); + PreferenceManager.setDefaultValues(getContext(), R.xml.settings, false); - if (!AcousticEchoCanceler.isAvailable()) { - getPreferenceScreen().getPreferenceManager().findPreference("aec").setEnabled(false); + if (!aecAvailable) { + findPreference(PREFERENCE_KEY_AEC).setEnabled(false); + updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, false); } getPreferenceScreen().getSharedPreferences().edit().putBoolean(PREFERENCE_KEY_AEC, - getHifiSettingBoolean(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, false)); + aecAvailable && getHifiSettingBoolean(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, DEFAULT_AEC_ENABLED)).commit(); + } public static SettingsFragment newInstance() { @@ -46,15 +52,13 @@ public class SettingsFragment extends PreferenceFragment implements SharedPrefer public void onPause() { super.onPause(); getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); - } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - Preference pref = findPreference(key); switch (key) { - case "aec": - updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, sharedPreferences.getBoolean(key, false)); + case PREFERENCE_KEY_AEC: + updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, sharedPreferences.getBoolean(key, DEFAULT_AEC_ENABLED)); break; default: break; diff --git a/android/app/src/main/res/xml/settings.xml b/android/app/src/main/res/xml/settings.xml index 5ec47b1aff..934d34ba73 100644 --- a/android/app/src/main/res/xml/settings.xml +++ b/android/app/src/main/res/xml/settings.xml @@ -6,6 +6,7 @@ + android:summary="@string/acoustic_echo_cancellation" + android:defaultValue="true" /> \ No newline at end of file diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index d00bc29054..abe8f628f7 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -465,7 +465,7 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) { #if defined (Q_OS_ANDROID) if (mode == QAudio::AudioInput) { - Setting::Handle enableAEC(SETTING_AEC_KEY, false); + Setting::Handle enableAEC(SETTING_AEC_KEY, DEFAULT_AEC_ENABLED); bool aecEnabled = enableAEC.get(); auto audioClient = DependencyManager::get(); bool headsetOn = audioClient? audioClient->isHeadsetPluggedIn() : false; @@ -1673,7 +1673,7 @@ void AudioClient::setHeadsetPluggedIn(bool pluggedIn) { QThread::msleep(200); } - Setting::Handle enableAEC(SETTING_AEC_KEY, false); + Setting::Handle enableAEC(SETTING_AEC_KEY, DEFAULT_AEC_ENABLED); bool aecEnabled = enableAEC.get(); if ((pluggedIn || !aecEnabled) && _inputDeviceInfo.deviceName() != VOICE_RECOGNITION) { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 5e7f1fb8a0..057f477777 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -69,6 +69,7 @@ #define VOICE_COMMUNICATION "voicecommunication" #define SETTING_AEC_KEY "Android/aec" +#define DEFAULT_AEC_ENABLED true #endif class QAudioInput; From 5063d0b527fc6f7b4d0a0721860ec5be9a78cbb2 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 16:51:56 -0700 Subject: [PATCH 05/25] changed handAzimuth to non const function --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f75f3fbdfc..ac919d4420 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -997,7 +997,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { // Find the vector halfway between the hip to hand azimuth vectors // This midpoint hand azimuth is in Avatar space -glm::vec2 MyAvatar::computeHandAzimuth() const { +glm::vec2 MyAvatar::computeHandAzimuth() { controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6783cb8995..1be07a244e 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -337,7 +337,7 @@ public: void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix); // compute the hip to hand average azimuth. - glm::vec2 computeHandAzimuth() const; + glm::vec2 computeHandAzimuth(); // read the location of a hand controller and save the transform void updateJointFromController(controller::Action poseKey, ThreadSafeValueCache& matrixCache); From 370801bd85a2f753453082c7cffb78b21b5756d0 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 24 Oct 2018 16:23:05 -0700 Subject: [PATCH 06/25] removed _spine2position variable and added handling for when there is no spine2 joint. In that case the head will do the recentering rotation and the shoulders will not move with the hand azimuth --- interface/src/avatar/MyAvatar.cpp | 72 ++++++++++-------------- interface/src/avatar/MyAvatar.h | 3 +- interface/src/avatar/MySkeletonModel.cpp | 3 +- 3 files changed, 33 insertions(+), 45 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ac919d4420..e4ff88974a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -538,33 +538,24 @@ void MyAvatar::update(float deltaTime) { // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter - if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { - int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); - if (!(spine2Index < 0)) { - // use the spine for the azimuth origin. - glm::quat spine2Rot = getAbsoluteJointRotationInObjectFrame(spine2Index); - glm::vec3 handHipAzimuthAvatarSpace = spine2Rot * glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y); - glm::vec3 handHipAzimuthWorldSpace = transformVectorFast(getTransform().getMatrix(), handHipAzimuthAvatarSpace); - glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); - glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); - glm::vec3 handHipAzimuthSensorSpace = transformVectorFast(worldToSensorMat, handHipAzimuthWorldSpace); - glm::vec2 normedHandHipAzimuthSensorSpace(0.0f, 1.0f); - if (glm::length(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)) > 0.0f) { - normedHandHipAzimuthSensorSpace = glm::normalize(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)); - } + int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); + if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && !(spine2Index < 0)) { + + // use the spine for the azimuth origin. + glm::quat spine2Rot = getAbsoluteJointRotationInObjectFrame(spine2Index); + glm::vec3 handHipAzimuthAvatarSpace = spine2Rot * glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y); + glm::vec3 handHipAzimuthWorldSpace = transformVectorFast(getTransform().getMatrix(), handHipAzimuthAvatarSpace); + glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); + glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); + glm::vec3 handHipAzimuthSensorSpace = transformVectorFast(worldToSensorMat, handHipAzimuthWorldSpace); + glm::vec2 normedHandHipAzimuthSensorSpace(0.0f, 1.0f); + if (glm::length(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)) > 0.0f) { + normedHandHipAzimuthSensorSpace = glm::normalize(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)); glm::vec2 headFacingPlusHandHipAzimuthMix = lerp(normedHandHipAzimuthSensorSpace, _headControllerFacing, PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH); _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, headFacingPlusHandHipAzimuthMix, tau); } else { - glm::vec3 handHipAzimuthWorldSpace = transformVectorFast(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); - glm::mat4 sensorToWorldMat = getSensorToWorldMatrix(); - glm::mat4 worldToSensorMat = glm::inverse(sensorToWorldMat); - glm::vec3 handHipAzimuthSensorSpace = transformVectorFast(worldToSensorMat, handHipAzimuthWorldSpace); - glm::vec2 normedHandHipAzimuthSensorSpace(0.0f, 1.0f); - if (glm::length(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)) > 0.0f) { - normedHandHipAzimuthSensorSpace = glm::normalize(glm::vec2(handHipAzimuthSensorSpace.x, handHipAzimuthSensorSpace.z)); - } - glm::vec2 headFacingPlusHandHipAzimuthMix = lerp(normedHandHipAzimuthSensorSpace, _headControllerFacing, PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH); - _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, headFacingPlusHandHipAzimuthMix, tau); + // use head facing if the chest arms vector is up or down. + _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau); } } else { _headControllerFacingMovingAverage = lerp(_headControllerFacingMovingAverage, _headControllerFacing, tau); @@ -996,30 +987,27 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { } // Find the vector halfway between the hip to hand azimuth vectors -// This midpoint hand azimuth is in Avatar space -glm::vec2 MyAvatar::computeHandAzimuth() { +// This midpoint hand azimuth is in Spine2 space +glm::vec2 MyAvatar::computeHandAzimuth() const { controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); - - int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); - glm::vec3 spine2Position(0.0f,0.0f,0.0f); - glm::quat spine2Rotation(0.0f, 0.0f, 0.0f, 1.0f); - if (!(spine2Index < 0)) { - // use the spine for the azimuth origin. - spine2Position = getAbsoluteJointTranslationInObjectFrame(spine2Index); - _spine2PositionAvatarSpace = _spine2PositionAvatarSpace + ((0.05f) * (spine2Position - _spine2PositionAvatarSpace)); - spine2Rotation = getAbsoluteJointRotationInObjectFrame(spine2Index); - } - glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - spine2Position; - glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - spine2Position; - glm::vec3 rightHandSpine2Space = glm::inverse(spine2Rotation) * rightHandOffset; - glm::vec3 leftHandSpine2Space = glm::inverse(spine2Rotation) * leftHandOffset; - controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD); const float HALFWAY = 0.50f; + const float SPINE2_POSITION_FILTER = 0.05f; + glm::vec2 latestHipToHandController = _hipToHandController; - if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid()) { + int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); + if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid() && !(spine2Index < 0)) { + + glm::vec3 spine2Position = getAbsoluteJointTranslationInObjectFrame(spine2Index); + glm::quat spine2Rotation = getAbsoluteJointRotationInObjectFrame(spine2Index); + + glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - spine2Position; + glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - spine2Position; + glm::vec3 rightHandSpine2Space = glm::inverse(spine2Rotation) * rightHandOffset; + glm::vec3 leftHandSpine2Space = glm::inverse(spine2Rotation) * leftHandOffset; + // we need the old azimuth reading to prevent flipping the facing direction 180 // in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart. glm::vec2 oldAzimuthReading = _hipToHandController; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1be07a244e..85ad6fe7a4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -337,7 +337,7 @@ public: void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix); // compute the hip to hand average azimuth. - glm::vec2 computeHandAzimuth(); + glm::vec2 computeHandAzimuth() const; // read the location of a hand controller and save the transform void updateJointFromController(controller::Action poseKey, ThreadSafeValueCache& matrixCache); @@ -1732,7 +1732,6 @@ private: glm::quat _averageHeadRotation { 0.0f, 0.0f, 0.0f, 1.0f }; glm::vec2 _hipToHandController { 0.0f, 1.0f }; // spine2 facing vector in xz plane (spine2 space) - glm::vec3 _spine2PositionAvatarSpace { 0.0f, 0.0f, 0.0f }; float _currentStandingHeight { 0.0f }; bool _resetMode { true }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 0cda71ca77..b5a495d296 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -243,6 +243,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { + const float SPINE2_ROTATION_FILTER = 0.5f; AnimPose currentSpine2Pose; AnimPose currentHeadPose; AnimPose currentHipsPose; @@ -262,7 +263,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { } generateBasisVectors(up, fwd, u, v, w); AnimPose newSpinePose(glm::mat4(glm::vec4(w, 0.0f), glm::vec4(u, 0.0f), glm::vec4(v, 0.0f), glm::vec4(glm::vec3(0.0f, 0.0f, 0.0f), 1.0f))); - currentSpine2Pose.rot() = safeLerp(currentSpine2Pose.rot(), newSpinePose.rot(), 0.5f); + currentSpine2Pose.rot() = safeLerp(currentSpine2Pose.rot(), newSpinePose.rot(), SPINE2_ROTATION_FILTER); params.primaryControllerPoses[Rig::PrimaryControllerType_Spine2] = currentSpine2Pose; params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; } From 7fe53d4399f8a24043b6154c7d7785bc321bf7af Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 24 Oct 2018 16:32:18 -0700 Subject: [PATCH 07/25] removed extra const float value --- interface/src/avatar/MyAvatar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e4ff88974a..15ddb2fe87 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -993,7 +993,6 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD); const float HALFWAY = 0.50f; - const float SPINE2_POSITION_FILTER = 0.05f; glm::vec2 latestHipToHandController = _hipToHandController; From db45aced6e0f932d853c1813989a03e5c769986e Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 5 Nov 2018 16:53:03 -0300 Subject: [PATCH 08/25] Mute when entering a domain --- android/app/CMakeLists.txt | 2 +- android/app/src/main/cpp/native.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt index 9930a9e152..0138b45146 100644 --- a/android/app/CMakeLists.txt +++ b/android/app/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME native-lib) setup_hifi_library() -link_hifi_libraries(shared task networking gl gpu qml image fbx render-utils physics entities octree ${PLATFORM_GL_BACKEND}) +link_hifi_libraries(shared task networking gl gpu qml image fbx render-utils physics entities octree audio-client ${PLATFORM_GL_BACKEND}) target_opengl() target_bullet() diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp index c7bca428e9..2f05a54fd5 100644 --- a/android/app/src/main/cpp/native.cpp +++ b/android/app/src/main/cpp/native.cpp @@ -21,6 +21,7 @@ #include #include "AndroidHelper.h" +#include "../../../../../libraries/audio-client/src/AudioClient.h" #include #include @@ -210,11 +211,15 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnDest JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGotoUrl(JNIEnv* env, jobject obj, jstring url) { QAndroidJniObject jniUrl("java/lang/String", "(Ljava/lang/String;)V", url); DependencyManager::get()->loadSettings(jniUrl.toString()); + auto audioClient = DependencyManager::get(); + audioClient->setMuted(true, true); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGoToUser(JNIEnv* env, jobject obj, jstring username) { QAndroidJniObject jniUsername("java/lang/String", "(Ljava/lang/String;)V", username); DependencyManager::get()->goToUser(jniUsername.toString(), false); + auto audioClient = DependencyManager::get(); + audioClient->setMuted(true, true); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) { From 611881e0024a10638aadd8c78555f4ba2800a697 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Mon, 5 Nov 2018 18:35:57 -0300 Subject: [PATCH 09/25] Mute when entering a domain --- android/app/CMakeLists.txt | 2 +- android/app/src/main/cpp/native.cpp | 7 ++----- interface/src/AndroidHelper.cpp | 8 ++++++++ interface/src/AndroidHelper.h | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt index 0138b45146..9930a9e152 100644 --- a/android/app/CMakeLists.txt +++ b/android/app/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME native-lib) setup_hifi_library() -link_hifi_libraries(shared task networking gl gpu qml image fbx render-utils physics entities octree audio-client ${PLATFORM_GL_BACKEND}) +link_hifi_libraries(shared task networking gl gpu qml image fbx render-utils physics entities octree ${PLATFORM_GL_BACKEND}) target_opengl() target_bullet() diff --git a/android/app/src/main/cpp/native.cpp b/android/app/src/main/cpp/native.cpp index 2f05a54fd5..760fdcb0b5 100644 --- a/android/app/src/main/cpp/native.cpp +++ b/android/app/src/main/cpp/native.cpp @@ -21,7 +21,6 @@ #include #include "AndroidHelper.h" -#include "../../../../../libraries/audio-client/src/AudioClient.h" #include #include @@ -211,15 +210,13 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnDest JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGotoUrl(JNIEnv* env, jobject obj, jstring url) { QAndroidJniObject jniUrl("java/lang/String", "(Ljava/lang/String;)V", url); DependencyManager::get()->loadSettings(jniUrl.toString()); - auto audioClient = DependencyManager::get(); - audioClient->setMuted(true, true); + AndroidHelper::instance().muteMic(); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGoToUser(JNIEnv* env, jobject obj, jstring username) { QAndroidJniObject jniUsername("java/lang/String", "(Ljava/lang/String;)V", username); DependencyManager::get()->goToUser(jniUsername.toString(), false); - auto audioClient = DependencyManager::get(); - audioClient->setMuted(true, true); + AndroidHelper::instance().muteMic(); } JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) { diff --git a/interface/src/AndroidHelper.cpp b/interface/src/AndroidHelper.cpp index ae6aa34cc9..708859c00a 100644 --- a/interface/src/AndroidHelper.cpp +++ b/interface/src/AndroidHelper.cpp @@ -73,6 +73,14 @@ void AndroidHelper::notifyHeadsetOn(bool pluggedIn) { #endif } +void AndroidHelper::muteMic() { + auto audioClient = DependencyManager::get(); + if (audioClient) { + QMetaObject::invokeMethod(audioClient.data(), "setMuted", Q_ARG(bool, true), Q_ARG(bool, true)); + } +} + + void AndroidHelper::signup(QString email, QString username, QString password) { JSONCallbackParameters callbackParams; callbackParams.callbackReceiver = this; diff --git a/interface/src/AndroidHelper.h b/interface/src/AndroidHelper.h index f1917deca0..f0aaa84214 100644 --- a/interface/src/AndroidHelper.h +++ b/interface/src/AndroidHelper.h @@ -35,6 +35,7 @@ public: void performHapticFeedback(int duration); void processURL(const QString &url); void notifyHeadsetOn(bool pluggedIn); + void muteMic(); AndroidHelper(AndroidHelper const&) = delete; void operator=(AndroidHelper const&) = delete; From 37c69ebe625000b61a95f79f95b21c09b9a22357 Mon Sep 17 00:00:00 2001 From: Clement Date: Mon, 5 Nov 2018 17:18:28 -0800 Subject: [PATCH 10/25] Add audio soloing feature --- assignment-client/src/audio/AudioMixer.cpp | 3 +- .../src/audio/AudioMixerClientData.cpp | 22 ++++++ .../src/audio/AudioMixerClientData.h | 6 ++ .../src/audio/AudioMixerSlave.cpp | 4 + libraries/audio-client/src/AudioClient.cpp | 8 +- libraries/audio-client/src/AudioClient.h | 4 +- libraries/audio/src/AbstractAudioInterface.h | 3 + libraries/audio/src/AudioSolo.cpp | 77 +++++++++++++++++++ libraries/audio/src/AudioSolo.h | 38 +++++++++ libraries/networking/src/udt/PacketHeaders.h | 3 +- .../src/AudioScriptingInterface.h | 22 +++++- 11 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 libraries/audio/src/AudioSolo.cpp create mode 100644 libraries/audio/src/AudioSolo.h diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index afd4047c68..d6f893c42e 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -89,7 +89,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketType::NodeIgnoreRequest, PacketType::RadiusIgnoreRequest, PacketType::RequestsDomainListData, - PacketType::PerAvatarGainSet }, + PacketType::PerAvatarGainSet, + PacketType::AudioSoloRequest }, this, "queueAudioPacket"); // packets whose consequences are global should be processed on the main thread diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 7e1420ef60..0aee185088 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -98,6 +98,9 @@ int AudioMixerClientData::processPackets(ConcurrentAddedStreams& addedStreams) { case PacketType::RadiusIgnoreRequest: parseRadiusIgnoreRequest(packet, node); break; + case PacketType::AudioSoloRequest: + parseSoloRequest(packet, node); + break; default: Q_UNREACHABLE(); } @@ -295,6 +298,25 @@ void AudioMixerClientData::parseRadiusIgnoreRequest(QSharedPointer message, const SharedNodePointer& node) { + + bool addToSolo; + message->readPrimitive(&addToSolo); + + while (message->getBytesLeftToRead()) { + // parse out the UUID being solod from the packet + QUuid solodUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + + if (addToSolo) { + _solodNodes.push_back(solodUUID); + } else { + auto it = std::find(std::begin(_solodNodes), std::end(_solodNodes), solodUUID); + _solodNodes.erase(it); + } + } +} + AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() { auto it = std::find_if(_audioStreams.begin(), _audioStreams.end(), [](const SharedStreamPointer& stream){ return stream->getStreamIdentifier().isNull(); diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 610b258789..dd5681c537 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -65,6 +65,7 @@ public: void parsePerAvatarGainSet(ReceivedMessage& message, const SharedNodePointer& node); void parseNodeIgnoreRequest(QSharedPointer message, const SharedNodePointer& node); void parseRadiusIgnoreRequest(QSharedPointer message, const SharedNodePointer& node); + void parseSoloRequest(QSharedPointer message, const SharedNodePointer& node); // attempt to pop a frame from each audio stream, and return the number of streams from this client int checkBuffersBeforeFrameSend(); @@ -150,6 +151,9 @@ public: const Node::IgnoredNodeIDs& getIgnoringNodeIDs() const { return _ignoringNodeIDs; } + + const std::vector& getSolodNodes() const { return _solodNodes; } + bool getHasReceivedFirstMix() const { return _hasReceivedFirstMix; } void setHasReceivedFirstMix(bool hasReceivedFirstMix) { _hasReceivedFirstMix = hasReceivedFirstMix; } @@ -209,6 +213,8 @@ private: std::atomic_bool _isIgnoreRadiusEnabled { false }; + std::vector _solodNodes; + bool _hasReceivedFirstMix { false }; }; diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 57bada47f1..7007e684cb 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -272,6 +272,10 @@ bool shouldBeSkipped(MixableStream& stream, const Node& listener, return true; } + if (!listenerData.getSolodNodes().empty()) { + return !contains(listenerData.getSolodNodes(), stream.nodeStreamID.nodeID); + } + bool shouldCheckIgnoreBox = (listenerAudioStream.isIgnoreBoxEnabled() || stream.positionalStream->isIgnoreBoxEnabled()); if (shouldCheckIgnoreBox && diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index bdd6d0edc1..ace8f72875 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -270,7 +270,8 @@ AudioClient::AudioClient() : configureReverb(); - auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); + auto nodeList = DependencyManager::get(); + auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::AudioStreamStats, &_stats, "processStreamStatsPacket"); packetReceiver.registerListener(PacketType::AudioEnvironment, this, "handleAudioEnvironmentDataPacket"); packetReceiver.registerListener(PacketType::SilentAudioFrame, this, "handleAudioDataPacket"); @@ -278,6 +279,11 @@ AudioClient::AudioClient() : packetReceiver.registerListener(PacketType::NoisyMute, this, "handleNoisyMutePacket"); packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); + + auto& domainHandler = nodeList->getDomainHandler(); + connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this] { + _solo.reset(); + }); } AudioClient::~AudioClient() { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 5e7f1fb8a0..751bddd35d 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -46,7 +46,6 @@ #include #include - #include #include @@ -171,6 +170,7 @@ public: void stopRecording(); void setAudioPaused(bool pause); + AudioSolo& getAudioSolo() override { return _solo; } #ifdef Q_OS_WIN static QString getWinDeviceName(wchar_t* guid); @@ -446,6 +446,8 @@ private: #if defined(Q_OS_ANDROID) bool _shouldRestartInputSetup { true }; // Should we restart the input device because of an unintended stop? #endif + + AudioSolo _solo; Mutex _checkDevicesMutex; QTimer* _checkDevicesTimer { nullptr }; diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index bbfd79d0aa..0f075ab224 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -19,6 +19,7 @@ #include "AudioInjectorOptions.h" #include "AudioInjector.h" +#include "AudioSolo.h" class AudioInjector; class AudioInjectorLocalBuffer; @@ -38,6 +39,8 @@ public: // take care to delete it when ~AudioInjector, as parenting Qt semantics will not work virtual bool outputLocalInjector(const AudioInjectorPointer& injector) = 0; + virtual AudioSolo& getAudioSolo() = 0; + public slots: virtual bool shouldLoopbackInjectors() { return false; } diff --git a/libraries/audio/src/AudioSolo.cpp b/libraries/audio/src/AudioSolo.cpp new file mode 100644 index 0000000000..306c728dcb --- /dev/null +++ b/libraries/audio/src/AudioSolo.cpp @@ -0,0 +1,77 @@ +// +// AudioSolo.cpp +// +// +// Created by Clement Brisset on 11/5/18. +// Copyright 2018 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 "AudioSolo.h" + +#include + +bool AudioSolo::isSoloing() const { + Lock lock(_mutex); + return !_nodesSoloed.empty(); +} + +QVector AudioSolo::getUUIDs() const { + Lock lock(_mutex); + return _nodesSoloed.values().toVector(); +} + +void AudioSolo::addUUIDs(QVector uuidList) { + // create a reliable NLPacket with space for the solo UUIDs + auto soloPacket = NLPacket::create(PacketType::AudioSoloRequest, + uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(bool), true); + soloPacket->writePrimitive(true); + + { + Lock lock(_mutex); + for (auto uuid : uuidList) { + if (_nodesSoloed.contains(uuid)) { + qWarning() << "Uuid already in solo list:" << uuid; + } else { + // write the node ID to the packet + soloPacket->write(uuid.toRfc4122()); + _nodesSoloed.insert(uuid); + } + } + } + + // send off this ignore packet reliably to the matching node + auto nodeList = DependencyManager::get(); + nodeList->broadcastToNodes(std::move(soloPacket), { NodeType::AudioMixer }); +} + +void AudioSolo::removeUUIDs(QVector uuidList) { + // create a reliable NLPacket with space for the solo UUIDs + auto soloPacket = NLPacket::create(PacketType::AudioSoloRequest, + uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(bool), true); + soloPacket->writePrimitive(false); + + { + Lock lock(_mutex); + for (auto uuid : uuidList) { + if (!_nodesSoloed.contains(uuid)) { + qWarning() << "Uuid not in solo list:" << uuid; + } else { + // write the node ID to the packet + soloPacket->write(uuid.toRfc4122()); + _nodesSoloed.remove(uuid); + } + } + } + + // send off this ignore packet reliably to the matching node + auto nodeList = DependencyManager::get(); + nodeList->broadcastToNodes(std::move(soloPacket), { NodeType::AudioMixer }); +} + +void AudioSolo::reset() { + removeUUIDs(getUUIDs()); +} + diff --git a/libraries/audio/src/AudioSolo.h b/libraries/audio/src/AudioSolo.h new file mode 100644 index 0000000000..ef2d2d0bec --- /dev/null +++ b/libraries/audio/src/AudioSolo.h @@ -0,0 +1,38 @@ +// +// AudioSolo.h +// libraries/audio/src +// +// Created by Clement Brisset on 11/5/18. +// Copyright 2018 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 +// + +#pragma once + +#ifndef hifi_AudioSolo_h +#define hifi_AudioSolo_h + +#include + +#include +#include + +class AudioSolo { + using Mutex = std::mutex; + using Lock = std::unique_lock; + +public: + bool isSoloing() const; + QVector getUUIDs() const; + void addUUIDs(QVector uuidList); + void removeUUIDs(QVector uuidList); + void reset(); + +private: + mutable Mutex _mutex; + QSet _nodesSoloed; +}; + +#endif // hifi_AudioSolo_h diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 37a4b32940..e5efe05ad0 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -126,14 +126,13 @@ public: EntityScriptCallMethod, ChallengeOwnershipRequest, ChallengeOwnershipReply, - OctreeDataFileRequest, OctreeDataFileReply, OctreeDataPersist, - EntityClone, EntityQueryInitialResultsComplete, BulkAvatarTraits, + AudioSoloRequest, NUM_PACKET_TYPE }; diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 1220a9b769..7808a86566 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -25,13 +25,31 @@ class AudioScriptingInterface : public QObject, public Dependency { // JSDoc for property is in Audio.h. Q_PROPERTY(bool isStereoInput READ isStereoInput WRITE setStereoInput NOTIFY isStereoInputChanged) + Q_PROPERTY(bool isSoloing READ isSoloing) + Q_PROPERTY(QVector soloList READ getSoloList) public: - virtual ~AudioScriptingInterface() {} + virtual ~AudioScriptingInterface() = default; void setLocalAudioInterface(AbstractAudioInterface* audioInterface); protected: - AudioScriptingInterface() {} + AudioScriptingInterface() = default; + + bool isSoloing() const { + return _localAudioInterface->getAudioSolo().isSoloing(); + } + QVector getSoloList() const { + return _localAudioInterface->getAudioSolo().getUUIDs(); + } + Q_INVOKABLE void addToSoloList(QVector uuidList) { + _localAudioInterface->getAudioSolo().addUUIDs(uuidList); + } + Q_INVOKABLE void removeFromSoloList(QVector uuidList) { + _localAudioInterface->getAudioSolo().removeUUIDs(uuidList); + } + Q_INVOKABLE void resetSoloList() { + _localAudioInterface->getAudioSolo().reset(); + } // these methods are protected to stop C++ callers from calling, but invokable from script From 4e802b0f3fd83f553e667a8d04c10e92e9f4df30 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 6 Nov 2018 11:59:15 -0800 Subject: [PATCH 11/25] Add JSDoc comments --- interface/src/scripting/Audio.h | 2 ++ .../src/AudioScriptingInterface.h | 24 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 4b8eb6aabc..738eeb5dfe 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -50,6 +50,8 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable { * Read-only. * @property {object} devices Read-only. Deprecated: This property is deprecated and will be * removed. + * @property {boolean} isSoloing Read-only. true if any nodes are soloed. + * @property {QVector} soloList Read-only. Get the list of currently soloed node UUIDs. */ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index 7808a86566..ba570fd7c0 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -32,25 +32,43 @@ public: virtual ~AudioScriptingInterface() = default; void setLocalAudioInterface(AbstractAudioInterface* audioInterface); -protected: - AudioScriptingInterface() = default; - bool isSoloing() const { return _localAudioInterface->getAudioSolo().isSoloing(); } + QVector getSoloList() const { return _localAudioInterface->getAudioSolo().getUUIDs(); } + + /**jsdoc + * Add nodes to the audio solo list + * @function Audio.addToSoloList + * @param {QVector} uuidList - List of node UUIDs to add to the solo list. + */ Q_INVOKABLE void addToSoloList(QVector uuidList) { _localAudioInterface->getAudioSolo().addUUIDs(uuidList); } + + /**jsdoc + * Remove nodes from the audio solo list + * @function Audio.removeFromSoloList + * @param {QVector} uuidList - List of node UUIDs to remove from the solo list. + */ Q_INVOKABLE void removeFromSoloList(QVector uuidList) { _localAudioInterface->getAudioSolo().removeUUIDs(uuidList); } + + /**jsdoc + * Reset the list of soloed nodes. + * @function Audio.resetSoloList + */ Q_INVOKABLE void resetSoloList() { _localAudioInterface->getAudioSolo().reset(); } +protected: + AudioScriptingInterface() = default; + // these methods are protected to stop C++ callers from calling, but invokable from script /**jsdoc From 6ecf850159d4d1f43826aa2a6ca47fcab3d665f6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 6 Nov 2018 12:37:55 -0800 Subject: [PATCH 12/25] clarify ShapeInfo::setCapsuleY() API and use it correctly --- .../src/avatars-renderer/Avatar.cpp | 17 ++++++------- libraries/shared/src/ShapeInfo.cpp | 24 +++++++++---------- libraries/shared/src/ShapeInfo.h | 2 +- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index f694148b30..03938dd3de 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1724,22 +1724,23 @@ void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { } void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) { - // FIXME: this doesn't take into account Avatar rotation ShapeInfo shapeInfo; computeShapeInfo(shapeInfo); - glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight - start = getWorldPosition() - glm::vec3(0, halfExtents.y, 0) + shapeInfo.getOffset(); - end = getWorldPosition() + glm::vec3(0, halfExtents.y, 0) + shapeInfo.getOffset(); + glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = cylinderHalfHeight + radius radius = halfExtents.x; + glm::vec3 halfCylinderAxis(0.0f, halfExtents.y - radius, 0.0f); + Transform transform = getTransform(); + start = transform.getTranslation() + transform.getRotation() * (shapeInfo.getOffset() - halfCylinderAxis); + end = transform.getTranslation() + transform.getRotation() * (shapeInfo.getOffset() + halfCylinderAxis); } glm::vec3 Avatar::getWorldFeetPosition() { ShapeInfo shapeInfo; - computeShapeInfo(shapeInfo); - glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight - glm::vec3 localFeet(0.0f, shapeInfo.getOffset().y - halfExtents.y - halfExtents.x, 0.0f); - return getWorldOrientation() * localFeet + getWorldPosition(); + glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = cylinderHalfHeight + radius + glm::vec3 localFeet(0.0f, shapeInfo.getOffset().y - halfExtents.y, 0.0f); + Transform transform = getTransform(); + return transform.getTranslation() + transform.getRotation() * localFeet; } float Avatar::computeMass() { diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 152e305bf2..52a8ad7254 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -148,12 +148,12 @@ void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollec _hashKey.clear(); } -void ShapeInfo::setCapsuleY(float radius, float halfHeight) { +void ShapeInfo::setCapsuleY(float radius, float cylinderHalfHeight) { _url = ""; _type = SHAPE_TYPE_CAPSULE_Y; radius = glm::max(radius, MIN_HALF_EXTENT); - halfHeight = glm::max(halfHeight, 0.0f); - _halfExtents = glm::vec3(radius, halfHeight, radius); + cylinderHalfHeight = glm::max(cylinderHalfHeight, 0.0f); + _halfExtents = glm::vec3(radius, cylinderHalfHeight + radius, radius); _hashKey.clear(); } @@ -262,26 +262,26 @@ bool ShapeInfo::contains(const glm::vec3& point) const { return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y; case SHAPE_TYPE_CAPSULE_X: { if (glm::abs(point.x) <= _halfExtents.x) { - return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z; + return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.y; } else { - glm::vec3 absPoint = glm::abs(point) - _halfExtents.x; - return glm::length(absPoint) <= _halfExtents.z; + glm::vec3 absPoint = glm::abs(point) - glm::vec3(_halfExtents.x, 0.0f, 0.0f); + return glm::length(absPoint) <= _halfExtents.y; } } case SHAPE_TYPE_CAPSULE_Y: { if (glm::abs(point.y) <= _halfExtents.y) { - return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x; + return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.z; } else { - glm::vec3 absPoint = glm::abs(point) - _halfExtents.y; - return glm::length(absPoint) <= _halfExtents.x; + glm::vec3 absPoint = glm::abs(point) - glm::vec3(0.0f, _halfExtents.y, 0.0f); + return glm::length(absPoint) <= _halfExtents.z; } } case SHAPE_TYPE_CAPSULE_Z: { if (glm::abs(point.z) <= _halfExtents.z) { - return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y; + return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.x; } else { - glm::vec3 absPoint = glm::abs(point) - _halfExtents.z; - return glm::length(absPoint) <= _halfExtents.y; + glm::vec3 absPoint = glm::abs(point) - glm::vec3(0.0f, 0.0f, _halfExtents.z); + return glm::length(absPoint) <= _halfExtents.x; } } case SHAPE_TYPE_BOX: diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 5020e492cf..16e260d9db 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -67,7 +67,7 @@ public: void setBox(const glm::vec3& halfExtents); void setSphere(float radius); void setPointCollection(const PointCollection& pointCollection); - void setCapsuleY(float radius, float halfHeight); + void setCapsuleY(float radius, float cylinderHalfHeight); void setOffset(const glm::vec3& offset); ShapeType getType() const { return _type; } From b38c263e604ef9663ce3e4ab1d4e644ecb7b3eee Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 6 Nov 2018 12:44:14 -0800 Subject: [PATCH 13/25] use correct capsule dimensions in teleport.js --- .../controllers/controllerModules/teleport.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 1aba6b92f6..44aa04b497 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -358,9 +358,9 @@ Script.include("/~/system/libraries/controllers.js"); var sensorToWorldScale = MyAvatar.getSensorToWorldScale(); - var radius = capsuleData.radius / sensorToWorldScale; - var height = (Vec3.distance(capsuleData.start, capsuleData.end) + (capsuleData.radius * 2.0)) / sensorToWorldScale; - var capsuleRatio = 10.0 * radius / height; + var diameter = 2.0 * capsuleData.radius / sensorToWorldScale; + var height = (Vec3.distance(capsuleData.start, capsuleData.end) + diameter) / sensorToWorldScale; + var capsuleRatio = 5.0 * diameter / height; var offset = _this.pickHeightOffset * capsuleRatio; _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { @@ -370,9 +370,9 @@ Script.include("/~/system/libraries/controllers.js"); shape: { shapeType: "capsule-y", dimensions: { - x: radius * 2.0, - y: height - (radius * 2.0), - z: radius * 2.0 + x: diameter, + y: height, + z: diameter } }, position: { x: 0, y: offset + height * 0.5, z: 0 }, @@ -386,9 +386,9 @@ Script.include("/~/system/libraries/controllers.js"); shape: { shapeType: "capsule-y", dimensions: { - x: radius * 2.0, - y: height - (radius * 2.0), - z: radius * 2.0 + x: diameter, + y: height, + z: diameter } }, position: { x: 0, y: offset + height * 0.5, z: 0 }, From 91f6a5057a884ee1b226043d74f64c84ec772a00 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 6 Nov 2018 12:54:56 -0800 Subject: [PATCH 14/25] correct capsule height when building btCapsuleShape --- libraries/physics/src/ShapeFactory.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 8057eb0e0c..d7ba2f0661 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -307,21 +307,21 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) case SHAPE_TYPE_CAPSULE_Y: { glm::vec3 halfExtents = info.getHalfExtents(); float radius = halfExtents.x; - float height = 2.0f * halfExtents.y; + float height = 2.0f * (halfExtents.y - radius); shape = new btCapsuleShape(radius, height); } break; case SHAPE_TYPE_CAPSULE_X: { glm::vec3 halfExtents = info.getHalfExtents(); float radius = halfExtents.y; - float height = 2.0f * halfExtents.x; + float height = 2.0f * (halfExtents.x - radius); shape = new btCapsuleShapeX(radius, height); } break; case SHAPE_TYPE_CAPSULE_Z: { glm::vec3 halfExtents = info.getHalfExtents(); float radius = halfExtents.x; - float height = 2.0f * halfExtents.z; + float height = 2.0f * (halfExtents.z - radius); shape = new btCapsuleShapeZ(radius, height); } break; From 0ca0a6f3bebc44c192e1038d5220546945a52ca2 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 6 Nov 2018 12:56:51 -0800 Subject: [PATCH 15/25] Fix JSDoc arrays --- interface/src/scripting/Audio.h | 2 +- libraries/script-engine/src/AudioScriptingInterface.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/scripting/Audio.h b/interface/src/scripting/Audio.h index 738eeb5dfe..4c4bf6dd60 100644 --- a/interface/src/scripting/Audio.h +++ b/interface/src/scripting/Audio.h @@ -51,7 +51,7 @@ class Audio : public AudioScriptingInterface, protected ReadWriteLockable { * @property {object} devices Read-only. Deprecated: This property is deprecated and will be * removed. * @property {boolean} isSoloing Read-only. true if any nodes are soloed. - * @property {QVector} soloList Read-only. Get the list of currently soloed node UUIDs. + * @property {Uuid[]} soloList Read-only. Get the list of currently soloed node UUIDs. */ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) diff --git a/libraries/script-engine/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h index ba570fd7c0..2854445b4f 100644 --- a/libraries/script-engine/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -43,7 +43,7 @@ public: /**jsdoc * Add nodes to the audio solo list * @function Audio.addToSoloList - * @param {QVector} uuidList - List of node UUIDs to add to the solo list. + * @param {Uuid[]} uuidList - List of node UUIDs to add to the solo list. */ Q_INVOKABLE void addToSoloList(QVector uuidList) { _localAudioInterface->getAudioSolo().addUUIDs(uuidList); @@ -52,7 +52,7 @@ public: /**jsdoc * Remove nodes from the audio solo list * @function Audio.removeFromSoloList - * @param {QVector} uuidList - List of node UUIDs to remove from the solo list. + * @param {Uuid[]} uuidList - List of node UUIDs to remove from the solo list. */ Q_INVOKABLE void removeFromSoloList(QVector uuidList) { _localAudioInterface->getAudioSolo().removeUUIDs(uuidList); From beb575a88d3a20c18c3884860bc48052d5de90ae Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 6 Nov 2018 13:18:26 -0800 Subject: [PATCH 16/25] Don't attenuate soloed nodes. --- assignment-client/src/audio/AudioMixerSlave.cpp | 17 ++++++++++++----- assignment-client/src/audio/AudioMixerSlave.h | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 7007e684cb..0308acc697 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -314,6 +314,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { memset(_mixSamples, 0, sizeof(_mixSamples)); bool isThrottling = _numToRetain != -1; + bool isSoloing = !listenerData->getSolodNodes().empty(); auto& streams = listenerData->getStreams(); @@ -380,13 +381,14 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { stream.approximateVolume = approximateVolume(stream, listenerAudioStream); } else { if (shouldBeSkipped(stream, *listener, *listenerAudioStream, *listenerData)) { - addStream(stream, *listenerAudioStream, 0.0f); + addStream(stream, *listenerAudioStream, 0.0f, isSoloing); streams.skipped.push_back(move(stream)); ++stats.activeToSkipped; return true; } - addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain()); + addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + isSoloing); if (shouldBeInactive(stream)) { // To reduce artifacts we still call render to flush the HRTF for every silent @@ -421,7 +423,8 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { return true; } - addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain()); + addStream(stream, *listenerAudioStream, listenerData->getMasterAvatarGain(), + isSoloing); if (shouldBeInactive(stream)) { // To reduce artifacts we still call render to flush the HRTF for every silent @@ -488,7 +491,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain) { + float masterListenerGain, bool isSoloing) { ++stats.totalMixes; auto streamToAdd = mixableStream.positionalStream; @@ -499,9 +502,13 @@ void AudioMixerSlave::addStream(AudioMixerClientData::MixableStream& mixableStre glm::vec3 relativePosition = streamToAdd->getPosition() - listeningNodeStream.getPosition(); float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); + float gain = 1.0f; + if (!isSoloing) { + gain = computeGain(masterListenerGain, listeningNodeStream, *streamToAdd, relativePosition, distance, isEcho); + } + const int HRTF_DATASET_INDEX = 1; if (!streamToAdd->lastPopSucceeded()) { diff --git a/assignment-client/src/audio/AudioMixerSlave.h b/assignment-client/src/audio/AudioMixerSlave.h index 6566c839b8..3d979da1fc 100644 --- a/assignment-client/src/audio/AudioMixerSlave.h +++ b/assignment-client/src/audio/AudioMixerSlave.h @@ -57,7 +57,7 @@ private: bool prepareMix(const SharedNodePointer& listener); void addStream(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, - float masterListenerGain); + float masterListenerGain, bool isSoloing); void updateHRTFParameters(AudioMixerClientData::MixableStream& mixableStream, AvatarAudioStream& listeningNodeStream, float masterListenerGain); From b8cb433fa13b0127572a9b4e6dbe8a03c3d188d6 Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 6 Nov 2018 13:20:03 -0800 Subject: [PATCH 17/25] Spelling --- assignment-client/src/audio/AudioMixerClientData.cpp | 10 +++++----- assignment-client/src/audio/AudioMixerClientData.h | 4 ++-- assignment-client/src/audio/AudioMixerSlave.cpp | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 0aee185088..3b47b058e7 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -305,14 +305,14 @@ void AudioMixerClientData::parseSoloRequest(QSharedPointer mess message->readPrimitive(&addToSolo); while (message->getBytesLeftToRead()) { - // parse out the UUID being solod from the packet - QUuid solodUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + // parse out the UUID being soloed from the packet + QUuid soloedUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); if (addToSolo) { - _solodNodes.push_back(solodUUID); + _soloedNodes.push_back(soloedUUID); } else { - auto it = std::find(std::begin(_solodNodes), std::end(_solodNodes), solodUUID); - _solodNodes.erase(it); + auto it = std::find(std::begin(_soloedNodes), std::end(_soloedNodes), soloedUUID); + _soloedNodes.erase(it); } } } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index dd5681c537..0232fe6bb6 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -152,7 +152,7 @@ public: const Node::IgnoredNodeIDs& getIgnoringNodeIDs() const { return _ignoringNodeIDs; } - const std::vector& getSolodNodes() const { return _solodNodes; } + const std::vector& getSoloedNodes() const { return _soloedNodes; } bool getHasReceivedFirstMix() const { return _hasReceivedFirstMix; } void setHasReceivedFirstMix(bool hasReceivedFirstMix) { _hasReceivedFirstMix = hasReceivedFirstMix; } @@ -213,7 +213,7 @@ private: std::atomic_bool _isIgnoreRadiusEnabled { false }; - std::vector _solodNodes; + std::vector _soloedNodes; bool _hasReceivedFirstMix { false }; }; diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 0308acc697..7a6ab9c3e2 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -272,8 +272,8 @@ bool shouldBeSkipped(MixableStream& stream, const Node& listener, return true; } - if (!listenerData.getSolodNodes().empty()) { - return !contains(listenerData.getSolodNodes(), stream.nodeStreamID.nodeID); + if (!listenerData.getSoloedNodes().empty()) { + return !contains(listenerData.getSoloedNodes(), stream.nodeStreamID.nodeID); } bool shouldCheckIgnoreBox = (listenerAudioStream.isIgnoreBoxEnabled() || @@ -314,7 +314,7 @@ bool AudioMixerSlave::prepareMix(const SharedNodePointer& listener) { memset(_mixSamples, 0, sizeof(_mixSamples)); bool isThrottling = _numToRetain != -1; - bool isSoloing = !listenerData->getSolodNodes().empty(); + bool isSoloing = !listenerData->getSoloedNodes().empty(); auto& streams = listenerData->getStreams(); From 65a83cb026b6b04210e1203b7b82b13eb7cda8c9 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 7 Nov 2018 11:41:04 -0800 Subject: [PATCH 18/25] Resend solo nodes on mixer reconnect --- libraries/audio-client/src/AudioClient.cpp | 5 +++++ libraries/audio/src/AudioSolo.cpp | 9 +++++++++ libraries/audio/src/AudioSolo.h | 4 +++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index ace8f72875..8bc211cf9a 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -284,6 +284,11 @@ AudioClient::AudioClient() : connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this] { _solo.reset(); }); + connect(nodeList.data(), &NodeList::nodeAdded, this, [this](SharedNodePointer node) { + if (node->getType() == NodeType::AudioMixer) { + _solo.resend(); + } + }); } AudioClient::~AudioClient() { diff --git a/libraries/audio/src/AudioSolo.cpp b/libraries/audio/src/AudioSolo.cpp index 306c728dcb..83ecc6e130 100644 --- a/libraries/audio/src/AudioSolo.cpp +++ b/libraries/audio/src/AudioSolo.cpp @@ -72,6 +72,15 @@ void AudioSolo::removeUUIDs(QVector uuidList) { } void AudioSolo::reset() { + Lock lock(_mutex); removeUUIDs(getUUIDs()); } + +void AudioSolo::resend() { + Lock lock(_mutex); + auto uuids = getUUIDs(); + _nodesSoloed.clear(); + addUUIDs(uuids); +} + diff --git a/libraries/audio/src/AudioSolo.h b/libraries/audio/src/AudioSolo.h index ef2d2d0bec..790280a14b 100644 --- a/libraries/audio/src/AudioSolo.h +++ b/libraries/audio/src/AudioSolo.h @@ -20,7 +20,7 @@ #include class AudioSolo { - using Mutex = std::mutex; + using Mutex = std::recursive_mutex; using Lock = std::unique_lock; public: @@ -30,6 +30,8 @@ public: void removeUUIDs(QVector uuidList); void reset(); + void resend(); + private: mutable Mutex _mutex; QSet _nodesSoloed; From 8f763dfd5036384ca496b67a50d897b639191679 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 7 Nov 2018 17:44:48 -0800 Subject: [PATCH 19/25] Fix bug and crash in solo logic --- assignment-client/src/audio/AudioMixerClientData.cpp | 4 ++-- libraries/audio-client/src/AudioClient.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 3b47b058e7..68727a16be 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -311,8 +311,8 @@ void AudioMixerClientData::parseSoloRequest(QSharedPointer mess if (addToSolo) { _soloedNodes.push_back(soloedUUID); } else { - auto it = std::find(std::begin(_soloedNodes), std::end(_soloedNodes), soloedUUID); - _soloedNodes.erase(it); + auto it = std::remove(std::begin(_soloedNodes), std::end(_soloedNodes), soloedUUID); + _soloedNodes.erase(it, std::end(_soloedNodes)); } } } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 8bc211cf9a..cab02e215e 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -284,7 +284,7 @@ AudioClient::AudioClient() : connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, [this] { _solo.reset(); }); - connect(nodeList.data(), &NodeList::nodeAdded, this, [this](SharedNodePointer node) { + connect(nodeList.data(), &NodeList::nodeActivated, this, [this](SharedNodePointer node) { if (node->getType() == NodeType::AudioMixer) { _solo.resend(); } From ef54a63de622f5362d9ae763a22614b7c7b35a95 Mon Sep 17 00:00:00 2001 From: Clement Date: Wed, 7 Nov 2018 17:54:49 -0800 Subject: [PATCH 20/25] Use uint8_t instead of bool on the wire --- .../src/audio/AudioMixerClientData.cpp | 2 +- libraries/audio/src/AudioSolo.cpp | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 68727a16be..a7edd3169c 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -301,7 +301,7 @@ void AudioMixerClientData::parseRadiusIgnoreRequest(QSharedPointer message, const SharedNodePointer& node) { - bool addToSolo; + uint8_t addToSolo; message->readPrimitive(&addToSolo); while (message->getBytesLeftToRead()) { diff --git a/libraries/audio/src/AudioSolo.cpp b/libraries/audio/src/AudioSolo.cpp index 83ecc6e130..3302636096 100644 --- a/libraries/audio/src/AudioSolo.cpp +++ b/libraries/audio/src/AudioSolo.cpp @@ -26,8 +26,9 @@ QVector AudioSolo::getUUIDs() const { void AudioSolo::addUUIDs(QVector uuidList) { // create a reliable NLPacket with space for the solo UUIDs auto soloPacket = NLPacket::create(PacketType::AudioSoloRequest, - uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(bool), true); - soloPacket->writePrimitive(true); + uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(uint8_t), true); + uint8_t addToSoloList = (uint8_t)true; + soloPacket->writePrimitive(addToSoloList); { Lock lock(_mutex); @@ -42,7 +43,7 @@ void AudioSolo::addUUIDs(QVector uuidList) { } } - // send off this ignore packet reliably to the matching node + // send off this solo packet reliably to the matching node auto nodeList = DependencyManager::get(); nodeList->broadcastToNodes(std::move(soloPacket), { NodeType::AudioMixer }); } @@ -50,8 +51,9 @@ void AudioSolo::addUUIDs(QVector uuidList) { void AudioSolo::removeUUIDs(QVector uuidList) { // create a reliable NLPacket with space for the solo UUIDs auto soloPacket = NLPacket::create(PacketType::AudioSoloRequest, - uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(bool), true); - soloPacket->writePrimitive(false); + uuidList.size() * NUM_BYTES_RFC4122_UUID + sizeof(uint8_t), true); + uint8_t addToSoloList = (uint8_t)false; + soloPacket->writePrimitive(addToSoloList); { Lock lock(_mutex); @@ -66,7 +68,7 @@ void AudioSolo::removeUUIDs(QVector uuidList) { } } - // send off this ignore packet reliably to the matching node + // send off this solo packet reliably to the matching node auto nodeList = DependencyManager::get(); nodeList->broadcastToNodes(std::move(soloPacket), { NodeType::AudioMixer }); } From 5bfb9c1f71bf2f6a569956f6911f1a27db2a5847 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 8 Nov 2018 08:39:43 -0800 Subject: [PATCH 21/25] fix ShapeInfo::contains() logic for capsule shapes --- libraries/shared/src/ShapeInfo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 52a8ad7254..df8e61114d 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -261,7 +261,7 @@ bool ShapeInfo::contains(const glm::vec3& point) const { case SHAPE_TYPE_CYLINDER_Z: return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y; case SHAPE_TYPE_CAPSULE_X: { - if (glm::abs(point.x) <= _halfExtents.x) { + if (glm::abs(point.x) <= _halfExtents.x - _halfExtents.y) { return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.y; } else { glm::vec3 absPoint = glm::abs(point) - glm::vec3(_halfExtents.x, 0.0f, 0.0f); @@ -269,7 +269,7 @@ bool ShapeInfo::contains(const glm::vec3& point) const { } } case SHAPE_TYPE_CAPSULE_Y: { - if (glm::abs(point.y) <= _halfExtents.y) { + if (glm::abs(point.y) <= _halfExtents.y - _halfExtents.z) { return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.z; } else { glm::vec3 absPoint = glm::abs(point) - glm::vec3(0.0f, _halfExtents.y, 0.0f); @@ -277,7 +277,7 @@ bool ShapeInfo::contains(const glm::vec3& point) const { } } case SHAPE_TYPE_CAPSULE_Z: { - if (glm::abs(point.z) <= _halfExtents.z) { + if (glm::abs(point.z) <= _halfExtents.z - _halfExtents.x) { return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.x; } else { glm::vec3 absPoint = glm::abs(point) - glm::vec3(0.0f, 0.0f, _halfExtents.z); From f337579616edfcd7a77606e5b7c09305d8cf7d2a Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 8 Nov 2018 11:31:22 -0800 Subject: [PATCH 22/25] CR --- libraries/audio/src/AudioSolo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioSolo.cpp b/libraries/audio/src/AudioSolo.cpp index 3302636096..9d63f01a8b 100644 --- a/libraries/audio/src/AudioSolo.cpp +++ b/libraries/audio/src/AudioSolo.cpp @@ -1,6 +1,6 @@ // // AudioSolo.cpp -// +// libraries/audio/src // // Created by Clement Brisset on 11/5/18. // Copyright 2018 High Fidelity, Inc. From cd4e56e7d54bb1f2f31955338a1b5785387e9ca6 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 9 Nov 2018 14:26:20 -0800 Subject: [PATCH 23/25] Case 19808 - Change MARKET and WALLET in tray notifier to be INVENTORY along with other appropriate messaging changes. --- server-console/src/main.js | 34 ++++++------- .../src/modules/hf-notifications.js | 48 +++++++++---------- 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index dc3fbd4333..5adb4be4cb 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -337,7 +337,17 @@ var notificationState = NotificationState.UNNOTIFIED; function setNotificationState (notificationType, pending = undefined) { if (pending !== undefined) { - pendingNotifications[notificationType] = pending; + if ((notificationType === HifiNotificationType.TRANSACTIONS || + notificationType === HifiNotificationType.ITEMS)) { + // special case, because we want to clear the indicator light + // on INVENTORY when either Transactions or Items are + // clicked on in the notification popup, we detect that case + // here and force both to be unnotified. + pendingNotifications[HifiNotificationType.TRANSACTIONS] = pending; + pendingNotifications[HifiNotificationType.ITEMS] = pending; + } else { + pendingNotifications[notificationType] = pending; + } notificationState = NotificationState.UNNOTIFIED; for (var key in pendingNotifications) { if (pendingNotifications[key]) { @@ -428,18 +438,12 @@ var labels = { setNotificationState(HifiNotificationType.PEOPLE, false); } }, - wallet: { - label: 'Wallet', + inventory: { + label: 'Inventory', click: function () { - StartInterface("hifiapp:WALLET"); - setNotificationState(HifiNotificationType.WALLET, false); - } - }, - marketplace: { - label: 'Market', - click: function () { - StartInterface("hifiapp:MARKET"); - setNotificationState(HifiNotificationType.MARKETPLACE, false); + StartInterface("hifiapp:INVENTORY"); + setNotificationState(HifiNotificationType.ITEMS, false); + setNotificationState(HifiNotificationType.TRANSACTIONS, false); } }, restart: { @@ -528,8 +532,7 @@ function buildMenuArray(serverState) { if (trayNotifications.enabled()) { menuArray.push(labels.goto); menuArray.push(labels.people); - menuArray.push(labels.wallet); - menuArray.push(labels.marketplace); + menuArray.push(labels.inventory); menuArray.push(separator); } menuArray.push(labels.showNotifications); @@ -565,8 +568,7 @@ function updateLabels(serverState) { labels.showNotifications.checked = trayNotifications.enabled(); labels.goto.icon = pendingNotifications[HifiNotificationType.GOTO] ? menuNotificationIcon : null; labels.people.icon = pendingNotifications[HifiNotificationType.PEOPLE] ? menuNotificationIcon : null; - labels.wallet.icon = pendingNotifications[HifiNotificationType.WALLET] ? menuNotificationIcon : null; - labels.marketplace.icon = pendingNotifications[HifiNotificationType.MARKETPLACE] ? menuNotificationIcon : null; + labels.inventory.icon = pendingNotifications[HifiNotificationType.ITEMS] || pendingNotifications[HifiNotificationType.TRANSACTIONS]? menuNotificationIcon : null; var onlineUsers = trayNotifications.getOnlineUsers(); delete labels.people.submenu; if (onlineUsers) { diff --git a/server-console/src/modules/hf-notifications.js b/server-console/src/modules/hf-notifications.js index 8a812625b4..1ddbd1d307 100644 --- a/server-console/src/modules/hf-notifications.js +++ b/server-console/src/modules/hf-notifications.js @@ -32,10 +32,10 @@ const StartInterface=hfApp.startInterface; const IsInterfaceRunning=hfApp.isInterfaceRunning; const NotificationType = { - GOTO: 'goto', - PEOPLE: 'people', - WALLET: 'wallet', - MARKETPLACE: 'marketplace' + GOTO: 'goto', + PEOPLE: 'people', + ITEMS: 'items', + TRANSACTIONS: 'transactions' }; @@ -89,34 +89,34 @@ HifiNotification.prototype = { } break; - case NotificationType.WALLET: + case NotificationType.TRANSACTIONS: if (typeof(this.data) === "number") { if (this.data === 1) { - text = "You have " + this.data + " unread Wallet transaction."; + text = "You have " + this.data + " unread transaction."; } else { - text = "You have " + this.data + " unread Wallet transactions."; + text = "You have " + this.data + " unread transactions."; } - message = "Click to open WALLET." - url = "hifiapp:hifi/commerce/wallet/Wallet.qml"; + message = "Click to open INVENTORY." + url = "hifiapp:INVENTORY"; break; } text = this.data.message.replace(/<\/?[^>]+(>|$)/g, ""); - message = "Click to open WALLET."; - url = "hifiapp:WALLET"; + message = "Click to open INVENTORY."; + url = "hifiapp:INVENTORY"; break; - case NotificationType.MARKETPLACE: + case NotificationType.ITEMS: if (typeof(this.data) === "number") { if (this.data === 1) { - text = this.data + " of your purchased items has an update available."; + text = this.data + " of your items has an update available."; } else { - text = this.data + " of your purchased items have updates available."; + text = this.data + " of your items have updates available."; } } else { text = "Update available for " + this.data.base_item_title + "."; } - message = "Click to open MARKET."; - url = "hifiapp:MARKET"; + message = "Click to open INVENTORY."; + url = "hifiapp:INVENTORY"; break; } notifier.notify({ @@ -235,7 +235,6 @@ HifiNotifications.prototype = { }, _showNotification: function () { var _this = this; - if (osType === 'Darwin') { this.pendingNotifications[0].show(function () { // For OSX @@ -325,10 +324,10 @@ HifiNotifications.prototype = { case NotificationType.PEOPLE: notifyData = content.data.users; break; - case NotificationType.WALLET: + case NotificationType.TRANSACTIONS: notifyData = content.data.history; break; - case NotificationType.MARKETPLACE: + case NotificationType.ITEMS: notifyData = content.data.updates; break; } @@ -376,19 +375,16 @@ HifiNotifications.prototype = { } }, function (error, data) { if (error || !data.body) { - console.log("Error: unable to get " + url); - finished(false); + console.log("Error: " + error + ": unable to get " + url); return; } var content = JSON.parse(data.body); if (!content || content.status != 'success') { console.log("Error: unable to get " + url); - finished(false); return; } if (!content.total_entries) { - finished(true, token); return; } if (!content.total_entries) { @@ -487,7 +483,7 @@ HifiNotifications.prototype = { console.log("Polling for economic activity"); var url = METAVERSE_SERVER_URL + ECONOMIC_ACTIVITY_URL + '?' + options.join('&'); console.log(url); - _this._pollCommon(NotificationType.WALLET, url, since, function () {}); + _this._pollCommon(NotificationType.TRANSACTIONS, url, since, function () {}); }, pollForMarketplaceUpdates: function (since) { var _this = this; @@ -499,7 +495,7 @@ HifiNotifications.prototype = { console.log("Polling for marketplace update"); var url = METAVERSE_SERVER_URL + UPDATES_URL + '?' + options.join('&'); console.log(url); - _this._pollCommon(NotificationType.MARKETPLACE, url, since, function (success, token) { + _this._pollCommon(NotificationType.ITEMS, url, since, function (success, token) { if (success) { var options = [ 'page=1', @@ -512,7 +508,7 @@ HifiNotifications.prototype = { 'bearer': token } }, function (error, data) { - _this._pollToDisableHighlight(NotificationType.MARKETPLACE, error, data); + _this._pollToDisableHighlight(NotificationType.ITEMS, error, data); }); } }); From 3431bdbb0e246fd045a08a930738d0195cd63952 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 12 Nov 2018 14:51:32 -0800 Subject: [PATCH 24/25] new inventory icons, and align message waiting light in items tab --- .../icons/tablet-icons/inventory-a-msg.svg | 24 +++++++++++++++--- .../icons/tablet-icons/inventory-a.svg | 17 +++++++++++-- .../icons/tablet-icons/inventory-i-msg.svg | 25 ++++++++++++++++--- .../icons/tablet-icons/inventory-i.svg | 20 +++++++++++++-- .../qml/hifi/commerce/wallet/Wallet.qml | 4 +-- 5 files changed, 76 insertions(+), 14 deletions(-) diff --git a/interface/resources/icons/tablet-icons/inventory-a-msg.svg b/interface/resources/icons/tablet-icons/inventory-a-msg.svg index 794bd1e414..b028c08b50 100644 --- a/interface/resources/icons/tablet-icons/inventory-a-msg.svg +++ b/interface/resources/icons/tablet-icons/inventory-a-msg.svg @@ -1,4 +1,20 @@ - - - - + + + + + + + + + + + + + + diff --git a/interface/resources/icons/tablet-icons/inventory-a.svg b/interface/resources/icons/tablet-icons/inventory-a.svg index 8b6f34eaa3..584ebd3b9b 100644 --- a/interface/resources/icons/tablet-icons/inventory-a.svg +++ b/interface/resources/icons/tablet-icons/inventory-a.svg @@ -1,3 +1,16 @@ - - + + + + + + + + + + + diff --git a/interface/resources/icons/tablet-icons/inventory-i-msg.svg b/interface/resources/icons/tablet-icons/inventory-i-msg.svg index 35d4fb54ae..d2abc7b7ca 100644 --- a/interface/resources/icons/tablet-icons/inventory-i-msg.svg +++ b/interface/resources/icons/tablet-icons/inventory-i-msg.svg @@ -1,4 +1,21 @@ - - - - + + + + + + + + + + + + + + diff --git a/interface/resources/icons/tablet-icons/inventory-i.svg b/interface/resources/icons/tablet-icons/inventory-i.svg index 071fabce88..733ea6df9a 100644 --- a/interface/resources/icons/tablet-icons/inventory-i.svg +++ b/interface/resources/icons/tablet-icons/inventory-i.svg @@ -1,3 +1,19 @@ - - + + + + + + + + + + + + diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 81fec4ace3..37ce50b469 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -536,8 +536,8 @@ Rectangle { Rectangle { id: exchangeMoneyMessagesWaitingLight; visible: parent.messagesWaiting; - anchors.right: exchangeMoneyTabIcon.left; - anchors.rightMargin: 9; + anchors.left: parent.left; + anchors.leftMargin: 16; anchors.top: exchangeMoneyTabIcon.top; anchors.topMargin: 4; height: 10; From e378a1b79cbea8c811af2472422c1d581545ba33 Mon Sep 17 00:00:00 2001 From: NissimHadar Date: Tue, 13 Nov 2018 08:39:52 -0800 Subject: [PATCH 25/25] Added missing CR --- tools/nitpick/src/TestRunner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/nitpick/src/TestRunner.cpp b/tools/nitpick/src/TestRunner.cpp index 868e608982..db6ce6cece 100644 --- a/tools/nitpick/src/TestRunner.cpp +++ b/tools/nitpick/src/TestRunner.cpp @@ -173,9 +173,9 @@ void TestRunner::setWorkingFolder() { } script.write("#!/bin/sh\n\n"); - script.write("echo resizing interface"); + script.write("echo resizing interface\n"); script.write(("osascript " + _workingFolder + "/setInterfaceSizeAndPosition.scpt\n").toStdString().c_str()); - script.write("echo resize complete"); + script.write("echo resize complete\n"); script.close(); script.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner); #endif