mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 08:33:12 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into orange
This commit is contained in:
commit
d471cc4ec5
12 changed files with 103 additions and 106 deletions
|
@ -19,6 +19,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <math.h>
|
||||
|
@ -577,15 +578,15 @@ void AudioMixer::domainSettingsRequestComplete() {
|
|||
void AudioMixer::broadcastMixes() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
int64_t nextFrame = 0;
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
int64_t usecToSleep = AudioConstants::NETWORK_FRAME_USECS;
|
||||
auto nextFrameTimestamp = p_high_resolution_clock::now();
|
||||
auto timeToSleep = std::chrono::microseconds(0);
|
||||
|
||||
const int TRAILING_AVERAGE_FRAMES = 100;
|
||||
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
|
||||
|
||||
int currentFrame { 1 };
|
||||
int numFramesPerSecond { (int) ceil(AudioConstants::NETWORK_FRAMES_PER_SEC) };
|
||||
|
||||
while (!_isFinished) {
|
||||
const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f;
|
||||
const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f;
|
||||
|
@ -595,12 +596,12 @@ void AudioMixer::broadcastMixes() {
|
|||
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES;
|
||||
const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
|
||||
|
||||
if (usecToSleep < 0) {
|
||||
usecToSleep = 0;
|
||||
if (timeToSleep.count() < 0) {
|
||||
timeToSleep = std::chrono::microseconds(0);
|
||||
}
|
||||
|
||||
_trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio)
|
||||
+ (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS);
|
||||
+ (timeToSleep.count() * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS);
|
||||
|
||||
float lastCutoffRatio = _performanceThrottlingRatio;
|
||||
bool hasRatioChanged = false;
|
||||
|
@ -694,10 +695,11 @@ void AudioMixer::broadcastMixes() {
|
|||
nodeList->sendPacket(std::move(mixPacket), *node);
|
||||
nodeData->incrementOutgoingMixedAudioSequenceNumber();
|
||||
|
||||
static const int FRAMES_PER_SECOND = int(ceilf(1.0f / AudioConstants::NETWORK_FRAME_SECS));
|
||||
|
||||
// send an audio stream stats packet to the client approximately every second
|
||||
if (nextFrame % FRAMES_PER_SECOND == 0) {
|
||||
++currentFrame;
|
||||
currentFrame %= numFramesPerSecond;
|
||||
|
||||
if (nodeData->shouldSendStats(currentFrame)) {
|
||||
nodeData->sendAudioStreamStatsPackets(node);
|
||||
}
|
||||
|
||||
|
@ -718,11 +720,14 @@ void AudioMixer::broadcastMixes() {
|
|||
break;
|
||||
}
|
||||
|
||||
usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - (timer.nsecsElapsed() / 1000);
|
||||
// push the next frame timestamp to when we should send the next
|
||||
nextFrameTimestamp += std::chrono::microseconds(AudioConstants::NETWORK_FRAME_USECS);
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
// sleep as long as we need until next frame, if we can
|
||||
auto now = p_high_resolution_clock::now();
|
||||
timeToSleep = std::chrono::duration_cast<std::chrono::microseconds>(nextFrameTimestamp - now);
|
||||
|
||||
std::this_thread::sleep_for(timeToSleep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QJsonArray>
|
||||
|
||||
|
@ -26,7 +28,14 @@ AudioMixerClientData::AudioMixerClientData(const QUuid& nodeID) :
|
|||
_outgoingMixedAudioSequenceNumber(0),
|
||||
_downstreamAudioStreamStats()
|
||||
{
|
||||
// of the ~94 blocks in a second of audio sent from the AudioMixer, pick a random one to send out a stats packet on
|
||||
// this ensures we send out stats to this client around every second
|
||||
// but do not send all of the stats packets out at the same time
|
||||
std::random_device randomDevice;
|
||||
std::mt19937 numberGenerator { randomDevice() };
|
||||
std::uniform_int_distribution<> distribution { 1, (int) ceil(1.0f / AudioConstants::NETWORK_FRAME_SECS) };
|
||||
|
||||
_frameToSendStats = distribution(numberGenerator);
|
||||
}
|
||||
|
||||
AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() {
|
||||
|
@ -180,6 +189,10 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() {
|
|||
}
|
||||
}
|
||||
|
||||
bool AudioMixerClientData::shouldSendStats(int frameNumber) {
|
||||
return frameNumber == _frameToSendStats;
|
||||
}
|
||||
|
||||
void AudioMixerClientData::sendAudioStreamStatsPackets(const SharedNodePointer& destinationNode) {
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
|
|
@ -58,6 +58,9 @@ public:
|
|||
void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; }
|
||||
quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; }
|
||||
|
||||
// uses randomization to have the AudioMixer send a stats packet to this node around every second
|
||||
bool shouldSendStats(int frameNumber);
|
||||
|
||||
signals:
|
||||
void injectorStreamFinished(const QUuid& streamIdentifier);
|
||||
|
||||
|
@ -72,6 +75,8 @@ private:
|
|||
quint16 _outgoingMixedAudioSequenceNumber;
|
||||
|
||||
AudioStreamStats _downstreamAudioStreamStats;
|
||||
|
||||
int _frameToSendStats { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_AudioMixerClientData_h
|
||||
|
|
|
@ -36,14 +36,7 @@ const unsigned int AVATAR_DATA_SEND_INTERVAL_MSECS = (1.0f / (float) AVATAR_MIXE
|
|||
|
||||
AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
||||
ThreadedAssignment(message),
|
||||
_broadcastThread(),
|
||||
_lastFrameTimestamp(QDateTime::currentMSecsSinceEpoch()),
|
||||
_trailingSleepRatio(1.0f),
|
||||
_performanceThrottlingRatio(0.0f),
|
||||
_sumListeners(0),
|
||||
_numStatFrames(0),
|
||||
_sumBillboardPackets(0),
|
||||
_sumIdentityPackets(0)
|
||||
_broadcastThread()
|
||||
{
|
||||
// make sure we hear about node kills so we can tell the other nodes
|
||||
connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
|
||||
|
@ -51,7 +44,6 @@ AvatarMixer::AvatarMixer(ReceivedMessage& message) :
|
|||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket");
|
||||
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket");
|
||||
packetReceiver.registerListener(PacketType::AvatarBillboard, this, "handleAvatarBillboardPacket");
|
||||
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
|
||||
}
|
||||
|
||||
|
@ -66,13 +58,18 @@ AvatarMixer::~AvatarMixer() {
|
|||
|
||||
// An 80% chance of sending a identity packet within a 5 second interval.
|
||||
// assuming 60 htz update rate.
|
||||
const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f;
|
||||
const float IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f;
|
||||
|
||||
// NOTE: some additional optimizations to consider.
|
||||
// 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
|
||||
// if the avatar is not in view or in the keyhole.
|
||||
void AvatarMixer::broadcastAvatarData() {
|
||||
int idleTime = QDateTime::currentMSecsSinceEpoch() - _lastFrameTimestamp;
|
||||
int idleTime = AVATAR_DATA_SEND_INTERVAL_MSECS;
|
||||
|
||||
if (_lastFrameTimestamp.time_since_epoch().count() > 0) {
|
||||
auto idleDuration = p_high_resolution_clock::now() - _lastFrameTimestamp;
|
||||
idleTime = std::chrono::duration_cast<std::chrono::microseconds>(idleDuration).count();
|
||||
}
|
||||
|
||||
++_numStatFrames;
|
||||
|
||||
|
@ -245,32 +242,13 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
return;
|
||||
}
|
||||
|
||||
// make sure we send out identity and billboard packets to and from new arrivals.
|
||||
// make sure we send out identity packets to and from new arrivals.
|
||||
bool forceSend = !otherNodeData->checkAndSetHasReceivedFirstPacketsFrom(node->getUUID());
|
||||
|
||||
// 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
|
||||
|| distribution(generator) < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
|
||||
|
||||
QByteArray rfcUUID = otherNode->getUUID().toRfc4122();
|
||||
QByteArray billboard = otherNodeData->getAvatar().getBillboard();
|
||||
|
||||
auto billboardPacket = NLPacket::create(PacketType::AvatarBillboard, rfcUUID.size() + billboard.size());
|
||||
billboardPacket->write(rfcUUID);
|
||||
billboardPacket->write(billboard);
|
||||
|
||||
nodeList->sendPacket(std::move(billboardPacket), *node);
|
||||
|
||||
++_sumBillboardPackets;
|
||||
}
|
||||
|
||||
if (otherNodeData->getIdentityChangeTimestamp() > 0
|
||||
if (otherNodeData->getIdentityChangeTimestamp().time_since_epoch().count() > 0
|
||||
&& (forceSend
|
||||
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|
||||
|| distribution(generator) < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
|
||||
|| distribution(generator) < IDENTITY_SEND_PROBABILITY)) {
|
||||
|
||||
QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
|
||||
|
||||
|
@ -385,7 +363,7 @@ void AvatarMixer::broadcastAvatarData() {
|
|||
otherAvatar.doneEncoding(false);
|
||||
});
|
||||
|
||||
_lastFrameTimestamp = QDateTime::currentMSecsSinceEpoch();
|
||||
_lastFrameTimestamp = p_high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
|
||||
|
@ -438,26 +416,12 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> mes
|
|||
// parse the identity packet and update the change timestamp if appropriate
|
||||
if (avatar.hasIdentityChangedAfterParsing(message->getMessage())) {
|
||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||
nodeData->setIdentityChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
||||
nodeData->flagIdentityChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::handleAvatarBillboardPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
|
||||
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
|
||||
if (nodeData) {
|
||||
AvatarData& avatar = nodeData->getAvatar();
|
||||
|
||||
// parse the billboard packet and update the change timestamp if appropriate
|
||||
if (avatar.hasBillboardChangedAfterParsing(message->getMessage())) {
|
||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||
nodeData->setBillboardChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message) {
|
||||
DependencyManager::get<NodeList>()->processKillNode(*message);
|
||||
}
|
||||
|
@ -466,7 +430,6 @@ void AvatarMixer::sendStatsPacket() {
|
|||
QJsonObject statsObject;
|
||||
statsObject["average_listeners_last_second"] = (float) _sumListeners / (float) _numStatFrames;
|
||||
|
||||
statsObject["average_billboard_packets_per_frame"] = (float) _sumBillboardPackets / (float) _numStatFrames;
|
||||
statsObject["average_identity_packets_per_frame"] = (float) _sumIdentityPackets / (float) _numStatFrames;
|
||||
|
||||
statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100;
|
||||
|
@ -507,7 +470,6 @@ void AvatarMixer::sendStatsPacket() {
|
|||
ThreadedAssignment::addPacketStatsAndSendStatsPacket(statsObject);
|
||||
|
||||
_sumListeners = 0;
|
||||
_sumBillboardPackets = 0;
|
||||
_sumIdentityPackets = 0;
|
||||
_numStatFrames = 0;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#ifndef hifi_AvatarMixer_h
|
||||
#define hifi_AvatarMixer_h
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#include <ThreadedAssignment.h>
|
||||
|
||||
/// Handles assignments of type AvatarMixer - distribution of avatar data to various clients
|
||||
|
@ -34,7 +36,6 @@ public slots:
|
|||
private slots:
|
||||
void handleAvatarDataPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleAvatarBillboardPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
|
||||
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> message);
|
||||
void domainSettingsRequestComplete();
|
||||
|
||||
|
@ -44,15 +45,14 @@ private:
|
|||
|
||||
QThread _broadcastThread;
|
||||
|
||||
quint64 _lastFrameTimestamp;
|
||||
p_high_resolution_clock::time_point _lastFrameTimestamp;
|
||||
|
||||
float _trailingSleepRatio;
|
||||
float _performanceThrottlingRatio;
|
||||
float _trailingSleepRatio { 1.0f };
|
||||
float _performanceThrottlingRatio { 0.0f };
|
||||
|
||||
int _sumListeners;
|
||||
int _numStatFrames;
|
||||
int _sumBillboardPackets;
|
||||
int _sumIdentityPackets;
|
||||
int _sumListeners { 0 };
|
||||
int _numStatFrames { 0 };
|
||||
int _sumIdentityPackets { 0 };
|
||||
|
||||
float _maxKbpsPerNode = 0.0f;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <NodeData.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <PortableHighResolutionClock.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
#include <UUIDHasher.h>
|
||||
|
||||
|
@ -33,6 +34,8 @@ const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps";
|
|||
class AvatarMixerClientData : public NodeData {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using HRCTime = p_high_resolution_clock::time_point;
|
||||
|
||||
int parseData(ReceivedMessage& message) override;
|
||||
AvatarData& getAvatar() { return *_avatar; }
|
||||
|
||||
|
@ -45,11 +48,8 @@ public:
|
|||
|
||||
uint16_t getLastReceivedSequenceNumber() const { return _lastReceivedSequenceNumber; }
|
||||
|
||||
quint64 getBillboardChangeTimestamp() const { return _billboardChangeTimestamp; }
|
||||
void setBillboardChangeTimestamp(quint64 billboardChangeTimestamp) { _billboardChangeTimestamp = billboardChangeTimestamp; }
|
||||
|
||||
quint64 getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
|
||||
void setIdentityChangeTimestamp(quint64 identityChangeTimestamp) { _identityChangeTimestamp = identityChangeTimestamp; }
|
||||
HRCTime getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
|
||||
void flagIdentityChange() { _identityChangeTimestamp = p_high_resolution_clock::now(); }
|
||||
|
||||
void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; }
|
||||
float getFullRateDistance() const { return _fullRateDistance; }
|
||||
|
@ -86,8 +86,7 @@ private:
|
|||
std::unordered_map<QUuid, uint16_t> _lastBroadcastSequenceNumbers;
|
||||
std::unordered_set<QUuid> _hasReceivedFirstPacketsFrom;
|
||||
|
||||
quint64 _billboardChangeTimestamp = 0;
|
||||
quint64 _identityChangeTimestamp = 0;
|
||||
HRCTime _identityChangeTimestamp;
|
||||
|
||||
float _fullRateDistance = FLT_MAX;
|
||||
float _maxAvatarDistance = FLT_MAX;
|
||||
|
|
|
@ -40,11 +40,10 @@ const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS;
|
|||
const float ADJUST_LOD_DOWN_BY = 0.9f;
|
||||
const float ADJUST_LOD_UP_BY = 1.1f;
|
||||
|
||||
// This controls how low the auto-adjust LOD will go a value of 1 means it will adjust to a point where you must be 0.25
|
||||
// meters away from an object of TREE_SCALE before you can see it (which is effectively completely blind). The default value
|
||||
// DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision).
|
||||
const float ADJUST_LOD_MIN_SIZE_SCALE = 1.0f;
|
||||
// The default value DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision).
|
||||
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
|
||||
// This controls how low the auto-adjust LOD will go. We want a minimum vision of ~20:500 or 0.04 of default
|
||||
const float ADJUST_LOD_MIN_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE * 0.04f;
|
||||
|
||||
class RenderArgs;
|
||||
class AABox;
|
||||
|
|
|
@ -51,8 +51,8 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) :
|
|||
connect(_manualLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust()));
|
||||
|
||||
_lodSize = new QSlider(Qt::Horizontal, this);
|
||||
const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER;
|
||||
const int MIN_LOD_SIZE = ADJUST_LOD_MIN_SIZE_SCALE;
|
||||
const int MAX_LOD_SIZE = 2000; // ~20:4 vision -- really good.
|
||||
const int MIN_LOD_SIZE = 5; // ~20:1600 vision -- really bad!
|
||||
const int STEP_LOD_SIZE = 1;
|
||||
const int PAGE_STEP_LOD_SIZE = 100;
|
||||
const int SLIDER_WIDTH = 300;
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace AudioConstants {
|
|||
const int NETWORK_FRAME_SAMPLES_PER_CHANNEL = NETWORK_FRAME_BYTES_PER_CHANNEL / sizeof(AudioSample);
|
||||
const float NETWORK_FRAME_SECS = (AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL / float(AudioConstants::SAMPLE_RATE));
|
||||
const float NETWORK_FRAME_MSECS = NETWORK_FRAME_SECS * 1000.0f;
|
||||
const float NETWORK_FRAMES_PER_SEC = 1.0f / NETWORK_FRAME_SECS;
|
||||
|
||||
// be careful with overflows when using this constant
|
||||
const int NETWORK_FRAME_USECS = static_cast<int>(NETWORK_FRAME_MSECS * 1000.0f);
|
||||
|
|
|
@ -38,7 +38,7 @@ bool compileShader(GLenum shaderDomain, const std::string& shaderSource, const s
|
|||
GLuint glshader = glCreateShader(shaderDomain);
|
||||
if (!glshader) {
|
||||
qCDebug(gpulogging) << "GLShader::compileShader - failed to create the gl shader object";
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assign the source
|
||||
|
|
|
@ -329,10 +329,21 @@ void SendQueue::run() {
|
|||
auto nextPacketDelta = (newPacketCount == 2 ? 2 : 1) * _packetSendPeriod;
|
||||
nextPacketTimestamp += std::chrono::microseconds(nextPacketDelta);
|
||||
|
||||
// sleep as long as we need until next packet send, if we can
|
||||
// sleep as long as we need for next packet send, if we can
|
||||
auto now = p_high_resolution_clock::now();
|
||||
|
||||
auto timeToSleep = duration_cast<microseconds>(nextPacketTimestamp - now);
|
||||
|
||||
// we use nextPacketTimestamp so that we don't fall behind, not to force long sleeps
|
||||
// we'll never allow nextPacketTimestamp to force us to sleep for more than nextPacketDelta
|
||||
// so cap it to that value
|
||||
if (timeToSleep > std::chrono::microseconds(nextPacketDelta)) {
|
||||
// reset the nextPacketTimestamp so that it is correct next time we come around
|
||||
nextPacketTimestamp = now + std::chrono::microseconds(nextPacketDelta);
|
||||
|
||||
timeToSleep = std::chrono::microseconds(nextPacketDelta);
|
||||
}
|
||||
|
||||
// we're seeing SendQueues sleep for a long period of time here,
|
||||
// which can lock the NodeList if it's attempting to clear connections
|
||||
// for now we guard this by capping the time this thread and sleep for
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <atomic>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QDir>
|
||||
|
@ -41,23 +42,28 @@ void logFatal(const char* what) {
|
|||
qFatal(error.c_str());
|
||||
}
|
||||
|
||||
static const QString OCULUS_RUNTIME_PATH { "C:\\Program Files (x86)\\Oculus\\Support\\oculus-runtime" };
|
||||
static const QString GOOD_OCULUS_RUNTIME_FILE { OCULUS_RUNTIME_PATH + "\\LibOVRRT64_1.dll" };
|
||||
|
||||
static wchar_t* REQUIRED_OCULUS_DLL = L"LibOVRRT64_1.dll";
|
||||
static wchar_t FOUND_PATH[MAX_PATH];
|
||||
|
||||
bool oculusAvailable() {
|
||||
ovrDetectResult detect = ovr_Detect(0);
|
||||
if (!detect.IsOculusServiceRunning || !detect.IsOculusHMDConnected) {
|
||||
return false;
|
||||
}
|
||||
static std::once_flag once;
|
||||
static bool result { false };
|
||||
std::call_once(once, [&] {
|
||||
ovrDetectResult detect = ovr_Detect(0);
|
||||
if (!detect.IsOculusServiceRunning || !detect.IsOculusHMDConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// HACK Explicitly check for the presence of the 1.0 runtime DLL, and fail if it
|
||||
// doesn't exist
|
||||
if (!QFile(GOOD_OCULUS_RUNTIME_FILE).exists()) {
|
||||
qCWarning(oculus) << "Oculus Runtime detected, but no 1.x DLL present: \"" + GOOD_OCULUS_RUNTIME_FILE + "\"";
|
||||
return false;
|
||||
}
|
||||
DWORD searchResult = SearchPathW(NULL, REQUIRED_OCULUS_DLL, NULL, MAX_PATH, FOUND_PATH, NULL);
|
||||
if (searchResult <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ovrSession acquireOculusSession() {
|
||||
|
@ -67,10 +73,6 @@ ovrSession acquireOculusSession() {
|
|||
}
|
||||
|
||||
if (!session) {
|
||||
ovrInitParams init = {};
|
||||
init.Flags = 0;
|
||||
init.ConnectionTimeoutMS = 0;
|
||||
init.LogCallback = nullptr;
|
||||
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
|
||||
logWarning("Failed to initialize Oculus SDK");
|
||||
return session;
|
||||
|
|
Loading…
Reference in a new issue