diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9a54f1adc..a62e4b2825 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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! diff --git a/cmake/macros/TargetOpus.cmake b/cmake/macros/TargetOpus.cmake new file mode 100644 index 0000000000..a8faf5139e --- /dev/null +++ b/cmake/macros/TargetOpus.cmake @@ -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() diff --git a/cmake/ports/hifi-deps/CONTROL b/cmake/ports/hifi-deps/CONTROL index 4cf952ccf0..b1a7f96a00 100644 --- a/cmake/ports/hifi-deps/CONTROL +++ b/cmake/ports/hifi-deps/CONTROL @@ -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) diff --git a/cmake/ports/opus/CONTROL b/cmake/ports/opus/CONTROL new file mode 100644 index 0000000000..4314774ab5 --- /dev/null +++ b/cmake/ports/opus/CONTROL @@ -0,0 +1,3 @@ +Source: opus +Version: 1.3.1 +Description: Totally open, royalty-free, highly versatile audio codec diff --git a/cmake/ports/opus/portfile.cmake b/cmake/ports/opus/portfile.cmake new file mode 100644 index 0000000000..bf23718df8 --- /dev/null +++ b/cmake/ports/opus/portfile.cmake @@ -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) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index b854955953..cdf92918c6 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -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 } ] diff --git a/interface/resources/qml/+webengine/BrowserWebView.qml b/interface/resources/qml/+webengine/BrowserWebView.qml index 137531f517..7f2136ec4f 100644 --- a/interface/resources/qml/+webengine/BrowserWebView.qml +++ b/interface/resources/qml/+webengine/BrowserWebView.qml @@ -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 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 83f7495372..a73281e569 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -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(); } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 2b8f2b4c14..9afaa5e85b 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -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: { diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index 04222b3ea1..dd5ec2a845 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -105,7 +105,7 @@ public: * @returns {TabletProxy} The tablet instance. * @example Display the High Fidelity home page on the system tablet. * 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); diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c9bc3e4c33..c88bb8a00d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -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") diff --git a/plugins/hifiCodec/CMakeLists.txt b/plugins/hifiCodec/CMakeLists.txt index 0d4f093fc2..5515602d2f 100644 --- a/plugins/hifiCodec/CMakeLists.txt +++ b/plugins/hifiCodec/CMakeLists.txt @@ -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() diff --git a/plugins/hifiCodec/src/HiFiCodec.cpp b/plugins/hifiCodec/src/HiFiCodec.cpp index 99bb411539..a93e6c47d0 100644 --- a/plugins/hifiCodec/src/HiFiCodec.cpp +++ b/plugins/hifiCodec/src/HiFiCodec.cpp @@ -13,6 +13,7 @@ #include #include +#include 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); diff --git a/plugins/opusCodec/CMakeLists.txt b/plugins/opusCodec/CMakeLists.txt new file mode 100644 index 0000000000..583aff85d6 --- /dev/null +++ b/plugins/opusCodec/CMakeLists.txt @@ -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 () diff --git a/plugins/opusCodec/src/OpusCodecManager.cpp b/plugins/opusCodec/src/OpusCodecManager.cpp new file mode 100644 index 0000000000..1e3d73a229 --- /dev/null +++ b/plugins/opusCodec/src/OpusCodecManager.cpp @@ -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 + +#include + +#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; +} diff --git a/plugins/opusCodec/src/OpusCodecManager.h b/plugins/opusCodec/src/OpusCodecManager.h new file mode 100644 index 0000000000..be6a6b2ff0 --- /dev/null +++ b/plugins/opusCodec/src/OpusCodecManager.h @@ -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 + +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 diff --git a/plugins/opusCodec/src/OpusCodecProvider.cpp b/plugins/opusCodec/src/OpusCodecProvider.cpp new file mode 100644 index 0000000000..79f01de4bd --- /dev/null +++ b/plugins/opusCodec/src/OpusCodecProvider.cpp @@ -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 + +#include +#include +#include + +#include +#include + +#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" diff --git a/plugins/opusCodec/src/OpusDecoder.cpp b/plugins/opusCodec/src/OpusDecoder.cpp new file mode 100644 index 0000000000..e3e4e3645a --- /dev/null +++ b/plugins/opusCodec/src/OpusDecoder.cpp @@ -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 +#include +#include + +#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(sizeof(int16_t)) + * _opusNumChannels; + + decodedBuffer.resize(bufferSize); + int bufferFrames = decodedBuffer.size() / _opusNumChannels / static_cast(sizeof(opus_int16)); + int decoded_frames = opus_decode(_decoder, reinterpret_cast(encodedBuffer.data()), + encodedBuffer.length(), reinterpret_cast(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(sizeof(int16_t)) * _opusNumChannels; + memset( &decodedBuffer.data()[start], 0, static_cast(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(sizeof(int16_t)) + * _opusNumChannels; + decodedBuffer.resize(bufferSize); + int bufferFrames = decodedBuffer.size() / _opusNumChannels / static_cast(sizeof(opus_int16)); + + int decoded_frames = opus_decode(_decoder, nullptr, 0, reinterpret_cast(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(sizeof(int16_t)) * _opusNumChannels; + memset( &decodedBuffer.data()[start], 0, static_cast(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'); + } + +} diff --git a/plugins/opusCodec/src/OpusDecoder.h b/plugins/opusCodec/src/OpusDecoder.h new file mode 100644 index 0000000000..095893856b --- /dev/null +++ b/plugins/opusCodec/src/OpusDecoder.h @@ -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 +#include + + +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 diff --git a/plugins/opusCodec/src/OpusEncoder.cpp b/plugins/opusCodec/src/OpusEncoder.cpp new file mode 100644 index 0000000000..3408701633 --- /dev/null +++ b/plugins/opusCodec/src/OpusEncoder.cpp @@ -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 +#include +#include + +#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(sizeof(opus_int16)); + + int bytes = opus_encode(_encoder, reinterpret_cast(decodedBuffer.constData()), frameSize, + reinterpret_cast(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); + } +} diff --git a/plugins/opusCodec/src/OpusEncoder.h b/plugins/opusCodec/src/OpusEncoder.h new file mode 100644 index 0000000000..10640bf409 --- /dev/null +++ b/plugins/opusCodec/src/OpusEncoder.h @@ -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 +#include + + +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 diff --git a/plugins/opusCodec/src/plugin.json b/plugins/opusCodec/src/plugin.json new file mode 100644 index 0000000000..17217d6017 --- /dev/null +++ b/plugins/opusCodec/src/plugin.json @@ -0,0 +1,4 @@ +{ + "name": "Opus Codec", + "version": 1 +} diff --git a/script-archive/tests/performance/renderableMatrix.js b/script-archive/tests/performance/renderableMatrix.js index dd0fd6e54d..04946328cc 100644 --- a/script-archive/tests/performance/renderableMatrix.js +++ b/script-archive/tests/performance/renderableMatrix.js @@ -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') { diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 795458f05d..7ea1632314 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -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(); }); diff --git a/scripts/system/create/edit.js b/scripts/system/create/edit.js index c57f4bae50..ef07aa4d6e 100644 --- a/scripts/system/create/edit.js +++ b/scripts/system/create/edit.js @@ -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: { diff --git a/tools/jsdoc/hifi-jsdoc-template/static/styles/main.css b/tools/jsdoc/hifi-jsdoc-template/static/styles/main.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/jsdoc/hifi-jsdoc-template/static/styles/responsive.css b/tools/jsdoc/hifi-jsdoc-template/static/styles/responsive.css new file mode 100644 index 0000000000..cc730818b6 --- /dev/null +++ b/tools/jsdoc/hifi-jsdoc-template/static/styles/responsive.css @@ -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; +} \ No newline at end of file diff --git a/tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl b/tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl index 7093109ae1..6d12ccd816 100644 --- a/tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl +++ b/tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl @@ -4,10 +4,10 @@ <?js= title ?> - - - - + + + + - - - - - - - - + + + + + + + + + + - -