Merge branch 'master' of git://github.com/worklist/hifi into 19498

This commit is contained in:
Lucas Crisman 2014-03-25 14:45:08 -03:00
commit c78bcc6d2f
7 changed files with 192 additions and 82 deletions

View file

@ -113,18 +113,18 @@
<context> <context>
<name>Menu</name> <name>Menu</name>
<message> <message>
<location filename="src/Menu.cpp" line="449"/> <location filename="src/Menu.cpp" line="455"/>
<source>Open .ini config file</source> <source>Open .ini config file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/Menu.cpp" line="451"/> <location filename="src/Menu.cpp" line="457"/>
<location filename="src/Menu.cpp" line="463"/> <location filename="src/Menu.cpp" line="469"/>
<source>Text files (*.ini)</source> <source>Text files (*.ini)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/Menu.cpp" line="461"/> <location filename="src/Menu.cpp" line="467"/>
<source>Save .ini config file</source> <source>Save .ini config file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View file

@ -61,6 +61,7 @@ Menu* Menu::getInstance() {
const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f}; const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f};
const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;
const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f;
const int FIVE_SECONDS_OF_FRAMES = 5 * 60; const int FIVE_SECONDS_OF_FRAMES = 5 * 60;
Menu::Menu() : Menu::Menu() :
@ -75,9 +76,11 @@ Menu::Menu() :
_lodToolsDialog(NULL), _lodToolsDialog(NULL),
_maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM),
_voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE),
_avatarLODDistanceMultiplier(DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER),
_boundaryLevelAdjust(0), _boundaryLevelAdjust(0),
_maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS), _maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS),
_lastAdjust(usecTimestampNow()), _lastAdjust(usecTimestampNow()),
_lastAvatarDetailDrop(usecTimestampNow()),
_fpsAverage(FIVE_SECONDS_OF_FRAMES), _fpsAverage(FIVE_SECONDS_OF_FRAMES),
_loginAction(NULL) _loginAction(NULL)
{ {
@ -386,6 +389,8 @@ void Menu::loadSettings(QSettings* settings) {
_maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM); _maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM);
_maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS); _maxVoxelPacketsPerSecond = loadSetting(settings, "maxVoxelsPPS", DEFAULT_MAX_VOXEL_PPS);
_voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_OCTREE_SIZE_SCALE); _voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_OCTREE_SIZE_SCALE);
_avatarLODDistanceMultiplier = loadSetting(settings, "avatarLODDistanceMultiplier",
DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER);
_boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0); _boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0);
settings->beginGroup("View Frustum Offset Camera"); settings->beginGroup("View Frustum Offset Camera");
@ -425,6 +430,7 @@ void Menu::saveSettings(QSettings* settings) {
settings->setValue("maxVoxels", _maxVoxels); settings->setValue("maxVoxels", _maxVoxels);
settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond); settings->setValue("maxVoxelsPPS", _maxVoxelPacketsPerSecond);
settings->setValue("voxelSizeScale", _voxelSizeScale); settings->setValue("voxelSizeScale", _voxelSizeScale);
settings->setValue("avatarLODDistanceMultiplier", _avatarLODDistanceMultiplier);
settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust); settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust);
settings->beginGroup("View Frustum Offset Camera"); settings->beginGroup("View Frustum Offset Camera");
settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw); settings->setValue("viewFrustumOffsetYaw", _viewFrustumOffset.yaw);
@ -1185,8 +1191,24 @@ void Menu::autoAdjustLOD(float currentFPS) {
} }
_fpsAverage.updateAverage(currentFPS); _fpsAverage.updateAverage(currentFPS);
bool changed = false;
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
if (_fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS) {
if (now - _lastAvatarDetailDrop > ADJUST_LOD_DOWN_DELAY) {
// attempt to lower the detail in proportion to the fps difference
float targetFps = (ADJUST_LOD_DOWN_FPS + ADJUST_LOD_UP_FPS) * 0.5f;
_avatarLODDistanceMultiplier *= (targetFps / _fpsAverage.getAverage());
_lastAvatarDetailDrop = now;
}
} else if (_fpsAverage.getAverage() > ADJUST_LOD_UP_FPS) {
// let the detail level creep slowly upwards
const float DISTANCE_DECREASE_RATE = 0.01f;
const float MINIMUM_DISTANCE_MULTIPLIER = 0.1f;
_avatarLODDistanceMultiplier = qMax(MINIMUM_DISTANCE_MULTIPLIER,
_avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE);
}
bool changed = false;
quint64 elapsed = now - _lastAdjust; quint64 elapsed = now - _lastAdjust;
if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS

View file

@ -89,7 +89,7 @@ public:
void autoAdjustLOD(float currentFPS); void autoAdjustLOD(float currentFPS);
void setVoxelSizeScale(float sizeScale); void setVoxelSizeScale(float sizeScale);
float getVoxelSizeScale() const { return _voxelSizeScale; } float getVoxelSizeScale() const { return _voxelSizeScale; }
float getAvatarLODDistanceMultiplier() const { return DEFAULT_OCTREE_SIZE_SCALE / _voxelSizeScale; } float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; }
void setBoundaryLevelAdjust(int boundaryLevelAdjust); void setBoundaryLevelAdjust(int boundaryLevelAdjust);
int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; }
@ -202,12 +202,14 @@ private:
LodToolsDialog* _lodToolsDialog; LodToolsDialog* _lodToolsDialog;
int _maxVoxels; int _maxVoxels;
float _voxelSizeScale; float _voxelSizeScale;
float _avatarLODDistanceMultiplier;
int _boundaryLevelAdjust; int _boundaryLevelAdjust;
QAction* _useVoxelShader; QAction* _useVoxelShader;
int _maxVoxelPacketsPerSecond; int _maxVoxelPacketsPerSecond;
QMenu* _activeScriptsMenu; QMenu* _activeScriptsMenu;
QString replaceLastOccurrence(QChar search, QChar replace, QString string); QString replaceLastOccurrence(QChar search, QChar replace, QString string);
quint64 _lastAdjust; quint64 _lastAdjust;
quint64 _lastAvatarDetailDrop;
SimpleMovingAverage _fpsAverage; SimpleMovingAverage _fpsAverage;
QAction* _loginAction; QAction* _loginAction;
QAction* _chatAction; QAction* _chatAction;

View file

@ -14,6 +14,7 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/noise.hpp> #include <glm/gtc/noise.hpp>
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
#include <glm/detail/func_common.hpp>
#include <SharedUtil.h> #include <SharedUtil.h>
@ -24,12 +25,6 @@
#include "Util.h" #include "Util.h"
#ifdef _WIN32
int isnan(double value) { return _isnan(value); }
#else
int isnan(double value) { return std::isnan(value); }
#endif
using namespace std; using namespace std;
// no clue which versions are affected... // no clue which versions are affected...
@ -88,7 +83,7 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2) {
// Helper function return the rotation from the first vector onto the second // Helper function return the rotation from the first vector onto the second
glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
float angle = angleBetween(v1, v2); float angle = angleBetween(v1, v2);
if (isnan(angle) || angle < EPSILON) { if (glm::isnan(angle) || angle < EPSILON) {
return glm::quat(); return glm::quat();
} }
glm::vec3 axis; glm::vec3 axis;
@ -586,7 +581,7 @@ void runTimingTests() {
float loadSetting(QSettings* settings, const char* name, float defaultValue) { float loadSetting(QSettings* settings, const char* name, float defaultValue) {
float value = settings->value(name, defaultValue).toFloat(); float value = settings->value(name, defaultValue).toFloat();
if (isnan(value)) { if (glm::isnan(value)) {
value = defaultValue; value = defaultValue;
} }
return value; return value;

View file

@ -8,6 +8,7 @@
#include <cstring> #include <cstring>
#include <glm/detail/func_common.hpp>
#include <QtCore/QDataStream> #include <QtCore/QDataStream>
#include <Node.h> #include <Node.h>
@ -16,12 +17,6 @@
#include "PositionalAudioRingBuffer.h" #include "PositionalAudioRingBuffer.h"
#ifdef _WIN32
int isnan(double value) { return _isnan(value); }
#else
int isnan(double value) { return std::isnan(value); }
#endif
PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type) : PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type) :
AudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL), AudioRingBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL),
_type(type), _type(type),
@ -69,7 +64,7 @@ int PositionalAudioRingBuffer::parsePositionalData(const QByteArray& positionalB
packetStream.readRawData(reinterpret_cast<char*>(&_orientation), sizeof(_orientation)); packetStream.readRawData(reinterpret_cast<char*>(&_orientation), sizeof(_orientation));
// if this node sent us a NaN for first float in orientation then don't consider this good audio and bail // if this node sent us a NaN for first float in orientation then don't consider this good audio and bail
if (isnan(_orientation.x)) { if (glm::isnan(_orientation.x)) {
reset(); reset();
return 0; return 0;
} }

View file

@ -25,7 +25,7 @@
#include "AvatarData.h" #include "AvatarData.h"
quint64 DEFAULT_FILTERED_LOG_EXPIRY = 20 * USECS_PER_SECOND; quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND;
using namespace std; using namespace std;
@ -46,7 +46,7 @@ AvatarData::AvatarData() :
_displayNameTargetAlpha(0.0f), _displayNameTargetAlpha(0.0f),
_displayNameAlpha(0.0f), _displayNameAlpha(0.0f),
_billboard(), _billboard(),
_debugLogExpiry(0) _errorLogExpiry(0)
{ {
} }
@ -178,6 +178,14 @@ QByteArray AvatarData::toByteArray() {
return avatarDataByteArray.left(destinationBuffer - startPosition); return avatarDataByteArray.left(destinationBuffer - startPosition);
} }
bool AvatarData::shouldLogError(const quint64& now) {
if (now > _errorLogExpiry) {
_errorLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
return true;
}
return false;
}
// read data in packet starting at byte offset and return number of bytes parsed // read data in packet starting at byte offset and return number of bytes parsed
int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
// lazily allocate memory for HeadData in case we're not an Avatar instance // lazily allocate memory for HeadData in case we're not an Avatar instance
@ -192,37 +200,80 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(packet.data()) + offset; const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(packet.data()) + offset;
const unsigned char* sourceBuffer = startPosition; const unsigned char* sourceBuffer = startPosition;
quint64 now = usecTimestampNow();
// 50 bytes of "plain old data" (POD) // The absolute minimum size of the update data is as follows:
// 1 byte for messageSize (0) // 50 bytes of "plain old data" {
// 1 byte for pupilSize // position = 12 bytes
// 1 byte for numJoints (0) // bodyYaw = 2 (compressed float)
// bodyPitch = 2 (compressed float)
// bodyRoll = 2 (compressed float)
// targetScale = 2 (compressed float)
// headYaw = 2 (compressed float)
// headPitch = 2 (compressed float)
// headRoll = 2 (compressed float)
// leanSideways = 4
// leanForward = 4
// lookAt = 12
// audioLoudness = 4
// }
// + 1 byte for messageSize (0)
// + 1 byte for pupilSize
// + 1 byte for numJoints (0)
// = 53 bytes
int minPossibleSize = 53; int minPossibleSize = 53;
int maxAvailableSize = packet.size() - offset; int maxAvailableSize = packet.size() - offset;
if (minPossibleSize > maxAvailableSize) { if (minPossibleSize > maxAvailableSize) {
// this packet is malformed so we pretend to read to the end if (shouldLogError(now)) {
quint64 now = usecTimestampNow(); qDebug() << "Malformed AvatarData packet at the start; "
if (now > _debugLogExpiry) { << " displayName = '" << _displayName << "'"
qDebug() << "Malformed AvatarData packet at the start: minPossibleSize = " << minPossibleSize << " minPossibleSize = " << minPossibleSize
<< " but maxAvailableSize = " << maxAvailableSize; << " maxAvailableSize = " << maxAvailableSize;
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
} }
// this packet is malformed so we report all bytes as consumed
return maxAvailableSize; return maxAvailableSize;
} }
{ // Body world position, rotation, and scale { // Body world position, rotation, and scale
// position // position
memcpy(&_position, sourceBuffer, sizeof(float) * 3); glm::vec3 position;
sourceBuffer += sizeof(float) * 3; memcpy(&position, sourceBuffer, sizeof(position));
sourceBuffer += sizeof(position);
if (glm::isnan(position.x) || glm::isnan(position.y) || glm::isnan(position.z)) {
if (shouldLogError(now)) {
qDebug() << "Discard nan AvatarData::position; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_position = position;
// rotation (NOTE: This needs to become a quaternion to save two bytes) // rotation (NOTE: This needs to become a quaternion to save two bytes)
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyYaw); float yaw, pitch, roll;
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyPitch); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &yaw);
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_bodyRoll); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &pitch);
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &roll);
if (glm::isnan(yaw) || glm::isnan(pitch) || glm::isnan(roll)) {
if (shouldLogError(now)) {
qDebug() << "Discard nan AvatarData::yaw,pitch,roll; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_bodyYaw = yaw;
_bodyPitch = pitch;
_bodyRoll = roll;
// scale // scale
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _targetScale); float scale;
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, scale);
if (glm::isnan(scale)) {
if (shouldLogError(now)) {
qDebug() << "Discard nan AvatarData::scale; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_targetScale = scale;
} // 20 bytes } // 20 bytes
{ // Head rotation { // Head rotation
@ -231,6 +282,12 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headYaw);
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headPitch);
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &headRoll);
if (glm::isnan(headYaw) || glm::isnan(headPitch) || glm::isnan(headRoll)) {
if (shouldLogError(now)) {
qDebug() << "Discard nan AvatarData::headYaw,headPitch,headRoll; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_headData->setYaw(headYaw); _headData->setYaw(headYaw);
_headData->setPitch(headPitch); _headData->setPitch(headPitch);
_headData->setRoll(headRoll); _headData->setRoll(headRoll);
@ -238,33 +295,57 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
// Head lean (relative to pelvis) // Head lean (relative to pelvis)
{ {
memcpy(&_headData->_leanSideways, sourceBuffer, sizeof(_headData->_leanSideways)); float leanSideways, leanForward;
memcpy(&leanSideways, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float); sourceBuffer += sizeof(float);
memcpy(&_headData->_leanForward, sourceBuffer, sizeof(_headData->_leanForward)); memcpy(&leanForward, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float); sourceBuffer += sizeof(float);
if (glm::isnan(leanSideways) || glm::isnan(leanForward)) {
if (shouldLogError(now)) {
qDebug() << "Discard nan AvatarData::leanSideways,leanForward; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_headData->_leanSideways = leanSideways;
_headData->_leanForward = leanForward;
} // 8 bytes } // 8 bytes
{ // Lookat Position { // Lookat Position
memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); glm::vec3 lookAt;
sourceBuffer += sizeof(_headData->_lookAtPosition); memcpy(&lookAt, sourceBuffer, sizeof(lookAt));
sourceBuffer += sizeof(lookAt);
if (glm::isnan(lookAt.x) || glm::isnan(lookAt.y) || glm::isnan(lookAt.z)) {
if (shouldLogError(now)) {
qDebug() << "Discard nan AvatarData::lookAt; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_headData->_lookAtPosition = lookAt;
} // 12 bytes } // 12 bytes
{ // AudioLoudness { // AudioLoudness
// Instantaneous audio loudness (used to drive facial animation) // Instantaneous audio loudness (used to drive facial animation)
memcpy(&_headData->_audioLoudness, sourceBuffer, sizeof(float)); float audioLoudness;
memcpy(&audioLoudness, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float); sourceBuffer += sizeof(float);
if (glm::isnan(audioLoudness)) {
if (shouldLogError(now)) {
qDebug() << "Discard nan AvatarData::audioLoudness; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_headData->_audioLoudness = audioLoudness;
} // 4 bytes } // 4 bytes
// chat // chat
int chatMessageSize = *sourceBuffer++; int chatMessageSize = *sourceBuffer++;
minPossibleSize += chatMessageSize; minPossibleSize += chatMessageSize;
if (minPossibleSize > maxAvailableSize) { if (minPossibleSize > maxAvailableSize) {
// this packet is malformed so we pretend to read to the end if (shouldLogError(now)) {
quint64 now = usecTimestampNow(); qDebug() << "Malformed AvatarData packet before ChatMessage;"
if (now > _debugLogExpiry) { << " displayName = '" << _displayName << "'"
qDebug() << "Malformed AvatarData packet before ChatMessage: minPossibleSize = " << minPossibleSize << " minPossibleSize = " << minPossibleSize
<< " but maxAvailableSize = " << maxAvailableSize; << " maxAvailableSize = " << maxAvailableSize;
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
} }
return maxAvailableSize; return maxAvailableSize;
} }
@ -287,40 +368,52 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
_isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); _isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED);
if (_headData->_isFaceshiftConnected) { if (_headData->_isFaceshiftConnected) {
minPossibleSize += 4 * sizeof(float) + 1; // four floats + one byte for blendDataSize float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift;
minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift);
minPossibleSize++; // one byte for blendDataSize
if (minPossibleSize > maxAvailableSize) { if (minPossibleSize > maxAvailableSize) {
// this packet is malformed so we pretend to read to the end if (shouldLogError(now)) {
quint64 now = usecTimestampNow(); qDebug() << "Malformed AvatarData packet after BitItems;"
if (now > _debugLogExpiry) { << " displayName = '" << _displayName << "'"
qDebug() << "Malformed AvatarData packet after BitItems: minPossibleSize = " << minPossibleSize << " minPossibleSize = " << minPossibleSize
<< " but maxAvailableSize = " << maxAvailableSize; << " maxAvailableSize = " << maxAvailableSize;
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
} }
return maxAvailableSize; return maxAvailableSize;
} }
// unpack face data // unpack face data
memcpy(&_headData->_leftEyeBlink, sourceBuffer, sizeof(float)); memcpy(&leftEyeBlink, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float); sourceBuffer += sizeof(float);
memcpy(&_headData->_rightEyeBlink, sourceBuffer, sizeof(float)); memcpy(&rightEyeBlink, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float); sourceBuffer += sizeof(float);
memcpy(&_headData->_averageLoudness, sourceBuffer, sizeof(float)); memcpy(&averageLoudness, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float); sourceBuffer += sizeof(float);
memcpy(&_headData->_browAudioLift, sourceBuffer, sizeof(float)); memcpy(&browAudioLift, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float); sourceBuffer += sizeof(float);
if (glm::isnan(leftEyeBlink) || glm::isnan(rightEyeBlink)
|| glm::isnan(averageLoudness) || glm::isnan(browAudioLift)) {
if (shouldLogError(now)) {
qDebug() << "Discard nan AvatarData::faceData; displayName = '" << _displayName << "'";
}
return maxAvailableSize;
}
_headData->_leftEyeBlink = leftEyeBlink;
_headData->_rightEyeBlink = rightEyeBlink;
_headData->_averageLoudness = averageLoudness;
_headData->_browAudioLift = browAudioLift;
int numCoefficients = (int)(*sourceBuffer++); int numCoefficients = (int)(*sourceBuffer++);
int blendDataSize = numCoefficients * sizeof(float); int blendDataSize = numCoefficients * sizeof(float);
minPossibleSize += blendDataSize; minPossibleSize += blendDataSize;
if (minPossibleSize > maxAvailableSize) { if (minPossibleSize > maxAvailableSize) {
// this packet is malformed so we pretend to read to the end if (shouldLogError(now)) {
quint64 now = usecTimestampNow(); qDebug() << "Malformed AvatarData packet after Blendshapes;"
if (now > _debugLogExpiry) { << " displayName = '" << _displayName << "'"
qDebug() << "Malformed AvatarData packet after Blendshapes: minPossibleSize = " << minPossibleSize << " minPossibleSize = " << minPossibleSize
<< " but maxAvailableSize = " << maxAvailableSize; << " maxAvailableSize = " << maxAvailableSize;
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
} }
return maxAvailableSize; return maxAvailableSize;
} }
@ -339,15 +432,14 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
// joint data // joint data
int numJoints = *sourceBuffer++; int numJoints = *sourceBuffer++;
int bytesOfValidity = (int)ceil((float)numJoints / 8.f); int bytesOfValidity = (int)ceil((float)numJoints / (float)BITS_IN_BYTE);
minPossibleSize += bytesOfValidity; minPossibleSize += bytesOfValidity;
if (minPossibleSize > maxAvailableSize) { if (minPossibleSize > maxAvailableSize) {
// this packet is malformed so we pretend to read to the end if (shouldLogError(now)) {
quint64 now = usecTimestampNow(); qDebug() << "Malformed AvatarData packet after JointValidityBits;"
if (now > _debugLogExpiry) { << " displayName = '" << _displayName << "'"
qDebug() << "Malformed AvatarData packet after JointValidityBits: minPossibleSize = " << minPossibleSize << " minPossibleSize = " << minPossibleSize
<< " but maxAvailableSize = " << maxAvailableSize; << " maxAvailableSize = " << maxAvailableSize;
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
} }
return maxAvailableSize; return maxAvailableSize;
} }
@ -370,14 +462,15 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
} }
// 1 + bytesOfValidity bytes // 1 + bytesOfValidity bytes
minPossibleSize += numValidJoints * 8; // 8 bytes per quaternion // each joint rotation component is stored in two bytes (sizeof(uint16_t))
int COMPONENTS_PER_QUATERNION = 4;
minPossibleSize += numValidJoints * COMPONENTS_PER_QUATERNION * sizeof(uint16_t);
if (minPossibleSize > maxAvailableSize) { if (minPossibleSize > maxAvailableSize) {
// this packet is malformed so we pretend to read to the end if (shouldLogError(now)) {
quint64 now = usecTimestampNow(); qDebug() << "Malformed AvatarData packet after JointData;"
if (now > _debugLogExpiry) { << " displayName = '" << _displayName << "'"
qDebug() << "Malformed AvatarData packet after JointData: minPossibleSize = " << minPossibleSize << " minPossibleSize = " << minPossibleSize
<< " but maxAvailableSize = " << maxAvailableSize; << " maxAvailableSize = " << maxAvailableSize;
_debugLogExpiry = now + DEFAULT_FILTERED_LOG_EXPIRY;
} }
return maxAvailableSize; return maxAvailableSize;
} }

View file

@ -105,6 +105,9 @@ public:
QByteArray toByteArray(); QByteArray toByteArray();
/// \return true if an error should be logged
bool shouldLogError(const quint64& now);
/// \param packet byte array of data /// \param packet byte array of data
/// \param offset number of bytes into packet where data starts /// \param offset number of bytes into packet where data starts
/// \return number of bytes parsed /// \return number of bytes parsed
@ -255,7 +258,7 @@ protected:
static QNetworkAccessManager* networkAccessManager; static QNetworkAccessManager* networkAccessManager;
quint64 _debugLogExpiry; quint64 _errorLogExpiry; ///< time in future when to log an error
private: private:
// privatize the copy constructor and assignment operator so they cannot be called // privatize the copy constructor and assignment operator so they cannot be called