Merge pull request #4722 from birarda/avatar-mixer-debug

add option to display AvatarData receive stats with display name
This commit is contained in:
Andrew Meadows 2015-04-29 10:00:24 -07:00
commit 5a388a0c14
9 changed files with 60 additions and 23 deletions

View file

@ -285,9 +285,6 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats,
0); // QML Qt::Key_Slash);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats);
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log,
Qt::CTRL | Qt::SHIFT | Qt::Key_L,
@ -397,6 +394,10 @@ Menu::Menu() {
QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true);
ddeFiltering->setVisible(false);
#endif
auto avatarManager = DependencyManager::get<AvatarManager>();
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false,
avatarManager.data(), SLOT(setShouldShowReceiveStats(bool)));
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes);
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes);

View file

@ -147,6 +147,7 @@ namespace MenuOption {
const QString AudioScopeTwentyFrames = "Twenty";
const QString AudioStats = "Audio Stats";
const QString AudioStatsShowInjectedStreams = "Audio Stats Show Injected Streams";
const QString AvatarReceiveStats = "Show Receive Stats";
const QString BandwidthDetails = "Bandwidth Details";
const QString BlueSpeechSphere = "Blue Sphere While Speaking";
const QString BookmarkLocation = "Bookmark Location";

View file

@ -581,7 +581,8 @@ void Avatar::renderBillboard() {
glm::vec2 texCoordTopLeft(0.0f, 0.0f);
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
glPopMatrix();
@ -709,11 +710,24 @@ void Avatar::renderDisplayName() {
glm::vec4(0.2f, 0.2f, 0.2f, _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA));
glm::vec4 color(0.93f, 0.93f, 0.93f, _displayNameAlpha);
// optionally render timing stats for this avatar with the display name
QString renderedDisplayName = _displayName;
if (DependencyManager::get<AvatarManager>()->shouldShowReceiveStats()) {
const float BYTES_PER_KILOBYTE = 1000.0f;
float kilobytesPerSecond = getAverageBytesReceivedPerSecond() / BYTES_PER_KILOBYTE;
renderedDisplayName += QString(" - (%1 KBps, %2 Hz)")
.arg(QString::number(kilobytesPerSecond, 'f', 2))
.arg(getReceiveRate());
}
QByteArray ba = _displayName.toLocal8Bit();
const char* text = ba.data();
glDisable(GL_POLYGON_OFFSET_FILL);
textRenderer(DISPLAYNAME)->draw(text_x, text_y, text, color);
textRenderer(DISPLAYNAME)->draw(text_x, text_y, renderedDisplayName, color);
glPopMatrix();

View file

@ -40,7 +40,9 @@ public:
void renderAvatars(RenderArgs::RenderMode renderMode, bool postLighting = false, bool selfAvatarOnly = false);
void clearOtherAvatars();
bool shouldShowReceiveStats() const { return _shouldShowReceiveStats; }
class LocalLight {
public:
glm::vec3 color;
@ -49,7 +51,10 @@ public:
Q_INVOKABLE void setLocalLights(const QVector<AvatarManager::LocalLight>& localLights);
Q_INVOKABLE QVector<AvatarManager::LocalLight> getLocalLights() const;
public slots:
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
private:
AvatarManager(QObject* parent = 0);
AvatarManager(const AvatarManager& other);
@ -67,6 +72,8 @@ private:
quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate.
QVector<AvatarManager::LocalLight> _localLights;
bool _shouldShowReceiveStats = false;
};
Q_DECLARE_METATYPE(AvatarManager::LocalLight)

View file

@ -58,11 +58,11 @@ AvatarData::AvatarData() :
_billboard(),
_errorLogExpiry(0),
_owningAvatarMixer(),
_lastUpdateTimer(),
_velocity(0.0f),
_targetVelocity(0.0f),
_localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE)
{
}
AvatarData::~AvatarData() {
@ -268,9 +268,6 @@ bool AvatarData::shouldLogError(const quint64& now) {
// read data in packet starting at byte offset and return number of bytes parsed
int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
// reset the last heard timer since we have new data for this AvatarData
_lastUpdateTimer.restart();
// lazily allocate memory for HeadData in case we're not an Avatar instance
if (!_headData) {
_headData = new HeadData(this);
@ -555,7 +552,17 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
}
} // numJoints * 8 bytes
return sourceBuffer - startPosition;
int numBytesRead = sourceBuffer - startPosition;
_averageBytesReceived.updateAverage(numBytesRead);
return numBytesRead;
}
int AvatarData::getAverageBytesReceivedPerSecond() const {
return lrint(_averageBytesReceived.getAverageSampleValuePerSecond());
}
int AvatarData::getReceiveRate() const {
return lrint(1.0f / _averageBytesReceived.getEventDeltaAverage());
}
bool AvatarData::hasReferential() {

View file

@ -46,9 +46,9 @@ typedef unsigned long long quint64;
#include <QReadWriteLock>
#include <CollisionInfo.h>
#include <RegisteredMetaTypes.h>
#include <Node.h>
#include <RegisteredMetaTypes.h>
#include <SimpleMovingAverage.h>
#include "AABox.h"
#include "HandData.h"
@ -293,11 +293,13 @@ public:
Node* getOwningAvatarMixer() { return _owningAvatarMixer.data(); }
void setOwningAvatarMixer(const QWeakPointer<Node>& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
QElapsedTimer& getLastUpdateTimer() { return _lastUpdateTimer; }
const AABox& getLocalAABox() const { return _localAABox; }
const Referential* getReferential() const { return _referential; }
int getUsecsSinceLastUpdate() const { return _averageBytesReceived.getUsecsSinceLastEvent(); }
int getAverageBytesReceivedPerSecond() const;
int getReceiveRate() const;
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
glm::vec3 getTargetVelocity() const { return _targetVelocity; }
@ -382,7 +384,6 @@ protected:
quint64 _errorLogExpiry; ///< time in future when to log an error
QWeakPointer<Node> _owningAvatarMixer;
QElapsedTimer _lastUpdateTimer;
PlayerPointer _player;
@ -395,6 +396,8 @@ protected:
AABox _localAABox;
SimpleMovingAverage _averageBytesReceived;
private:
// privatize the copy constructor and assignment operator so they cannot be called
AvatarData(const AvatarData&);

View file

@ -11,6 +11,7 @@
#include <NodeList.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include "AvatarLogging.h"
#include "AvatarHashMap.h"
@ -25,11 +26,11 @@ AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator)
return _avatarHash.erase(iterator);
}
const qint64 AVATAR_SILENCE_THRESHOLD_MSECS = 5 * 1000;
const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND;
bool AvatarHashMap::shouldKillAvatar(const AvatarSharedPointer& sharedAvatar) {
return (sharedAvatar->getOwningAvatarMixer() == NULL
|| sharedAvatar->getLastUpdateTimer().elapsed() > AVATAR_SILENCE_THRESHOLD_MSECS);
|| sharedAvatar->getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS);
}
void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer) {

View file

@ -55,6 +55,6 @@ float SimpleMovingAverage::getEventDeltaAverage() const {
(WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000.0f));
}
float SimpleMovingAverage::getAverageSampleValuePerSecond() const {
return _average * (1.0f / getEventDeltaAverage());
uint64_t SimpleMovingAverage::getUsecsSinceLastEvent() const {
return usecTimestampNow() - _lastEventTimestamp;
}

View file

@ -25,8 +25,11 @@ public:
int getSampleCount() const { return _numSamples; };
float getAverage() const { return _average; };
float getEventDeltaAverage() const;
float getAverageSampleValuePerSecond() const;
float getEventDeltaAverage() const; // returned in seconds
float getAverageSampleValuePerSecond() const { return _average * (1.0f / getEventDeltaAverage()); }
uint64_t getUsecsSinceLastEvent() const;
private:
int _numSamples;
uint64_t _lastEventTimestamp;