mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 17:01:18 +02:00
more cleanup and some CR feedback fixes
This commit is contained in:
parent
f61e16fccf
commit
8cb8d686ec
1 changed files with 182 additions and 213 deletions
|
@ -80,13 +80,6 @@ int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData,
|
||||||
|
|
||||||
static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
||||||
|
|
||||||
// only send extra avatar data (avatars out of view, ignored) every Nth AvatarData frame
|
|
||||||
// Extra avatar data will be sent (AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND/EXTRA_AVATAR_DATA_FRAME_RATIO) times
|
|
||||||
// per second.
|
|
||||||
// This value should be a power of two for performance purposes, as the mixer performs a modulo operation every frame
|
|
||||||
// to determine whether the extra data should be sent.
|
|
||||||
static const int EXTRA_AVATAR_DATA_FRAME_RATIO = 16;
|
|
||||||
|
|
||||||
// FIXME - There is some old logic (unchanged as of 2/17/17) that randomly decides to send an identity
|
// FIXME - There is some old logic (unchanged as of 2/17/17) that randomly decides to send an identity
|
||||||
// packet. That logic had the following comment about the constants it uses...
|
// packet. That logic had the following comment about the constants it uses...
|
||||||
//
|
//
|
||||||
|
@ -156,6 +149,20 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
// setup a PacketList for the avatarPackets
|
// setup a PacketList for the avatarPackets
|
||||||
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
||||||
|
|
||||||
|
// Define the minimum bubble size
|
||||||
|
static const glm::vec3 minBubbleSize = glm::vec3(0.3f, 1.3f, 0.3f);
|
||||||
|
// Define the scale of the box for the current node
|
||||||
|
glm::vec3 nodeBoxScale = (nodeData->getPosition() - nodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
||||||
|
// Set up the bounding box for the current node
|
||||||
|
AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale);
|
||||||
|
// Clamp the size of the bounding box to a minimum scale
|
||||||
|
if (glm::any(glm::lessThan(nodeBoxScale, minBubbleSize))) {
|
||||||
|
nodeBox.setScaleStayCentered(minBubbleSize);
|
||||||
|
}
|
||||||
|
// Quadruple the scale of both bounding boxes
|
||||||
|
nodeBox.embiggen(4.0f);
|
||||||
|
|
||||||
|
|
||||||
// setup list of AvatarData as well as maps to map betweeen the AvatarData and the original nodes
|
// setup list of AvatarData as well as maps to map betweeen the AvatarData and the original nodes
|
||||||
// for calling the AvatarData::sortAvatars() function and getting our sorted list of client nodes
|
// for calling the AvatarData::sortAvatars() function and getting our sorted list of client nodes
|
||||||
QList<AvatarSharedPointer> avatarList;
|
QList<AvatarSharedPointer> avatarList;
|
||||||
|
@ -170,7 +177,6 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
avatarList << otherAvatar;
|
avatarList << otherAvatar;
|
||||||
avatarDataToNodes[otherAvatar] = otherNode;
|
avatarDataToNodes[otherAvatar] = otherNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AvatarSharedPointer thisAvatar = nodeData->getAvatarSharedPointer();
|
AvatarSharedPointer thisAvatar = nodeData->getAvatarSharedPointer();
|
||||||
|
@ -191,8 +197,87 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
||||||
},
|
},
|
||||||
|
|
||||||
[thisAvatar](AvatarSharedPointer avatar)->bool{
|
[&](AvatarSharedPointer avatar)->bool{
|
||||||
return (avatar == thisAvatar); // ignore ourselves...
|
if (avatar == thisAvatar) {
|
||||||
|
return true; // ignore ourselves...
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldIgnore = false;
|
||||||
|
|
||||||
|
// We will also ignore other nodes for a couple of different reasons:
|
||||||
|
// 1) ignore bubbles and ignore specific node
|
||||||
|
// 2) the node hasn't really updated it's frame data recently, this can
|
||||||
|
// happen if for example the avatar is connected on a desktop and sending
|
||||||
|
// updates at ~30hz. So every 3 frames we skip a frame.
|
||||||
|
auto avatarNode = avatarDataToNodes[avatar];
|
||||||
|
if (avatarNode) {
|
||||||
|
const AvatarMixerClientData* avatarNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||||
|
if (avatarNodeData) {
|
||||||
|
quint64 startIgnoreCalculation = usecTimestampNow();
|
||||||
|
|
||||||
|
// make sure we have data for this avatar, that it isn't the same node,
|
||||||
|
// and isn't an avatar that the viewing node has ignored
|
||||||
|
// or that has ignored the viewing node
|
||||||
|
if (!avatarNode->getLinkedData()
|
||||||
|
|| avatarNode->getUUID() == node->getUUID()
|
||||||
|
|| (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !getsIgnoredByMe)
|
||||||
|
|| (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
||||||
|
shouldIgnore = true;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Check to see if the space bubble is enabled
|
||||||
|
if (node->isIgnoreRadiusEnabled() || avatarNode->isIgnoreRadiusEnabled()) {
|
||||||
|
|
||||||
|
// Define the scale of the box for the current other node
|
||||||
|
glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
||||||
|
// Set up the bounding box for the current other node
|
||||||
|
AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||||
|
// Clamp the size of the bounding box to a minimum scale
|
||||||
|
if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) {
|
||||||
|
otherNodeBox.setScaleStayCentered(minBubbleSize);
|
||||||
|
}
|
||||||
|
// Quadruple the scale of both bounding boxes
|
||||||
|
otherNodeBox.embiggen(4.0f);
|
||||||
|
|
||||||
|
// Perform the collision check between the two bounding boxes
|
||||||
|
if (nodeBox.touches(otherNodeBox)) {
|
||||||
|
nodeData->ignoreOther(node, avatarNode);
|
||||||
|
shouldIgnore = !getsAnyIgnored;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not close enough to ignore
|
||||||
|
if (!shouldIgnore) {
|
||||||
|
nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
quint64 endIgnoreCalculation = usecTimestampNow();
|
||||||
|
_stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation);
|
||||||
|
|
||||||
|
if (!shouldIgnore) {
|
||||||
|
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID());
|
||||||
|
AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber();
|
||||||
|
|
||||||
|
// FIXME - This code does appear to be working. But it seems brittle.
|
||||||
|
// It supports determining if the frame of data for this "other"
|
||||||
|
// avatar has already been sent to the reciever. This has been
|
||||||
|
// verified to work on a desktop display that renders at 60hz and
|
||||||
|
// therefore sends to mixer at 30hz. Each second you'd expect to
|
||||||
|
// have 15 (45hz-30hz) duplicate frames. In this case, the stat
|
||||||
|
// avg_other_av_skips_per_second does report 15.
|
||||||
|
//
|
||||||
|
// make sure we haven't already sent this data from this sender to this receiver
|
||||||
|
// or that somehow we haven't sent
|
||||||
|
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
||||||
|
++numAvatarsHeldBack;
|
||||||
|
shouldIgnore = true;
|
||||||
|
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
|
||||||
|
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
|
||||||
|
++numAvatarsWithSkippedFrames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shouldIgnore;
|
||||||
});
|
});
|
||||||
|
|
||||||
// loop through our sorted avatars and allocate our bandwidth to them accordingly
|
// loop through our sorted avatars and allocate our bandwidth to them accordingly
|
||||||
|
@ -219,75 +304,7 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
// NOTE: Here's where we determine if we are over budget and drop to bare minimum data
|
// NOTE: Here's where we determine if we are over budget and drop to bare minimum data
|
||||||
int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars;
|
int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars;
|
||||||
bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame;
|
bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame;
|
||||||
/**
|
|
||||||
qDebug() << "Budget debugging:"
|
|
||||||
<< "numAvatarDataBytes:" << numAvatarDataBytes << "\n"
|
|
||||||
<< "identityBytesSent:" << identityBytesSent << "\n"
|
|
||||||
<< "remainingAvatars:" << remainingAvatars << "\n"
|
|
||||||
<< "minimumBytesPerAvatar:" << minimumBytesPerAvatar << "\n"
|
|
||||||
<< "minimRemainingAvatarBytes:" << minimRemainingAvatarBytes << "\n"
|
|
||||||
<< "overBudget:" << overBudget << "\n"
|
|
||||||
<< "overBudgetAvatars:" << overBudgetAvatars;
|
|
||||||
**/
|
|
||||||
|
|
||||||
bool shouldConsider = false;
|
|
||||||
quint64 startIgnoreCalculation = usecTimestampNow();
|
|
||||||
|
|
||||||
// make sure we have data for this avatar, that it isn't the same node,
|
|
||||||
// and isn't an avatar that the viewing node has ignored
|
|
||||||
// or that has ignored the viewing node
|
|
||||||
if (!otherNode->getLinkedData()
|
|
||||||
|| otherNode->getUUID() == node->getUUID()
|
|
||||||
|| (node->isIgnoringNodeWithID(otherNode->getUUID()) && !getsIgnoredByMe)
|
|
||||||
|| (otherNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
|
||||||
|
|
||||||
shouldConsider = false;
|
|
||||||
} else {
|
|
||||||
const AvatarMixerClientData* otherData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
|
|
||||||
|
|
||||||
shouldConsider = true; // assume we will consider...
|
|
||||||
|
|
||||||
// Check to see if the space bubble is enabled
|
|
||||||
if (node->isIgnoreRadiusEnabled() || otherNode->isIgnoreRadiusEnabled()) {
|
|
||||||
// Define the minimum bubble size
|
|
||||||
static const glm::vec3 minBubbleSize = glm::vec3(0.3f, 1.3f, 0.3f);
|
|
||||||
// Define the scale of the box for the current node
|
|
||||||
glm::vec3 nodeBoxScale = (nodeData->getPosition() - nodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
|
||||||
// Define the scale of the box for the current other node
|
|
||||||
glm::vec3 otherNodeBoxScale = (otherData->getPosition() - otherData->getGlobalBoundingBoxCorner()) * 2.0f;
|
|
||||||
|
|
||||||
// Set up the bounding box for the current node
|
|
||||||
AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale);
|
|
||||||
// Clamp the size of the bounding box to a minimum scale
|
|
||||||
if (glm::any(glm::lessThan(nodeBoxScale, minBubbleSize))) {
|
|
||||||
nodeBox.setScaleStayCentered(minBubbleSize);
|
|
||||||
}
|
|
||||||
// Set up the bounding box for the current other node
|
|
||||||
AABox otherNodeBox(otherData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
|
||||||
// Clamp the size of the bounding box to a minimum scale
|
|
||||||
if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) {
|
|
||||||
otherNodeBox.setScaleStayCentered(minBubbleSize);
|
|
||||||
}
|
|
||||||
// Quadruple the scale of both bounding boxes
|
|
||||||
nodeBox.embiggen(4.0f);
|
|
||||||
otherNodeBox.embiggen(4.0f);
|
|
||||||
|
|
||||||
// Perform the collision check between the two bounding boxes
|
|
||||||
if (nodeBox.touches(otherNodeBox)) {
|
|
||||||
nodeData->ignoreOther(node, otherNode);
|
|
||||||
shouldConsider = getsAnyIgnored;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Not close enough to ignore
|
|
||||||
if (shouldConsider) {
|
|
||||||
nodeData->removeFromRadiusIgnoringSet(node, otherNode->getUUID());
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 endIgnoreCalculation = usecTimestampNow();
|
|
||||||
_stats.ignoreCalculationElapsedTime += (endIgnoreCalculation - startIgnoreCalculation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldConsider) {
|
|
||||||
quint64 startAvatarDataPacking = usecTimestampNow();
|
quint64 startAvatarDataPacking = usecTimestampNow();
|
||||||
|
|
||||||
++numOtherAvatars;
|
++numOtherAvatars;
|
||||||
|
@ -308,55 +325,13 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const AvatarData* otherAvatar = otherNodeData->getConstAvatarData();
|
const AvatarData* otherAvatar = otherNodeData->getConstAvatarData();
|
||||||
// Decide whether to send this avatar's data based on it's distance from us
|
|
||||||
|
|
||||||
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
||||||
float distanceToAvatar = glm::length(myPosition - otherPosition);
|
|
||||||
|
|
||||||
if (shouldConsider) {
|
|
||||||
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID());
|
|
||||||
AvatarDataSequenceNumber lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber();
|
|
||||||
|
|
||||||
// FIXME - This code does appear to be working. But it seems brittle.
|
|
||||||
// It supports determining if the frame of data for this "other"
|
|
||||||
// avatar has already been sent to the reciever. This has been
|
|
||||||
// verified to work on a desktop display that renders at 60hz and
|
|
||||||
// therefore sends to mixer at 30hz. Each second you'd expect to
|
|
||||||
// have 15 (45hz-30hz) duplicate frames. In this case, the stat
|
|
||||||
// avg_other_av_skips_per_second does report 15.
|
|
||||||
//
|
|
||||||
// make sure we haven't already sent this data from this sender to this receiver
|
|
||||||
// or that somehow we haven't sent
|
|
||||||
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
|
||||||
++numAvatarsHeldBack;
|
|
||||||
|
|
||||||
quint64 endAvatarDataPacking = usecTimestampNow();
|
|
||||||
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
|
||||||
shouldConsider = false;
|
|
||||||
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
|
|
||||||
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
|
|
||||||
++numAvatarsWithSkippedFrames;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we're going to send this avatar
|
|
||||||
if (shouldConsider) {
|
|
||||||
|
|
||||||
// determine if avatar is in view, to determine how much data to include...
|
// determine if avatar is in view, to determine how much data to include...
|
||||||
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
||||||
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||||
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
||||||
|
|
||||||
// this throttles the extra data to only be sent every Nth message
|
|
||||||
/**
|
|
||||||
if (!isInView && !getsOutOfView && (lastSeqToReceiver % EXTRA_AVATAR_DATA_FRAME_RATIO > 0)) {
|
|
||||||
quint64 endAvatarDataPacking = usecTimestampNow();
|
|
||||||
|
|
||||||
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
|
||||||
shouldConsider = false;
|
|
||||||
}
|
|
||||||
***/
|
|
||||||
|
|
||||||
if (shouldConsider) {
|
|
||||||
// start a new segment in the PacketList for this avatar
|
// start a new segment in the PacketList for this avatar
|
||||||
avatarPacketList->startSegment();
|
avatarPacketList->startSegment();
|
||||||
|
|
||||||
|
@ -375,7 +350,6 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
nodeData->incrementAvatarInView();
|
nodeData->incrementAvatarInView();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
bool includeThisAvatar = true;
|
bool includeThisAvatar = true;
|
||||||
auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID());
|
auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID());
|
||||||
QVector<JointData>& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID());
|
QVector<JointData>& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID());
|
||||||
|
@ -426,16 +400,11 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
|
nodeData->setLastBroadcastTime(otherNode->getUUID(), start);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
avatarPacketList->endSegment();
|
avatarPacketList->endSegment();
|
||||||
|
|
||||||
quint64 endAvatarDataPacking = usecTimestampNow();
|
quint64 endAvatarDataPacking = usecTimestampNow();
|
||||||
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
quint64 startPacketSending = usecTimestampNow();
|
quint64 startPacketSending = usecTimestampNow();
|
||||||
|
|
Loading…
Reference in a new issue