mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Merge branch 'daleglass/opus-plugin' into opus-plugin
This commit is contained in:
commit
2b8c0ffbdc
47 changed files with 760 additions and 185 deletions
4
BUILD.md
4
BUILD.md
|
@ -32,7 +32,7 @@ These are not placed in your normal build tree when doing an out of source build
|
|||
|
||||
#### CMake
|
||||
|
||||
Hifi uses CMake to generate build files and project files for your platform.
|
||||
Athena uses CMake to generate build files and project files for your platform.
|
||||
|
||||
#### Qt
|
||||
CMake will download Qt 5.12.3 using vcpkg.
|
||||
|
@ -47,7 +47,7 @@ This can either be entered directly into your shell session before you build or
|
|||
|
||||
#### Vcpkg
|
||||
|
||||
Hifi uses vcpkg to download and build dependencies.
|
||||
Athena uses vcpkg to download and build dependencies.
|
||||
You do not need to install vcpkg.
|
||||
|
||||
Building the dependencies can be lengthy and the resulting files will be stored in your OS temp directory.
|
||||
|
|
|
@ -62,7 +62,7 @@ The above code to suppress modules is not necessary, but will speed up the build
|
|||
|
||||
### Clone the repository
|
||||
|
||||
`git clone https://github.com/highfidelity/hifi.git `
|
||||
`git clone https://github.com/kasenvr/project-athena.git`
|
||||
|
||||
# Building & Running
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ sudo apt-get install nodejs
|
|||
|
||||
Clone this repository:
|
||||
```bash
|
||||
git clone https://github.com/highfidelity/hifi.git
|
||||
git clone https://github.com/kasenvr/project-athena.git
|
||||
```
|
||||
|
||||
To compile a RELEASE version checkout the tag you need getting a list of all tags:
|
||||
|
|
12
BUILD_WIN.md
12
BUILD_WIN.md
|
@ -1,5 +1,5 @@
|
|||
This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit.
|
||||
## Building High Fidelity
|
||||
This is a stand-alone guide for creating your first Project Athena build for Windows 64-bit.
|
||||
## Building Project Athena
|
||||
Note: We are now using Visual Studio 2017 or 2019 and Qt 5.12.3.
|
||||
If you are upgrading from previous versions, do a clean uninstall of those versions before going through this guide.
|
||||
|
||||
|
@ -37,7 +37,7 @@ Download and install the latest version of CMake 3.15.
|
|||
Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.15 Version page](https://cmake.org/files/v3.15/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
|
||||
|
||||
### Step 3. Create VCPKG environment variable
|
||||
In the next step, you will use CMake to build High Fidelity. By default, the CMake process builds dependency files in Windows' `%TEMP%` directory, which is periodically cleared by the operating system. To prevent you from having to re-build the dependencies in the event that Windows clears that directory, we recommend that you create a `HIFI_VCPKG_BASE` environment variable linked to a directory somewhere on your machine. That directory will contain all dependency files until you manually remove them.
|
||||
In the next step, you will use CMake to build Project Athena. By default, the CMake process builds dependency files in Windows' `%TEMP%` directory, which is periodically cleared by the operating system. To prevent you from having to re-build the dependencies in the event that Windows clears that directory, we recommend that you create a `HIFI_VCPKG_BASE` environment variable linked to a directory somewhere on your machine. That directory will contain all dependency files until you manually remove them.
|
||||
|
||||
To create this variable:
|
||||
* Naviagte to 'Edit the System Environment Variables' Through the start menu.
|
||||
|
@ -72,7 +72,7 @@ Where `%HIFI_DIR%` is the directory for the highfidelity repository.
|
|||
|
||||
### Step 5. Making a Build
|
||||
|
||||
Open `%HIFI_DIR%\build\hifi.sln` using Visual Studio.
|
||||
Open `%HIFI_DIR%\build\athena.sln` using Visual Studio.
|
||||
|
||||
Change the Solution Configuration (menu ribbon under the menu bar, next to the green play button) from "Debug" to "Release" for best performance.
|
||||
|
||||
|
@ -88,7 +88,7 @@ Restart Visual Studio again.
|
|||
|
||||
In Visual Studio, right+click "interface" under the Apps folder in Solution Explorer and select "Set as Startup Project". Run from the menu bar `Debug > Start Debugging`.
|
||||
|
||||
Now, you should have a full build of High Fidelity and be able to run the Interface using Visual Studio. Please check our [Docs](https://wiki.highfidelity.com/wiki/Main_Page) for more information regarding the programming workflow.
|
||||
Now, you should have a full build of Project Athena and be able to run the Interface using Visual Studio. Please check our [Docs](https://wiki.highfidelity.com/wiki/Main_Page) for more information regarding the programming workflow.
|
||||
|
||||
Note: You can also run Interface by launching it from command line or File Explorer from `%HIFI_DIR%\build\interface\Release\interface.exe`
|
||||
|
||||
|
@ -97,7 +97,7 @@ Note: You can also run Interface by launching it from command line or File Explo
|
|||
For any problems after Step #6, first try this:
|
||||
* Delete your locally cloned copy of the highfidelity repository
|
||||
* Restart your computer
|
||||
* Redownload the [repository](https://github.com/kasenvr/hificommunity)
|
||||
* Redownload the [repository](https://github.com/kasenvr/project-athena)
|
||||
* Restart directions from Step #6
|
||||
|
||||
#### CMake gives you the same error message repeatedly after the build fails
|
||||
|
|
40
README.md
40
README.md
|
@ -1,10 +1,10 @@
|
|||
# HiFi Community Edition
|
||||
# Project Athena
|
||||
|
||||
### [Download v0.86.0 K1 (Windows 64-bit, .zip)](https://realities.dev/cdn/hifi-community/v0860-kasen-VS-release+freshstart/Packaged_Release.zip)
|
||||
### [Download ALPHA-DEV v0.86.0 K1 (Windows 64-bit, .zip)](https://realities.dev/cdn/hifi-community/v0860-kasen-VS-release+freshstart/Packaged_Release.zip)
|
||||
|
||||
#### Changes for **v0.86.0** consist of:
|
||||
This build has been tested on Windows 10 Pro 64-bit w/ Nvidia graphics drivers.
|
||||
|
||||
#### Added in K1 (12/3/19)
|
||||
#### v0.86.0 K1 (12/3/19)
|
||||
|
||||
* Audio Buffer choppy audio bugfix by increasing the buffer size.
|
||||
* User Activity Logger disabled, option in code to log the reports to console.
|
||||
|
@ -13,15 +13,10 @@
|
|||
* Entity Script Whitelist, no scripts are whitelisted by default.
|
||||
* Background CMD outputs full log, instant close of application on closing of the CMD-line.
|
||||
|
||||
#### Added in K2 (TBD)
|
||||
#### v0.86.0 K2 (TBD)
|
||||
|
||||
* QML Interface to access and save whitelist live to interface.json.
|
||||
* Add "VideoDecodeStats" to .gitignore.
|
||||
* Fix VCPKG SDL2 to port files from 2.0.8 to 2.0.10 to fix CMake build issues.
|
||||
* Added Github link to "About High Fidelity".
|
||||
* Removed environment variable requirement for "procedural shader materials".
|
||||
|
||||
This build has been tested on Windows 10 Pro 64-bit w/ Nvidia graphics drivers.
|
||||
##### Features, Bugs, and Housekeeping
|
||||
Check out the releases page for more information!
|
||||
|
||||
### Whitelist Instructions
|
||||
|
||||
|
@ -31,15 +26,7 @@ The Interface has the whitelist settings under "**Settings -> Entity Script Whit
|
|||
|
||||
Do not use spaces or commas in the whitelist interface, you will only separate by commas and not new lines in the environment variables.
|
||||
|
||||
It is recommended that you add High Fidelity's CDN URLs ahead of time to ensure general content works right off the bat:
|
||||
|
||||
```
|
||||
http://mpassets.highfidelity.com/
|
||||
https://raw.githubusercontent.com/highfidelity/
|
||||
https://hifi-content.s3.amazonaws.com/
|
||||
```
|
||||
|
||||
You can also set the Windows environment variable "**EXTRA_WHITELIST**" with your whitelisted domains comma separated like so: "**https://kasen.io/,http://kasen.io/,https://exampledomain.com/scriptFolder/**"
|
||||
You can also set the Windows environment variable "**EXTRA_WHITELIST**" with your whitelisted domains comma separated like so: "**http://mpassets.highfidelity.com/,https://raw.githubusercontent.com/highfidelity/,https://hifi-content.s3.amazonaws.com/**"
|
||||
|
||||
Alternatively you can make a batch file placed in the same folder as interface.exe that sets the whitelist environment variable temporarily:
|
||||
|
||||
|
@ -50,7 +37,8 @@ interface.exe
|
|||
|
||||
### How to build interface.exe
|
||||
|
||||
[For Windows](https://github.com/kasenvr/hifi-community/blob/kasen/core/BUILD_WIN.md)
|
||||
[For Windows](https://github.com/kasenvr/project-athena/blob/kasen/core/BUILD_WIN.md)
|
||||
[For Linux](https://github.com/kasenvr/project-athena/blob/kasen/core/BUILD_LINUX.md)
|
||||
|
||||
### Boot to Metaverse: The Goal
|
||||
|
||||
|
@ -58,7 +46,7 @@ Too many of us have our own personal combinations of High Fidelity from C++ modi
|
|||
|
||||
The goal of this repo is to give a common area to PR the very best of our findings and creations so that we may effectively take each necessary step towards our common goal of living in a true metaverse.
|
||||
|
||||
### Why High Fidelity?
|
||||
### Why High Fidelity's Engine?
|
||||
|
||||
Because of all the options, it is the only starting point that is open-source, cross-platform, fully VR integrated + fully desktop integrated with an aim for quality visuals and performance. It also does us the service of providing a foundation to start from such as entity management, full body IK, etc.
|
||||
|
||||
|
@ -68,6 +56,8 @@ Platforms like NeosVR or VRChat are unusable from go due to their fundamental cl
|
|||
|
||||
So the necessary desire is to use High Fidelity as our foundation as a community of one, of all to build a metaverse worth living in.
|
||||
|
||||
### Contributors
|
||||
### Contribution
|
||||
|
||||
A special thanks to the contributors of the community edition.
|
||||
A special thanks to the contributors of the Project Athena.
|
||||
|
||||
[Contribution](CONTRIBUTING.md)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# 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)
|
||||
macro(TARGET_OPUS)
|
||||
if (ANDROID)
|
||||
# no idea if this is correct
|
||||
target_link_libraries(${TARGET_NAME})
|
||||
|
|
|
@ -19,7 +19,7 @@ include(vcpkg_common_functions)
|
|||
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO highfidelity/etc2comp
|
||||
REPO kasenvr/etc2comp
|
||||
REF 7f1843bf07825c21cab711360c1ddbad04641036
|
||||
SHA512 d747076acda8537d39585858c793a35c3dcc9ef283d723619a47f8c81ec1454c95b3340ad35f0655a939eae5b8271c801c48a9a7568311a01903a344c44af25b
|
||||
HEAD_REF master
|
||||
|
|
|
@ -3,7 +3,7 @@ include(vcpkg_common_functions)
|
|||
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO highfidelity/scribe
|
||||
REPO kasenvr/scribe
|
||||
REF 1bd638a36ca771e5a68d01985b6389b71835cbd2
|
||||
SHA512 dbe241d86df3912e544f6b9839873f9875df54efc93822b145e7b13243eaf2e3d690bc8a28b1e52d05bdcd7e68fca6b0b2f5c43ffd0f56a9b7a50d54dcf9e31e
|
||||
HEAD_REF master
|
||||
|
|
|
@ -9,7 +9,7 @@ include(vcpkg_common_functions)
|
|||
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO highfidelity/nvidia-texture-tools
|
||||
REPO kasenvr/nvidia-texture-tools
|
||||
REF 330c4d56274a0f602a5c70596e2eb670a4ed56c2
|
||||
SHA512 4c0bc2f369120d696cc27710b6d33086b27eef55f537ec66b9a5c8b1839bc2426c0413670b0f65be52c5d353468f0126dfe024be1f0690611d4d7e33ac530127
|
||||
HEAD_REF master
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
||||
|
|
|
@ -164,7 +164,7 @@ endif()
|
|||
if downloadVcpkg:
|
||||
if "HIFI_VCPKG_BOOTSTRAP" in os.environ:
|
||||
print("Cloning vcpkg from github to {}".format(self.path))
|
||||
hifi_utils.executeSubprocess(['git', 'clone', 'git@github.com:microsoft/vcpkg.git', self.path])
|
||||
hifi_utils.executeSubprocess(['git', 'clone', 'https://github.com/microsoft/vcpkg', self.path])
|
||||
print("Bootstrapping vcpkg")
|
||||
hifi_utils.executeSubprocess([self.bootstrapCmd], folder=self.path)
|
||||
else:
|
||||
|
|
|
@ -15,9 +15,9 @@ set(CUSTOM_INTERFACE_QRC_PATHS "")
|
|||
|
||||
find_npm()
|
||||
|
||||
#if (BUILD_TOOLS AND NPM_EXECUTABLE)
|
||||
# add_custom_qrc_path(CUSTOM_INTERFACE_QRC_PATHS "${CMAKE_SOURCE_DIR}/tools/jsdoc/out/hifiJSDoc.json" "auto-complete/hifiJSDoc.json")
|
||||
#endif ()
|
||||
if (BUILD_TOOLS AND NPM_EXECUTABLE)
|
||||
add_custom_qrc_path(CUSTOM_INTERFACE_QRC_PATHS "${CMAKE_SOURCE_DIR}/tools/jsdoc/out/hifiJSDoc.json" "auto-complete/hifiJSDoc.json")
|
||||
endif ()
|
||||
|
||||
set(RESOURCES_QRC ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc)
|
||||
set(RESOURCES_RCC ${CMAKE_CURRENT_SOURCE_DIR}/compiledResources/resources.rcc)
|
||||
|
@ -161,9 +161,9 @@ elseif (WIN32)
|
|||
configure_file("${HF_CMAKE_DIR}/templates/VersionInfo.rc.in" ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
||||
|
||||
# add an executable that also has the icon itself and the configured rc file as resources
|
||||
#add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT} ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
||||
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT} ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
||||
##^^^^^ creates native Win32 app w/o cmd console vvvvvv forces cmd console for logging
|
||||
add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT} ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
||||
# add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT} ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
||||
|
||||
if (NOT DEV_BUILD)
|
||||
add_custom_command(
|
||||
|
@ -182,10 +182,10 @@ else ()
|
|||
endif ()
|
||||
|
||||
|
||||
#if (BUILD_TOOLS AND NPM_EXECUTABLE)
|
||||
if (BUILD_TOOLS AND NPM_EXECUTABLE)
|
||||
# require JSDoc to be build before interface is deployed
|
||||
# add_dependencies(resources jsdoc)
|
||||
#endif()
|
||||
add_dependencies(resources jsdoc)
|
||||
endif()
|
||||
|
||||
add_dependencies(${TARGET_NAME} resources)
|
||||
|
||||
|
@ -326,9 +326,9 @@ if (APPLE)
|
|||
"${CMAKE_SOURCE_DIR}/scripts"
|
||||
"${RESOURCES_DEV_DIR}/scripts"
|
||||
# copy JSDoc files beside the executable
|
||||
#COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
# "${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
# "${RESOURCES_DEV_DIR}/jsdoc"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${RESOURCES_DEV_DIR}/jsdoc"
|
||||
# copy the resources files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${RESOURCES_RCC}"
|
||||
|
@ -381,9 +381,9 @@ else()
|
|||
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||
# copy JSDoc files beside the executable
|
||||
#COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
# "${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
# "${INTERFACE_EXEC_DIR}/jsdoc"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
"${INTERFACE_EXEC_DIR}/jsdoc"
|
||||
)
|
||||
|
||||
# link target to external libraries
|
||||
|
|
|
@ -40,7 +40,7 @@ Controls.WebView {
|
|||
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
|
||||
|
||||
function onWebEventReceived(event) {
|
||||
if (event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
if (typeof event === "string" && event.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
ApplicationInterface.addAssetToWorldFromURL(event.slice(18));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ Item {
|
|||
}
|
||||
|
||||
function openDocs() {
|
||||
Qt.openUrlExternally("https://docs.highfidelity.com/create/avatars/package-avatar.html");
|
||||
Qt.openUrlExternally("https://docs.projectathena.dev/create/avatars/package-avatar.html");
|
||||
}
|
||||
|
||||
function openVideo() {
|
||||
|
|
|
@ -128,6 +128,8 @@ ShadowRectangle {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Link to a Project Athena version of the video.
|
||||
/*
|
||||
RalewayButton {
|
||||
id: video
|
||||
visible: false
|
||||
|
@ -141,6 +143,12 @@ ShadowRectangle {
|
|||
|
||||
onClicked: videoButtonClicked()
|
||||
}
|
||||
*/
|
||||
// Temporary placeholder for video button.
|
||||
Rectangle {
|
||||
id: video
|
||||
visible: false
|
||||
}
|
||||
|
||||
RalewayButton {
|
||||
id: docs
|
||||
|
|
|
@ -44,7 +44,11 @@ Item {
|
|||
HifiControls.Button {
|
||||
id: uploadButton
|
||||
|
||||
// FIXME: Re-enable if ability to upload to hosted location is added.
|
||||
/*
|
||||
visible: AvatarPackagerCore.currentAvatarProject && !AvatarPackagerCore.currentAvatarProject.fst.hasMarketplaceID && !root.hasSuccessfullyUploaded
|
||||
*/
|
||||
visible: false
|
||||
enabled: Account.loggedIn
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
@ -62,7 +66,11 @@ Item {
|
|||
HifiControls.Button {
|
||||
id: updateButton
|
||||
|
||||
// FIXME: Re-enable if ability to upload to hosted location is added.
|
||||
/*
|
||||
visible: AvatarPackagerCore.currentAvatarProject && AvatarPackagerCore.currentAvatarProject.fst.hasMarketplaceID && !root.hasSuccessfullyUploaded
|
||||
*/
|
||||
visible: false
|
||||
enabled: Account.loggedIn
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
@ -79,7 +87,12 @@ Item {
|
|||
}
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
// FIXME: Re-enable if ability to upload to hosted location is added.
|
||||
/*
|
||||
visible: root.hasSuccessfullyUploaded
|
||||
*/
|
||||
visible: false;
|
||||
|
||||
HifiControls.Button {
|
||||
enabled: Account.loggedIn
|
||||
|
@ -115,6 +128,22 @@ Item {
|
|||
onClicked: AvatarPackagerCore.currentAvatarProject.openInInventory()
|
||||
}
|
||||
}
|
||||
// FIXME: Remove if "Upload" button is reinstated.
|
||||
HifiControls.Button {
|
||||
id: openDirectoryButton
|
||||
visible: AvatarPackagerCore.currentAvatarProject
|
||||
enabled: true
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
text: qsTr("Open Project Folder")
|
||||
color: hifi.buttons.blue
|
||||
colorScheme: root.colorScheme
|
||||
width: 200
|
||||
height: 40
|
||||
onClicked: {
|
||||
fileDialogHelper.openDirectory(fileDialogHelper.pathToUrl(AvatarPackagerCore.currentAvatarProject.projectFolderPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
@ -263,13 +292,58 @@ Item {
|
|||
color: 'white'
|
||||
size: 20
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: errorsGlyph.bottom
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: notForSaleMessage
|
||||
|
||||
visible: root.hasSuccessfullyUploaded
|
||||
|
||||
color: 'white'
|
||||
linkColor: '#00B4EF'
|
||||
size: 20
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: doctorStatusMessage.bottom
|
||||
anchors.topMargin: 10
|
||||
|
||||
anchors.bottomMargin: 24
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
text: "This item is not for sale yet, <a href='#'>learn more</a>."
|
||||
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally("https://docs.projectathena.dev/sell/add-item/upload-avatar.html");
|
||||
}
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: showErrorsLink
|
||||
|
||||
color: 'white'
|
||||
linkColor: '#00B4EF'
|
||||
|
||||
visible: AvatarPackagerCore.currentAvatarProject && AvatarPackagerCore.currentAvatarProject.hasErrors
|
||||
|
||||
anchors {
|
||||
top: notForSaleMessage.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
size: 28
|
||||
|
||||
text: "<a href='toggle'>View all errors</a>"
|
||||
|
||||
onLinkActivated: {
|
||||
avatarPackager.state = AvatarPackagerState.avatarDoctorErrorReport;
|
||||
}
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: infoMessage
|
||||
|
||||
|
@ -297,60 +371,14 @@ Item {
|
|||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: doctorStatusMessage.bottom
|
||||
|
||||
anchors.bottom: showFilesText.top
|
||||
anchors.bottomMargin: 24
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
text: "You can upload your files to our servers to always access them, and to make your avatar visible to other users."
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: notForSaleMessage
|
||||
|
||||
visible: root.hasSuccessfullyUploaded
|
||||
|
||||
color: 'white'
|
||||
linkColor: '#00B4EF'
|
||||
size: 20
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: infoMessage.bottom
|
||||
anchors.topMargin: 10
|
||||
|
||||
anchors.bottomMargin: 24
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
text: "This item is not for sale yet, <a href='#'>learn more</a>."
|
||||
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally("https://docs.highfidelity.com/sell/add-item/upload-avatar.html");
|
||||
}
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: showErrorsLink
|
||||
|
||||
color: 'white'
|
||||
linkColor: '#00B4EF'
|
||||
|
||||
visible: AvatarPackagerCore.currentAvatarProject && AvatarPackagerCore.currentAvatarProject.hasErrors
|
||||
|
||||
anchors {
|
||||
top: notForSaleMessage.visible ? notForSaleMessage.bottom : infoMessage .bottom
|
||||
bottom: showFilesText.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
size: 28
|
||||
|
||||
text: "<a href='toggle'>View all errors</a>"
|
||||
|
||||
onLinkActivated: {
|
||||
avatarPackager.state = AvatarPackagerState.avatarDoctorErrorReport;
|
||||
}
|
||||
// FIXME: Restore original text if ability to upload to hosted location is added.
|
||||
//text: "You can upload your files to our servers to always access them, and to make your avatar visible to other users."
|
||||
text: "Your files are ready to be uploaded to a server to make your avatar visible to other users."
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
|
@ -389,8 +417,13 @@ Item {
|
|||
Rectangle {
|
||||
id: loginRequiredMessage
|
||||
|
||||
// FIXME: Re-enable if ability to upload to hosted location is added.
|
||||
/*
|
||||
visible: !Account.loggedIn
|
||||
height: !Account.loggedIn ? loginRequiredTextRow.height + 20 : 0
|
||||
*/
|
||||
visible: false
|
||||
height: 0
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
|
|
|
@ -53,18 +53,7 @@ Rectangle {
|
|||
textFormat: Text.StyledText
|
||||
linkColor: "#00B4EF"
|
||||
color: "white"
|
||||
text: "<a href=\"https:/www.highfidelity.com\">www.highfidelity.com</a>."
|
||||
size: 20
|
||||
onLinkActivated: {
|
||||
HiFiAbout.openUrl("https:/www.highfidelity.com");
|
||||
}
|
||||
|
||||
}
|
||||
RalewayRegular {
|
||||
textFormat: Text.StyledText
|
||||
linkColor: "#00B4EF"
|
||||
color: "white"
|
||||
text: "<a href=\"https:/github.com/kasenvr/hifi-community\">HiFi Community Github</a>."
|
||||
text: "<a href=\"https:/github.com/kasenvr/hifi-community\">Project Athena Github</a>."
|
||||
size: 20
|
||||
onLinkActivated: {
|
||||
HiFiAbout.openUrl("https:/github.com/kasenvr/hifi-community");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// ScriptWhitelist.qml
|
||||
// EntityScriptQMLWhitelist.qml
|
||||
// interface/resources/qml/hifi/dialogs/security
|
||||
//
|
||||
// Created by Kasen IO on 2019.12.05 | realities.dev | kasenvr@gmail.com
|
||||
|
@ -145,7 +145,9 @@ Rectangle {
|
|||
https://google.com/
|
||||
https://bing.com/
|
||||
https://mydomain.here/
|
||||
\nEnsure there are no spaces or whitespace."
|
||||
\nEnsure there are no spaces or whitespace.
|
||||
\nFor QML files, you can only whitelist each file individually
|
||||
ending with '.qml'."
|
||||
// Text size
|
||||
size: 16;
|
||||
// Style
|
|
@ -200,7 +200,7 @@ Rectangle {
|
|||
id: eventBridgeConnection
|
||||
target: eventBridge
|
||||
onWebEventReceived: {
|
||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
if (typeof message === "string" && message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ Windows.ScrollingWindow {
|
|||
id: eventBridgeConnection
|
||||
target: eventBridge
|
||||
onWebEventReceived: {
|
||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
if (typeof message === "string" && message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1158,7 +1158,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-SemiBold.ttf");
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-Regular.ttf");
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "fonts/Graphik-Medium.ttf");
|
||||
_window->setWindowTitle("High Fidelity");
|
||||
_window->setWindowTitle("Project Athena");
|
||||
|
||||
Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us
|
||||
|
||||
|
@ -3202,10 +3202,30 @@ void Application::initializeUi() {
|
|||
// Allow remote QML content from trusted sources ONLY
|
||||
{
|
||||
auto defaultUrlValidator = OffscreenQmlSurface::getUrlValidator();
|
||||
auto newValidator = [=](const QUrl& url)->bool {
|
||||
if (AUTHORIZED_EXTERNAL_QML_SOURCE.isParentOf(url)) {
|
||||
return true;
|
||||
auto newValidator = [=](const QUrl& url) -> bool {
|
||||
QString whitelistPrefix = "[WHITELIST ENTITY SCRIPTS]";
|
||||
QList<QString> safeURLS = { "" };
|
||||
safeURLS += qEnvironmentVariable("EXTRA_WHITELIST").trimmed().split(QRegExp("\\s*,\\s*"), QString::SkipEmptyParts);
|
||||
|
||||
// PULL SAFEURLS FROM INTERFACE.JSON Settings
|
||||
|
||||
QVariant raw = Setting::Handle<QVariant>("private/settingsSafeURLS").get();
|
||||
QStringList settingsSafeURLS = raw.toString().trimmed().split(QRegExp("\\s*[,\r\n]+\\s*"), QString::SkipEmptyParts);
|
||||
safeURLS += settingsSafeURLS;
|
||||
|
||||
// END PULL SAFEURLS FROM INTERFACE.JSON Settings
|
||||
|
||||
bool isInWhitelist = false; // assume unsafe
|
||||
for (const auto& str : safeURLS) {
|
||||
if (!str.isEmpty() && str.endsWith(".qml") && url.toString().endsWith(".qml") &&
|
||||
url.toString().startsWith(str)) {
|
||||
qCDebug(interfaceapp) << "Found matching url!" << url.host();
|
||||
isInWhitelist = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(interfaceapp) << "No matching url" << url.host();
|
||||
return defaultUrlValidator(url);
|
||||
};
|
||||
OffscreenQmlSurface::setUrlValidator(newValidator);
|
||||
|
@ -7046,7 +7066,7 @@ void Application::updateWindowTitle() const {
|
|||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
auto isInErrorState = nodeList->getDomainHandler().isInErrorState();
|
||||
|
||||
QString buildVersion = " - Kasen Community Edition v0.86.0 K2 - "
|
||||
QString buildVersion = " - Project Athena v0.86.0 K2 - "
|
||||
+ (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable ? QString("Version") : QString("Build"))
|
||||
+ " " + applicationVersion();
|
||||
|
||||
|
|
|
@ -288,13 +288,12 @@ Menu::Menu() {
|
|||
});
|
||||
|
||||
// Settings > Entity Script Whitelist
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Entity Script Whitelist");
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Entity Script / QML Whitelist");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
|
||||
DependencyManager::get<OffscreenUi>()->clearCache();
|
||||
tablet->pushOntoStack("hifi/dialogs/security/EntityScriptWhitelist.qml");
|
||||
tablet->pushOntoStack("hifi/dialogs/security/EntityScriptQMLWhitelist.qml");
|
||||
|
||||
if (!hmd->getShouldShowTablet()) {
|
||||
hmd->toggleShouldShowTablet();
|
||||
|
@ -808,7 +807,7 @@ Menu::Menu() {
|
|||
// Help > Report a Bug!
|
||||
action = addActionToQMenuAndActionHash(helpMenu, "Report a Bug!");
|
||||
connect(action, &QAction::triggered, qApp, [] {
|
||||
QDesktopServices::openUrl(QUrl("mailto:support@highfidelity.com"));
|
||||
QDesktopServices::openUrl(QUrl("https://github.com/kasenvr/hifi-community/issues"));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ namespace MenuOption {
|
|||
const QString RunningScripts = "Running Scripts...";
|
||||
const QString RunTimingTests = "Run Timing Tests";
|
||||
const QString ScriptedMotorControl = "Enable Scripted Motor Control";
|
||||
const QString EntityScriptWhitelist = "Entity Script Whitelist";
|
||||
const QString EntityScriptQMLWhitelist = "Entity Script / QML Whitelist";
|
||||
const QString ShowTrackedObjects = "Show Tracked Objects";
|
||||
const QString SelfieCamera = "Selfie";
|
||||
const QString SendWrongDSConnectVersion = "Send wrong DS connect version";
|
||||
|
|
|
@ -55,7 +55,7 @@ static QStringList HAND_MAPPING_SUFFIXES = {
|
|||
"HandThumb1",
|
||||
};
|
||||
|
||||
const QUrl PACKAGE_AVATAR_DOCS_BASE_URL = QUrl("https://docs.highfidelity.com/create/avatars/package-avatar.html");
|
||||
const QUrl PACKAGE_AVATAR_DOCS_BASE_URL = QUrl("https://docs.projectathena.dev/create/avatars/package-avatar.html");
|
||||
|
||||
AvatarDoctor::AvatarDoctor(const QUrl& avatarFSTFileUrl) :
|
||||
_avatarFSTFileUrl(avatarFSTFileUrl) {
|
||||
|
|
|
@ -95,7 +95,7 @@ public:
|
|||
static bool isValidNewProjectName(const QString& projectPath, const QString& projectName);
|
||||
|
||||
static QString getDefaultProjectsPath() {
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/High Fidelity Projects";
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Project Athena Projects";
|
||||
}
|
||||
|
||||
signals:
|
||||
|
|
|
@ -3825,7 +3825,7 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
|||
}
|
||||
_actionMotorVelocity = motorSpeed * direction;
|
||||
} else {
|
||||
_actionMotorVelocity = direction;
|
||||
_actionMotorVelocity = sensorToWorldScale * direction;
|
||||
}
|
||||
|
||||
float previousBoomLength = _boomLength;
|
||||
|
|
|
@ -130,6 +130,10 @@ void FetchSpatialTree::configure(const Config& config) {
|
|||
}
|
||||
|
||||
void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemSpatialTree::ItemSelection& outSelection) {
|
||||
if (!renderContext){
|
||||
return;
|
||||
}
|
||||
|
||||
// start fresh
|
||||
outSelection.clear();
|
||||
|
||||
|
@ -142,6 +146,10 @@ void FetchSpatialTree::run(const RenderContextPointer& renderContext, const Inpu
|
|||
RenderArgs* args = renderContext->args;
|
||||
auto& scene = renderContext->_scene;
|
||||
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto queryFrustum = args->getViewFrustum();
|
||||
// Eventually use a frozen frustum
|
||||
if (_freezeFrustum) {
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "ScriptEngine.h"
|
||||
|
||||
#include "ScriptEngineLogging.h"
|
||||
|
||||
WebSocketClass::WebSocketClass(QScriptEngine* engine, QString url) :
|
||||
_webSocket(new QWebSocket()),
|
||||
_engine(engine)
|
||||
|
@ -34,10 +36,11 @@ WebSocketClass::WebSocketClass(QScriptEngine* engine, QWebSocket* qWebSocket) :
|
|||
void WebSocketClass::initialize() {
|
||||
connect(_webSocket, &QWebSocket::disconnected, this, &WebSocketClass::handleOnClose);
|
||||
connect(_webSocket, &QWebSocket::textMessageReceived, this, &WebSocketClass::handleOnMessage);
|
||||
connect(_webSocket, &QWebSocket::binaryMessageReceived, this, &WebSocketClass::handleOnBinaryMessage);
|
||||
connect(_webSocket, &QWebSocket::connected, this, &WebSocketClass::handleOnOpen);
|
||||
connect(_webSocket, static_cast<void(QWebSocket::*)(QAbstractSocket::SocketError)>(&QWebSocket::error), this,
|
||||
&WebSocketClass::handleOnError);
|
||||
_binaryType = QStringLiteral("blob");
|
||||
_binaryType = QStringLiteral("arraybuffer");
|
||||
}
|
||||
|
||||
QScriptValue WebSocketClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||
|
@ -53,7 +56,12 @@ WebSocketClass::~WebSocketClass() {
|
|||
}
|
||||
|
||||
void WebSocketClass::send(QScriptValue message) {
|
||||
_webSocket->sendTextMessage(message.toString());
|
||||
if (message.isObject()) {
|
||||
QByteArray ba = qscriptvalue_cast<QByteArray>(message);
|
||||
_webSocket->sendBinaryMessage(ba);
|
||||
} else {
|
||||
_webSocket->sendTextMessage(message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketClass::close() {
|
||||
|
@ -97,6 +105,25 @@ void WebSocketClass::handleOnMessage(const QString& message) {
|
|||
}
|
||||
}
|
||||
|
||||
void WebSocketClass::handleOnBinaryMessage(const QByteArray& message) {
|
||||
if (_onMessageEvent.isFunction()) {
|
||||
QScriptValueList args;
|
||||
QScriptValue arg = _engine->newObject();
|
||||
QScriptValue data = _engine->newVariant(QVariant::fromValue(message));
|
||||
QScriptValue ctor = _engine->globalObject().property("ArrayBuffer");
|
||||
auto array = qscriptvalue_cast<ArrayBufferClass*>(ctor.data());
|
||||
QScriptValue arrayBuffer;
|
||||
if (!array) {
|
||||
qCWarning(scriptengine) << "WebSocketClass::handleOnBinaryMessage !ArrayBuffer";
|
||||
} else {
|
||||
arrayBuffer = _engine->newObject(array, data);
|
||||
}
|
||||
arg.setProperty("data", arrayBuffer);
|
||||
args << arg;
|
||||
_onMessageEvent.call(QScriptValue(), args);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketClass::handleOnOpen() {
|
||||
if (_onOpenEvent.isFunction()) {
|
||||
_onOpenEvent.call();
|
||||
|
|
|
@ -123,6 +123,7 @@ private slots:
|
|||
void handleOnClose();
|
||||
void handleOnError(QAbstractSocket::SocketError error);
|
||||
void handleOnMessage(const QString& message);
|
||||
void handleOnBinaryMessage(const QByteArray& message);
|
||||
void handleOnOpen();
|
||||
|
||||
};
|
||||
|
|
|
@ -269,7 +269,11 @@ void VrMenu::insertAction(QAction* before, QAction* action) {
|
|||
Q_ASSERT(invokeResult);
|
||||
QObject* result = reinterpret_cast<QObject*>(returnedValue); // returnedValue.value<QObject*>();
|
||||
Q_ASSERT(result);
|
||||
bindActionToQmlAction(result, action, _rootMenu);
|
||||
if ( result ) {
|
||||
bindActionToQmlAction(result, action, _rootMenu);
|
||||
} else {
|
||||
qWarning() << "Failed to find addItem() method in object " << menu << ". Not inserting action " << action;
|
||||
}
|
||||
}
|
||||
|
||||
class QQuickMenuBase;
|
||||
|
|
|
@ -39,9 +39,11 @@ if (NOT SERVER_ONLY AND NOT ANDROID)
|
|||
endif()
|
||||
|
||||
# server-side plugins
|
||||
set(DIR "pcmCodec")
|
||||
add_subdirectory(${DIR})
|
||||
set(DIR "hifiCodec")
|
||||
# set(DIR "pcmCodec")
|
||||
# add_subdirectory(${DIR})
|
||||
# set(DIR "hifiCodec")
|
||||
# add_subdirectory(${DIR})
|
||||
set(DIR "opusCodec")
|
||||
add_subdirectory(${DIR})
|
||||
set(DIR "opusCodec")
|
||||
add_subdirectory(${DIR})
|
||||
|
|
|
@ -108,9 +108,11 @@ QString getVrSettingString(const char* section, const char* setting) {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool isHMDInErrorState = false;
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem() {
|
||||
bool hmdPresent = vr::VR_IsHmdPresent();
|
||||
if (hmdPresent) {
|
||||
if (hmdPresent && !isHMDInErrorState) {
|
||||
Lock lock(mutex);
|
||||
if (!activeHmd) {
|
||||
#if DEV_BUILD
|
||||
|
@ -122,6 +124,14 @@ vr::IVRSystem* acquireOpenVrSystem() {
|
|||
#if DEV_BUILD
|
||||
qCDebug(displayplugins) << "OpenVR display: HMD is " << activeHmd << " error is " << eError;
|
||||
#endif
|
||||
|
||||
if (eError == vr::VRInitError_Init_HmdNotFound) {
|
||||
isHMDInErrorState = true;
|
||||
activeHmd = nullptr;
|
||||
#if DEV_BUILD
|
||||
qCDebug(displayplugins) << "OpenVR: No HMD connected, setting nullptr!";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (activeHmd) {
|
||||
#if DEV_BUILD
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
set(TARGET_NAME opusCodec)
|
||||
setup_hifi_client_server_plugin()
|
||||
link_hifi_libraries(shared plugins)
|
||||
link_hifi_libraries(shared audio plugins)
|
||||
target_opus()
|
||||
|
||||
if (BUILD_SERVER)
|
||||
install_beside_console()
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include <opus/opus_multistream.h>
|
||||
#include <opus/opus_projection.h>
|
||||
|
||||
#include "OpusEncoder.h"
|
||||
#include "OpusDecoder.h"
|
||||
|
||||
#define FRAME_SIZE 960
|
||||
#define SAMPLE_RATE 48000
|
||||
#define CHANNELS 2
|
||||
|
@ -31,56 +34,41 @@
|
|||
#define MAX_FRAME_SIZE 6*FRAME_SIZE
|
||||
#define MAX_PACKET_SIZE 3*1276
|
||||
|
||||
const char* OpusCodec::NAME { "opus" };
|
||||
const char* AthenaOpusCodec::NAME { "opus" };
|
||||
|
||||
void OpusCodec::init() {
|
||||
void AthenaOpusCodec::init() {
|
||||
}
|
||||
|
||||
void OpusCodec::deinit() {
|
||||
void AthenaOpusCodec::deinit() {
|
||||
}
|
||||
|
||||
bool OpusCodec::activate() {
|
||||
bool AthenaOpusCodec::activate() {
|
||||
CodecPlugin::activate();
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpusCodec::deactivate() {
|
||||
void AthenaOpusCodec::deactivate() {
|
||||
CodecPlugin::deactivate();
|
||||
}
|
||||
|
||||
|
||||
bool OpusCodec::isSupported() const {
|
||||
bool AthenaOpusCodec::isSupported() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class OpusEncoder : public Encoder {
|
||||
public:
|
||||
OpusEncoder(int sampleRate, int numChannels) {
|
||||
|
||||
}
|
||||
|
||||
virtual void encode(const QByteArray& decodedBuffer, QByteArray& encodedBuffer) override {
|
||||
encodedBuffer.resize(_encodedSize);
|
||||
}
|
||||
|
||||
private:
|
||||
int _encodedSize;
|
||||
};
|
||||
|
||||
|
||||
Encoder* OpusCodec::createEncoder(int sampleRate, int numChannels) {
|
||||
return new OpusEncoder(sampleRate, numChannels);
|
||||
Encoder* AthenaOpusCodec::createEncoder(int sampleRate, int numChannels) {
|
||||
return new AthenaOpusEncoder(sampleRate, numChannels);
|
||||
}
|
||||
|
||||
Decoder* OpusCodec::createDecoder(int sampleRate, int numChannels) {
|
||||
return this;
|
||||
Decoder* AthenaOpusCodec::createDecoder(int sampleRate, int numChannels) {
|
||||
return new AthenaOpusDecoder(sampleRate, numChannels);
|
||||
}
|
||||
|
||||
void OpusCodec::releaseEncoder(Encoder* encoder) {
|
||||
void AthenaOpusCodec::releaseEncoder(Encoder* encoder) {
|
||||
delete encoder;
|
||||
}
|
||||
|
||||
void OpusCodec::releaseDecoder(Decoder* decoder) {
|
||||
void AthenaOpusCodec::releaseDecoder(Decoder* decoder) {
|
||||
delete decoder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <plugins/CodecPlugin.h>
|
||||
|
||||
class OpusCodec : public CodecPlugin, public Encoder, public Decoder {
|
||||
class AthenaOpusCodec : public CodecPlugin {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -17,20 +17,20 @@
|
|||
|
||||
#include "OpusCodecManager.h"
|
||||
|
||||
class OpusCodecProvider : public QObject, public CodecProvider {
|
||||
class AthenaOpusCodecProvider : public QObject, public CodecProvider {
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID CodecProvider_iid FILE "plugin.json")
|
||||
Q_INTERFACES(CodecProvider)
|
||||
|
||||
public:
|
||||
OpusCodecProvider(QObject* parent = nullptr) : QObject(parent) {}
|
||||
virtual ~OpusCodecProvider() {}
|
||||
AthenaOpusCodecProvider(QObject* parent = nullptr) : QObject(parent) {}
|
||||
virtual ~AthenaOpusCodecProvider() {}
|
||||
|
||||
virtual CodecPluginList getCodecPlugins() override {
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
|
||||
CodecPluginPointer opusCodec(new OpusCodec());
|
||||
CodecPluginPointer opusCodec(new AthenaOpusCodec());
|
||||
if (opusCodec->isSupported()) {
|
||||
_codecPlugins.push_back(opusCodec);
|
||||
}
|
||||
|
|
123
plugins/opusCodec/src/OpusDecoder.cpp
Normal file
123
plugins/opusCodec/src/OpusDecoder.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
#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;
|
||||
|
||||
_opus_sample_rate = sampleRate;
|
||||
_opus_num_channels = 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 buffer_size = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * static_cast<int>(sizeof(int16_t)) * _opus_num_channels;
|
||||
|
||||
decodedBuffer.resize( buffer_size );
|
||||
int buffer_frames = decodedBuffer.size() / _opus_num_channels / static_cast<int>(sizeof( opus_int16 ));
|
||||
|
||||
qCDebug(decoder) << "Opus decode: encodedBytes = " << encodedBuffer.length() << "; decodedBufferBytes = " << decodedBuffer.size() << "; frameCount = " << buffer_frames;
|
||||
int decoded_frames = opus_decode( _decoder, reinterpret_cast<const unsigned char*>(encodedBuffer.data()), encodedBuffer.length(), reinterpret_cast<opus_int16*>(decodedBuffer.data()), buffer_frames, 0 );
|
||||
|
||||
if ( decoded_frames >= 0 ) {
|
||||
//qCDebug(decoder) << "Decoded " << decoded_frames << " Opus frames, " << buffer_frames << " expected";
|
||||
|
||||
if ( decoded_frames < buffer_frames ) {
|
||||
qCWarning(decoder) << "Opus decoder returned " << decoded_frames << ", but " << buffer_frames << " were expected!";
|
||||
|
||||
int start = decoded_frames * static_cast<int>(sizeof(int16_t)) * _opus_num_channels;
|
||||
memset( &decodedBuffer.data()[start], 0, static_cast<size_t>(decodedBuffer.length() - start));
|
||||
} else if ( decoded_frames > buffer_frames ) {
|
||||
// This should never happen
|
||||
qCCritical(decoder) << "Opus decoder returned " << decoded_frames << ", but only " << buffer_frames << " 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 buffer_size = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL * static_cast<int>(sizeof(int16_t)) * _opus_num_channels;
|
||||
decodedBuffer.resize( buffer_size );
|
||||
int buffer_frames = decodedBuffer.size() / _opus_num_channels / static_cast<int>(sizeof( opus_int16 ));
|
||||
|
||||
int decoded_frames = opus_decode( _decoder, nullptr, 0, reinterpret_cast<opus_int16*>(decodedBuffer.data()), buffer_frames, 1 );
|
||||
|
||||
if ( decoded_frames >= 0 ) {
|
||||
//qCDebug(decoder) << "Produced " << decoded_frames << " opus frames from a lost frame, " << buffer_frames << " expected";
|
||||
|
||||
if ( decoded_frames < buffer_frames ) {
|
||||
qCWarning(decoder) << "Opus decoder returned " << decoded_frames << ", but " << buffer_frames << " were expected!";
|
||||
|
||||
int start = decoded_frames * static_cast<int>(sizeof(int16_t)) * _opus_num_channels;
|
||||
memset( &decodedBuffer.data()[start], 0, static_cast<size_t>(decodedBuffer.length() - start));
|
||||
} else if ( decoded_frames > buffer_frames ) {
|
||||
// This should never happen
|
||||
qCCritical(decoder) << "Opus decoder returned " << decoded_frames << ", but only " << buffer_frames << " were expected! Buffer overflow!?";
|
||||
}
|
||||
} else {
|
||||
qCCritical(decoder) << "Failed to decode lost frame: " << error_to_string(decoded_frames);
|
||||
decodedBuffer.fill('\0');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
29
plugins/opusCodec/src/OpusDecoder.h
Normal file
29
plugins/opusCodec/src/OpusDecoder.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#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 _opus_sample_rate = 0;
|
||||
int _opus_num_channels = 0;
|
||||
int _decoded_size = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // OPUSDECODER_H
|
270
plugins/opusCodec/src/OpusEncoder.cpp
Normal file
270
plugins/opusCodec/src/OpusEncoder.cpp
Normal file
|
@ -0,0 +1,270 @@
|
|||
|
||||
#include <PerfStat.h>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include "OpusEncoder.h"
|
||||
#include "OpusWrapper.h"
|
||||
#include "opus/opus.h"
|
||||
|
||||
static QLoggingCategory encoder("AthenaOpusEncoder");
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AthenaOpusEncoder::AthenaOpusEncoder(int sampleRate, int numChannels)
|
||||
{
|
||||
_opus_sample_rate = sampleRate;
|
||||
_opus_channels = numChannels;
|
||||
|
||||
int error;
|
||||
|
||||
_encoder = opus_encoder_create(sampleRate, numChannels, DEFAULT_APPLICATION, &error);
|
||||
|
||||
if ( error != OPUS_OK ) {
|
||||
qCCritical(encoder) << "Failed to initialize Opus encoder: " << error_to_string(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 frame_size = decodedBuffer.length()/ _opus_channels / static_cast<int>(sizeof(opus_int16));
|
||||
|
||||
int bytes = opus_encode(_encoder, reinterpret_cast<const opus_int16*>(decodedBuffer.constData()), frame_size, reinterpret_cast<unsigned char*>(encodedBuffer.data()), encodedBuffer.size() );
|
||||
|
||||
if ( bytes >= 0 ) {
|
||||
//qCDebug(encoder) << "Encoded " << decodedBuffer.length() << " bytes into " << bytes << " opus bytes";
|
||||
encodedBuffer.resize(bytes);
|
||||
} else {
|
||||
encodedBuffer.resize(0);
|
||||
|
||||
qCWarning(encoder) << "Error when encoding " << decodedBuffer.length() << " bytes of audio: " << error_to_string(bytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getComplexity() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_COMPLEXITY(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setComplexity(int complexity)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_COMPLEXITY(complexity));
|
||||
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting complexity to " << complexity << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getBitrate() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_BITRATE(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setBitrate(int bitrate)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting bitrate to " << bitrate << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getVBR() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_VBR(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setVBR(int vbr)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_VBR(vbr));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting VBR to " << vbr << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getVBRConstraint() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_VBR_CONSTRAINT(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setVBRConstraint(int vbr_const)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_VBR_CONSTRAINT(vbr_const));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting VBR constraint to " << vbr_const << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getMaxBandwidth() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_MAX_BANDWIDTH(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setMaxBandwidth(int maxbw)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_MAX_BANDWIDTH(maxbw));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting max bandwidth to " << maxbw << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getBandwidth() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_BANDWIDTH(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setBandwidth(int bw)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_BANDWIDTH(bw));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting bandwidth to " << bw << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getSignal() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_SIGNAL(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setSignal(int signal)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_SIGNAL(signal));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting signal to " << signal << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getApplication() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_APPLICATION(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setApplication(int app)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_APPLICATION(app));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting application to " << app << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getLookahead() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_LOOKAHEAD(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getInbandFEC() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_INBAND_FEC(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setInbandFEC(int fec)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_INBAND_FEC(fec));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting inband FEC to " << fec << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getExpectedPacketLossPercent() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_PACKET_LOSS_PERC(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setExpectedPacketLossPercent(int perc)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_PACKET_LOSS_PERC(perc));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting loss percent to " << perc << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
int AthenaOpusEncoder::getDTX() const
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret;
|
||||
opus_encoder_ctl(_encoder, OPUS_GET_DTX(&ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AthenaOpusEncoder::setDTX(int dtx)
|
||||
{
|
||||
assert(_encoder);
|
||||
int ret = opus_encoder_ctl(_encoder, OPUS_SET_DTX(dtx));
|
||||
if ( ret != OPUS_OK )
|
||||
qCWarning(encoder) << "Error when setting DTX to " << dtx << ": " << error_to_string(ret);
|
||||
}
|
||||
|
||||
|
69
plugins/opusCodec/src/OpusEncoder.h
Normal file
69
plugins/opusCodec/src/OpusEncoder.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef OPUSENCODER_H
|
||||
#define OPUSENCODER_H
|
||||
#include <plugins/CodecPlugin.h>
|
||||
#include "OpusWrapper.h"
|
||||
#include "opus/opus.h"
|
||||
|
||||
|
||||
class AthenaOpusEncoder : public Encoder {
|
||||
public:
|
||||
const int DEFAULT_BITRATE = 128000;
|
||||
const int DEFAULT_COMPLEXITY = 10;
|
||||
const int DEFAULT_APPLICATION = OPUS_APPLICATION_VOIP;
|
||||
const int DEFAULT_SIGNAL = OPUS_AUTO;
|
||||
|
||||
|
||||
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 vbr_const);
|
||||
|
||||
int getMaxBandwidth() const;
|
||||
void setMaxBandwidth(int maxbw);
|
||||
|
||||
int getBandwidth() const;
|
||||
void setBandwidth(int bw);
|
||||
|
||||
int getSignal() const;
|
||||
void setSignal(int signal);
|
||||
|
||||
int getApplication() const;
|
||||
void setApplication(int app);
|
||||
|
||||
int getLookahead() const;
|
||||
|
||||
int getInbandFEC() const;
|
||||
void setInbandFEC(int fec);
|
||||
|
||||
int getExpectedPacketLossPercent() const;
|
||||
void setExpectedPacketLossPercent(int perc);
|
||||
|
||||
int getDTX() const;
|
||||
void setDTX(int dtx);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
int _opus_sample_rate = 0;
|
||||
int _opus_channels = 0;
|
||||
int _opus_expected_loss = 0;
|
||||
|
||||
|
||||
OpusEncoder *_encoder = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif // OPUSENCODER_H
|
|
@ -1,4 +1,4 @@
|
|||
The High Fidelity JavaScript API lets content creators and developers create new experiences and transform virtual worlds within the High Fidelity metaverse. With it, you can build great content, customize avatars, play audio and so much more.
|
||||
The Project Athena JavaScript API lets content creators and developers create new experiences and transform virtual worlds within the High Fidelity metaverse. With it, you can build great content, customize avatars, play audio and so much more.
|
||||
|
||||
You are most likely to interact with these APIs:
|
||||
|
||||
|
@ -6,4 +6,4 @@ You are most likely to interact with these APIs:
|
|||
* The **[AvatarList](AvatarList.html)**, **[MyAvatar](MyAvatar.html)**, and **[Avatar](Avatar.html)** namespaces affect your personal avatars, and lets you get information on other people's avatars.
|
||||
* The **[Script](Script.html)** namespace lets you to connect callbacks from your client to script, such as functionality that is dependent on time (`Script.update`, `Script.setTimeout`, `Script.setInterval`, etc), connect paths relatively to assets (`Script.resolvePath`), refer to other scripts (`Script.require`, `Script.include`), or connect functions to events which occur when the script is turned off (`Script.scriptEnding`).
|
||||
|
||||
To learn more about using High Fidelity and exploring the metaverse, visit the [High Fidelity Documentation](https://docs.highfidelity.com).
|
||||
To learn more about using High Fidelity and exploring the metaverse, visit the [Project Athena Documentation](https://docs.projectathena.dev).
|
||||
|
|
|
@ -697,7 +697,7 @@ exports.publish = function(taffyData, opts, tutorials) {
|
|||
var files = find({kind: 'file'});
|
||||
var packages = find({kind: 'package'});
|
||||
|
||||
generate('', 'High Fidelity API Reference',
|
||||
generate('', 'Project Athena API Reference',
|
||||
packages.concat(
|
||||
[{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}]
|
||||
).concat(files),
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 132 KiB |
Binary file not shown.
After Width: | Height: | Size: 213 KiB |
Binary file not shown.
Before Width: | Height: | Size: 49 KiB |
|
@ -67,6 +67,7 @@ h1
|
|||
font-size: 3.25rem;
|
||||
text-align: center;
|
||||
margin: 50px 25px 25px;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
h2
|
||||
|
|
|
@ -12,15 +12,16 @@
|
|||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
||||
<link href="images/fav-icon.ico" rel="shortcut icon">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="nav-header">
|
||||
<p><a href="https://www.highfidelity.com"><img src="images/white-logo.png" width="214px" /></a></p>
|
||||
<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.highfidelity.com">Looking for <strong>High Fidelity</strong><br /> Documentation?</a></p>
|
||||
<p><a href="https://docs.projectathena.dev">Looking for <strong>Project Athena</strong><br /> Documentation?</a></p>
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
|
|
Loading…
Reference in a new issue