mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-23 16:54:35 +02:00
Merge branch 'master' into 21255
This commit is contained in:
commit
d27ad061cb
17 changed files with 224 additions and 212 deletions
5
BUILD.md
5
BUILD.md
|
@ -31,15 +31,18 @@ These are not placed in your normal build tree when doing an out of source build
|
||||||
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE_LOCAL_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
|
If you would like to use a specific install of a dependency instead of the version that would be grabbed as a CMake ExternalProject, you can pass -DUSE_LOCAL_$NAME=0 (where $NAME is the name of the subfolder in [cmake/externals](cmake/externals)) when you run CMake to tell it not to get that dependency as an external project.
|
||||||
|
|
||||||
### OS Specific Build Guides
|
### OS Specific Build Guides
|
||||||
|
|
||||||
* [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
|
* [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X.
|
||||||
* [BUILD_LINUX.md](BUILD_LINUX.md) - additional instructions for Linux.
|
* [BUILD_LINUX.md](BUILD_LINUX.md) - additional instructions for Linux.
|
||||||
* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows.
|
* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows.
|
||||||
* [BUILD_ANDROID.md](BUILD_ANDROID.md) - additional instructions for Android
|
* [BUILD_ANDROID.md](BUILD_ANDROID.md) - additional instructions for Android
|
||||||
|
|
||||||
### CMake
|
### CMake
|
||||||
|
|
||||||
Hifi uses CMake to generate build files and project files for your platform.
|
Hifi uses CMake to generate build files and project files for your platform.
|
||||||
|
|
||||||
#### Qt
|
#### Qt
|
||||||
|
|
||||||
In order for CMake to find the Qt5 find modules, you will need to set a QT_CMAKE_PREFIX_PATH environment variable pointing to your Qt installation.
|
In order for CMake to find the Qt5 find modules, you will need to set a QT_CMAKE_PREFIX_PATH environment variable pointing to your Qt installation.
|
||||||
|
|
||||||
This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||||
|
@ -51,6 +54,7 @@ The path it needs to be set to will depend on where and how Qt5 was installed. e
|
||||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||||
|
|
||||||
#### Generating build files
|
#### Generating build files
|
||||||
|
|
||||||
Create a build directory in the root of your checkout and then run the CMake build from there. This will keep the rest of the directory clean.
|
Create a build directory in the root of your checkout and then run the CMake build from there. This will keep the rest of the directory clean.
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
|
@ -60,6 +64,7 @@ Create a build directory in the root of your checkout and then run the CMake bui
|
||||||
If cmake gives you the same error message repeatedly after the build fails (e.g. you had a typo in the QT_CMAKE_PREFIX_PATH that you fixed but the `.cmake` files still cannot be found), try removing `CMakeCache.txt`.
|
If cmake gives you the same error message repeatedly after the build fails (e.g. you had a typo in the QT_CMAKE_PREFIX_PATH that you fixed but the `.cmake` files still cannot be found), try removing `CMakeCache.txt`.
|
||||||
|
|
||||||
#### Variables
|
#### Variables
|
||||||
|
|
||||||
Any variables that need to be set for CMake to find dependencies can be set as ENV variables in your shell profile, or passed directly to CMake with a `-D` flag appended to the `cmake ..` command.
|
Any variables that need to be set for CMake to find dependencies can be set as ENV variables in your shell profile, or passed directly to CMake with a `-D` flag appended to the `cmake ..` command.
|
||||||
|
|
||||||
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
|
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
|
||||||
|
|
||||||
### Qt5 Dependencies
|
### Qt5 Dependencies
|
||||||
|
|
||||||
Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required:
|
Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required:
|
||||||
|
|
||||||
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev
|
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
||||||
|
|
||||||
### Homebrew
|
### Homebrew
|
||||||
|
|
||||||
[Homebrew](https://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple.
|
[Homebrew](https://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple.
|
||||||
|
|
||||||
brew tap homebrew/versions
|
brew tap homebrew/versions
|
||||||
|
@ -16,6 +17,7 @@ For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
|
||||||
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
|
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
|
||||||
|
|
||||||
### Qt
|
### Qt
|
||||||
|
|
||||||
Download and install the [Qt 5.6.2 for macOS](http://download.qt.io/official_releases/qt/5.6/5.6.2/qt-opensource-mac-x64-clang-5.6.2.dmg).
|
Download and install the [Qt 5.6.2 for macOS](http://download.qt.io/official_releases/qt/5.6/5.6.2/qt-opensource-mac-x64-clang-5.6.2.dmg).
|
||||||
|
|
||||||
Keep the default components checked when going through the installer.
|
Keep the default components checked when going through the installer.
|
||||||
|
@ -24,6 +26,7 @@ Once Qt is installed, you need to manually configure the following:
|
||||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt5.6.2/5.6/clang_64/lib/cmake/` directory.
|
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt5.6.2/5.6/clang_64/lib/cmake/` directory.
|
||||||
|
|
||||||
### Xcode
|
### Xcode
|
||||||
|
|
||||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||||
|
|
||||||
cmake .. -GXcode
|
cmake .. -GXcode
|
||||||
|
|
|
@ -24,7 +24,7 @@ Go to "Control Panel > System > Advanced System Settings > Environment Variables
|
||||||
|
|
||||||
### Step 5. Installing OpenSSL
|
### Step 5. Installing OpenSSL
|
||||||
|
|
||||||
Download and install the [Win64 OpenSSL v1.0.2k Installer](https://slproweb.com/download/Win64OpenSSL-1_0_2k.exe).
|
Download and install the [Win64 OpenSSL v1.0.2L Installer](https://slproweb.com/download/Win64OpenSSL-1_0_2L.exe).
|
||||||
|
|
||||||
### Step 6. Running CMake to Generate Build Files
|
### Step 6. Running CMake to Generate Build Files
|
||||||
|
|
||||||
|
|
BIN
interface/resources/snapshot/img/no-image.jpg
Normal file
BIN
interface/resources/snapshot/img/no-image.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -438,6 +438,10 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
|
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
|
||||||
const int listenPort = portStr ? atoi(portStr) : INVALID_PORT;
|
const int listenPort = portStr ? atoi(portStr) : INVALID_PORT;
|
||||||
|
|
||||||
|
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
|
||||||
|
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
|
||||||
|
bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||||
|
|
||||||
Setting::init();
|
Setting::init();
|
||||||
|
|
||||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||||
|
@ -458,10 +462,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
QCoreApplication::addLibraryPath(audioDLLPath);
|
QCoreApplication::addLibraryPath(audioDLLPath);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
|
|
||||||
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
|
|
||||||
bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
|
||||||
|
|
||||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
|
||||||
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, InterfaceDynamicFactory>();
|
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, InterfaceDynamicFactory>();
|
||||||
|
|
|
@ -24,12 +24,15 @@
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include <SettingHandle.h>
|
|
||||||
|
|
||||||
#include <RunningMarker.h>
|
#include <RunningMarker.h>
|
||||||
|
#include <SettingHandle.h>
|
||||||
|
#include <SettingHelpers.h>
|
||||||
|
|
||||||
|
|
||||||
bool CrashHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) {
|
bool CrashHandler::checkForResetSettings(bool wasLikelyCrash, bool suppressPrompt) {
|
||||||
Settings settings;
|
QSettings::setDefaultFormat(JSON_FORMAT);
|
||||||
|
QSettings settings;
|
||||||
settings.beginGroup("Developer");
|
settings.beginGroup("Developer");
|
||||||
QVariant displayCrashOptions = settings.value(MenuOption::DisplayCrashOptions);
|
QVariant displayCrashOptions = settings.value(MenuOption::DisplayCrashOptions);
|
||||||
QVariant askToResetSettingsOption = settings.value(MenuOption::AskToResetSettings);
|
QVariant askToResetSettingsOption = settings.value(MenuOption::AskToResetSettings);
|
||||||
|
@ -106,7 +109,7 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings settings;
|
QSettings settings;
|
||||||
const QString ADDRESS_MANAGER_GROUP = "AddressManager";
|
const QString ADDRESS_MANAGER_GROUP = "AddressManager";
|
||||||
const QString ADDRESS_KEY = "address";
|
const QString ADDRESS_KEY = "address";
|
||||||
const QString AVATAR_GROUP = "Avatar";
|
const QString AVATAR_GROUP = "Avatar";
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::Friends;
|
const Discoverability::Mode DEFAULT_DISCOVERABILITY_MODE = Discoverability::Connections;
|
||||||
|
|
||||||
DiscoverabilityManager::DiscoverabilityManager() :
|
DiscoverabilityManager::DiscoverabilityManager() :
|
||||||
_mode("discoverabilityMode", DEFAULT_DISCOVERABILITY_MODE)
|
_mode("discoverabilityMode", DEFAULT_DISCOVERABILITY_MODE)
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <QRunnable>
|
||||||
|
#include <QThreadPool>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QtNetwork/QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
|
@ -49,13 +51,43 @@ Sound::Sound(const QUrl& url, bool isStereo, bool isAmbisonic) :
|
||||||
_isAmbisonic(isAmbisonic),
|
_isAmbisonic(isAmbisonic),
|
||||||
_isReady(false)
|
_isReady(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::downloadFinished(const QByteArray& data) {
|
void Sound::downloadFinished(const QByteArray& data) {
|
||||||
|
// this is a QRunnable, will delete itself after it has finished running
|
||||||
|
SoundProcessor* soundProcessor = new SoundProcessor(_url, data, _isStereo, _isAmbisonic);
|
||||||
|
connect(soundProcessor, &SoundProcessor::onSuccess, this, &Sound::soundProcessSuccess);
|
||||||
|
connect(soundProcessor, &SoundProcessor::onError, this, &Sound::soundProcessError);
|
||||||
|
QThreadPool::globalInstance()->start(soundProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound::soundProcessSuccess(QByteArray data, bool stereo, bool ambisonic, float duration) {
|
||||||
|
|
||||||
|
qCDebug(audio) << "Setting ready state for sound file" << _url.toDisplayString();
|
||||||
|
|
||||||
|
_byteArray = data;
|
||||||
|
_isStereo = stereo;
|
||||||
|
_isAmbisonic = ambisonic;
|
||||||
|
_duration = duration;
|
||||||
|
_isReady = true;
|
||||||
|
finishedLoading(true);
|
||||||
|
|
||||||
|
emit ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound::soundProcessError(int error, QString str) {
|
||||||
|
qCCritical(audio) << "Failed to process sound file" << _url.toDisplayString() << "code =" << error << str;
|
||||||
|
emit failed(QNetworkReply::UnknownContentError);
|
||||||
|
finishedLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundProcessor::run() {
|
||||||
|
|
||||||
|
qCDebug(audio) << "Processing sound file" << _url.toDisplayString();
|
||||||
|
|
||||||
// replace our byte array with the downloaded data
|
// replace our byte array with the downloaded data
|
||||||
QByteArray rawAudioByteArray = QByteArray(data);
|
QByteArray rawAudioByteArray = QByteArray(_data);
|
||||||
QString fileName = getURL().fileName().toLower();
|
QString fileName = _url.fileName().toLower();
|
||||||
|
|
||||||
static const QString WAV_EXTENSION = ".wav";
|
static const QString WAV_EXTENSION = ".wav";
|
||||||
static const QString RAW_EXTENSION = ".raw";
|
static const QString RAW_EXTENSION = ".raw";
|
||||||
|
@ -72,31 +104,28 @@ void Sound::downloadFinished(const QByteArray& data) {
|
||||||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||||
if (fileName.toLower().endsWith("stereo.raw")) {
|
if (fileName.toLower().endsWith("stereo.raw")) {
|
||||||
_isStereo = true;
|
_isStereo = true;
|
||||||
qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << getURL() << "as stereo audio file.";
|
qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << _url << "as stereo audio file.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process as 48khz RAW file
|
// Process as 48khz RAW file
|
||||||
downSample(rawAudioByteArray, 48000);
|
downSample(rawAudioByteArray, 48000);
|
||||||
} else {
|
} else {
|
||||||
qCDebug(audio) << "Unknown sound file type";
|
qCDebug(audio) << "Unknown sound file type";
|
||||||
|
emit onError(300, "Failed to load sound file, reason: unknown sound file type");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
finishedLoading(true);
|
emit onSuccess(_data, _isStereo, _isAmbisonic, _duration);
|
||||||
|
|
||||||
_isReady = true;
|
|
||||||
emit ready();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sound::downSample(const QByteArray& rawAudioByteArray, int sampleRate) {
|
void SoundProcessor::downSample(const QByteArray& rawAudioByteArray, int sampleRate) {
|
||||||
|
|
||||||
// we want to convert it to the format that the audio-mixer wants
|
// we want to convert it to the format that the audio-mixer wants
|
||||||
// which is signed, 16-bit, 24Khz
|
// which is signed, 16-bit, 24Khz
|
||||||
|
|
||||||
if (sampleRate == AudioConstants::SAMPLE_RATE) {
|
if (sampleRate == AudioConstants::SAMPLE_RATE) {
|
||||||
|
|
||||||
// no resampling needed
|
// no resampling needed
|
||||||
_byteArray = rawAudioByteArray;
|
_data = rawAudioByteArray;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
int numChannels = _isAmbisonic ? AudioConstants::AMBISONIC : (_isStereo ? AudioConstants::STEREO : AudioConstants::MONO);
|
int numChannels = _isAmbisonic ? AudioConstants::AMBISONIC : (_isStereo ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||||
|
@ -106,15 +135,15 @@ void Sound::downSample(const QByteArray& rawAudioByteArray, int sampleRate) {
|
||||||
int numSourceFrames = rawAudioByteArray.size() / (numChannels * sizeof(AudioConstants::AudioSample));
|
int numSourceFrames = rawAudioByteArray.size() / (numChannels * sizeof(AudioConstants::AudioSample));
|
||||||
int maxDestinationFrames = resampler.getMaxOutput(numSourceFrames);
|
int maxDestinationFrames = resampler.getMaxOutput(numSourceFrames);
|
||||||
int maxDestinationBytes = maxDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
|
int maxDestinationBytes = maxDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
|
||||||
_byteArray.resize(maxDestinationBytes);
|
_data.resize(maxDestinationBytes);
|
||||||
|
|
||||||
int numDestinationFrames = resampler.render((int16_t*)rawAudioByteArray.data(),
|
int numDestinationFrames = resampler.render((int16_t*)rawAudioByteArray.data(),
|
||||||
(int16_t*)_byteArray.data(),
|
(int16_t*)_data.data(),
|
||||||
numSourceFrames);
|
numSourceFrames);
|
||||||
|
|
||||||
// truncate to actual output
|
// truncate to actual output
|
||||||
int numDestinationBytes = numDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
|
int numDestinationBytes = numDestinationFrames * numChannels * sizeof(AudioConstants::AudioSample);
|
||||||
_byteArray.resize(numDestinationBytes);
|
_data.resize(numDestinationBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +192,7 @@ struct WAVEFormat {
|
||||||
};
|
};
|
||||||
|
|
||||||
// returns wavfile sample rate, used for resampling
|
// returns wavfile sample rate, used for resampling
|
||||||
int Sound::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) {
|
int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) {
|
||||||
|
|
||||||
// Create a data stream to analyze the data
|
// Create a data stream to analyze the data
|
||||||
QDataStream waveStream(const_cast<QByteArray *>(&inputAudioByteArray), QIODevice::ReadOnly);
|
QDataStream waveStream(const_cast<QByteArray *>(&inputAudioByteArray), QIODevice::ReadOnly);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#ifndef hifi_Sound_h
|
#ifndef hifi_Sound_h
|
||||||
#define hifi_Sound_h
|
#define hifi_Sound_h
|
||||||
|
|
||||||
|
#include <QRunnable>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
#include <QtScript/qscriptengine.h>
|
#include <QtScript/qscriptengine.h>
|
||||||
|
@ -29,12 +30,15 @@ public:
|
||||||
bool isReady() const { return _isReady; }
|
bool isReady() const { return _isReady; }
|
||||||
float getDuration() const { return _duration; }
|
float getDuration() const { return _duration; }
|
||||||
|
|
||||||
|
|
||||||
const QByteArray& getByteArray() const { return _byteArray; }
|
const QByteArray& getByteArray() const { return _byteArray; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void ready();
|
void ready();
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void soundProcessSuccess(QByteArray data, bool stereo, bool ambisonic, float duration);
|
||||||
|
void soundProcessError(int error, QString str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray _byteArray;
|
QByteArray _byteArray;
|
||||||
bool _isStereo;
|
bool _isStereo;
|
||||||
|
@ -42,10 +46,33 @@ private:
|
||||||
bool _isReady;
|
bool _isReady;
|
||||||
float _duration; // In seconds
|
float _duration; // In seconds
|
||||||
|
|
||||||
|
virtual void downloadFinished(const QByteArray& data) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SoundProcessor : public QObject, public QRunnable {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SoundProcessor(const QUrl& url, const QByteArray& data, bool stereo, bool ambisonic)
|
||||||
|
: _url(url), _data(data), _isStereo(stereo), _isAmbisonic(ambisonic)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void run() override;
|
||||||
|
|
||||||
void downSample(const QByteArray& rawAudioByteArray, int sampleRate);
|
void downSample(const QByteArray& rawAudioByteArray, int sampleRate);
|
||||||
int interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
int interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
||||||
|
|
||||||
virtual void downloadFinished(const QByteArray& data) override;
|
signals:
|
||||||
|
void onSuccess(QByteArray data, bool stereo, bool ambisonic, float duration);
|
||||||
|
void onError(int error, QString str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QUrl _url;
|
||||||
|
QByteArray _data;
|
||||||
|
bool _isStereo;
|
||||||
|
bool _isAmbisonic;
|
||||||
|
float _duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QSharedPointer<Sound> SharedSoundPointer;
|
typedef QSharedPointer<Sound> SharedSoundPointer;
|
||||||
|
|
|
@ -241,6 +241,9 @@ void SendQueue::handshakeACK(SequenceNumber initialSequenceNumber) {
|
||||||
std::lock_guard<std::mutex> locker { _handshakeMutex };
|
std::lock_guard<std::mutex> locker { _handshakeMutex };
|
||||||
_hasReceivedHandshakeACK = true;
|
_hasReceivedHandshakeACK = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lastReceiverResponse = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
|
||||||
// Notify on the handshake ACK condition
|
// Notify on the handshake ACK condition
|
||||||
_handshakeACKCondition.notify_one();
|
_handshakeACKCondition.notify_one();
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,6 +293,7 @@ function addImage(image_data, isLoggedIn, canShare, isGifLoading, isShowingPrevi
|
||||||
isGif = img.src.split('.').pop().toLowerCase() === "gif";
|
isGif = img.src.split('.').pop().toLowerCase() === "gif";
|
||||||
imageContainer.appendChild(img);
|
imageContainer.appendChild(img);
|
||||||
document.getElementById("snapshot-images").appendChild(imageContainer);
|
document.getElementById("snapshot-images").appendChild(imageContainer);
|
||||||
|
img.onload = function () {
|
||||||
paths.push(image_data.localPath);
|
paths.push(image_data.localPath);
|
||||||
if (isGif) {
|
if (isGif) {
|
||||||
imageContainer.innerHTML += '<span class="gifLabel">GIF</span>';
|
imageContainer.innerHTML += '<span class="gifLabel">GIF</span>';
|
||||||
|
@ -306,6 +307,11 @@ function addImage(image_data, isLoggedIn, canShare, isGifLoading, isShowingPrevi
|
||||||
if (isShowingPreviousImages && isLoggedIn && image_data.story_id) {
|
if (isShowingPreviousImages && isLoggedIn && image_data.story_id) {
|
||||||
updateShareInfo(id, image_data.story_id);
|
updateShareInfo(id, image_data.story_id);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
img.onerror = function () {
|
||||||
|
img.onload = null;
|
||||||
|
img.src = image_data.errorPath;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
function showConfirmationMessage(selectedID, destination) {
|
function showConfirmationMessage(selectedID, destination) {
|
||||||
if (selectedID.id) {
|
if (selectedID.id) {
|
||||||
|
|
|
@ -82,11 +82,23 @@ function showElements(els, show) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateProperty(propertyName, propertyValue) {
|
||||||
|
var properties = {};
|
||||||
|
properties[propertyName] = propertyValue;
|
||||||
|
updateProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateProperties(properties) {
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
|
id: lastEntityID,
|
||||||
|
type: "update",
|
||||||
|
properties: properties
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
function createEmitCheckedPropertyUpdateFunction(propertyName) {
|
function createEmitCheckedPropertyUpdateFunction(propertyName) {
|
||||||
return function() {
|
return function() {
|
||||||
EventBridge.emitWebEvent(
|
updateProperty(propertyName, this.checked);
|
||||||
'{"id":' + lastEntityID + ', "type":"update", "properties":{"' + propertyName + '":' + this.checked + '}}'
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,13 +117,7 @@ function createEmitGroupCheckedPropertyUpdateFunction(group, propertyName) {
|
||||||
var properties = {};
|
var properties = {};
|
||||||
properties[group] = {};
|
properties[group] = {};
|
||||||
properties[group][propertyName] = this.checked;
|
properties[group][propertyName] = this.checked;
|
||||||
EventBridge.emitWebEvent(
|
updateProperties(properties);
|
||||||
JSON.stringify({
|
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: properties
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,10 +125,7 @@ function createEmitNumberPropertyUpdateFunction(propertyName, decimals) {
|
||||||
decimals = decimals == undefined ? 4 : decimals;
|
decimals = decimals == undefined ? 4 : decimals;
|
||||||
return function() {
|
return function() {
|
||||||
var value = parseFloat(this.value).toFixed(decimals);
|
var value = parseFloat(this.value).toFixed(decimals);
|
||||||
|
updateProperty(propertyName, value);
|
||||||
EventBridge.emitWebEvent(
|
|
||||||
'{"id":' + lastEntityID + ', "type":"update", "properties":{"' + propertyName + '":' + value + '}}'
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,28 +134,14 @@ function createEmitGroupNumberPropertyUpdateFunction(group, propertyName) {
|
||||||
var properties = {};
|
var properties = {};
|
||||||
properties[group] = {};
|
properties[group] = {};
|
||||||
properties[group][propertyName] = this.value;
|
properties[group][propertyName] = this.value;
|
||||||
EventBridge.emitWebEvent(
|
updateProperties(properties);
|
||||||
JSON.stringify({
|
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: properties,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function createEmitTextPropertyUpdateFunction(propertyName) {
|
function createEmitTextPropertyUpdateFunction(propertyName) {
|
||||||
return function() {
|
return function() {
|
||||||
var properties = {};
|
updateProperty(propertyName, this.value);
|
||||||
properties[propertyName] = this.value;
|
|
||||||
EventBridge.emitWebEvent(
|
|
||||||
JSON.stringify({
|
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: properties,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,62 +150,44 @@ function createEmitGroupTextPropertyUpdateFunction(group, propertyName) {
|
||||||
var properties = {};
|
var properties = {};
|
||||||
properties[group] = {};
|
properties[group] = {};
|
||||||
properties[group][propertyName] = this.value;
|
properties[group][propertyName] = this.value;
|
||||||
EventBridge.emitWebEvent(
|
updateProperties(properties);
|
||||||
JSON.stringify({
|
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: properties,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) {
|
function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) {
|
||||||
return function() {
|
return function() {
|
||||||
var data = {
|
var properties = {};
|
||||||
id: lastEntityID,
|
properties[property] = {
|
||||||
type: "update",
|
|
||||||
properties: {}
|
|
||||||
};
|
|
||||||
data.properties[property] = {
|
|
||||||
x: elX.value,
|
x: elX.value,
|
||||||
y: elY.value,
|
y: elY.value,
|
||||||
z: elZ.value,
|
z: elZ.value,
|
||||||
};
|
};
|
||||||
EventBridge.emitWebEvent(JSON.stringify(data));
|
updateProperties(properties);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, elZ) {
|
function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, elZ) {
|
||||||
return function() {
|
return function() {
|
||||||
var data = {
|
var properties = {};
|
||||||
id: lastEntityID,
|
properties[group] = {};
|
||||||
type: "update",
|
properties[group][property] = {
|
||||||
properties: {}
|
|
||||||
};
|
|
||||||
data.properties[group] = {};
|
|
||||||
data.properties[group][property] = {
|
|
||||||
x: elX.value,
|
x: elX.value,
|
||||||
y: elY.value,
|
y: elY.value,
|
||||||
z: elZ ? elZ.value : 0,
|
z: elZ ? elZ.value : 0,
|
||||||
};
|
};
|
||||||
EventBridge.emitWebEvent(JSON.stringify(data));
|
updateProperties(properties);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) {
|
function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) {
|
||||||
return function() {
|
return function() {
|
||||||
var data = {
|
var properties = {};
|
||||||
id: lastEntityID,
|
properties[property] = {
|
||||||
type: "update",
|
|
||||||
properties: {}
|
|
||||||
};
|
|
||||||
data.properties[property] = {
|
|
||||||
x: elX.value * multiplier,
|
x: elX.value * multiplier,
|
||||||
y: elY.value * multiplier,
|
y: elY.value * multiplier,
|
||||||
z: elZ.value * multiplier,
|
z: elZ.value * multiplier,
|
||||||
};
|
};
|
||||||
EventBridge.emitWebEvent(JSON.stringify(data));
|
updateProperties(properties);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,44 +198,35 @@ function createEmitColorPropertyUpdateFunction(property, elRed, elGreen, elBlue)
|
||||||
};
|
};
|
||||||
|
|
||||||
function emitColorPropertyUpdate(property, red, green, blue, group) {
|
function emitColorPropertyUpdate(property, red, green, blue, group) {
|
||||||
var data = {
|
var properties = {};
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: {}
|
|
||||||
};
|
|
||||||
if (group) {
|
if (group) {
|
||||||
data.properties[group] = {};
|
properties[group] = {};
|
||||||
data.properties[group][property] = {
|
properties[group][property] = {
|
||||||
red: red,
|
red: red,
|
||||||
green: green,
|
green: green,
|
||||||
blue: blue,
|
blue: blue,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
data.properties[property] = {
|
properties[property] = {
|
||||||
red: red,
|
red: red,
|
||||||
green: green,
|
green: green,
|
||||||
blue: blue,
|
blue: blue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
EventBridge.emitWebEvent(JSON.stringify(data));
|
updateProperties(properties);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function createEmitGroupColorPropertyUpdateFunction(group, property, elRed, elGreen, elBlue) {
|
function createEmitGroupColorPropertyUpdateFunction(group, property, elRed, elGreen, elBlue) {
|
||||||
return function() {
|
return function() {
|
||||||
var data = {
|
var properties = {};
|
||||||
id: lastEntityID,
|
properties[group] = {};
|
||||||
type: "update",
|
properties[group][property] = {
|
||||||
properties: {}
|
|
||||||
};
|
|
||||||
data.properties[group] = {};
|
|
||||||
|
|
||||||
data.properties[group][property] = {
|
|
||||||
red: elRed.value,
|
red: elRed.value,
|
||||||
green: elGreen.value,
|
green: elGreen.value,
|
||||||
blue: elBlue.value,
|
blue: elBlue.value,
|
||||||
};
|
};
|
||||||
EventBridge.emitWebEvent(JSON.stringify(data));
|
updateProperties(properties);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -277,18 +239,7 @@ function updateCheckedSubProperty(propertyName, propertyValue, subPropertyElemen
|
||||||
// We've unchecked, so remove
|
// We've unchecked, so remove
|
||||||
propertyValue = propertyValue.replace(subPropertyString + ",", "");
|
propertyValue = propertyValue.replace(subPropertyString + ",", "");
|
||||||
}
|
}
|
||||||
|
updateProperty(propertyName, propertyValue);
|
||||||
var _properties = {}
|
|
||||||
_properties[propertyName] = propertyValue;
|
|
||||||
|
|
||||||
EventBridge.emitWebEvent(
|
|
||||||
JSON.stringify({
|
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: _properties
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUserDataFromEditor(noUpdate) {
|
function setUserDataFromEditor(noUpdate) {
|
||||||
|
@ -314,18 +265,11 @@ function setUserDataFromEditor(noUpdate) {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
EventBridge.emitWebEvent(
|
updateProperty('userData', text);
|
||||||
JSON.stringify({
|
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: {
|
|
||||||
userData: text
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) {
|
function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) {
|
||||||
var properties = {};
|
var properties = {};
|
||||||
var parsedData = {};
|
var parsedData = {};
|
||||||
|
@ -372,13 +316,7 @@ function multiDataUpdater(groupName, updateKeyPair, userDataElement, defaults) {
|
||||||
|
|
||||||
userDataElement.value = properties['userData'];
|
userDataElement.value = properties['userData'];
|
||||||
|
|
||||||
EventBridge.emitWebEvent(
|
updateProperties(properties);
|
||||||
JSON.stringify({
|
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: properties,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
function userDataChanger(groupName, keyName, values, userDataElement, defaultValue) {
|
function userDataChanger(groupName, keyName, values, userDataElement, defaultValue) {
|
||||||
var val = {}, def = {};
|
var val = {}, def = {};
|
||||||
|
@ -900,7 +838,6 @@ function loaded() {
|
||||||
elCloneable.checked = parsedUserData["grabbableKey"].cloneable;
|
elCloneable.checked = parsedUserData["grabbableKey"].cloneable;
|
||||||
elCloneableGroup.style.display = elCloneable.checked ? "block": "none";
|
elCloneableGroup.style.display = elCloneable.checked ? "block": "none";
|
||||||
elCloneableDynamic.checked = parsedUserData["grabbableKey"].cloneDynamic ? parsedUserData["grabbableKey"].cloneDynamic : properties.dynamic;
|
elCloneableDynamic.checked = parsedUserData["grabbableKey"].cloneDynamic ? parsedUserData["grabbableKey"].cloneDynamic : properties.dynamic;
|
||||||
elDynamic.checked = elCloneable.checked ? false: properties.dynamic;
|
|
||||||
if (elCloneable.checked) {
|
if (elCloneable.checked) {
|
||||||
if ("cloneLifetime" in parsedUserData["grabbableKey"]) {
|
if ("cloneLifetime" in parsedUserData["grabbableKey"]) {
|
||||||
elCloneableLifetime.value = parsedUserData["grabbableKey"].cloneLifetime ? parsedUserData["grabbableKey"].cloneLifetime : 300;
|
elCloneableLifetime.value = parsedUserData["grabbableKey"].cloneLifetime ? parsedUserData["grabbableKey"].cloneLifetime : 300;
|
||||||
|
@ -1213,17 +1150,22 @@ function loaded() {
|
||||||
elCloneable.addEventListener('change', function (event) {
|
elCloneable.addEventListener('change', function (event) {
|
||||||
var checked = event.target.checked;
|
var checked = event.target.checked;
|
||||||
if (checked) {
|
if (checked) {
|
||||||
multiDataUpdater("grabbableKey",
|
multiDataUpdater("grabbableKey", {
|
||||||
{cloneLifetime: elCloneableLifetime, cloneLimit: elCloneableLimit, cloneDynamic: elCloneableDynamic, cloneable: event.target},
|
cloneLifetime: elCloneableLifetime,
|
||||||
elUserData, {});
|
cloneLimit: elCloneableLimit,
|
||||||
|
cloneDynamic: elCloneableDynamic,
|
||||||
|
cloneable: event.target,
|
||||||
|
grabbable: null
|
||||||
|
}, elUserData, {});
|
||||||
elCloneableGroup.style.display = "block";
|
elCloneableGroup.style.display = "block";
|
||||||
EventBridge.emitWebEvent(
|
updateProperty('dynamic', false);
|
||||||
'{"id":' + lastEntityID + ', "type":"update", "properties":{"dynamic":false, "grabbable": false}}'
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
multiDataUpdater("grabbableKey",
|
multiDataUpdater("grabbableKey", {
|
||||||
{cloneLifetime: null, cloneLimit: null, cloneDynamic: null, cloneable: false},
|
cloneLifetime: null,
|
||||||
elUserData, {});
|
cloneLimit: null,
|
||||||
|
cloneDynamic: null,
|
||||||
|
cloneable: false
|
||||||
|
}, elUserData, {});
|
||||||
elCloneableGroup.style.display = "none";
|
elCloneableGroup.style.display = "none";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1258,15 +1200,7 @@ function loaded() {
|
||||||
showUserDataTextArea();
|
showUserDataTextArea();
|
||||||
showNewJSONEditorButton();
|
showNewJSONEditorButton();
|
||||||
hideSaveUserDataButton();
|
hideSaveUserDataButton();
|
||||||
var properties = {};
|
updateProperty('userData', elUserData.value)
|
||||||
properties['userData'] = elUserData.value;
|
|
||||||
EventBridge.emitWebEvent(
|
|
||||||
JSON.stringify({
|
|
||||||
id: lastEntityID,
|
|
||||||
type: "update",
|
|
||||||
properties: properties,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
elSaveUserData.addEventListener("click", function() {
|
elSaveUserData.addEventListener("click", function() {
|
||||||
|
|
|
@ -613,7 +613,6 @@
|
||||||
error = "All participants must be logged in to connect.";
|
error = "All participants must be logged in to connect.";
|
||||||
}
|
}
|
||||||
result = error ? {status: 'error', connection: error} : response;
|
result = error ? {status: 'error', connection: error} : response;
|
||||||
UserActivityLogger.makeUserConnection(connectingId, false, error || response);
|
|
||||||
connectionRequestCompleted();
|
connectionRequestCompleted();
|
||||||
} else {
|
} else {
|
||||||
result = response;
|
result = response;
|
||||||
|
|
|
@ -273,7 +273,8 @@ function fillImageDataFromPrevious() {
|
||||||
localPath: previousStillSnapPath,
|
localPath: previousStillSnapPath,
|
||||||
story_id: previousStillSnapStoryID,
|
story_id: previousStillSnapStoryID,
|
||||||
blastButtonDisabled: previousStillSnapBlastingDisabled,
|
blastButtonDisabled: previousStillSnapBlastingDisabled,
|
||||||
hifiButtonDisabled: previousStillSnapHifiSharingDisabled
|
hifiButtonDisabled: previousStillSnapHifiSharingDisabled,
|
||||||
|
errorPath: Script.resolvePath(Script.resourcesPath() + 'snapshot/img/no-image.jpg')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (previousAnimatedSnapPath !== "") {
|
if (previousAnimatedSnapPath !== "") {
|
||||||
|
@ -281,7 +282,8 @@ function fillImageDataFromPrevious() {
|
||||||
localPath: previousAnimatedSnapPath,
|
localPath: previousAnimatedSnapPath,
|
||||||
story_id: previousAnimatedSnapStoryID,
|
story_id: previousAnimatedSnapStoryID,
|
||||||
blastButtonDisabled: previousAnimatedSnapBlastingDisabled,
|
blastButtonDisabled: previousAnimatedSnapBlastingDisabled,
|
||||||
hifiButtonDisabled: previousAnimatedSnapHifiSharingDisabled
|
hifiButtonDisabled: previousAnimatedSnapHifiSharingDisabled,
|
||||||
|
errorPath: Script.resolvePath(Script.resourcesPath() + 'snapshot/img/no-image.jpg')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue