mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into editHandleDebugWindowFix
This commit is contained in:
commit
4b1d2af5fe
15 changed files with 8919 additions and 50 deletions
|
@ -21,6 +21,7 @@ To produce an executable installer on Windows, the following are required:
|
|||
- [NSISpcre Plug-in for Nullsoft](http://nsis.sourceforge.net/NSISpcre_plug-in) - 1.0
|
||||
- [nsisSlideshow Plug-in for Nullsoft](http://nsis.sourceforge.net/NsisSlideshow_plug-in) - 1.7
|
||||
- [Nsisunz plug-in for Nullsoft](http://nsis.sourceforge.net/Nsisunz_plug-in)
|
||||
- [ApplicationID plug-in for Nullsoft](http://nsis.sourceforge.net/ApplicationID_plug-in) - 1.0
|
||||
|
||||
Run the `package` target to create an executable installer using the Nullsoft Scriptable Install System.
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(BUILD_GLOBAL_SERVICES "DEVELOPMENT")
|
||||
set(USE_STABLE_GLOBAL_SERVICES 0)
|
||||
set(BUILD_NUMBER 0)
|
||||
set(APP_USER_MODEL_ID "com.highfidelity.sandbox-dev")
|
||||
|
||||
set_from_env(RELEASE_TYPE RELEASE_TYPE "DEV")
|
||||
set_from_env(RELEASE_NUMBER RELEASE_NUMBER "")
|
||||
|
@ -172,6 +173,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
if (PRODUCTION_BUILD)
|
||||
set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface")
|
||||
set(CONSOLE_SHORTCUT_NAME "Sandbox")
|
||||
set(APP_USER_MODEL_ID "com.highfidelity.sandbox")
|
||||
else ()
|
||||
set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface - ${BUILD_VERSION_NO_SHA}")
|
||||
set(CONSOLE_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION_NO_SHA}")
|
||||
|
|
|
@ -49,3 +49,4 @@ set(ADD_REMOVE_ICON_PATH "@ADD_REMOVE_ICON_PATH@")
|
|||
set(SERVER_COMPONENT_CONDITIONAL "@SERVER_COMPONENT_CONDITIONAL@")
|
||||
set(CLIENT_COMPONENT_CONDITIONAL "@CLIENT_COMPONENT_CONDITIONAL@")
|
||||
set(INSTALLER_TYPE "@INSTALLER_TYPE@")
|
||||
set(APP_USER_MODEL_ID "@APP_USER_MODEL_ID@")
|
||||
|
|
|
@ -905,6 +905,8 @@ Function HandlePostInstallOptions
|
|||
${If} $DesktopServerState == ${BST_CHECKED}
|
||||
CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
|
||||
!insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES
|
||||
; Set appUserModelId
|
||||
ApplicationID::Set "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@"
|
||||
${Else}
|
||||
!insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO
|
||||
${EndIf}
|
||||
|
@ -1162,6 +1164,8 @@ Section "-Core installation"
|
|||
${If} @SERVER_COMPONENT_CONDITIONAL@
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \
|
||||
"$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"
|
||||
; Set appUserModelId
|
||||
ApplicationID::Set "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@"
|
||||
${EndIf}
|
||||
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@UNINSTALLER_NAME@"
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
"buildNumber": "@BUILD_NUMBER@",
|
||||
"stableBuild": "@STABLE_BUILD@",
|
||||
"buildIdentifier": "@BUILD_VERSION@",
|
||||
"organization": "@BUILD_ORGANIZATION@"
|
||||
"organization": "@BUILD_ORGANIZATION@",
|
||||
"appUserModelId": "@APP_USER_MODEL_ID@"
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "AudioLogging.h"
|
||||
#include "AudioSRC.h"
|
||||
|
||||
#include "flump3dec.h"
|
||||
|
||||
QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) {
|
||||
return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership);
|
||||
}
|
||||
|
@ -90,19 +92,35 @@ void SoundProcessor::run() {
|
|||
QString fileName = _url.fileName().toLower();
|
||||
|
||||
static const QString WAV_EXTENSION = ".wav";
|
||||
static const QString MP3_EXTENSION = ".mp3";
|
||||
static const QString RAW_EXTENSION = ".raw";
|
||||
|
||||
if (fileName.endsWith(WAV_EXTENSION)) {
|
||||
|
||||
QByteArray outputAudioByteArray;
|
||||
|
||||
int sampleRate = interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
||||
if (sampleRate == 0) {
|
||||
qCDebug(audio) << "Unsupported WAV file type";
|
||||
qCWarning(audio) << "Unsupported WAV file type";
|
||||
emit onError(300, "Failed to load sound file, reason: unsupported WAV file type");
|
||||
return;
|
||||
}
|
||||
|
||||
downSample(outputAudioByteArray, sampleRate);
|
||||
|
||||
} else if (fileName.endsWith(MP3_EXTENSION)) {
|
||||
|
||||
QByteArray outputAudioByteArray;
|
||||
|
||||
int sampleRate = interpretAsMP3(rawAudioByteArray, outputAudioByteArray);
|
||||
if (sampleRate == 0) {
|
||||
qCWarning(audio) << "Unsupported MP3 file type";
|
||||
emit onError(300, "Failed to load sound file, reason: unsupported MP3 file type");
|
||||
return;
|
||||
}
|
||||
|
||||
downSample(outputAudioByteArray, sampleRate);
|
||||
|
||||
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
||||
// check if this was a stereo raw file
|
||||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||
|
@ -113,8 +131,9 @@ void SoundProcessor::run() {
|
|||
|
||||
// Process as 48khz RAW file
|
||||
downSample(rawAudioByteArray, 48000);
|
||||
|
||||
} else {
|
||||
qCDebug(audio) << "Unknown sound file type";
|
||||
qCWarning(audio) << "Unknown sound file type";
|
||||
emit onError(300, "Failed to load sound file, reason: unknown sound file type");
|
||||
return;
|
||||
}
|
||||
|
@ -204,7 +223,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
// Read the "RIFF" chunk
|
||||
RIFFHeader riff;
|
||||
if (waveStream.readRawData((char*)&riff, sizeof(RIFFHeader)) != sizeof(RIFFHeader)) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -212,11 +231,11 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
if (strncmp(riff.descriptor.id, "RIFF", 4) == 0) {
|
||||
waveStream.setByteOrder(QDataStream::LittleEndian);
|
||||
} else {
|
||||
qCDebug(audio) << "Currently not supporting big-endian audio files.";
|
||||
qCWarning(audio) << "Currently not supporting big-endian audio files.";
|
||||
return 0;
|
||||
}
|
||||
if (strncmp(riff.type, "WAVE", 4) != 0) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -224,7 +243,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
chunk fmt;
|
||||
while (true) {
|
||||
if (waveStream.readRawData((char*)&fmt, sizeof(chunk)) != sizeof(chunk)) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
if (strncmp(fmt.id, "fmt ", 4) == 0) {
|
||||
|
@ -236,14 +255,14 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
// Read the "fmt " chunk
|
||||
WAVEFormat wave;
|
||||
if (waveStream.readRawData((char*)&wave, sizeof(WAVEFormat)) != sizeof(WAVEFormat)) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse the "fmt " chunk
|
||||
if (qFromLittleEndian<quint16>(wave.audioFormat) != WAVEFORMAT_PCM &&
|
||||
qFromLittleEndian<quint16>(wave.audioFormat) != WAVEFORMAT_EXTENSIBLE) {
|
||||
qCDebug(audio) << "Currently not supporting non PCM audio files.";
|
||||
qCWarning(audio) << "Currently not supporting non PCM audio files.";
|
||||
return 0;
|
||||
}
|
||||
if (qFromLittleEndian<quint16>(wave.numChannels) == 2) {
|
||||
|
@ -251,11 +270,11 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
} else if (qFromLittleEndian<quint16>(wave.numChannels) == 4) {
|
||||
_isAmbisonic = true;
|
||||
} else if (qFromLittleEndian<quint16>(wave.numChannels) != 1) {
|
||||
qCDebug(audio) << "Currently not supporting audio files with other than 1/2/4 channels.";
|
||||
qCWarning(audio) << "Currently not supporting audio files with other than 1/2/4 channels.";
|
||||
return 0;
|
||||
}
|
||||
if (qFromLittleEndian<quint16>(wave.bitsPerSample) != 16) {
|
||||
qCDebug(audio) << "Currently not supporting non 16bit audio files.";
|
||||
qCWarning(audio) << "Currently not supporting non 16bit audio files.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -266,7 +285,7 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
chunk data;
|
||||
while (true) {
|
||||
if (waveStream.readRawData((char*)&data, sizeof(chunk)) != sizeof(chunk)) {
|
||||
qCDebug(audio) << "Not a valid WAVE file.";
|
||||
qCWarning(audio) << "Not a valid WAVE file.";
|
||||
return 0;
|
||||
}
|
||||
if (strncmp(data.id, "data", 4) == 0) {
|
||||
|
@ -279,10 +298,101 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
|
|||
quint32 outputAudioByteArraySize = qFromLittleEndian<quint32>(data.size);
|
||||
outputAudioByteArray.resize(outputAudioByteArraySize);
|
||||
if (waveStream.readRawData(outputAudioByteArray.data(), outputAudioByteArraySize) != (int)outputAudioByteArraySize) {
|
||||
qCDebug(audio) << "Error reading WAV file";
|
||||
qCWarning(audio) << "Error reading WAV file";
|
||||
return 0;
|
||||
}
|
||||
|
||||
_duration = (float)(outputAudioByteArraySize / (wave.sampleRate * wave.numChannels * wave.bitsPerSample / 8.0f));
|
||||
return wave.sampleRate;
|
||||
}
|
||||
|
||||
// returns MP3 sample rate, used for resampling
|
||||
int SoundProcessor::interpretAsMP3(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) {
|
||||
using namespace flump3dec;
|
||||
|
||||
static const int MP3_SAMPLES_MAX = 1152;
|
||||
static const int MP3_CHANNELS_MAX = 2;
|
||||
static const int MP3_BUFFER_SIZE = MP3_SAMPLES_MAX * MP3_CHANNELS_MAX * sizeof(int16_t);
|
||||
uint8_t mp3Buffer[MP3_BUFFER_SIZE];
|
||||
|
||||
// create bitstream
|
||||
Bit_stream_struc *bitstream = bs_new();
|
||||
if (bitstream == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// create decoder
|
||||
mp3tl *decoder = mp3tl_new(bitstream, MP3TL_MODE_16BIT);
|
||||
if (decoder == nullptr) {
|
||||
bs_free(bitstream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// initialize
|
||||
bs_set_data(bitstream, (uint8_t*)inputAudioByteArray.data(), inputAudioByteArray.size());
|
||||
int frameCount = 0;
|
||||
int sampleRate = 0;
|
||||
int numChannels = 0;
|
||||
|
||||
// skip ID3 tag, if present
|
||||
Mp3TlRetcode result = mp3tl_skip_id3(decoder);
|
||||
|
||||
while (!(result == MP3TL_ERR_NO_SYNC || result == MP3TL_ERR_NEED_DATA)) {
|
||||
|
||||
mp3tl_sync(decoder);
|
||||
|
||||
// find MP3 header
|
||||
const fr_header *header = nullptr;
|
||||
result = mp3tl_decode_header(decoder, &header);
|
||||
|
||||
if (result == MP3TL_ERR_OK) {
|
||||
|
||||
if (frameCount++ == 0) {
|
||||
|
||||
qCDebug(audio) << "Decoding MP3 with bitrate =" << header->bitrate
|
||||
<< "sample rate =" << header->sample_rate
|
||||
<< "channels =" << header->channels;
|
||||
|
||||
// save header info
|
||||
sampleRate = header->sample_rate;
|
||||
numChannels = header->channels;
|
||||
|
||||
// skip Xing header, if present
|
||||
result = mp3tl_skip_xing(decoder, header);
|
||||
}
|
||||
|
||||
// decode MP3 frame
|
||||
if (result == MP3TL_ERR_OK) {
|
||||
|
||||
result = mp3tl_decode_frame(decoder, mp3Buffer, MP3_BUFFER_SIZE);
|
||||
|
||||
// fill bad frames with silence
|
||||
int len = header->frame_samples * header->channels * sizeof(int16_t);
|
||||
if (result == MP3TL_ERR_BAD_FRAME) {
|
||||
memset(mp3Buffer, 0, len);
|
||||
}
|
||||
|
||||
if (result == MP3TL_ERR_OK || result == MP3TL_ERR_BAD_FRAME) {
|
||||
outputAudioByteArray.append((char*)mp3Buffer, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free decoder
|
||||
mp3tl_free(decoder);
|
||||
|
||||
// free bitstream
|
||||
bs_free(bitstream);
|
||||
|
||||
int outputAudioByteArraySize = outputAudioByteArray.size();
|
||||
if (outputAudioByteArraySize == 0) {
|
||||
qCWarning(audio) << "Error decoding MP3 file";
|
||||
return 0;
|
||||
}
|
||||
|
||||
_isStereo = (numChannels == 2);
|
||||
_isAmbisonic = false;
|
||||
_duration = (float)outputAudioByteArraySize / (sampleRate * numChannels * sizeof(int16_t));
|
||||
return sampleRate;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
|
||||
void downSample(const QByteArray& rawAudioByteArray, int sampleRate);
|
||||
int interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
||||
int interpretAsMP3(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
|
||||
|
||||
signals:
|
||||
void onSuccess(QByteArray data, bool stereo, bool ambisonic, float duration);
|
||||
|
|
8205
libraries/audio/src/flump3dec.cpp
Normal file
8205
libraries/audio/src/flump3dec.cpp
Normal file
File diff suppressed because it is too large
Load diff
428
libraries/audio/src/flump3dec.h
Normal file
428
libraries/audio/src/flump3dec.h
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* FLUENDO S.A.
|
||||
* Copyright (C) <2005 - 2011> <support@fluendo.com>
|
||||
*
|
||||
* This Source Code is licensed under MIT license and the explanations attached
|
||||
* in MIT License Statements.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* MIT license Statements for Fluendo's mp3 plug-in Source Code
|
||||
* ------------------------------------------------------------
|
||||
*
|
||||
* Fluendo's mp3 software Source Code (the "Source Code") is licensed under the
|
||||
* MIT license provisions.
|
||||
*
|
||||
* The MIT license is an open source license that permits the User to operate and
|
||||
* use in many forms the Source Code, which would be governed under its
|
||||
* regulations.
|
||||
*
|
||||
* The purpose of this note is to clarify the intellectual property rights granted
|
||||
* over the Source Code by Fluendo, as well as other legal issues that concern
|
||||
* your use of it.
|
||||
*
|
||||
* MIT license contents and provisions
|
||||
* -----------------------------------
|
||||
*
|
||||
* The MIT license allows you to do the following things with the Source Code:
|
||||
*
|
||||
* - Copy and use the Source Code alone or jointly with other code for any
|
||||
* purposes.
|
||||
* Copy of the Source Code is not limited and is royalty-free.
|
||||
*
|
||||
* - Merge the Source Code with other code for developing new applications with no
|
||||
* limits.
|
||||
*
|
||||
* - Modifying the Source Code for developing the plug-in or for implementing the
|
||||
* plug-in in other applications for any purposes. The MIT License does not
|
||||
* require you to share these modifications with anyone.
|
||||
*
|
||||
* - Publish, distribute, sublicense and sell copies of the Source Code to third
|
||||
* parties.
|
||||
*
|
||||
* - Permit anyone to whom the Source Code is licensed to enjoy the rights above
|
||||
* subject to the MIT license provisions.
|
||||
*
|
||||
* By licensing this Source Code under the MIT License, Fluendo is offering to the
|
||||
* community the rights set out above without restriction and without any
|
||||
* obligation for the User of the Source Code to release his/her modifications
|
||||
* back to the community. Anyone operating with the Source Code released from
|
||||
* Fluendo must grant the same MIT license rights to the community, except for any
|
||||
* modifications operated on the Source Code which can be granted under a
|
||||
* different license (even a proprietary license).
|
||||
*
|
||||
* All these rights granted to the User for the Source Code hold a limitation
|
||||
* which is to include MIT permission notice and the following copyright notice:
|
||||
* "Copyright 2005 Fluendo, S.L. This Source Code is licensed under MIT license
|
||||
* and the explanations attached in MIT License Statements". These notices shall
|
||||
* be included in all copies of the Source Code or in substantial parts of the
|
||||
* Source Code which may be released separately or with modifications.
|
||||
*
|
||||
* Patents over the plug-in and/or Source Code
|
||||
* -------------------------------------------
|
||||
*
|
||||
* The binaries that can be created by compiling this Source Code released by
|
||||
* Fluendo might be covered by patents in various parts of the world. Fluendo
|
||||
* does not own or claim to own any patents on the techniques used in the code.
|
||||
* (Such patents are owned or claimed to be owned by Thompson Licensing, S.A. and
|
||||
* some other entities as the case may be).
|
||||
*
|
||||
* Fluendo has got the relevant licenses to cover its own activities with the
|
||||
* Source Code but it is not authorized to sublicense nor to grant the rights
|
||||
* which it has acquired over the patents. In this sense, you can work and deal
|
||||
* freely with the Source Code under MIT provisions set out above, bearing in mind
|
||||
* that some activities might not be allowed under applicable patent regulations
|
||||
* and that Fluendo is not granting any rights in relation to such patents.
|
||||
*
|
||||
* The patent license granted to Fluendo only covers Fluendo's own Software and
|
||||
* Source Code activities. In any case, this software license does not allow you
|
||||
* to redistribute or copy complete, ready to use mp3 software decoder binaries
|
||||
* made from the Source Code as made available by Fluendo. You can of course
|
||||
* distribute binaries you make yourself under any terms allowed by the MIT
|
||||
* license and whatever necessary rights you have or have acquired according to
|
||||
* applicable patent regulations.
|
||||
*
|
||||
* As Fluendo can not assure that any of the activities you undertake do not
|
||||
* infringe any patents or other industrial or intellectual property rights,
|
||||
* Fluendo hereby disclaims any liability for any patent infringement that may be
|
||||
* claimed to you or to any other person from any legitimate right’s owner, as
|
||||
* stated in MIT license. So it is your responsibility to get information and to
|
||||
* acquire the necessary patent licenses to undertake your activities legally.
|
||||
*/
|
||||
|
||||
//
|
||||
// Modifications and bug fixes copyright 2018 High Fidelity, Inc.
|
||||
// Now passes ISO/IEC 11172-4 "full accuracy" compliance testing.
|
||||
//
|
||||
|
||||
#ifndef __FLUMP3DEC_H__
|
||||
#define __FLUMP3DEC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
#define G_GINT64_FORMAT "lld"
|
||||
#define G_GUINT64_FORMAT "llu"
|
||||
|
||||
#define GST_LOG(f, ...) do { printf(f "\n", __VA_ARGS__); } while (0)
|
||||
#define GST_DEBUG(f, ...) do { printf(f "\n", __VA_ARGS__); } while (0)
|
||||
#define GST_WARNING(f, ...) do { printf(f "\n", __VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define GST_LOG(f, ...) do {} while (0)
|
||||
#define GST_DEBUG(f, ...) do {} while (0)
|
||||
#define GST_WARNING(f, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define g_assert(cond) assert(cond)
|
||||
#define g_return_if_fail(cond) { if (!(cond)) return; }
|
||||
#define g_return_val_if_fail(cond, val) { if (!(cond)) return (val); }
|
||||
|
||||
namespace flump3dec {
|
||||
|
||||
typedef char gchar;
|
||||
typedef unsigned char guchar;
|
||||
typedef int gint;
|
||||
typedef unsigned int guint;
|
||||
typedef float gfloat;
|
||||
typedef double gdouble;
|
||||
typedef int gboolean;
|
||||
typedef size_t gsize;
|
||||
|
||||
typedef int8_t gint8;
|
||||
typedef uint8_t guint8;
|
||||
typedef int16_t gint16;
|
||||
typedef uint16_t guint16;
|
||||
typedef int32_t gint32;
|
||||
typedef uint32_t guint32;
|
||||
typedef int64_t gint64;
|
||||
typedef uint64_t guint64;
|
||||
|
||||
/* Accumulator optimization on bitstream management */
|
||||
#define ENABLE_OPT_BS 1
|
||||
|
||||
/* Bit stream reader definitions */
|
||||
#define MAX_LENGTH 32 /* Maximum length of word written or
|
||||
read from bit stream */
|
||||
#define BS_BYTE_SIZE 8
|
||||
|
||||
#if ENABLE_OPT_BS
|
||||
#define BS_ACUM_SIZE 32
|
||||
#else
|
||||
#define BS_ACUM_SIZE 8
|
||||
#endif
|
||||
|
||||
typedef struct BSReader
|
||||
{
|
||||
guint64 bitpos; /* Number of bits read so far */
|
||||
|
||||
gsize size; /* Number of bytes in the buffer list */
|
||||
const guint8 *data; /* Current data buffer */
|
||||
guint8 *cur_byte; /* ptr to the current byte */
|
||||
guint8 cur_bit; /* the next bit to be used in the current byte,
|
||||
* numbered from 8 down to 1 */
|
||||
gsize cur_used; /* Number of bytes _completely_ consumed out of
|
||||
* the 'cur buffer' */
|
||||
} BSReader;
|
||||
|
||||
typedef struct Bit_stream_struc
|
||||
{
|
||||
BSReader master; /* Master tracking position, advanced
|
||||
* by bs_consume() */
|
||||
BSReader read; /* Current read position, set back to the
|
||||
* master by bs_reset() */
|
||||
} Bit_stream_struc;
|
||||
|
||||
/* Create and initialise a new bitstream reader */
|
||||
Bit_stream_struc *bs_new ();
|
||||
|
||||
/* Release a bitstream reader */
|
||||
void bs_free (Bit_stream_struc * bs);
|
||||
|
||||
/* Reset the current read position to the master position */
|
||||
static inline void
|
||||
bs_reset (Bit_stream_struc * bs)
|
||||
{
|
||||
memcpy (&bs->read, &bs->master, sizeof (BSReader));
|
||||
}
|
||||
|
||||
/* Reset master and read states */
|
||||
static inline void
|
||||
bs_flush (Bit_stream_struc * bs)
|
||||
{
|
||||
g_return_if_fail (bs != NULL);
|
||||
|
||||
bs->master.cur_bit = 8;
|
||||
bs->master.size = 0;
|
||||
bs->master.cur_used = 0;
|
||||
bs->master.cur_byte = NULL;
|
||||
bs->master.data = NULL;
|
||||
bs->master.bitpos = 0;
|
||||
|
||||
bs_reset (bs);
|
||||
}
|
||||
|
||||
/* Set data as the stream for processing */
|
||||
gboolean bs_set_data (Bit_stream_struc * bs, const guint8 * data, gsize size);
|
||||
|
||||
/* Advance the master position by Nbits */
|
||||
void bs_consume (Bit_stream_struc * bs, guint32 Nbits);
|
||||
|
||||
/* Number of bits available for reading */
|
||||
static inline gsize bs_bits_avail (Bit_stream_struc * bs)
|
||||
{
|
||||
return ((bs->read.size - bs->read.cur_used) * 8 + (bs->read.cur_bit - 8));
|
||||
}
|
||||
|
||||
/* Extract N bytes from the bitstream into the out array. */
|
||||
void bs_getbytes (Bit_stream_struc * bs, guint8 * out, guint32 N);
|
||||
|
||||
/* Advance the read pointer by N bits */
|
||||
void bs_skipbits (Bit_stream_struc * bs, guint32 N);
|
||||
|
||||
/* give number of consumed bytes */
|
||||
static inline gsize bs_get_consumed (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs->master.cur_used;
|
||||
}
|
||||
|
||||
/* Current bitstream position in bits */
|
||||
static inline guint64
|
||||
bs_pos (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs->master.bitpos;
|
||||
}
|
||||
|
||||
/* Current read bitstream position in bits */
|
||||
static inline guint64
|
||||
bs_read_pos (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs->read.bitpos;
|
||||
}
|
||||
|
||||
/* Advances the read position to the first bit of next frame or
|
||||
* last byte in the buffer when the sync code is not found */
|
||||
gboolean bs_seek_sync (Bit_stream_struc * bs);
|
||||
|
||||
/* Read N bits from the stream */
|
||||
/* bs - bit stream structure */
|
||||
/* N - number of bits to read from the bit stream */
|
||||
/* v - output value */
|
||||
static inline guint32
|
||||
bs_getbits (Bit_stream_struc * bs, guint32 N)
|
||||
{
|
||||
guint32 val = 0;
|
||||
gint j = N;
|
||||
|
||||
g_assert (N <= MAX_LENGTH);
|
||||
|
||||
while (j > 0) {
|
||||
gint tmp;
|
||||
gint k;
|
||||
gint mask;
|
||||
|
||||
/* Move to the next byte if we consumed the current one */
|
||||
if (bs->read.cur_bit == 0) {
|
||||
bs->read.cur_bit = 8;
|
||||
bs->read.cur_used++;
|
||||
bs->read.cur_byte++;
|
||||
}
|
||||
|
||||
/* Protect against data limit */
|
||||
if ((bs->read.cur_used >= bs->read.size)) {
|
||||
GST_WARNING ("Attempted to read beyond data");
|
||||
/* Return the bits we got so far */
|
||||
return val;
|
||||
}
|
||||
/* Take as many bits as we can from the current byte */
|
||||
k = MIN (j, bs->read.cur_bit);
|
||||
|
||||
/* We want the k bits from the current byte, starting from
|
||||
* the cur_bit. Mask out the top 'already used' bits, then shift
|
||||
* the bits we want down to the bottom */
|
||||
mask = (1 << bs->read.cur_bit) - 1;
|
||||
tmp = bs->read.cur_byte[0] & mask;
|
||||
|
||||
/* Trim off the bits we're leaving for next time */
|
||||
tmp = tmp >> (bs->read.cur_bit - k);
|
||||
|
||||
/* Adjust our tracking vars */
|
||||
bs->read.cur_bit -= k;
|
||||
j -= k;
|
||||
bs->read.bitpos += k;
|
||||
|
||||
/* Put these bits in the right spot in the output */
|
||||
val |= tmp << j;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Read 1 bit from the stream */
|
||||
static inline guint32
|
||||
bs_get1bit (Bit_stream_struc * bs)
|
||||
{
|
||||
return bs_getbits (bs, 1);
|
||||
}
|
||||
|
||||
/* read the next byte aligned N bits from the bit stream */
|
||||
static inline guint32
|
||||
bs_getbits_aligned (Bit_stream_struc * bs, guint32 N)
|
||||
{
|
||||
guint32 align;
|
||||
|
||||
align = bs->read.cur_bit;
|
||||
if (align != 8 && align != 0)
|
||||
bs_getbits (bs, align);
|
||||
|
||||
return bs_getbits (bs, N);
|
||||
}
|
||||
|
||||
/* MPEG Header Definitions - ID Bit Values */
|
||||
#define MPEG_VERSION_1 0x03
|
||||
#define MPEG_VERSION_2 0x02
|
||||
#define MPEG_VERSION_2_5 0x00
|
||||
|
||||
/* Header Information Structure */
|
||||
typedef struct
|
||||
{
|
||||
/* Stuff read straight from the MPEG header */
|
||||
guint version;
|
||||
guint layer;
|
||||
gboolean error_protection;
|
||||
|
||||
gint bitrate_idx; /* Index into the bitrate tables */
|
||||
guint srate_idx; /* Index into the sample rate table */
|
||||
|
||||
gboolean padding;
|
||||
gboolean extension;
|
||||
guint mode;
|
||||
guint mode_ext;
|
||||
gboolean copyright;
|
||||
gboolean original;
|
||||
guint emphasis;
|
||||
|
||||
/* Derived attributes */
|
||||
guint bitrate; /* Bitrate of the frame, kbps */
|
||||
guint sample_rate; /* sample rate in Hz */
|
||||
guint sample_size; /* in bits */
|
||||
guint frame_samples; /* Number of samples per channels in this
|
||||
frame */
|
||||
guint channels; /* Number of channels in the frame */
|
||||
|
||||
guint bits_per_slot; /* Number of bits per slot */
|
||||
guint frame_slots; /* Total number of data slots in this frame */
|
||||
guint main_slots; /* Slots of main data in this frame */
|
||||
guint frame_bits; /* Number of bits in the frame, including header
|
||||
and sync word */
|
||||
guint side_info_slots; /* Number of slots of side info in the frame */
|
||||
} fr_header;
|
||||
|
||||
typedef struct mp3tl mp3tl;
|
||||
typedef enum
|
||||
{
|
||||
MP3TL_ERR_OK = 0, /* Successful return code */
|
||||
MP3TL_ERR_NO_SYNC, /* There was no sync word in the data buffer */
|
||||
MP3TL_ERR_NEED_DATA, /* Not enough data in the buffer for the requested op */
|
||||
MP3TL_ERR_BAD_FRAME, /* The frame data was corrupt and skipped */
|
||||
MP3TL_ERR_STREAM, /* Encountered invalid data in the stream */
|
||||
MP3TL_ERR_UNSUPPORTED_STREAM, /* Encountered valid but unplayable data in
|
||||
* the stream */
|
||||
MP3TL_ERR_PARAM, /* Invalid parameter was passed in */
|
||||
MP3TL_ERR_UNKNOWN /* Unspecified internal decoder error (bug) */
|
||||
} Mp3TlRetcode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MP3TL_MODE_16BIT = 0 /* Decoder mode to use */
|
||||
} Mp3TlMode;
|
||||
|
||||
mp3tl *mp3tl_new (Bit_stream_struc * bs, Mp3TlMode mode);
|
||||
|
||||
void mp3tl_free (mp3tl * tl);
|
||||
|
||||
void mp3tl_set_eos (mp3tl * tl, gboolean more_data);
|
||||
Mp3TlRetcode mp3tl_sync (mp3tl * tl);
|
||||
Mp3TlRetcode mp3tl_gather_frame (mp3tl * tl, guint64 * _offset, gint * _length);
|
||||
Mp3TlRetcode mp3tl_decode_header (mp3tl * tl, const fr_header ** ret_hdr);
|
||||
Mp3TlRetcode mp3tl_skip_frame (mp3tl * tl);
|
||||
Mp3TlRetcode mp3tl_decode_frame (mp3tl * tl, guint8 * samples, guint bufsize);
|
||||
const char *mp3tl_get_err_reason (mp3tl * tl);
|
||||
void mp3tl_flush (mp3tl * tl);
|
||||
|
||||
Mp3TlRetcode mp3tl_skip_id3 (mp3tl * tl);
|
||||
Mp3TlRetcode mp3tl_skip_xing (mp3tl * tl, const fr_header * hdr);
|
||||
|
||||
} // namespace flump3dec
|
||||
|
||||
#endif //__FLUMP3DEC_H__
|
|
@ -65,9 +65,9 @@ function getBuildInfo() {
|
|||
buildIdentifier: "dev",
|
||||
buildNumber: "0",
|
||||
stableBuild: "0",
|
||||
organization: "High Fidelity - dev"
|
||||
organization: "High Fidelity - dev",
|
||||
appUserModelId: "com.highfidelity.sandbox-dev"
|
||||
};
|
||||
|
||||
var buildInfo = DEFAULT_BUILD_INFO;
|
||||
|
||||
if (buildInfoPath) {
|
||||
|
@ -258,6 +258,8 @@ function deleteOldFiles(directoryPath, maxAgeInSeconds, filenameRegex) {
|
|||
}
|
||||
}
|
||||
|
||||
app.setAppUserModelId(buildInfo.appUserModelId);
|
||||
|
||||
// print out uncaught exceptions in the console
|
||||
process.on('uncaughtException', function(err) {
|
||||
log.error(err);
|
||||
|
@ -780,6 +782,7 @@ function onContentLoaded() {
|
|||
// maybeShowSplash();
|
||||
|
||||
if (buildInfo.releaseType == 'PRODUCTION' && !argv.noUpdater) {
|
||||
|
||||
const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30;
|
||||
var hasShownUpdateNotification = false;
|
||||
const updateChecker = new updater.UpdateChecker(buildInfo, CHECK_FOR_UPDATES_INTERVAL_SECONDS);
|
||||
|
@ -790,6 +793,7 @@ function onContentLoaded() {
|
|||
title: 'An update is available!',
|
||||
message: 'High Fidelity version ' + latestVersion + ' is available',
|
||||
wait: true,
|
||||
appID: buildInfo.appUserModelId,
|
||||
url: url
|
||||
});
|
||||
hasShownUpdateNotification = true;
|
||||
|
|
|
@ -25,6 +25,8 @@ Rectangle {
|
|||
HifiStylesUit.HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property bool uiReady: false;
|
||||
property bool processingStillSnapshot: false;
|
||||
property bool processing360Snapshot: false;
|
||||
// Style
|
||||
color: "#404040";
|
||||
|
@ -58,7 +60,7 @@ Rectangle {
|
|||
// "Spectator" text
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
id: titleBarText;
|
||||
text: "Spectator Camera";
|
||||
text: "Spectator Camera 2.2";
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
|
@ -91,13 +93,16 @@ Rectangle {
|
|||
}
|
||||
|
||||
onClicked: {
|
||||
if (!checked) {
|
||||
flashCheckBox.checked = false;
|
||||
}
|
||||
sendToScript({method: (checked ? 'spectatorCameraOn' : 'spectatorCameraOff')});
|
||||
sendToScript({method: 'updateCameravFoV', vFoV: fieldOfViewSlider.value});
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: parent.checked ? "#1FC6A6" : hifi.colors.white;
|
||||
implicitWidth: masterSwitch.switchWidth;
|
||||
implicitWidth: masterSwitch.width;
|
||||
implicitHeight: masterSwitch.height;
|
||||
radius: height/2;
|
||||
}
|
||||
|
@ -127,7 +132,7 @@ Rectangle {
|
|||
z: 999;
|
||||
id: processingSnapshot;
|
||||
anchors.fill: parent;
|
||||
visible: root.processing360Snapshot;
|
||||
visible: root.processing360Snapshot || !root.uiReady;
|
||||
color: Qt.rgba(0.0, 0.0, 0.0, 0.85);
|
||||
|
||||
// This object is always used in a popup.
|
||||
|
@ -149,7 +154,7 @@ Rectangle {
|
|||
}
|
||||
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
text: "Processing...";
|
||||
text: root.uiReady ? "Processing..." : "";
|
||||
// Anchors
|
||||
anchors.top: processingImage.bottom;
|
||||
anchors.topMargin: 4;
|
||||
|
@ -202,10 +207,20 @@ Rectangle {
|
|||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
HifiStylesUit.FiraSansRegular {
|
||||
text: ":)";
|
||||
size: 28;
|
||||
color: hifi.colors.white;
|
||||
visible: root.processing360Snapshot || root.processingStillSnapshot;
|
||||
anchors.fill: parent;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
// Spectator Camera Preview
|
||||
Hifi.ResourceImageItem {
|
||||
id: spectatorCameraPreview;
|
||||
visible: masterSwitch.checked && !root.processing360Snapshot;
|
||||
visible: masterSwitch.checked && !root.processing360Snapshot && !root.processingStillSnapshot;
|
||||
url: showCameraView.checked || !HMD.active ? "resource://spectatorCameraFrame" : "resource://hmdPreviewFrame";
|
||||
ready: masterSwitch.checked;
|
||||
mirrorVertically: true;
|
||||
|
@ -311,7 +326,30 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HifiStylesUit.HiFiGlyphs {
|
||||
id: flashGlyph;
|
||||
visible: flashCheckBox.visible;
|
||||
text: hifi.glyphs.lightning;
|
||||
size: 26;
|
||||
color: hifi.colors.white;
|
||||
anchors.verticalCenter: flashCheckBox.verticalCenter;
|
||||
anchors.right: flashCheckBox.left;
|
||||
anchors.rightMargin: -2;
|
||||
}
|
||||
HifiControlsUit.CheckBox {
|
||||
id: flashCheckBox;
|
||||
visible: masterSwitch.checked;
|
||||
color: hifi.colors.white;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.right: takeSnapshotButton.left;
|
||||
anchors.rightMargin: -8;
|
||||
anchors.verticalCenter: takeSnapshotButton.verticalCenter;
|
||||
boxSize: 22;
|
||||
onClicked: {
|
||||
sendToScript({method: 'setFlashStatus', enabled: checked});
|
||||
}
|
||||
}
|
||||
HifiControlsUit.Button {
|
||||
id: takeSnapshotButton;
|
||||
enabled: masterSwitch.checked;
|
||||
|
@ -325,6 +363,7 @@ Rectangle {
|
|||
width: 135;
|
||||
height: 35;
|
||||
onClicked: {
|
||||
root.processingStillSnapshot = true;
|
||||
sendToScript({method: 'takeSecondaryCameraSnapshot'});
|
||||
}
|
||||
}
|
||||
|
@ -582,8 +621,12 @@ Rectangle {
|
|||
//
|
||||
function fromScript(message) {
|
||||
switch (message.method) {
|
||||
case 'updateSpectatorCameraCheckbox':
|
||||
masterSwitch.checked = message.params;
|
||||
case 'initializeUI':
|
||||
masterSwitch.checked = message.masterSwitchOn;
|
||||
flashCheckBox.checked = message.flashCheckboxChecked;
|
||||
showCameraView.checked = message.monitorShowsCamView;
|
||||
showHmdPreview.checked = !message.monitorShowsCamView;
|
||||
root.uiReady = true;
|
||||
break;
|
||||
case 'updateMonitorShowsSwitch':
|
||||
showCameraView.checked = message.params;
|
||||
|
@ -611,6 +654,12 @@ Rectangle {
|
|||
case 'finishedProcessing360Snapshot':
|
||||
root.processing360Snapshot = false;
|
||||
break;
|
||||
case 'startedProcessingStillSnapshot':
|
||||
root.processingStillSnapshot = true;
|
||||
break;
|
||||
case 'finishedProcessingStillSnapshot':
|
||||
root.processingStillSnapshot = false;
|
||||
break;
|
||||
default:
|
||||
console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message));
|
||||
}
|
||||
|
|
BIN
unpublishedScripts/marketplace/spectator-camera/flashOff.wav
Normal file
BIN
unpublishedScripts/marketplace/spectator-camera/flashOff.wav
Normal file
Binary file not shown.
BIN
unpublishedScripts/marketplace/spectator-camera/flashOn.wav
Normal file
BIN
unpublishedScripts/marketplace/spectator-camera/flashOn.wav
Normal file
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"scriptURL": "http://mpassets-staging.highfidelity.com/26156ea5-cdff-43c2-9581-d6b0fa5e00ef-v1/spectatorCamera.js",
|
||||
"homeURL": "http://mpassets-staging.highfidelity.com/26156ea5-cdff-43c2-9581-d6b0fa5e00ef-v1/SpectatorCamera.qml"
|
||||
"scriptURL": "http://mpassets.highfidelity.com/80d02930-f409-4f1a-824f-ae0109da32d6-v1/spectatorCamera.js",
|
||||
"homeURL": "http://mpassets.highfidelity.com/80d02930-f409-4f1a-824f-ae0109da32d6-v1/SpectatorCamera.qml"
|
||||
}
|
|
@ -97,7 +97,7 @@
|
|||
if (button) {
|
||||
button.editProperties({ isActive: onSpectatorCameraScreen || camera });
|
||||
}
|
||||
Audio.playSound(CAMERA_ON_SOUND, {
|
||||
Audio.playSound(SOUND_CAMERA_ON, {
|
||||
volume: 0.15,
|
||||
position: cameraPosition,
|
||||
localOnly: true
|
||||
|
@ -113,8 +113,14 @@
|
|||
var WAIT_AFTER_DOMAIN_SWITCH_BEFORE_CAMERA_DELETE_MS = 1 * 1000;
|
||||
function spectatorCameraOff(isChangingDomains) {
|
||||
function deleteCamera() {
|
||||
Entities.deleteEntity(camera);
|
||||
camera = false;
|
||||
if (flash) {
|
||||
Entities.deleteEntity(flash);
|
||||
flash = false;
|
||||
}
|
||||
if (camera) {
|
||||
Entities.deleteEntity(camera);
|
||||
camera = false;
|
||||
}
|
||||
if (button) {
|
||||
// Change button to active when window is first openend OR if the camera is on, false otherwise.
|
||||
button.editProperties({ isActive: onSpectatorCameraScreen || camera });
|
||||
|
@ -391,21 +397,81 @@
|
|||
}
|
||||
var takeSnapshotControllerMapping;
|
||||
var takeSnapshotControllerMappingName = 'Hifi-SpectatorCamera-Mapping-TakeSnapshot';
|
||||
|
||||
var flash = false;
|
||||
function setFlashStatus(enabled) {
|
||||
var cameraPosition = Entities.getEntityProperties(camera, ["positon"]).position;
|
||||
if (enabled) {
|
||||
if (camera) {
|
||||
Audio.playSound(SOUND_FLASH_ON, {
|
||||
position: cameraPosition,
|
||||
localOnly: true,
|
||||
volume: 0.8
|
||||
});
|
||||
flash = Entities.addEntity({
|
||||
"collidesWith": "",
|
||||
"collisionMask": 0,
|
||||
"color": {
|
||||
"blue": 173,
|
||||
"green": 252,
|
||||
"red": 255
|
||||
},
|
||||
"cutoff": 90,
|
||||
"dimensions": {
|
||||
"x": 4,
|
||||
"y": 4,
|
||||
"z": 4
|
||||
},
|
||||
"dynamic": false,
|
||||
"falloffRadius": 0.20000000298023224,
|
||||
"intensity": 37,
|
||||
"isSpotlight": true,
|
||||
"localRotation": { w: 1, x: 0, y: 0, z: 0 },
|
||||
"localPosition": { x: 0, y: -0.005, z: -0.08 },
|
||||
"name": "Camera Flash",
|
||||
"type": "Light",
|
||||
"parentID": camera,
|
||||
}, true);
|
||||
}
|
||||
} else {
|
||||
if (flash) {
|
||||
Audio.playSound(SOUND_FLASH_OFF, {
|
||||
position: cameraPosition,
|
||||
localOnly: true,
|
||||
volume: 0.8
|
||||
});
|
||||
Entities.deleteEntity(flash);
|
||||
flash = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onStillSnapshotTaken() {
|
||||
Render.getConfig("SecondaryCameraJob.ToneMapping").curve = 1;
|
||||
sendToQml({
|
||||
method: 'finishedProcessingStillSnapshot'
|
||||
});
|
||||
}
|
||||
function maybeTakeSnapshot() {
|
||||
if (camera) {
|
||||
sendToQml({
|
||||
method: 'startedProcessingStillSnapshot'
|
||||
});
|
||||
|
||||
Render.getConfig("SecondaryCameraJob.ToneMapping").curve = 0;
|
||||
// Wait a moment before taking the snapshot for the tonemapping curve to update
|
||||
Script.setTimeout(function () {
|
||||
Audio.playSound(SNAPSHOT_SOUND, {
|
||||
Audio.playSound(SOUND_SNAPSHOT, {
|
||||
position: { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z },
|
||||
localOnly: true,
|
||||
volume: 1.0
|
||||
});
|
||||
Window.takeSecondaryCameraSnapshot();
|
||||
}, 250);
|
||||
} else {
|
||||
sendToQml({
|
||||
method: 'finishedProcessingStillSnapshot'
|
||||
});
|
||||
}
|
||||
}
|
||||
function on360SnapshotTaken() {
|
||||
|
@ -418,7 +484,7 @@
|
|||
}
|
||||
function maybeTake360Snapshot() {
|
||||
if (camera) {
|
||||
Audio.playSound(SNAPSHOT_SOUND, {
|
||||
Audio.playSound(SOUND_SNAPSHOT, {
|
||||
position: { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z },
|
||||
localOnly: true,
|
||||
volume: 1.0
|
||||
|
@ -508,18 +574,8 @@
|
|||
}
|
||||
|
||||
function updateSpectatorCameraQML() {
|
||||
sendToQml({ method: 'updateSpectatorCameraCheckbox', params: !!camera });
|
||||
sendToQml({ method: 'updateMonitorShowsSwitch', params: monitorShowsCameraView });
|
||||
if (!switchViewControllerMapping || !takeSnapshotControllerMapping) {
|
||||
registerButtonMappings();
|
||||
} else {
|
||||
sendToQml({
|
||||
method: 'updateControllerMappingCheckbox',
|
||||
switchViewSetting: switchViewFromController,
|
||||
takeSnapshotSetting: takeSnapshotFromController,
|
||||
controller: controllerType
|
||||
});
|
||||
}
|
||||
sendToQml({ method: 'initializeUI', masterSwitchOn: !!camera, flashCheckboxChecked: !!flash, monitorShowsCamView: monitorShowsCameraView });
|
||||
registerButtonMappings();
|
||||
Menu.setIsOptionChecked("Disable Preview", false);
|
||||
Menu.setIsOptionChecked("Mono Preview", true);
|
||||
}
|
||||
|
@ -537,9 +593,13 @@
|
|||
button.editProperties({ isActive: onSpectatorCameraScreen || camera });
|
||||
}
|
||||
|
||||
if (onSpectatorCameraScreen) {
|
||||
updateSpectatorCameraQML();
|
||||
}
|
||||
// In the case of a remote QML app, it takes a bit of time
|
||||
// for the event bridge to actually connect, so we have to wait...
|
||||
Script.setTimeout(function () {
|
||||
if (onSpectatorCameraScreen) {
|
||||
updateSpectatorCameraQML();
|
||||
}
|
||||
}, 700);
|
||||
}
|
||||
|
||||
// Function Name: sendToQml()
|
||||
|
@ -576,6 +636,9 @@
|
|||
case 'updateCameravFoV':
|
||||
spectatorCameraConfig.vFoV = message.vFoV;
|
||||
break;
|
||||
case 'setFlashStatus':
|
||||
setFlashStatus(message.enabled);
|
||||
break;
|
||||
case 'takeSecondaryCameraSnapshot':
|
||||
maybeTakeSnapshot();
|
||||
break;
|
||||
|
@ -600,9 +663,7 @@
|
|||
// Description:
|
||||
// -Called from C++ when HMD mode is changed. The argument "isHMDMode" is true if HMD is on; false otherwise.
|
||||
function onHMDChanged(isHMDMode) {
|
||||
if (!switchViewControllerMapping || !takeSnapshotControllerMapping) {
|
||||
registerButtonMappings();
|
||||
}
|
||||
registerButtonMappings();
|
||||
if (!isHMDMode) {
|
||||
setMonitorShowsCameraView(false);
|
||||
} else {
|
||||
|
@ -646,8 +707,10 @@
|
|||
}
|
||||
|
||||
// These functions will be called when the script is loaded.
|
||||
var CAMERA_ON_SOUND = SoundCache.getSound(Script.resolvePath("cameraOn.wav"));
|
||||
var SNAPSHOT_SOUND = SoundCache.getSound(Script.resourcesPath() + "sounds/snapshot/snap.wav");
|
||||
var SOUND_CAMERA_ON = SoundCache.getSound(Script.resolvePath("cameraOn.wav"));
|
||||
var SOUND_SNAPSHOT = SoundCache.getSound(Script.resolvePath("snap.wav"));
|
||||
var SOUND_FLASH_ON = SoundCache.getSound(Script.resolvePath("flashOn.wav"));
|
||||
var SOUND_FLASH_OFF = SoundCache.getSound(Script.resolvePath("flashOff.wav"));
|
||||
startup();
|
||||
Script.scriptEnding.connect(shutdown);
|
||||
|
||||
|
|
Loading…
Reference in a new issue