mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 21:33:35 +02:00
Merge branch 'kasen/core' into fix/http-serverless
This commit is contained in:
commit
e6c54faaf2
28 changed files with 904 additions and 101 deletions
CONTRIBUTING.md
cmake
domain-server/resources
interface
libraries
plugins
script-archive/tests/performance
scripts
tools/jsdoc/hifi-jsdoc-template
|
@ -1,6 +1,4 @@
|
|||
The project embraces distributed development and if you'd like to help, we'll pay you -- find out more at [Worklist.net](https://worklist.net). If you find a small bug and have a fix, pull requests are welcome. If you'd like to get paid for your work, make sure you report the bug via a job on Worklist.net.
|
||||
|
||||
We're hiring! We're looking for skilled developers; send your resume to hiring@highfidelity.io
|
||||
The project embraces distributed development and if you'd like to help, it would be greatly appreciated. Just open a pull request with the revisions.
|
||||
|
||||
Contributing
|
||||
===
|
||||
|
@ -8,7 +6,7 @@ Contributing
|
|||
2. Clone your fork of the repository locally
|
||||
|
||||
```
|
||||
git clone git://github.com/USERNAME/hifi.git
|
||||
git clone git://github.com/USERNAME/project-athena.git
|
||||
```
|
||||
3. Create a new branch
|
||||
|
||||
|
@ -22,15 +20,16 @@ Contributing
|
|||
6. Update your branch
|
||||
|
||||
```
|
||||
git remote add upstream https://github.com/highfidelity/hifi
|
||||
git pull upstream master
|
||||
git remote add upstream https://github.com/kasenvr/project-athena
|
||||
git pull upstream kasen/core
|
||||
```
|
||||
|
||||
Resolve any conflicts that arise with this step.
|
||||
|
||||
7. Push to your fork
|
||||
|
||||
```
|
||||
git push origin master
|
||||
git push origin kasen/core
|
||||
```
|
||||
8. Submit a pull request
|
||||
|
||||
|
@ -39,10 +38,10 @@ Contributing
|
|||
Reporting Bugs
|
||||
===
|
||||
1. Always update to the latest code on master, we make many merges every day and it is possible the bug has already been fixed!
|
||||
2. Search jobs [on Worklist](https://worklist.net) to make sure that somebody has not already reported the same bug.
|
||||
3. Add a [job on Worklist](https://worklist.net/job/add) including information about your system and how to reproduce the bug.
|
||||
2. Search [issues](https://github.com/kasenvr/project-athena/issues) to make sure that somebody has not already reported the same bug.
|
||||
3. [Add](https://github.com/kasenvr/project-athena/issues/new) your report to the issues list!
|
||||
|
||||
Requesting a feature
|
||||
Requesting a Feature
|
||||
===
|
||||
1. Search the [the Worklist](https://worklist.net) to make sure that somebody has not already requested the same feature. If you find a matching request, feel free to add any additional comments to the existing issue.
|
||||
2. Add a [job on Worklist](https://worklist.net/job/add) that is labeled as a Feature (and select any other appropriate Labels) and includes a detailed description of your request.
|
||||
1. Search [issues](https://github.com/kasenvr/project-athena/issues) to make sure that somebody has not already requested the same feature.
|
||||
2. [Add](https://github.com/kasenvr/project-athena/issues/new) your request to the issues list!
|
||||
|
|
13
cmake/macros/TargetOpus.cmake
Normal file
13
cmake/macros/TargetOpus.cmake
Normal file
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# Created by Michael Bailey on 12/20/2019
|
||||
# Copyright 2019 Michael Bailey
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
macro(TARGET_opus)
|
||||
find_library(OPUS_LIBRARY_RELEASE NAMES opus PATHS ${VCPKG_INSTALL_ROOT}/lib)
|
||||
find_library(OPUS_LIBRARY_DEBUG NAMES opus PATHS ${VCPKG_INSTALL_ROOT}/debug/lib)
|
||||
select_library_configurations(OPUS)
|
||||
target_link_libraries(${TARGET_NAME} ${OPUS_LIBRARY})
|
||||
endmacro()
|
|
@ -1,4 +1,4 @@
|
|||
Source: hifi-deps
|
||||
Version: 0.3
|
||||
Version: 0.4
|
||||
Description: Collected dependencies for High Fidelity applications
|
||||
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), tbb (!android&!osx), zlib, webrtc (!android)
|
||||
Build-Depends: bullet3, draco, etc2comp, glm, nvtt, openexr (!android), openssl (windows), opus, tbb (!android&!osx), zlib, webrtc (!android)
|
||||
|
|
3
cmake/ports/opus/CONTROL
Normal file
3
cmake/ports/opus/CONTROL
Normal file
|
@ -0,0 +1,3 @@
|
|||
Source: opus
|
||||
Version: 1.3.1
|
||||
Description: Totally open, royalty-free, highly versatile audio codec
|
28
cmake/ports/opus/portfile.cmake
Normal file
28
cmake/ports/opus/portfile.cmake
Normal file
|
@ -0,0 +1,28 @@
|
|||
include(vcpkg_common_functions)
|
||||
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH
|
||||
SOURCE_PATH
|
||||
REPO
|
||||
xiph/opus
|
||||
REF
|
||||
e85ed7726db5d677c9c0677298ea0cb9c65bdd23
|
||||
SHA512
|
||||
a8c7e5bf383c06f1fdffd44d9b5f658f31eb4800cb59d12da95ddaeb5646f7a7b03025f4663362b888b1374d4cc69154f006ba07b5840ec61ddc1a1af01d6c54
|
||||
HEAD_REF
|
||||
master)
|
||||
|
||||
vcpkg_configure_cmake(SOURCE_PATH ${SOURCE_PATH} PREFER_NINJA)
|
||||
vcpkg_install_cmake()
|
||||
vcpkg_fixup_cmake_targets(CONFIG_PATH lib/cmake/Opus)
|
||||
vcpkg_copy_pdbs()
|
||||
|
||||
file(INSTALL
|
||||
${SOURCE_PATH}/COPYING
|
||||
DESTINATION
|
||||
${CURRENT_PACKAGES_DIR}/share/opus
|
||||
RENAME copyright)
|
||||
|
||||
file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/lib/cmake
|
||||
${CURRENT_PACKAGES_DIR}/lib/cmake
|
||||
${CURRENT_PACKAGES_DIR}/debug/include)
|
|
@ -1227,8 +1227,8 @@
|
|||
"name": "codec_preference_order",
|
||||
"label": "Audio Codec Preference Order",
|
||||
"help": "List of codec names in order of preferred usage",
|
||||
"placeholder": "hifiAC, zlib, pcm",
|
||||
"default": "hifiAC,zlib,pcm",
|
||||
"placeholder": "opus, hifiAC, zlib, pcm",
|
||||
"default": "opus,hifiAC,zlib,pcm",
|
||||
"advanced": true
|
||||
}
|
||||
]
|
||||
|
|
|
@ -6,7 +6,7 @@ import controlsUit 1.0
|
|||
|
||||
WebView {
|
||||
id: webview
|
||||
url: "https://highfidelity.com/"
|
||||
url: "https://projectathena.io/"
|
||||
profile: FileTypeProfile;
|
||||
|
||||
property var parentRoot: null
|
||||
|
|
|
@ -3156,7 +3156,7 @@ void Application::showLoginScreen() {
|
|||
QJsonObject loginData = {};
|
||||
loginData["action"] = "login dialog popped up";
|
||||
UserActivityLogger::getInstance().logAction("encourageLoginDialog", loginData);
|
||||
_window->setWindowTitle("High Fidelity");
|
||||
_window->setWindowTitle("Project Athena");
|
||||
} else {
|
||||
resumeAfterLoginDialogActionTaken();
|
||||
}
|
||||
|
|
|
@ -1366,7 +1366,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* var METERS_TO_INCHES = 39.3701;
|
||||
* var entity = Entities.addEntity({
|
||||
* type: "Web",
|
||||
* sourceUrl: "https://highfidelity.com/",
|
||||
* sourceUrl: "https://projectathena.io/",
|
||||
* position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -4 })),
|
||||
* rotation: MyAvatar.orientation,
|
||||
* dimensions: {
|
||||
|
|
|
@ -105,7 +105,7 @@ public:
|
|||
* @returns {TabletProxy} The tablet instance.
|
||||
* @example <caption>Display the High Fidelity home page on the system tablet.</caption>
|
||||
* var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
* tablet.gotoWebScreen("https://highfidelity.com/");
|
||||
* tablet.gotoWebScreen("https://projectathena.io/");
|
||||
*/
|
||||
Q_INVOKABLE TabletProxy* getTablet(const QString& tabletId);
|
||||
|
||||
|
|
|
@ -43,6 +43,8 @@ set(DIR "pcmCodec")
|
|||
add_subdirectory(${DIR})
|
||||
set(DIR "hifiCodec")
|
||||
add_subdirectory(${DIR})
|
||||
set(DIR "opusCodec")
|
||||
add_subdirectory(${DIR})
|
||||
|
||||
# example plugins
|
||||
set(DIR "KasenAPIExample")
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
set(TARGET_NAME hifiCodec)
|
||||
setup_hifi_client_server_plugin()
|
||||
link_hifi_libraries(audio plugins)
|
||||
link_hifi_libraries(shared audio plugins)
|
||||
target_hifiAudioCodec()
|
||||
if (BUILD_SERVER)
|
||||
install_beside_console()
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <AudioCodec.h>
|
||||
#include <AudioConstants.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
|
||||
const char* HiFiCodec::NAME { "hifiAC" };
|
||||
|
@ -44,6 +45,8 @@ public:
|
|||
}
|
||||
|
||||
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override {
|
||||
PerformanceTimer perfTimer("HiFiEncoder::encode");
|
||||
|
||||
encodedBuffer.resize(_encodedSize);
|
||||
AudioEncoder::process((const int16_t*)decodedBuffer.constData(), (int16_t*)encodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL);
|
||||
}
|
||||
|
@ -58,11 +61,15 @@ public:
|
|||
}
|
||||
|
||||
virtual void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) override {
|
||||
PerformanceTimer perfTimer("HiFiEncoder::decode");
|
||||
|
||||
decodedBuffer.resize(_decodedSize);
|
||||
AudioDecoder::process((const int16_t*)encodedBuffer.constData(), (int16_t*)decodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL, true);
|
||||
}
|
||||
|
||||
virtual void lostFrame(QByteArray& decodedBuffer) override {
|
||||
PerformanceTimer perfTimer("HiFiEncoder::lostFrame");
|
||||
|
||||
decodedBuffer.resize(_decodedSize);
|
||||
// this performs packet loss interpolation
|
||||
AudioDecoder::process(nullptr, (int16_t*)decodedBuffer.data(), AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL, false);
|
||||
|
|
16
plugins/opusCodec/CMakeLists.txt
Normal file
16
plugins/opusCodec/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# Created by Michael Bailey on 12/20/2019
|
||||
# Copyright 2019 Michael Bailey
|
||||
#
|
||||
# Distributed under the Apache License, Version 2.0.
|
||||
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
|
||||
#
|
||||
|
||||
set(TARGET_NAME opusCodec)
|
||||
setup_hifi_client_server_plugin()
|
||||
link_hifi_libraries(shared audio plugins)
|
||||
target_opus()
|
||||
|
||||
if (BUILD_SERVER)
|
||||
install_beside_console()
|
||||
endif ()
|
58
plugins/opusCodec/src/OpusCodecManager.cpp
Normal file
58
plugins/opusCodec/src/OpusCodecManager.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// opusCodec.cpp
|
||||
// plugins/opusCodec/src
|
||||
//
|
||||
// Created by Michael Bailey on 12/20/2019
|
||||
// Copyright 2019 Michael Bailey
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "OpusCodecManager.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "OpusEncoder.h"
|
||||
#include "OpusDecoder.h"
|
||||
|
||||
const char* AthenaOpusCodec::NAME { "opus" };
|
||||
|
||||
void AthenaOpusCodec::init() {
|
||||
}
|
||||
|
||||
void AthenaOpusCodec::deinit() {
|
||||
}
|
||||
|
||||
bool AthenaOpusCodec::activate() {
|
||||
CodecPlugin::activate();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AthenaOpusCodec::deactivate() {
|
||||
CodecPlugin::deactivate();
|
||||
}
|
||||
|
||||
|
||||
bool AthenaOpusCodec::isSupported() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Encoder* AthenaOpusCodec::createEncoder(int sampleRate, int numChannels) {
|
||||
return new AthenaOpusEncoder(sampleRate, numChannels);
|
||||
}
|
||||
|
||||
Decoder* AthenaOpusCodec::createDecoder(int sampleRate, int numChannels) {
|
||||
return new AthenaOpusDecoder(sampleRate, numChannels);
|
||||
}
|
||||
|
||||
void AthenaOpusCodec::releaseEncoder(Encoder* encoder) {
|
||||
delete encoder;
|
||||
}
|
||||
|
||||
void AthenaOpusCodec::releaseDecoder(Decoder* decoder) {
|
||||
delete decoder;
|
||||
}
|
42
plugins/opusCodec/src/OpusCodecManager.h
Normal file
42
plugins/opusCodec/src/OpusCodecManager.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// OpusCodecManager.h
|
||||
// plugins/opusCodec/src
|
||||
//
|
||||
// Created by Michael Bailey on 12/20/2019
|
||||
// Copyright 2019 Michael Bailey
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi__OpusCodecManager_h
|
||||
#define hifi__OpusCodecManager_h
|
||||
|
||||
#include <plugins/CodecPlugin.h>
|
||||
|
||||
class AthenaOpusCodec : public CodecPlugin {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// Plugin functions
|
||||
bool isSupported() const override;
|
||||
const QString getName() const override { return NAME; }
|
||||
|
||||
void init() override;
|
||||
void deinit() override;
|
||||
|
||||
/// Called when a plugin is being activated for use. May be called multiple times.
|
||||
bool activate() override;
|
||||
/// Called when a plugin is no longer being used. May be called multiple times.
|
||||
void deactivate() override;
|
||||
|
||||
virtual Encoder* createEncoder(int sampleRate, int numChannels) override;
|
||||
virtual Decoder* createDecoder(int sampleRate, int numChannels) override;
|
||||
virtual void releaseEncoder(Encoder* encoder) override;
|
||||
virtual void releaseDecoder(Decoder* decoder) override;
|
||||
|
||||
private:
|
||||
static const char* NAME;
|
||||
};
|
||||
|
||||
#endif // hifi__opusCodecManager_h
|
45
plugins/opusCodec/src/OpusCodecProvider.cpp
Normal file
45
plugins/opusCodec/src/OpusCodecProvider.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// Created by Michael Bailey on 12/20/2019
|
||||
// Copyright 2019 Michael Bailey
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QtPlugin>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include <plugins/RuntimePlugin.h>
|
||||
#include <plugins/CodecPlugin.h>
|
||||
|
||||
#include "OpusCodecManager.h"
|
||||
|
||||
class AthenaOpusCodecProvider : public QObject, public CodecProvider {
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID CodecProvider_iid FILE "plugin.json")
|
||||
Q_INTERFACES(CodecProvider)
|
||||
|
||||
public:
|
||||
AthenaOpusCodecProvider(QObject* parent = nullptr) : QObject(parent) {}
|
||||
virtual ~AthenaOpusCodecProvider() {}
|
||||
|
||||
virtual CodecPluginList getCodecPlugins() override {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
|
||||
CodecPluginPointer opusCodec(new AthenaOpusCodec());
|
||||
if (opusCodec->isSupported()) {
|
||||
_codecPlugins.push_back(opusCodec);
|
||||
}
|
||||
});
|
||||
return _codecPlugins;
|
||||
}
|
||||
|
||||
private:
|
||||
CodecPluginList _codecPlugins;
|
||||
};
|
||||
|
||||
#include "OpusCodecProvider.moc"
|
131
plugins/opusCodec/src/OpusDecoder.cpp
Normal file
131
plugins/opusCodec/src/OpusDecoder.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
//
|
||||
// OpusCodecManager.h
|
||||
// plugins/opusCodec/src
|
||||
//
|
||||
// Copyright 2020 Dale Glass
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <AudioConstants.h>
|
||||
|
||||
#include "OpusDecoder.h"
|
||||
|
||||
static QLoggingCategory decoder("AthenaOpusDecoder");
|
||||
|
||||
static QString error_to_string(int error) {
|
||||
switch (error) {
|
||||
case OPUS_OK:
|
||||
return "OK";
|
||||
case OPUS_BAD_ARG:
|
||||
return "One or more invalid/out of range arguments.";
|
||||
case OPUS_BUFFER_TOO_SMALL:
|
||||
return "The mode struct passed is invalid.";
|
||||
case OPUS_INTERNAL_ERROR:
|
||||
return "An internal error was detected.";
|
||||
case OPUS_INVALID_PACKET:
|
||||
return "The compressed data passed is corrupted.";
|
||||
case OPUS_UNIMPLEMENTED:
|
||||
return "Invalid/unsupported request number.";
|
||||
case OPUS_INVALID_STATE:
|
||||
return "An encoder or decoder structure is invalid or already freed.";
|
||||
default:
|
||||
return QString("Unknown error code: %i").arg(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AthenaOpusDecoder::AthenaOpusDecoder(int sampleRate, int numChannels) {
|
||||
int error;
|
||||
|
||||
_opusSampleRate = sampleRate;
|
||||
_opusNumChannels = numChannels;
|
||||
|
||||
_decoder = opus_decoder_create(sampleRate, numChannels, &error);
|
||||
|
||||
if (error != OPUS_OK) {
|
||||
qCCritical(decoder) << "Failed to initialize Opus encoder: " << error_to_string(error);
|
||||
_decoder = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
qCDebug(decoder) << "Opus decoder initialized, sampleRate = " << sampleRate << "; numChannels = " << numChannels;
|
||||
}
|
||||
|
||||
AthenaOpusDecoder::~AthenaOpusDecoder() {
|
||||
if (_decoder) {
|
||||
opus_decoder_destroy(_decoder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AthenaOpusDecoder::decode(const QByteArray &encodedBuffer, QByteArray &decodedBuffer) {
|
||||
assert(_decoder);
|
||||
PerformanceTimer perfTimer("AthenaOpusDecoder::decode");
|
||||
|
||||
// The audio system encodes and decodes always in fixed size chunks
|
||||
int bufferSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * static_cast<int>(sizeof(int16_t))
|
||||
* _opusNumChannels;
|
||||
|
||||
decodedBuffer.resize(bufferSize);
|
||||
int bufferFrames = decodedBuffer.size() / _opusNumChannels / static_cast<int>(sizeof(opus_int16));
|
||||
int decoded_frames = opus_decode(_decoder, reinterpret_cast<const unsigned char*>(encodedBuffer.data()),
|
||||
encodedBuffer.length(), reinterpret_cast<opus_int16*>(decodedBuffer.data()), bufferFrames, 0);
|
||||
|
||||
if (decoded_frames >= 0) {
|
||||
|
||||
if (decoded_frames < bufferFrames) {
|
||||
qCWarning(decoder) << "Opus decoder returned " << decoded_frames << ", but " << bufferFrames
|
||||
<< " were expected!";
|
||||
|
||||
int start = decoded_frames * static_cast<int>(sizeof(int16_t)) * _opusNumChannels;
|
||||
memset( &decodedBuffer.data()[start], 0, static_cast<size_t>(decodedBuffer.length() - start));
|
||||
} else if (decoded_frames > bufferFrames) {
|
||||
// This should never happen
|
||||
qCCritical(decoder) << "Opus decoder returned " << decoded_frames << ", but only " << bufferFrames
|
||||
<< " were expected! Buffer overflow!?";
|
||||
}
|
||||
} else {
|
||||
qCCritical(decoder) << "Failed to decode audio: " << error_to_string(decoded_frames);
|
||||
decodedBuffer.fill('\0');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AthenaOpusDecoder::lostFrame(QByteArray &decodedBuffer) {
|
||||
assert(_decoder);
|
||||
|
||||
PerformanceTimer perfTimer("AthenaOpusDecoder::lostFrame");
|
||||
|
||||
int bufferSize = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * static_cast<int>(sizeof(int16_t))
|
||||
* _opusNumChannels;
|
||||
decodedBuffer.resize(bufferSize);
|
||||
int bufferFrames = decodedBuffer.size() / _opusNumChannels / static_cast<int>(sizeof(opus_int16));
|
||||
|
||||
int decoded_frames = opus_decode(_decoder, nullptr, 0, reinterpret_cast<opus_int16*>(decodedBuffer.data()),
|
||||
bufferFrames, 1);
|
||||
|
||||
if (decoded_frames >= 0) {
|
||||
|
||||
if ( decoded_frames < bufferFrames ) {
|
||||
qCWarning(decoder) << "Opus decoder returned " << decoded_frames << ", but " << bufferFrames
|
||||
<< " were expected!";
|
||||
|
||||
int start = decoded_frames * static_cast<int>(sizeof(int16_t)) * _opusNumChannels;
|
||||
memset( &decodedBuffer.data()[start], 0, static_cast<size_t>(decodedBuffer.length() - start));
|
||||
} else if (decoded_frames > bufferFrames) {
|
||||
// This should never happen
|
||||
qCCritical(decoder) << "Opus decoder returned " << decoded_frames << ", but only " << bufferFrames
|
||||
<< " were expected! Buffer overflow!?";
|
||||
}
|
||||
|
||||
} else {
|
||||
qCCritical(decoder) << "Failed to decode lost frame: " << error_to_string(decoded_frames);
|
||||
decodedBuffer.fill('\0');
|
||||
}
|
||||
|
||||
}
|
39
plugins/opusCodec/src/OpusDecoder.h
Normal file
39
plugins/opusCodec/src/OpusDecoder.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// OpusCodecManager.h
|
||||
// plugins/opusCodec/src
|
||||
//
|
||||
// Copyright 2020 Dale Glass
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef OPUSDECODER_H
|
||||
#define OPUSDECODER_H
|
||||
|
||||
|
||||
#include <plugins/CodecPlugin.h>
|
||||
#include <opus/opus.h>
|
||||
|
||||
|
||||
class AthenaOpusDecoder : public Decoder {
|
||||
public:
|
||||
AthenaOpusDecoder(int sampleRate, int numChannels);
|
||||
~AthenaOpusDecoder() override;
|
||||
|
||||
|
||||
virtual void decode(const QByteArray& encodedBuffer, QByteArray& decodedBuffer) override;
|
||||
virtual void lostFrame(QByteArray &decodedBuffer) override;
|
||||
|
||||
|
||||
private:
|
||||
int _encodedSize;
|
||||
|
||||
OpusDecoder* _decoder = nullptr;
|
||||
int _opusSampleRate = 0;
|
||||
int _opusNumChannels = 0;
|
||||
int _decodedSize = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // OPUSDECODER_H
|
273
plugins/opusCodec/src/OpusEncoder.cpp
Normal file
273
plugins/opusCodec/src/OpusEncoder.cpp
Normal file
|
@ -0,0 +1,273 @@
|
|||
//
|
||||
// OpusCodecManager.h
|
||||
// plugins/opusCodec/src
|
||||
//
|
||||
// Copyright 2020 Dale Glass
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <opus/opus.h>
|
||||
|
||||
#include "OpusEncoder.h"
|
||||
|
||||
static QLoggingCategory encoder("AthenaOpusEncoder");
|
||||
|
||||
static QString errorToString(int error) {
|
||||
switch (error) {
|
||||
case OPUS_OK:
|
||||
return "OK";
|
||||
case OPUS_BAD_ARG:
|
||||
return "One or more invalid/out of range arguments.";
|
||||
case OPUS_BUFFER_TOO_SMALL:
|
||||
return "The mode struct passed is invalid.";
|
||||
case OPUS_INTERNAL_ERROR:
|
||||
return "An internal error was detected.";
|
||||
case OPUS_INVALID_PACKET:
|
||||
return "The compressed data passed is corrupted.";
|
||||
case OPUS_UNIMPLEMENTED:
|
||||
return "Invalid/unsupported request number.";
|
||||
case OPUS_INVALID_STATE:
|
||||
return "An encoder or decoder structure is invalid or already freed.";
|
||||
default:
|
||||
return QString("Unknown error code: %i").arg(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AthenaOpusEncoder::AthenaOpusEncoder(int sampleRate, int numChannels) {
|
||||
_opusSampleRate = sampleRate;
|
||||
_opusChannels = numChannels;
|
||||
|
||||
int error;
|
||||
|
||||
_encoder = opus_encoder_create(sampleRate, numChannels, DEFAULT_APPLICATION, &error);
|
||||
|
||||
if (error != OPUS_OK) {
|
||||
qCCritical(encoder) << "Failed to initialize Opus encoder: " << errorToString(error);
|
||||
_encoder = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
setBitrate(DEFAULT_BITRATE);
|
||||
setComplexity(DEFAULT_COMPLEXITY);
|
||||
setApplication(DEFAULT_APPLICATION);
|
||||
setSignal(DEFAULT_SIGNAL);
|
||||
|
||||
qCDebug(encoder) << "Opus encoder initialized, sampleRate = " << sampleRate << "; numChannels = " << numChannels;
|
||||
}
|
||||
|
||||
AthenaOpusEncoder::~AthenaOpusEncoder() {
|
||||
opus_encoder_destroy(_encoder);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AthenaOpusEncoder::encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) {
|
||||
|
||||
PerformanceTimer perfTimer("AthenaOpusEncoder::encode");
|
||||
assert(_encoder);
|
||||
|
||||
encodedBuffer.resize(decodedBuffer.size());
|
||||
int frameSize = decodedBuffer.length() / _opusChannels / static_cast<int>(sizeof(opus_int16));
|
||||
|
||||
int bytes = opus_encode(_encoder, reinterpret_cast<const opus_int16*>(decodedBuffer.constData()), frameSize,
|
||||
reinterpret_cast<unsigned char*>(encodedBuffer.data()), encodedBuffer.size() );
|
||||
|
||||
if (bytes >= 0) {
|
||||
encodedBuffer.resize(bytes);
|
||||
} else {
|
||||
encodedBuffer.resize(0);
|
||||
|
||||
qCWarning(encoder) << "Error when encoding " << decodedBuffer.length() << " bytes of audio: "
|
||||
<< errorToString(bytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getComplexity() const {
|
||||
assert(_encoder);
|
||||
int returnValue;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_COMPLEXITY(&returnValue));
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setComplexity(int complexity) {
|
||||
assert(_encoder);
|
||||
int returnValue = opus_encoder_ctl(_encoder, OPUS_SET_COMPLEXITY(complexity));
|
||||
|
||||
if (returnValue != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting complexity to " << complexity << ": " << errorToString(returnValue);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getBitrate() const {
|
||||
assert(_encoder);
|
||||
int returnValue;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_BITRATE(&returnValue));
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setBitrate(int bitrate) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting bitrate to " << bitrate << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getVBR() const {
|
||||
assert(_encoder);
|
||||
int returnValue;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_VBR(&returnValue));
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setVBR(int vbr) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_VBR(vbr));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting VBR to " << vbr << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getVBRConstraint() const {
|
||||
assert(_encoder);
|
||||
int returnValue;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_VBR_CONSTRAINT(&returnValue));
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setVBRConstraint(int vbr_const) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_VBR_CONSTRAINT(vbr_const));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting VBR constraint to " << vbr_const << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getMaxBandwidth() const {
|
||||
assert(_encoder);
|
||||
int returnValue;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_MAX_BANDWIDTH(&returnValue));
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setMaxBandwidth(int maxBandwidth) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_MAX_BANDWIDTH(maxBandwidth));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting max bandwidth to " << maxBandwidth << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getBandwidth() const {
|
||||
assert(_encoder);
|
||||
int bandwidth;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_BANDWIDTH(&bandwidth));
|
||||
return bandwidth;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setBandwidth(int bandwidth) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_BANDWIDTH(bandwidth));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting bandwidth to " << bandwidth << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getSignal() const {
|
||||
assert(_encoder);
|
||||
int signal;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_SIGNAL(&signal));
|
||||
return signal;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setSignal(int signal) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_SIGNAL(signal));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting signal to " << signal << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getApplication() const {
|
||||
assert(_encoder);
|
||||
int applicationValue;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_APPLICATION(&applicationValue));
|
||||
return applicationValue;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setApplication(int application) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_APPLICATION(application));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting application to " << application << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getLookahead() const {
|
||||
assert(_encoder);
|
||||
int lookAhead;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_LOOKAHEAD(&lookAhead));
|
||||
return lookAhead;
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getInbandFEC() const {
|
||||
assert(_encoder);
|
||||
int fec;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_INBAND_FEC(&fec));
|
||||
return fec;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setInbandFEC(int inBandFEC) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_INBAND_FEC(inBandFEC));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting inband FEC to " << inBandFEC << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getExpectedPacketLossPercentage() const {
|
||||
assert(_encoder);
|
||||
int lossPercentage;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_PACKET_LOSS_PERC(&lossPercentage));
|
||||
return lossPercentage;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setExpectedPacketLossPercentage(int percentage) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_PACKET_LOSS_PERC(percentage));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting loss percent to " << percentage << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getDTX() const {
|
||||
assert(_encoder);
|
||||
int dtx;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_DTX(&dtx));
|
||||
return dtx;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setDTX(int dtx) {
|
||||
assert(_encoder);
|
||||
int errorCode = opus_encoder_ctl(_encoder, OPUS_SET_DTX(dtx));
|
||||
|
||||
if (errorCode != OPUS_OK) {
|
||||
qCWarning(encoder) << "Error when setting DTX to " << dtx << ": " << errorToString(errorCode);
|
||||
}
|
||||
}
|
78
plugins/opusCodec/src/OpusEncoder.h
Normal file
78
plugins/opusCodec/src/OpusEncoder.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// OpusCodecManager.h
|
||||
// plugins/opusCodec/src
|
||||
//
|
||||
// Copyright 2020 Dale Glass
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef OPUSENCODER_H
|
||||
#define OPUSENCODER_H
|
||||
#include <plugins/CodecPlugin.h>
|
||||
#include <opus/opus.h>
|
||||
|
||||
|
||||
class AthenaOpusEncoder : public Encoder {
|
||||
public:
|
||||
|
||||
AthenaOpusEncoder(int sampleRate, int numChannels);
|
||||
~AthenaOpusEncoder() override;
|
||||
|
||||
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override;
|
||||
|
||||
|
||||
int getComplexity() const;
|
||||
void setComplexity(int complexity);
|
||||
|
||||
int getBitrate() const;
|
||||
void setBitrate(int bitrate);
|
||||
|
||||
int getVBR() const;
|
||||
void setVBR(int vbr);
|
||||
|
||||
int getVBRConstraint() const;
|
||||
void setVBRConstraint(int vbrConstraint);
|
||||
|
||||
int getMaxBandwidth() const;
|
||||
void setMaxBandwidth(int maxBandwidth);
|
||||
|
||||
int getBandwidth() const;
|
||||
void setBandwidth(int bandwidth);
|
||||
|
||||
int getSignal() const;
|
||||
void setSignal(int signal);
|
||||
|
||||
int getApplication() const;
|
||||
void setApplication(int application);
|
||||
|
||||
int getLookahead() const;
|
||||
|
||||
int getInbandFEC() const;
|
||||
void setInbandFEC(int inBandFEC);
|
||||
|
||||
int getExpectedPacketLossPercentage() const;
|
||||
void setExpectedPacketLossPercentage(int percentage);
|
||||
|
||||
int getDTX() const;
|
||||
void setDTX(int dtx);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
const int DEFAULT_BITRATE = 128000;
|
||||
const int DEFAULT_COMPLEXITY = 10;
|
||||
const int DEFAULT_APPLICATION = OPUS_APPLICATION_VOIP;
|
||||
const int DEFAULT_SIGNAL = OPUS_AUTO;
|
||||
|
||||
int _opusSampleRate = 0;
|
||||
int _opusChannels = 0;
|
||||
int _opusExpectedLoss = 0;
|
||||
|
||||
|
||||
OpusEncoder* _encoder = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif // OPUSENCODER_H
|
4
plugins/opusCodec/src/plugin.json
Normal file
4
plugins/opusCodec/src/plugin.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "Opus Codec",
|
||||
"version": 1
|
||||
}
|
|
@ -114,7 +114,7 @@ Script.setInterval(function () {
|
|||
if (isModel) {
|
||||
properties.modelURL = type;
|
||||
} else if (type === 'Web') {
|
||||
properties.sourceUrl = 'https://highfidelity.com';
|
||||
properties.sourceUrl = 'https://projectathena.io';
|
||||
} else {
|
||||
properties.color = { red: x / ROWS_X * 255, green: y / ROWS_Y * 255, blue: z / ROWS_Z * 255 };
|
||||
if (type === 'ParticleEffect') {
|
||||
|
|
|
@ -39,7 +39,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
|||
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||
"system/controllers/controllerScripts.js",
|
||||
"communityModules/notificationCore/notificationCore.js",
|
||||
"communityModules/chat/FloofChat.js"
|
||||
{"stable": "communityModules/chat/FloofChat.js", "beta": "https://content.fluffy.ws/scripts/chat/FloofChat.js"}
|
||||
//"system/chat.js"
|
||||
];
|
||||
|
||||
|
@ -53,7 +53,9 @@ var MENU_CATEGORY = "Developer > Scripting";
|
|||
var MENU_ITEM = "Debug defaultScripts.js";
|
||||
|
||||
var SETTINGS_KEY = '_debugDefaultScriptsIsChecked';
|
||||
var previousSetting = Settings.getValue(SETTINGS_KEY);
|
||||
var SETTINGS_KEY_BETA = '_betaDefaultScriptsIsChecked';
|
||||
var previousSetting = Settings.getValue(SETTINGS_KEY, false);
|
||||
var previousSettingBeta = Settings.getValue(SETTINGS_KEY_BETA, false);
|
||||
|
||||
if (previousSetting === '' || previousSetting === false || previousSetting === 'false') {
|
||||
previousSetting = false;
|
||||
|
@ -77,17 +79,30 @@ function loadSeparateDefaults() {
|
|||
|
||||
for (var i in DEFAULT_SCRIPTS_SEPARATE) {
|
||||
var shouldLoadCurrentDefaultScript = true;
|
||||
var scriptItem = DEFAULT_SCRIPTS_SEPARATE[i];
|
||||
if (typeof scriptItem === "object") {
|
||||
if (previousSettingBeta) {
|
||||
console.log("Loading Beta item " + scriptItem.beta);
|
||||
scriptItem = scriptItem.beta;
|
||||
} else {
|
||||
scriptItem = scriptItem.stable;
|
||||
}
|
||||
}
|
||||
|
||||
for (var j = 0; j < currentlyRunningScripts.length; j++) {
|
||||
var currentRunningScriptObject = currentlyRunningScripts[j];
|
||||
var currentDefaultScriptName = DEFAULT_SCRIPTS_SEPARATE[i].substr((DEFAULT_SCRIPTS_SEPARATE[i].lastIndexOf("/") + 1), DEFAULT_SCRIPTS_SEPARATE[i].length);
|
||||
var currentDefaultScriptName = scriptItem.substr((scriptItem.lastIndexOf("/") + 1), scriptItem.length);
|
||||
if (currentDefaultScriptName === currentRunningScriptObject.name) {
|
||||
shouldLoadCurrentDefaultScript = false;
|
||||
if (currentRunningScriptObject.url !== scriptItem) {
|
||||
ScriptDiscoveryService.stopScript(currentRunningScriptObject.url);
|
||||
} else {
|
||||
shouldLoadCurrentDefaultScript = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldLoadCurrentDefaultScript) {
|
||||
Script.load(DEFAULT_SCRIPTS_SEPARATE[i]);
|
||||
Script.load(scriptItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +176,7 @@ function removeMenuItem() {
|
|||
}
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
Script.scriptEnding.connect(function () {
|
||||
removeMenuItem();
|
||||
});
|
||||
|
||||
|
|
|
@ -427,7 +427,7 @@ const DEFAULT_ENTITY_PROPERTIES = {
|
|||
y: 0.9,
|
||||
z: 0.01
|
||||
},
|
||||
sourceUrl: "https://highfidelity.com/",
|
||||
sourceUrl: "https://projectathena.io/",
|
||||
dpi: 30,
|
||||
},
|
||||
ParticleEffect: {
|
||||
|
|
0
tools/jsdoc/hifi-jsdoc-template/static/styles/main.css
Normal file
0
tools/jsdoc/hifi-jsdoc-template/static/styles/main.css
Normal file
17
tools/jsdoc/hifi-jsdoc-template/static/styles/responsive.css
Normal file
17
tools/jsdoc/hifi-jsdoc-template/static/styles/responsive.css
Normal file
|
@ -0,0 +1,17 @@
|
|||
.nav-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-right: 0px !important;
|
||||
}
|
||||
|
||||
#main {
|
||||
margin-left: 15px !important;
|
||||
margin-right: 15px !important;
|
||||
overflow: auto;
|
||||
}
|
|
@ -4,10 +4,10 @@
|
|||
<?js if (!env.conf.docdash) { env.conf.docdash = {};} ?>
|
||||
<meta charset="utf-8">
|
||||
<title><?js= title ?></title>
|
||||
|
||||
<script src="scripts/vue.min.js"></script>
|
||||
<script src="scripts/vuetify.js"></script>
|
||||
|
||||
|
||||
<script src="scripts/vue.min.js"></script>
|
||||
<script src="scripts/vuetify.js"></script>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"></script>
|
||||
<script src="scripts/prettify/lang-css.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
|
@ -15,55 +15,80 @@
|
|||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/night.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet">
|
||||
<link href="styles/materialdesignicons.min.css" rel="stylesheet">
|
||||
<link href="styles/vuetify.css" rel="stylesheet">
|
||||
<style>
|
||||
.v-application--wrap {
|
||||
min-height: 0 !important;
|
||||
}
|
||||
|
||||
/** Override Vue CSS. */
|
||||
.theme--dark.v-application {
|
||||
background: #27343b !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
//We are running the check here to preload the theme because it may load the incorrect one first for a split second.
|
||||
var darkDisabled = JSON.parse(localStorage.getItem('darkDisabled'));
|
||||
if (darkDisabled == null) {
|
||||
localStorage.setItem('darkDisabled', JSON.stringify(false));
|
||||
} else {
|
||||
var nightSheet = document.querySelector('[href="styles/night.css"]');
|
||||
nightSheet.disabled = darkDisabled;
|
||||
}
|
||||
</script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
|
||||
<link type="text/css" rel="stylesheet" href="styles/night.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/responsive.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/main.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet">
|
||||
<link href="styles/materialdesignicons.min.css" rel="stylesheet">
|
||||
<link href="styles/vuetify.css" rel="stylesheet">
|
||||
<style>
|
||||
.v-application--wrap {
|
||||
min-height: 0 !important;
|
||||
}
|
||||
|
||||
/** Override Vue CSS. */
|
||||
.theme--dark.v-application {
|
||||
background: #27343b !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
//We are running the check here to preload the theme because it may load the incorrect one first for a split second.
|
||||
var isLocalStorageSupported = false;
|
||||
try { // Edge browsing files on local file system doesn't support localStorage.
|
||||
if (localStorage) {
|
||||
isLocalStorageSupported = true;
|
||||
}
|
||||
} catch (e) {
|
||||
// nop
|
||||
}
|
||||
|
||||
var defaultDarkDisabled = false;
|
||||
var darkDisabled = isLocalStorageSupported ? JSON.parse(localStorage.getItem('darkDisabled')) : defaultDarkDisabled;
|
||||
if (darkDisabled === null) {
|
||||
localStorage.setItem('darkDisabled', JSON.stringify(defaultDarkDisabled));
|
||||
} else {
|
||||
var nightSheet = document.querySelector('[href="styles/night.css"]');
|
||||
nightSheet.disabled = darkDisabled;
|
||||
}
|
||||
|
||||
var defaultResponsiveDisabled = true;
|
||||
var responsiveDisabled =
|
||||
isLocalStorageSupported ? JSON.parse(localStorage.getItem('responsiveDisabled')) : defaultResponsiveDisabled;
|
||||
if (responsiveDisabled === null) {
|
||||
localStorage.setItem('responsiveDisabled', JSON.stringify(defaultResponsiveDisabled));
|
||||
} else {
|
||||
var responsiveSheet = document.querySelector('[href="styles/responsive.css"]');
|
||||
responsiveSheet.disabled = responsiveDisabled;
|
||||
}
|
||||
</script>
|
||||
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui"> -->
|
||||
<link href="images/fav-icon.ico" rel="shortcut icon">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="nav-header">
|
||||
<p><a href="https://projectathena.io"><img src="images/project-athena-logo.png" width="214px" /></a></p>
|
||||
<?js if (env.conf.docdash.search) { ?>
|
||||
<input type="text" class="search-input" id="nav-search" placeholder="Search API Docs ..." />
|
||||
<?js } ?>
|
||||
<p><a href="https://docs.projectathena.dev">Looking for <strong>Project Athena</strong><br /> Documentation?</a></p>
|
||||
<div id="app">
|
||||
<v-app dark>
|
||||
<v-btn @click="toggleNightMode" text dark>
|
||||
Toggle
|
||||
<v-icon class="ml-2">mdi-theme-light-dark</v-icon>
|
||||
</v-btn>
|
||||
</v-app>
|
||||
<v-app dark>
|
||||
<div id="vue-menu">
|
||||
<template>
|
||||
<v-btn @click="toggleResponsive" fab large dark style="position: fixed; right: 15px; top: 15px;">
|
||||
<v-icon class="ml-4">mdi-backburger</v-icon>
|
||||
</v-btn>
|
||||
<div class="nav-header">
|
||||
<p><a href="https://projectathena.io"><img src="images/project-athena-logo.png" width="214px" /></a></p>
|
||||
<?js if (env.conf.docdash.search) { ?>
|
||||
<input type="text" class="search-input" id="nav-search" placeholder="Search API Docs ..." />
|
||||
<?js } ?>
|
||||
<p><a href="https://docs.projectathena.dev">Looking for <strong>Project Athena</strong><br /> Documentation?</a></p>
|
||||
<v-btn @click="toggleNightMode" text dark>
|
||||
<span>Toggle</span>
|
||||
<v-icon style="margin-left: 5px;">mdi-theme-light-dark</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<nav>
|
||||
<?js= this.nav ?>
|
||||
</nav>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<?js= this.nav ?>
|
||||
</nav>
|
||||
</v-app>
|
||||
|
||||
<div id="main">
|
||||
<h1 class="page-title"><?js= title ?></h1>
|
||||
|
@ -109,30 +134,38 @@
|
|||
<?js } ?>
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
vuetify: new Vuetify({
|
||||
theme: {
|
||||
dark: true,
|
||||
},
|
||||
}),
|
||||
data: () => ({
|
||||
new Vue({
|
||||
el: '#vue-menu',
|
||||
vuetify: new Vuetify({
|
||||
theme: {
|
||||
dark: true,
|
||||
},
|
||||
}),
|
||||
data: () => ({
|
||||
|
||||
}),
|
||||
created: function () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
toggleNightMode: function() {
|
||||
var darkDisabled = JSON.parse(localStorage.getItem('darkDisabled'));
|
||||
localStorage.setItem('darkDisabled', JSON.stringify(!darkDisabled));
|
||||
darkDisabled = !darkDisabled;
|
||||
|
||||
var nightSheet = document.querySelector('[href="styles/night.css"]');
|
||||
nightSheet.disabled = darkDisabled;
|
||||
}
|
||||
},
|
||||
})
|
||||
}),
|
||||
created: function () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
toggleNightMode: function() {
|
||||
var darkDisabled = JSON.parse(localStorage.getItem('darkDisabled'));
|
||||
localStorage.setItem('darkDisabled', JSON.stringify(!darkDisabled));
|
||||
darkDisabled = !darkDisabled;
|
||||
|
||||
var nightSheet = document.querySelector('[href="styles/night.css"]');
|
||||
nightSheet.disabled = darkDisabled;
|
||||
},
|
||||
toggleResponsive: function() {
|
||||
var responsiveDisabled = JSON.parse(localStorage.getItem('responsiveDisabled'));
|
||||
localStorage.setItem('responsiveDisabled', JSON.stringify(!responsiveDisabled));
|
||||
responsiveDisabled = !responsiveDisabled;
|
||||
|
||||
var responsiveSheet = document.querySelector('[href="styles/responsive.css"]');
|
||||
responsiveSheet.disabled = responsiveDisabled;
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<!-- Start Google Analytics Tag -->
|
||||
|
|
Loading…
Reference in a new issue