diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 5864cadc15..96b2336af8 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -584,6 +584,7 @@ void Agent::setIsAvatar(bool isAvatar) { void Agent::sendAvatarIdentityPacket() { if (_isAvatar) { auto scriptedAvatar = DependencyManager::get(); + scriptedAvatar->markIdentityDataChanged(); scriptedAvatar->sendIdentityPacket(); } } diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index b95c429b2d..bb03a6ec93 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -38,13 +38,14 @@ #include "AudioMixer.h" static const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.5f; // attenuation = -6dB * log2(distance) +static const int DISABLE_STATIC_JITTER_FRAMES = -1; static const float DEFAULT_NOISE_MUTING_THRESHOLD = 1.0f; static const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; static const QString AUDIO_ENV_GROUP_KEY = "audio_env"; static const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer"; static const QString AUDIO_THREADING_GROUP_KEY = "audio_threading"; -int AudioMixer::_numStaticJitterFrames{ -1 }; +int AudioMixer::_numStaticJitterFrames{ DISABLE_STATIC_JITTER_FRAMES }; float AudioMixer::_noiseMutingThreshold{ DEFAULT_NOISE_MUTING_THRESHOLD }; float AudioMixer::_attenuationPerDoublingInDistance{ DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE }; std::map> AudioMixer::_availableCodecs{ }; @@ -56,7 +57,12 @@ QVector AudioMixer::_zoneReverbSettings; AudioMixer::AudioMixer(ReceivedMessage& message) : ThreadedAssignment(message) { + // Always clear settings first + // This prevents previous assignment settings from sticking around + clearDomainSettings(); + // hash the available codecs (on the mixer) + _availableCodecs.clear(); // Make sure struct is clean auto codecPlugins = PluginManager::getInstance()->getCodecPlugins(); std::for_each(codecPlugins.cbegin(), codecPlugins.cend(), [&](const CodecPluginPointer& codec) { @@ -232,7 +238,7 @@ void AudioMixer::sendStatsPacket() { } // general stats - statsObject["useDynamicJitterBuffers"] = _numStaticJitterFrames == -1; + statsObject["useDynamicJitterBuffers"] = _numStaticJitterFrames == DISABLE_STATIC_JITTER_FRAMES; statsObject["threads"] = _slavePool.numThreads(); @@ -490,6 +496,16 @@ int AudioMixer::prepareFrame(const SharedNodePointer& node, unsigned int frame) return data->checkBuffersBeforeFrameSend(); } +void AudioMixer::clearDomainSettings() { + _numStaticJitterFrames = DISABLE_STATIC_JITTER_FRAMES; + _attenuationPerDoublingInDistance = DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE; + _noiseMutingThreshold = DEFAULT_NOISE_MUTING_THRESHOLD; + _codecPreferenceOrder.clear(); + _audioZones.clear(); + _zoneSettings.clear(); + _zoneReverbSettings.clear(); +} + void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { qDebug() << "AVX2 Support:" << (cpuSupportsAVX2() ? "enabled" : "disabled"); @@ -525,7 +541,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject &settingsObject) { qDebug() << "Static desired jitter buffer frames:" << _numStaticJitterFrames; } else { qDebug() << "Disabling dynamic jitter buffers."; - _numStaticJitterFrames = -1; + _numStaticJitterFrames = DISABLE_STATIC_JITTER_FRAMES; } // check for deprecated audio settings diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 0641c04a6c..18e754016e 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -79,6 +79,7 @@ private: QString percentageForMixStats(int counter); void parseSettingsObject(const QJsonObject& settingsObject); + void clearDomainSettings(); float _trailingMixRatio { 0.0f }; float _throttlingRatio { 0.0f }; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 33e07088a6..d234c574d1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -431,7 +431,7 @@ static const QString STATE_ADVANCED_MOVEMENT_CONTROLS = "AdvancedMovement"; static const QString STATE_GROUNDED = "Grounded"; static const QString STATE_NAV_FOCUSED = "NavigationFocused"; -bool setupEssentials(int& argc, char** argv) { +bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); const int listenPort = portStr ? atoi(portStr) : INVALID_PORT; @@ -458,7 +458,7 @@ bool setupEssentials(int& argc, char** argv) { static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; bool suppressPrompt = cmdOptionExists(argc, const_cast(argv), SUPPRESS_SETTINGS_RESET); - bool previousSessionCrashed = CrashHandler::checkForResetSettings(suppressPrompt); + bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); DependencyManager::registerInheritance(); DependencyManager::registerInheritance(); @@ -563,11 +563,11 @@ const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true; const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false; const bool DEFAULT_PREFER_AVATAR_FINGER_OVER_STYLUS = false; -Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : +Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runningMarkerExisted) : QApplication(argc, argv), _window(new MainWindow(desktop())), _sessionRunTimer(startupTimer), - _previousSessionCrashed(setupEssentials(argc, argv)), + _previousSessionCrashed(setupEssentials(argc, argv, runningMarkerExisted)), _undoStackScriptingInterface(&_undoStack), _entitySimulation(new PhysicalEntitySimulation()), _physicsEngine(new PhysicsEngine(Vectors::ZERO)), @@ -6428,7 +6428,7 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa if (!includeAnimated) { // Tell the dependency manager that the capture of the still snapshot has taken place. emit DependencyManager::get()->stillSnapshotTaken(path, notify); - } else { + } else if (!SnapshotAnimated::isAlreadyTakingSnapshotAnimated()) { // Get an animated GIF snapshot and save it SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get()); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 5cf3580c09..d9dc3f389f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -136,7 +136,7 @@ public: static void initPlugins(const QStringList& arguments); static void shutdownPlugins(); - Application(int& argc, char** argv, QElapsedTimer& startup_time); + Application(int& argc, char** argv, QElapsedTimer& startup_time, bool runningMarkerExisted); ~Application(); void postLambdaEvent(std::function f) override; diff --git a/interface/src/CrashHandler.cpp b/interface/src/CrashHandler.cpp index b254cd58de..8081dd3ffc 100644 --- a/interface/src/CrashHandler.cpp +++ b/interface/src/CrashHandler.cpp @@ -28,7 +28,7 @@ #include -bool CrashHandler::checkForResetSettings(bool suppressPrompt) { +bool CrashHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) { Settings settings; settings.beginGroup("Developer"); QVariant displayCrashOptions = settings.value(MenuOption::DisplayCrashOptions); @@ -39,9 +39,6 @@ bool CrashHandler::checkForResetSettings(bool suppressPrompt) { // If option does not exist in Interface.ini so assume default behavior. bool displaySettingsResetOnCrash = !displayCrashOptions.isValid() || displayCrashOptions.toBool(); - QFile runningMarkerFile(RunningMarker::getMarkerFilePath(RUNNING_MARKER_FILENAME)); - bool wasLikelyCrash = runningMarkerFile.exists(); - if (suppressPrompt) { return wasLikelyCrash; } diff --git a/interface/src/CrashHandler.h b/interface/src/CrashHandler.h index 308cac3411..da2e1575db 100644 --- a/interface/src/CrashHandler.h +++ b/interface/src/CrashHandler.h @@ -17,7 +17,7 @@ class CrashHandler { public: - static bool checkForResetSettings(bool suppressPrompt = false); + static bool checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt = false); private: enum Action { diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 3430ffbd15..49517eb38e 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -192,6 +192,7 @@ int main(int argc, const char* argv[]) { int exitCode; { RunningMarker runningMarker(nullptr, RUNNING_MARKER_FILENAME); + bool runningMarkerExisted = runningMarker.fileExists(); runningMarker.writeRunningMarkerFile(); bool noUpdater = parser.isSet(noUpdaterOption); @@ -202,7 +203,7 @@ int main(int argc, const char* argv[]) { SandboxUtils::runLocalSandbox(serverContentPath, true, RUNNING_MARKER_FILENAME, noUpdater); } - Application app(argc, const_cast(argv), startupTime); + Application app(argc, const_cast(argv), startupTime, runningMarkerExisted); // Now that the main event loop is setup, launch running marker thread runningMarker.startRunningMarker(); diff --git a/interface/src/ui/SnapshotAnimated.h b/interface/src/ui/SnapshotAnimated.h index 1cf21edfb8..dd32e4893d 100644 --- a/interface/src/ui/SnapshotAnimated.h +++ b/interface/src/ui/SnapshotAnimated.h @@ -51,6 +51,7 @@ private: static void processFrames(); public: static void saveSnapshotAnimated(QString pathStill, float aspectRatio, Application* app, QSharedPointer dm); + static bool isAlreadyTakingSnapshotAnimated() { return snapshotAnimatedFirstFrameTimestamp != 0; }; static Setting::Handle alsoTakeAnimatedSnapshot; static Setting::Handle snapshotAnimatedDuration; }; diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 1282dbb2dc..a4ac3feddc 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1506,6 +1506,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice // cleanup any previously initialized device if (_audioOutput) { + _audioOutputIODevice.close(); _audioOutput->stop(); //must be deleted in next eventloop cycle when its called from notify() diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 47808767b3..a1e56df33b 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -94,7 +94,6 @@ public: _audio(audio), _unfulfilledReads(0) {} void start() { open(QIODevice::ReadOnly | QIODevice::Unbuffered); } - void stop() { close(); } qint64 readData(char * data, qint64 maxSize) override; qint64 writeData(const char * data, qint64 maxSize) override { return 0; } int getRecentUnfulfilledReads() { int unfulfilledReads = _unfulfilledReads; _unfulfilledReads = 0; return unfulfilledReads; } diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 92ead5f616..14282ec525 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -184,6 +184,11 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { } std::shared_ptr KtxStorage::maybeOpenFile() const { + // 1. Try to get the shared ptr + // 2. If it doesn't exist, grab the mutex around its creation + // 3. If it was created before we got the mutex, return it + // 4. Otherwise, create it + std::shared_ptr file = _cacheFile.lock(); if (file) { return file; @@ -205,7 +210,6 @@ std::shared_ptr KtxStorage::maybeOpenFile() const { } PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { - storage::StoragePointer result; auto faceOffset = _ktxDescriptor->getMipFaceTexelsOffset(level, face); auto faceSize = _ktxDescriptor->getMipFaceTexelsSize(level, face); if (faceSize != 0 && faceOffset != 0) { @@ -221,7 +225,7 @@ PixelsPointer KtxStorage::getMipFace(uint16 level, uint8 face) const { qWarning() << "Failed to get a valid file out of maybeOpenFile " << QString::fromStdString(_filename); } } - return result; + return nullptr; } Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const { @@ -255,8 +259,18 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor } auto file = maybeOpenFile(); + if (!file) { + qWarning() << "Failed to open file to assign mip data " << QString::fromStdString(_filename); + return; + } - auto imageData = file->mutableData(); + auto fileData = file->mutableData(); + if (!fileData) { + qWarning() << "Failed to get mutable data for " << QString::fromStdString(_filename); + return; + } + + auto imageData = fileData; imageData += ktx::KTX_HEADER_SIZE + _ktxDescriptor->header.bytesOfKeyValueData + _ktxDescriptor->images[level]._imageOffset; imageData += ktx::IMAGE_SIZE_WIDTH; @@ -271,7 +285,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor memcpy(imageData, storage->data(), storage->size()); _minMipLevelAvailable = level; if (_offsetToMinMipKV > 0) { - auto minMipKeyData = file->mutableData() + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV; + auto minMipKeyData = fileData + ktx::KTX_HEADER_SIZE + _offsetToMinMipKV; memcpy(minMipKeyData, (void*)&_minMipLevelAvailable, 1); } } diff --git a/libraries/ktx/src/ktx/Writer.cpp b/libraries/ktx/src/ktx/Writer.cpp index 2dcd0ea583..23f9d05596 100644 --- a/libraries/ktx/src/ktx/Writer.cpp +++ b/libraries/ktx/src/ktx/Writer.cpp @@ -149,7 +149,8 @@ namespace ktx { for (size_t i = 0; i < descriptors.size(); ++i) { auto ptr = reinterpret_cast(currentDestPtr); - *ptr = descriptors[i]._imageSize; + uint32_t imageFaceSize = descriptors[i]._faceSize; + *ptr = imageFaceSize; // the imageSize written in the ktx is the FACE size #ifdef DEBUG ptr++; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index c66fe8daf0..8fc1d66cf1 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -30,9 +30,9 @@ #include "udt/PacketHeaders.h" #if USE_STABLE_GLOBAL_SERVICES -const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome"; +const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome/hello"; #else -const QString DEFAULT_HIFI_ADDRESS = "hifi://dev-welcome"; +const QString DEFAULT_HIFI_ADDRESS = "hifi://dev-welcome/hello"; #endif const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager"; diff --git a/libraries/shared/src/RunningMarker.cpp b/libraries/shared/src/RunningMarker.cpp index f8aaee42df..0c1fd06df8 100644 --- a/libraries/shared/src/RunningMarker.cpp +++ b/libraries/shared/src/RunningMarker.cpp @@ -53,6 +53,11 @@ RunningMarker::~RunningMarker() { _runningMarkerThread->deleteLater(); } +bool RunningMarker::fileExists() const { + QFile runningMarkerFile(getFilePath()); + return runningMarkerFile.exists(); +} + void RunningMarker::writeRunningMarkerFile() { QFile runningMarkerFile(getFilePath()); @@ -69,7 +74,7 @@ void RunningMarker::deleteRunningMarkerFile() { } } -QString RunningMarker::getFilePath() { +QString RunningMarker::getFilePath() const { return QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + _name; } diff --git a/libraries/shared/src/RunningMarker.h b/libraries/shared/src/RunningMarker.h index 1137dbf5fa..f9c8e72d37 100644 --- a/libraries/shared/src/RunningMarker.h +++ b/libraries/shared/src/RunningMarker.h @@ -25,9 +25,11 @@ public: void startRunningMarker(); - QString getFilePath(); + QString getFilePath() const; static QString getMarkerFilePath(QString name); + bool fileExists() const; + void writeRunningMarkerFile(); void deleteRunningMarkerFile(); diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index e479559e6a..b07f896df0 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -70,7 +70,15 @@ StoragePointer FileStorage::create(const QString& filename, size_t size, const u } FileStorage::FileStorage(const QString& filename) : _file(filename) { - if (_file.open(QFile::ReadOnly)) { + bool opened = _file.open(QFile::ReadWrite); + if (opened) { + _hasWriteAccess = true; + } else { + _hasWriteAccess = false; + opened = _file.open(QFile::ReadOnly); + } + + if (opened) { _mapped = _file.map(0, _file.size()); if (_mapped) { _valid = true; @@ -91,35 +99,4 @@ FileStorage::~FileStorage() { if (_file.isOpen()) { _file.close(); } -} - -void FileStorage::ensureWriteAccess() { - if (_hasWriteAccess) { - return; - } - - if (_mapped) { - if (!_file.unmap(_mapped)) { - throw std::runtime_error("Unable to unmap file"); - } - } - if (_file.isOpen()) { - _file.close(); - } - _valid = false; - _mapped = nullptr; - - if (_file.open(QFile::ReadWrite)) { - _mapped = _file.map(0, _file.size()); - if (_mapped) { - _valid = true; - _hasWriteAccess = true; - } else { - qCWarning(storagelogging) << "Failed to map file " << _file.fileName(); - throw std::runtime_error("Failed to map file"); - } - } else { - qCWarning(storagelogging) << "Failed to open file " << _file.fileName(); - throw std::runtime_error("Failed to open file"); - } } \ No newline at end of file diff --git a/libraries/shared/src/shared/Storage.h b/libraries/shared/src/shared/Storage.h index 4cad9fa083..d7946738cf 100644 --- a/libraries/shared/src/shared/Storage.h +++ b/libraries/shared/src/shared/Storage.h @@ -60,11 +60,10 @@ namespace storage { FileStorage& operator=(const FileStorage& other) = delete; const uint8_t* data() const override { return _mapped; } - uint8_t* mutableData() override { ensureWriteAccess(); return _mapped; } + uint8_t* mutableData() override { return _hasWriteAccess ? _mapped : nullptr; } size_t size() const override { return _file.size(); } operator bool() const override { return _valid; } private: - void ensureWriteAccess(); bool _valid { false }; bool _hasWriteAccess { false }; diff --git a/scripts/system/html/js/SnapshotReview.js b/scripts/system/html/js/SnapshotReview.js index f962c7b624..6c5829d64f 100644 --- a/scripts/system/html/js/SnapshotReview.js +++ b/scripts/system/html/js/SnapshotReview.js @@ -44,6 +44,7 @@ function showSetupComplete() { '

Snapshot location set.

' + '

Press the big red button to take a snap!

' + ''; + document.getElementById("snap-button").disabled = false; } function showSnapshotInstructions() { var snapshotImagesDiv = document.getElementById("snapshot-images"); @@ -69,7 +70,6 @@ function login() { })); } function clearImages() { - document.getElementById("snap-button").disabled = false; var snapshotImagesDiv = document.getElementById("snapshot-images"); snapshotImagesDiv.classList.remove("snapshotInstructions"); while (snapshotImagesDiv.hasChildNodes()) { @@ -300,7 +300,7 @@ function addImage(image_data, isLoggedIn, canShare, isGifLoading, isShowingPrevi if (!isGifLoading) { appendShareBar(id, isLoggedIn, canShare, isGif, blastButtonDisabled, hifiButtonDisabled, canBlast); } - if (!isGifLoading && !isShowingPreviousImages) { + if (!isGifLoading || (isShowingPreviousImages && !image_data.story_id)) { shareForUrl(id); } if (isShowingPreviousImages && isLoggedIn && image_data.story_id) { @@ -650,6 +650,7 @@ window.onload = function () { shareForUrl("p1"); appendShareBar("p1", messageOptions.isLoggedIn, messageOptions.canShare, true, false, false, messageOptions.canBlast); document.getElementById("p1").classList.remove("processingGif"); + document.getElementById("snap-button").disabled = false; } } else { imageCount = message.image_data.length; @@ -688,6 +689,9 @@ function takeSnapshot() { type: "snapshot", action: "takeSnapshot" })); + if (document.getElementById('stillAndGif').checked === true) { + document.getElementById("snap-button").disabled = true; + } } function testInBrowser(test) { diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 8b5ae3c9a7..4c661482fc 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -138,10 +138,10 @@ function onMessage(message) { isLoggedIn = Account.isLoggedIn(); if (isLoggedIn) { print('Sharing snapshot with audience "for_url":', message.data); - Window.shareSnapshot(message.data, message.href || href); + Window.shareSnapshot(message.data, Settings.getValue("previousSnapshotHref")); } else { shareAfterLogin = true; - snapshotToShareAfterLogin.push({ path: message.data, href: message.href || href }); + snapshotToShareAfterLogin.push({ path: message.data, href: Settings.getValue("previousSnapshotHref") }); } } }); @@ -349,6 +349,7 @@ function takeSnapshot() { // We will record snapshots based on the starting location. That could change, e.g., when recording a .gif. // Even the domainId could change (e.g., if the user falls into a teleporter while recording). href = location.href; + Settings.setValue("previousSnapshotHref", href); domainId = location.domainId; Settings.setValue("previousSnapshotDomainID", domainId); diff --git a/server-console/src/main.js b/server-console/src/main.js index 4ce1ccfb02..98bda9a10f 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -42,7 +42,7 @@ const appIcon = path.join(__dirname, '../resources/console.png'); const DELETE_LOG_FILES_OLDER_THAN_X_SECONDS = 60 * 60 * 24 * 7; // 7 Days const LOG_FILE_REGEX = /(domain-server|ac-monitor|ac)-.*-std(out|err).txt/; -const HOME_CONTENT_URL = "http://cdn.highfidelity.com/content-sets/home-tutorial-RC39.tar.gz"; +const HOME_CONTENT_URL = "http://cdn.highfidelity.com/content-sets/home-tutorial-RC40.tar.gz"; function getBuildInfo() { var buildInfoPath = null;