Work in progress

This commit is contained in:
Brad Davis 2015-03-17 12:04:04 -07:00
parent 1c6db9c8cf
commit 6415ff99f6
6 changed files with 115 additions and 75 deletions

View file

@ -20,9 +20,9 @@
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <UUID.h>
#include <TryLocker.h>
#include "AvatarMixerClientData.h"
#include "AvatarMixer.h"
const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
@ -134,7 +134,8 @@ void AvatarMixer::broadcastAvatarData() {
},
[&](const SharedNodePointer& node) {
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
if (!nodeData->getMutex().tryLock()) {
MutexTryLocker lock(nodeData->getMutex());
if (!lock.tryLock()) {
return;
}
++_sumListeners;
@ -144,6 +145,7 @@ void AvatarMixer::broadcastAvatarData() {
AvatarData& avatar = nodeData->getAvatar();
glm::vec3 myPosition = avatar.getPosition();
float outputBandwidth = node->getBandwidthRecorder().getTotalAverageOutputKilobitsPerSecond();
// this is an AGENT we have received head data from
// send back a packet with other active node data to this node
@ -155,82 +157,81 @@ void AvatarMixer::broadcastAvatarData() {
if (otherNode->getUUID() == node->getUUID()) {
return false;
}
// Check throttling value
if (!(_performanceThrottlingRatio == 0 || randFloat() < (1.0f - _performanceThrottlingRatio))) {
return;
}
return true;
},
[&](const SharedNodePointer& otherNode) {
AvatarMixerClientData* otherNodeData = otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
if (!otherNodeData->getMutex().tryLock()) {
MutexTryLocker lock(otherNodeData->getMutex());
if (!lock.tryLock()) {
return;
}
AvatarMixerClientData* otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData());
AvatarData& otherAvatar = otherNodeData->getAvatar();
glm::vec3 otherPosition = otherAvatar.getPosition();
float distanceToAvatar = glm::length(myPosition - otherPosition);
// Decide whether to send this avatar's data based on it's distance from us
// The full rate distance is the distance at which EVERY update will be sent for this avatar
// at a distance of twice the full rate distance, there will be a 50% chance of sending this avatar's update
const float FULL_RATE_DISTANCE = 2.0f;
// Decide whether to send this avatar's data based on it's distance from us
if ((_performanceThrottlingRatio == 0 || randFloat() < (1.0f - _performanceThrottlingRatio))
&& (distanceToAvatar == 0.0f || randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)) {
QByteArray avatarByteArray;
avatarByteArray.append(otherNode->getUUID().toRfc4122());
avatarByteArray.append(otherAvatar.toByteArray());
if (avatarByteArray.size() + mixedAvatarByteArray.size() > MAX_PACKET_SIZE) {
nodeList->writeDatagram(mixedAvatarByteArray, node);
// reset the packet
mixedAvatarByteArray.resize(numPacketHeaderBytes);
}
// copy the avatar into the mixedAvatarByteArray packet
mixedAvatarByteArray.append(avatarByteArray);
// if the receiving avatar has just connected make sure we send out the mesh and billboard
// for this avatar (assuming they exist)
bool forceSend = !nodeData->checkAndSetHasReceivedFirstPackets();
// we will also force a send of billboard or identity packet
// if either has changed in the last frame
if (otherNodeData->getBillboardChangeTimestamp() > 0
&& (forceSend
|| otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp
|| randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
QByteArray billboardPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard);
billboardPacket.append(otherNode->getUUID().toRfc4122());
billboardPacket.append(otherNodeData->getAvatar().getBillboard());
nodeList->writeDatagram(billboardPacket, node);
++_sumBillboardPackets;
}
if (otherNodeData->getIdentityChangeTimestamp() > 0
&& (forceSend
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|| randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity);
QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122());
identityPacket.append(individualData);
nodeList->writeDatagram(identityPacket, node);
++_sumIdentityPackets;
}
glm::vec3 otherPosition = otherAvatar.getPosition();
float distanceToAvatar = glm::length(myPosition - otherPosition);
if (!(distanceToAvatar == 0.0f || randFloat() < FULL_RATE_DISTANCE / distanceToAvatar)) {
return;
}
QByteArray avatarByteArray;
avatarByteArray.append(otherNode->getUUID().toRfc4122());
avatarByteArray.append(otherAvatar.toByteArray());
if (avatarByteArray.size() + mixedAvatarByteArray.size() > MAX_PACKET_SIZE) {
nodeList->writeDatagram(mixedAvatarByteArray, node);
// reset the packet
mixedAvatarByteArray.resize(numPacketHeaderBytes);
}
// copy the avatar into the mixedAvatarByteArray packet
mixedAvatarByteArray.append(avatarByteArray);
// if the receiving avatar has just connected make sure we send out the mesh and billboard
// for this avatar (assuming they exist)
bool forceSend = !nodeData->checkAndSetHasReceivedFirstPackets();
// we will also force a send of billboard or identity packet
// if either has changed in the last frame
if (otherNodeData->getBillboardChangeTimestamp() > 0
&& (forceSend
|| otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp
|| randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
QByteArray billboardPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard);
billboardPacket.append(otherNode->getUUID().toRfc4122());
billboardPacket.append(otherNodeData->getAvatar().getBillboard());
nodeList->writeDatagram(billboardPacket, node);
++_sumBillboardPackets;
}
if (otherNodeData->getIdentityChangeTimestamp() > 0
&& (forceSend
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|| randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity);
QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122());
identityPacket.append(individualData);
nodeList->writeDatagram(identityPacket, node);
++_sumIdentityPackets;
}
otherNodeData->getMutex().unlock();
});
nodeList->writeDatagram(mixedAvatarByteArray, node);
nodeData->getMutex().unlock();
});
_lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch();

View file

@ -17,7 +17,6 @@
#include <QObject>
#include <QElapsedTimer>
#include "DependencyManager.h"
#include "Node.h"
#include "SimpleMovingAverage.h"

View file

@ -263,8 +263,10 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
}
emit dataSent(destinationNode->getType(), datagram.size());
return writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret());
auto bytesWritten = writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret());
// Keep track of per-destination-node bandwidth
destinationNode->recordBytesSent(bytesWritten);
return bytesWritten;
}
// didn't have a destinationNode to send to, return 0

View file

@ -15,6 +15,7 @@
#include <UUID.h>
#include "NetworkPeer.h"
#include "BandwidthRecorder.h"
NetworkPeer::NetworkPeer() :
_uuid(),
@ -96,4 +97,38 @@ QDebug operator<<(QDebug debug, const NetworkPeer &peer) {
<< "- public:" << peer.getPublicSocket()
<< "- local:" << peer.getLocalSocket();
return debug;
}
}
// FIXME this is a temporary implementation to determine if this is the right approach.
// If so, migrate the BandwidthRecorder into the NetworkPeer class
using BandwidthRecorderPtr = QSharedPointer < BandwidthRecorder > ;
static QHash<QUuid, BandwidthRecorderPtr> PEER_BANDWIDTH;
BandwidthRecorder & getBandwidthRecorder(const QUuid & uuid) {
if (!PEER_BANDWIDTH.count(uuid)) {
PEER_BANDWIDTH.insert(uuid, BandwidthRecorderPtr(new BandwidthRecorder()));
}
return *PEER_BANDWIDTH[uuid].data();
}
void NetworkPeer::recordBytesSent(int count) {
auto & bw = getBandwidthRecorder(_uuid);
bw.updateOutboundData(0, count);
}
void NetworkPeer::recordBytesReceived(int count) {
auto & bw = getBandwidthRecorder(_uuid);
bw.updateInboundData(0, count);
}
float NetworkPeer::getOutboundBandwidth() {
auto & bw = getBandwidthRecorder(_uuid);
return bw.getAverageOutputKilobitsPerSecond(0);
}
float NetworkPeer::getInboundBandwidth() {
auto & bw = getBandwidthRecorder(_uuid);
return bw.getAverageInputKilobitsPerSecond(0);
}

View file

@ -54,6 +54,12 @@ public:
int getConnectionAttempts() const { return _connectionAttempts; }
void incrementConnectionAttempts() { ++_connectionAttempts; }
void resetConnectionAttemps() { _connectionAttempts = 0; }
void recordBytesSent(int count);
void recordBytesReceived(int count);
float getOutboundBandwidth();
float getInboundBandwidth();
friend QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer);
friend QDataStream& operator>>(QDataStream& in, NetworkPeer& peer);

View file

@ -18,13 +18,10 @@ class MutexTryLocker {
QMutex & _mutex;
bool _locked{false};
public:
MutexTryLocker(QMutex &m) : _mutex(m) {}
MutexTryLocker(QMutex &m) : _mutex(m), _locked(m.tryLock()) {}
~MutexTryLocker() { if (_locked) _mutex.unlock(); }
bool tryLock() {
if (_locked) {
return true;
}
return (_locked = _mutex.tryLock());
bool isLocked() {
return _locked;
}
}