From cfff7657310c6e1f7fd85be9cf9bf82b14abe9ad Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 14:21:34 -0800 Subject: [PATCH 01/14] allow for absolute path handling at entity-server --- assignment-client/src/octree/OctreeServer.cpp | 27 ++++++++++++------- assignment-client/src/octree/OctreeServer.h | 2 +- .../resources/describe-settings.json | 6 ++--- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 81e25cc7ba..95c869c874 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1030,13 +1030,12 @@ void OctreeServer::readConfiguration() { qDebug() << "wantPersist=" << _wantPersist; if (_wantPersist) { - QString persistFilename; - if (!readOptionString(QString("persistFilename"), settingsSectionObject, persistFilename)) { - persistFilename = getMyDefaultPersistFilename(); + if (!readOptionString("persistFilePath", settingsSectionObject, _persistFilePath) + && !readOptionString("persistFilename", settingsSectionObject, _persistFilePath)) { + _persistFilePath = getMyDefaultPersistFilename(); } - strcpy(_persistFilename, qPrintable(persistFilename)); - qDebug("persistFilename=%s", _persistFilename); + qDebug() << "persistFilePath=" << _persistFilePath; _persistAsFileType = "json.gz"; @@ -1145,8 +1144,16 @@ void OctreeServer::domainSettingsRequestComplete() { if (_wantPersist) { // If persist filename does not exist, let's see if there is one beside the application binary // If there is, let's copy it over to our target persist directory - auto persistPath = ServerPathUtils::getDataFilePath("entities/" + QString(_persistFilename)); - if (!QFile::exists(persistPath)) { + QDir persistPath { _persistFilePath }; + QString absoluteFilePath = persistPath.path(); + + if (persistPath.isRelative()) { + // if the domain settings passed us a relative path, make an absolute path that is relative to the + // default data directory + absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath); + } + + if (!QFile::exists(absoluteFilePath)) { qDebug() << "Persist file does not exist, checking for existence of persist file next to application"; static const QString OLD_DEFAULT_PERSIST_FILENAME = "resources/models.json.gz"; @@ -1154,7 +1161,7 @@ void OctreeServer::domainSettingsRequestComplete() { // This is the old persist path, based on the current persist filename, which could // be a custom filename set by the user. - auto oldPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(_persistFilename); + auto oldPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(_persistFilePath); // This is the old default persist path. auto oldDefaultPersistPath = QDir(oldResourcesDirectory).absoluteFilePath(OLD_DEFAULT_PERSIST_FILENAME); @@ -1181,14 +1188,14 @@ void OctreeServer::domainSettingsRequestComplete() { if (shouldCopy) { qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << persistPath; - QFile::copy(pathToCopyFrom, persistPath); + QFile::copy(pathToCopyFrom, absoluteFilePath); } else { qDebug() << "No existing persist file found"; } } // now set up PersistThread - _persistThread = new OctreePersistThread(_tree, persistPath, _persistInterval, + _persistThread = new OctreePersistThread(_tree, absoluteFilePath, _persistInterval, _wantBackup, _settings, _debugTimestampNow, _persistAsFileType); _persistThread->initialize(true); } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index f1aa9531e8..1430715571 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -169,7 +169,7 @@ protected: int _statusPort; QString _statusHost; - char _persistFilename[MAX_FILENAME_LENGTH]; + QString _persistFilePath; QString _persistAsFileType; int _packetsPerClientPerInterval; int _packetsTotalPerInterval; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index e38aa2a75a..f024ba5648 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -383,9 +383,9 @@ "assignment-types": [6], "settings": [ { - "name": "persistFilename", - "label": "Entities Filename", - "help": "the path to the file entities are stored in. Make sure the path exists.", + "name": "persistFilePath", + "label": "Entities File Path", + "help": "The path to the file entities are stored in. If path is relative it will be relative to the application data directory.", "placeholder": "models.json.gz", "default": "models.json.gz", "advanced": true From 4d91b8b7d625271d44bf551b7a88f7a3bfb60585 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 14:38:17 -0800 Subject: [PATCH 02/14] fix check for existing persist file directory --- assignment-client/src/octree/OctreeServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 95c869c874..c35d3d1cf8 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1179,14 +1179,14 @@ void OctreeServer::domainSettingsRequestComplete() { pathToCopyFrom = oldDefaultPersistPath; } - QDir persistFileDirectory = QDir(persistPath).filePath(".."); + QDir persistFileDirectory { QDir { absoluteFilePath }.dirName() }; if (!persistFileDirectory.exists()) { qDebug() << "Creating data directory " << persistFileDirectory.absolutePath(); persistFileDirectory.mkpath("."); } if (shouldCopy) { - qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << persistPath; + qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << absoluteFilePath; QFile::copy(pathToCopyFrom, absoluteFilePath); } else { From 13d58003bec98ce646c9676eaa5bdf040b391a35 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:02:12 -0800 Subject: [PATCH 03/14] migrate persistFilename to persistFilePath in DS settings --- .../resources/describe-settings.json | 2 +- .../src/DomainServerSettingsManager.cpp | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index f024ba5648..f34d7ec8fb 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1,5 +1,5 @@ { - "version": 1.0, + "version": 1.1, "settings": [ { "name": "metaverse", diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index e10007784f..a0e647ed89 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -124,6 +124,30 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList // reload the master and user config so that the merged config is right _configMap.loadMasterAndUserConfig(argumentList); } + } else if (oldVersion < 1.1) { + static const QString ENTITY_FILE_NAME_KEYPATH = "entity_server_settings.persistFilename"; + static const QString ENTITY_FILE_PATH_KEYPATH = "entity_server_settings.persistFilePath"; + + // this was prior to change of poorly named entitiesFileName to entitiesFilePath + QVariant* persistFileNameVariant = valueForKeyPath(_configMap.getMergedConfig(), ENTITY_FILE_NAME_KEYPATH); + if (persistFileNameVariant && persistFileNameVariant->canConvert(QMetaType::QString)) { + QString persistFileName = persistFileNameVariant->toString(); + + qDebug() << "Migrating persistFilename to persistFilePath for entity-server settings"; + + // grab the persistFilePath option, create it if it doesn't exist + QVariant* persistFilePath = valueForKeyPath(_configMap.getUserConfig(), ENTITY_FILE_PATH_KEYPATH, true); + + // write the migrated value + *persistFilePath = persistFileName; + + // write the new settings to the json file + persistToFile(); + + // reload the master and user config so that the merged config is right + _configMap.loadMasterAndUserConfig(argumentList); + } + } } From 9633e40c6e61a80f4fa9f6bba10c6208e6b9589e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:15:19 -0800 Subject: [PATCH 04/14] add code to remove old persistFilename setting --- .../src/DomainServerSettingsManager.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index a0e647ed89..98bb63241e 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -125,11 +125,13 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList _configMap.loadMasterAndUserConfig(argumentList); } } else if (oldVersion < 1.1) { - static const QString ENTITY_FILE_NAME_KEYPATH = "entity_server_settings.persistFilename"; - static const QString ENTITY_FILE_PATH_KEYPATH = "entity_server_settings.persistFilePath"; + static const QString ENTITY_SERVER_SETTINGS_KEY = "entity_server_settings"; + static const QString ENTITY_FILE_NAME_KEY = "persistFilename"; + static const QString ENTITY_FILE_PATH_KEYPATH = ENTITY_SERVER_SETTINGS_KEY + ".persistFilePath"; // this was prior to change of poorly named entitiesFileName to entitiesFilePath - QVariant* persistFileNameVariant = valueForKeyPath(_configMap.getMergedConfig(), ENTITY_FILE_NAME_KEYPATH); + QVariant* persistFileNameVariant = valueForKeyPath(_configMap.getMergedConfig(), + ENTITY_SERVER_SETTINGS_KEY + "." + ENTITY_FILE_NAME_KEY); if (persistFileNameVariant && persistFileNameVariant->canConvert(QMetaType::QString)) { QString persistFileName = persistFileNameVariant->toString(); @@ -141,6 +143,15 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList // write the migrated value *persistFilePath = persistFileName; + // remove the old setting + QVariant* entityServerVariant = valueForKeyPath(_configMap.getUserConfig(), ENTITY_SERVER_SETTINGS_KEY); + if (entityServerVariant && entityServerVariant->canConvert(QMetaType::QVariantMap)) { + QVariantMap entityServerMap = entityServerVariant->toMap(); + entityServerMap.remove(ENTITY_FILE_NAME_KEY); + + *entityServerVariant = entityServerMap; + } + // write the new settings to the json file persistToFile(); From ff239a7c6afe3e68748fc379ddedd12a48ca693b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:17:45 -0800 Subject: [PATCH 05/14] add helper text for extension to persistFilePath --- domain-server/resources/describe-settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index f34d7ec8fb..65949e98a0 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -385,7 +385,7 @@ { "name": "persistFilePath", "label": "Entities File Path", - "help": "The path to the file entities are stored in. If path is relative it will be relative to the application data directory.", + "help": "The path to the file entities are stored in. If this path is relative it will be relative to the application data directory. The entities file extension should be .json.gz.", "placeholder": "models.json.gz", "default": "models.json.gz", "advanced": true From 90b78feb1ee27ecd3dd35ab31f453f4912362e5b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:37:34 -0800 Subject: [PATCH 06/14] force models file to end in .json.gz --- assignment-client/src/octree/OctreeServer.cpp | 8 +++++++- domain-server/resources/describe-settings.json | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c35d3d1cf8..9a5b6ec0fd 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1153,6 +1153,11 @@ void OctreeServer::domainSettingsRequestComplete() { absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath); } + // force the persist file to end with .json.gz + if (!absoluteFilePath.endsWith(".json.gz", Qt::CaseInsensitive)) { + absoluteFilePath += ".json.gz"; + } + if (!QFile::exists(absoluteFilePath)) { qDebug() << "Persist file does not exist, checking for existence of persist file next to application"; @@ -1179,7 +1184,8 @@ void OctreeServer::domainSettingsRequestComplete() { pathToCopyFrom = oldDefaultPersistPath; } - QDir persistFileDirectory { QDir { absoluteFilePath }.dirName() }; + QDir persistFileDirectory { QDir::cleanPath(absoluteFilePath + "/..") }; + if (!persistFileDirectory.exists()) { qDebug() << "Creating data directory " << persistFileDirectory.absolutePath(); persistFileDirectory.mkpath("."); diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 65949e98a0..870573ef6c 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -385,7 +385,7 @@ { "name": "persistFilePath", "label": "Entities File Path", - "help": "The path to the file entities are stored in. If this path is relative it will be relative to the application data directory. The entities file extension should be .json.gz.", + "help": "The path to the file entities are stored in. If this path is relative it will be relative to the application data directory. The filename must end in .json.gz.", "placeholder": "models.json.gz", "default": "models.json.gz", "advanced": true From 99d1fa08fdd2fc51cad7f20f9f1ac0df361305be Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:49:40 -0800 Subject: [PATCH 07/14] handle incorrect casing in persist file extension --- assignment-client/src/octree/OctreeServer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9a5b6ec0fd..2eb7d00af8 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1154,8 +1154,11 @@ void OctreeServer::domainSettingsRequestComplete() { } // force the persist file to end with .json.gz - if (!absoluteFilePath.endsWith(".json.gz", Qt::CaseInsensitive)) { - absoluteFilePath += ".json.gz"; + if (!absoluteFilePath.endsWith(_persistAsFileType, Qt::CaseInsensitive)) { + absoluteFilePath += _persistAsFileType; + } else { + // make sure the casing of .json.gz is correct + absoluteFilePath.replace(_persistAsFileType, _persistAsFileType, Qt::CaseInsensitive); } if (!QFile::exists(absoluteFilePath)) { From 8ab15770b8c7840fe09612ab2b3351266be9681f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 15:52:12 -0800 Subject: [PATCH 08/14] use absolutePath for absolute persist path --- assignment-client/src/octree/OctreeServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 2eb7d00af8..558b59edf7 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1145,7 +1145,7 @@ void OctreeServer::domainSettingsRequestComplete() { // If persist filename does not exist, let's see if there is one beside the application binary // If there is, let's copy it over to our target persist directory QDir persistPath { _persistFilePath }; - QString absoluteFilePath = persistPath.path(); + QString absoluteFilePath = persistPath.absolutePath(); if (persistPath.isRelative()) { // if the domain settings passed us a relative path, make an absolute path that is relative to the From 2c1623ed427b326a844c276e663a4ed9d377ac1f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 2 Feb 2016 16:07:14 -0800 Subject: [PATCH 09/14] use extension with preceeding period --- assignment-client/src/octree/OctreeServer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 558b59edf7..69c54a17d5 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1153,12 +1153,14 @@ void OctreeServer::domainSettingsRequestComplete() { absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath); } + static const QString ENTITY_PERSIST_EXTENSION = ".json.gz"; + // force the persist file to end with .json.gz - if (!absoluteFilePath.endsWith(_persistAsFileType, Qt::CaseInsensitive)) { - absoluteFilePath += _persistAsFileType; + if (!absoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) { + absoluteFilePath += ENTITY_PERSIST_EXTENSION; } else { // make sure the casing of .json.gz is correct - absoluteFilePath.replace(_persistAsFileType, _persistAsFileType, Qt::CaseInsensitive); + absoluteFilePath.replace(ENTITY_PERSIST_EXTENSION, ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive); } if (!QFile::exists(absoluteFilePath)) { From 26abca92aeab150f198f5d21da12e62cf9881288 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 3 Feb 2016 10:55:07 -0800 Subject: [PATCH 10/14] don't move the re-used mute environment packet --- assignment-client/src/audio/AudioMixer.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 54032e993f..ca60528a71 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -553,15 +553,24 @@ void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer mes if (sendingNode->isAllowedEditor()) { qDebug() << "Received a mute environment packet of" << message->getSize() << "bytes"; - - auto newPacket = NLPacket::create(PacketType::MuteEnvironment, message->getSize()); - // Copy payload - newPacket->write(message->getRawMessage(), message->getSize()); + + glm::vec3 position; + float radius; + + auto newPacket = NLPacket::create(PacketType::MuteEnvironment, sizeof(position) + sizeof(radius)); + + // read the position and radius from the sent packet + message->readPrimitive(&position); + message->readPrimitive(&radius); + + // write them to our packet + newPacket->writePrimitive(position); + newPacket->writePrimitive(radius); nodeList->eachNode([&](const SharedNodePointer& node){ if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != sendingNode) { - nodeList->sendPacket(std::move(newPacket), *node); + nodeList->sendUnreliablePacket(*newPacket, *node); } }); } From 0e20392e663d887c4dbc21927493cdedadb85cba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 3 Feb 2016 11:07:16 -0800 Subject: [PATCH 11/14] remove debug for mute environment packet --- assignment-client/src/audio/AudioMixer.cpp | 102 ++++++++++----------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index ca60528a71..227ac843bb 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -458,7 +458,7 @@ int AudioMixer::prepareMixForListeningNode(Node* node) { if (otherNodeStream->getType() == PositionalAudioStream::Microphone) { streamUUID = otherNode->getUUID(); } - + // clear out the pre-mix samples before filling it up with this source memset(_preMixSamples, 0, sizeof(_preMixSamples)); @@ -498,7 +498,7 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) { break; } } - + AudioMixerClientData* nodeData = static_cast(node->getLinkedData()); AvatarAudioStream* stream = nodeData->getAvatarAudioStream(); bool dataChanged = (stream->hasReverb() != hasReverb) || @@ -550,10 +550,8 @@ void AudioMixer::handleNodeAudioPacket(QSharedPointer message, void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer message, SharedNodePointer sendingNode) { auto nodeList = DependencyManager::get(); - - if (sendingNode->isAllowedEditor()) { - qDebug() << "Received a mute environment packet of" << message->getSize() << "bytes"; + if (sendingNode->isAllowedEditor()) { glm::vec3 position; float radius; @@ -658,185 +656,185 @@ void AudioMixer::sendStatsPacket() { } void AudioMixer::run() { - + qDebug() << "Waiting for connection to domain to request settings from domain-server."; - + // wait until we have the domain-server settings, otherwise we bail DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); connect(&domainHandler, &DomainHandler::settingsReceived, this, &AudioMixer::domainSettingsRequestComplete); connect(&domainHandler, &DomainHandler::settingsReceiveFail, this, &AudioMixer::domainSettingsRequestFailed); - + ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); } void AudioMixer::domainSettingsRequestComplete() { auto nodeList = DependencyManager::get(); - + nodeList->addNodeTypeToInterestSet(NodeType::Agent); - + nodeList->linkedDataCreateCallback = [](Node* node) { node->setLinkedData(std::unique_ptr { new AudioMixerClientData }); }; - + DomainHandler& domainHandler = nodeList->getDomainHandler(); const QJsonObject& settingsObject = domainHandler.getSettingsObject(); - + // check the settings object to see if we have anything we can parse out parseSettingsObject(settingsObject); - + // queue up a connection to start broadcasting mixes now that we're ready to go QMetaObject::invokeMethod(this, "broadcastMixes", Qt::QueuedConnection); } void AudioMixer::broadcastMixes() { - auto nodeList = DependencyManager::get(); - + auto nodeList = DependencyManager::get(); + int64_t nextFrame = 0; QElapsedTimer timer; timer.start(); - + int64_t usecToSleep = AudioConstants::NETWORK_FRAME_USECS; - + const int TRAILING_AVERAGE_FRAMES = 100; int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES; - + while (!_isFinished) { const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f; const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f; - + const float RATIO_BACK_OFF = 0.02f; - + 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; } - + _trailingSleepRatio = (PREVIOUS_FRAMES_RATIO * _trailingSleepRatio) + (usecToSleep * CURRENT_FRAME_RATIO / (float) AudioConstants::NETWORK_FRAME_USECS); - + float lastCutoffRatio = _performanceThrottlingRatio; bool hasRatioChanged = false; - + if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) { if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) { // we're struggling - change our min required loudness to reduce some load _performanceThrottlingRatio = _performanceThrottlingRatio + (0.5f * (1.0f - _performanceThrottlingRatio)); - + qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; hasRatioChanged = true; } else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && _performanceThrottlingRatio != 0) { // we've recovered and can back off the required loudness _performanceThrottlingRatio = _performanceThrottlingRatio - RATIO_BACK_OFF; - + if (_performanceThrottlingRatio < 0) { _performanceThrottlingRatio = 0; } - + qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was" << lastCutoffRatio << "and is now" << _performanceThrottlingRatio; hasRatioChanged = true; } - + if (hasRatioChanged) { // set out min audability threshold from the new ratio _minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - _performanceThrottlingRatio)); qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold; - + framesSinceCutoffEvent = 0; } } - + if (!hasRatioChanged) { ++framesSinceCutoffEvent; } - + quint64 now = usecTimestampNow(); if (now - _lastPerSecondCallbackTime > USECS_PER_SECOND) { perSecondActions(); _lastPerSecondCallbackTime = now; } - + nodeList->eachNode([&](const SharedNodePointer& node) { - + if (node->getLinkedData()) { AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); - + // this function will attempt to pop a frame from each audio stream. // a pointer to the popped data is stored as a member in InboundAudioStream. // That's how the popped audio data will be read for mixing (but only if the pop was successful) nodeData->checkBuffersBeforeFrameSend(); - + // if the stream should be muted, send mute packet if (nodeData->getAvatarAudioStream() && shouldMute(nodeData->getAvatarAudioStream()->getQuietestFrameLoudness())) { auto mutePacket = NLPacket::create(PacketType::NoisyMute, 0); nodeList->sendPacket(std::move(mutePacket), *node); } - + if (node->getType() == NodeType::Agent && node->getActiveSocket() && nodeData->getAvatarAudioStream()) { - + int streamsMixed = prepareMixForListeningNode(node.data()); - + std::unique_ptr mixPacket; - + if (streamsMixed > 0) { int mixPacketBytes = sizeof(quint16) + AudioConstants::NETWORK_FRAME_BYTES_STEREO; mixPacket = NLPacket::create(PacketType::MixedAudio, mixPacketBytes); - + // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); mixPacket->writePrimitive(sequence); - + // pack mixed audio samples mixPacket->write(reinterpret_cast(_mixSamples), AudioConstants::NETWORK_FRAME_BYTES_STEREO); } else { int silentPacketBytes = sizeof(quint16) + sizeof(quint16); mixPacket = NLPacket::create(PacketType::SilentAudioFrame, silentPacketBytes); - + // pack sequence number quint16 sequence = nodeData->getOutgoingSequenceNumber(); mixPacket->writePrimitive(sequence); - + // pack number of silent audio samples quint16 numSilentSamples = AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; mixPacket->writePrimitive(numSilentSamples); } - + // Send audio environment sendAudioEnvironmentPacket(node); - + // send mixed audio packet nodeList->sendPacket(std::move(mixPacket), *node); nodeData->incrementOutgoingMixedAudioSequenceNumber(); - + // send an audio stream stats packet if it's time if (_sendAudioStreamStats) { nodeData->sendAudioStreamStatsPackets(node); _sendAudioStreamStats = false; } - + ++_sumListeners; } } }); - + ++_numStatFrames; - + // since we're a while loop we need to help Qt's event processing QCoreApplication::processEvents(); - + if (_isFinished) { // at this point the audio-mixer is done // check if we have a deferred delete event to process (which we should once finished) QCoreApplication::sendPostedEvents(this, QEvent::DeferredDelete); break; } - + usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - (timer.nsecsElapsed() / 1000); if (usecToSleep > 0) { @@ -1114,5 +1112,3 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { } } } - - From ea9d84bdc47556b9e31dad5385b566840417723c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 3 Feb 2016 13:18:29 -0800 Subject: [PATCH 12/14] handle downloading of absolute persist file contents --- assignment-client/src/octree/OctreeServer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 69c54a17d5..31cab68cdf 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -289,6 +289,8 @@ void OctreeServer::initHTTPManager(int port) { _httpManager = new HTTPManager(QHostAddress::AnyIPv4, port, documentRoot, this, this); } +const QString PERSIST_FILE_DOWNLOAD_PATH = "/models.json.gz"; + bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) { #ifdef FORCE_CRASH @@ -310,7 +312,6 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url #endif bool showStats = false; - QString persistFile = "/" + getPersistFilename(); if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (url.path() == "/") { @@ -320,7 +321,7 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url _tree->resetEditStats(); resetSendingStats(); showStats = true; - } else if ((url.path() == persistFile) || (url.path() == persistFile + "/")) { + } else if ((url.path() == PERSIST_FILE_DOWNLOAD_PATH) || (url.path() == PERSIST_FILE_DOWNLOAD_PATH + "/")) { if (_persistFileDownload) { QByteArray persistFileContents = getPersistFileContents(); if (persistFileContents.length() > 0) { @@ -374,9 +375,9 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url statsString += "\r\n"; if (_persistFileDownload) { - statsString += QString("Persist file: %1\r\n").arg(persistFile); + statsString += QString("Persist file: Click to Download\r\n").arg(PERSIST_FILE_DOWNLOAD_PATH); } else { - statsString += QString("Persist file: %1\r\n").arg(persistFile); + statsString += QString("Persist file: %1\r\n").arg(_persistFilePath); } } else { From 058bba7b55941e9f0f1b00789ddd5ab2269a13d3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 3 Feb 2016 17:13:35 -0800 Subject: [PATCH 13/14] move avatar invokables from AvatarManager to AvatarHashMap --- interface/src/avatar/AvatarManager.cpp | 11 ----------- interface/src/avatar/AvatarManager.h | 5 +---- libraries/avatars/src/AvatarHashMap.cpp | 10 ++++++++++ libraries/avatars/src/AvatarHashMap.h | 6 ++++++ 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 833ed26cc9..e12ff8f857 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -268,17 +268,6 @@ QVector AvatarManager::getLocalLights() const { return _localLights; } -QVector AvatarManager::getAvatarIdentifiers() { - QReadLocker locker(&_hashLock); - return _avatarHash.keys().toVector(); -} - -AvatarData* AvatarManager::getAvatar(QUuid avatarID) { - // Null/Default-constructed QUuids will return MyAvatar - return getAvatarBySessionID(avatarID).get(); -} - - void AvatarManager::getObjectsToRemoveFromPhysics(VectorOfMotionStates& result) { result.clear(); result.swap(_motionStatesToRemoveFromPhysics); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 72fcb3f862..2aff98a1d2 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -39,7 +39,7 @@ public: void init(); MyAvatar* getMyAvatar() { return _myAvatar.get(); } - AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID); + AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) override; void updateMyAvatar(float deltaTime); void updateOtherAvatars(float deltaTime); @@ -56,9 +56,6 @@ public: Q_INVOKABLE void setLocalLights(const QVector& localLights); Q_INVOKABLE QVector getLocalLights() const; - // Currently, your own avatar will be included as the null avatar id. - Q_INVOKABLE QVector getAvatarIdentifiers(); - Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID); void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates); diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 845a6a6245..ef7ff9684a 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -22,6 +22,16 @@ AvatarHashMap::AvatarHashMap() { connect(DependencyManager::get().data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged); } +QVector AvatarHashMap::getAvatarIdentifiers() { + QReadLocker locker(&_hashLock); + return _avatarHash.keys().toVector(); +} + +AvatarData* AvatarHashMap::getAvatar(QUuid avatarID) { + // Null/Default-constructed QUuids will return MyAvatar + return getAvatarBySessionID(avatarID).get(); +} + bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) { auto hashCopy = getHashCopy(); foreach(const AvatarSharedPointer& sharedAvatar, hashCopy) { diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index cb6c6cb0cc..0949b3ccea 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -34,6 +34,12 @@ public: AvatarHash getHashCopy() { QReadLocker lock(&_hashLock); return _avatarHash; } int size() { return _avatarHash.size(); } + // Currently, your own avatar will be included as the null avatar id. + Q_INVOKABLE QVector getAvatarIdentifiers(); + Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID); + + AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) { return findAvatar(sessionID); } + signals: void avatarAddedEvent(const QUuid& sessionUUID); void avatarRemovedEvent(const QUuid& sessionUUID); From 816fe52c5b1c38a8c9d7aadfe38e6287b6e65faf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 3 Feb 2016 17:31:38 -0800 Subject: [PATCH 14/14] mark getAvatarBySessionID as virtual --- libraries/avatars/src/AvatarHashMap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index 0949b3ccea..ee1197367c 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -38,7 +38,7 @@ public: Q_INVOKABLE QVector getAvatarIdentifiers(); Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID); - AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) { return findAvatar(sessionID); } + virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) { return findAvatar(sessionID); } signals: void avatarAddedEvent(const QUuid& sessionUUID);