diff --git a/.patch/opus/0001-disable-clang-runtime-neon.patch b/.patch/opus/0001-disable-clang-runtime-neon.patch deleted file mode 100644 index 27a905c366..0000000000 --- a/.patch/opus/0001-disable-clang-runtime-neon.patch +++ /dev/null @@ -1,28 +0,0 @@ -From cc15da16e533b2a801934eab2dfeaf3c3949a1dc Mon Sep 17 00:00:00 2001 -From: crueter -Date: Mon, 8 Sep 2025 12:28:55 -0400 -Subject: [PATCH] [cmake] disable NEON runtime check on clang-cl - -When enabling runtime NEON checking for clang-cl, the linker would error out with `undefined symbol: __emit`, since clang doesn't actually implement this instruction. Therefore it makes sense to disable the runtime check by default on this platform, until either this is fixed or a clang-cl compatible intrinsic check is added (I don't have enough knowledge of MSVC to do this) ---- - cmake/OpusConfig.cmake | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/cmake/OpusConfig.cmake b/cmake/OpusConfig.cmake -index e9319fbad..d0f459e88 100644 ---- a/cmake/OpusConfig.cmake -+++ b/cmake/OpusConfig.cmake -@@ -71,7 +71,12 @@ elseif(OPUS_CPU_ARM AND NOT OPUS_DISABLE_INTRINSICS) - opus_detect_neon(COMPILER_SUPPORT_NEON) - if(COMPILER_SUPPORT_NEON) - option(OPUS_USE_NEON "Option to enable NEON" ON) -- option(OPUS_MAY_HAVE_NEON "Does runtime check for neon support" ON) -+ if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") -+ set(NEON_RUNTIME_CHECK_DEFAULT OFF) -+ else() -+ set(NEON_RUNTIME_CHECK_DEFAULT ON) -+ endif() -+ option(OPUS_MAY_HAVE_NEON "Does runtime check for neon support" ${NEON_RUNTIME_CHECK_DEFAULT}) - option(OPUS_PRESUME_NEON "Assume target CPU has NEON support" OFF) - if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") - set(OPUS_PRESUME_NEON ON) diff --git a/.patch/opus/0002-no-install.patch b/.patch/opus/0002-no-install.patch deleted file mode 100644 index 833a3e4178..0000000000 --- a/.patch/opus/0002-no-install.patch +++ /dev/null @@ -1,153 +0,0 @@ -From bf455b67b4eaa446ffae5d25410b141b7b1b1082 Mon Sep 17 00:00:00 2001 -From: crueter -Date: Mon, 8 Sep 2025 12:08:20 -0400 -Subject: [PATCH] [cmake] `OPUS_INSTALL` option; only default install if root - project - -Signed-off-by: crueter ---- - CMakeLists.txt | 112 ++++++++++++++++++++++++++++--------------------- - 1 file changed, 64 insertions(+), 48 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index fcf034b19..08b5e16f8 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -4,6 +4,13 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - include(OpusPackageVersion) - get_package_version(PACKAGE_VERSION PROJECT_VERSION) - -+# root project detection -+if(DEFINED PROJECT_NAME) -+ set(root_project OFF) -+else() -+ set(root_project ON) -+endif() -+ - project(Opus LANGUAGES C VERSION ${PROJECT_VERSION}) - - include(OpusFunctions) -@@ -83,12 +90,16 @@ set(OPUS_DNN_FLOAT_DEBUG_HELP_STR "Run DNN computations as float for debugging p - option(OPUS_DNN_FLOAT_DEBUG ${OPUS_DNN_FLOAT_DEBUG_HELP_STR} OFF) - add_feature_info(OPUS_DNN_FLOAT_DEBUG OPUS_DNN_FLOAT_DEBUG ${OPUS_DNN_FLOAT_DEBUG_HELP_STR}) - -+set(OPUS_INSTALL_HELP_STR "Install Opus targets") -+option(OPUS_INSTALL ${OPUS_INSTALL_HELP_STR} ${root_project}) -+add_feature_info(OPUS_INSTALL OPUS_INSTALL ${OPUS_INSTALL_HELP_STR}) -+ - set(OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR "install pkg-config module.") --option(OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR} ON) -+option(OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR} ${OPUS_INSTALL}) - add_feature_info(OPUS_INSTALL_PKG_CONFIG_MODULE OPUS_INSTALL_PKG_CONFIG_MODULE ${OPUS_INSTALL_PKG_CONFIG_MODULE_HELP_STR}) - - set(OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR "install CMake package config module.") --option(OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR} ON) -+option(OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR} ${OPUS_INSTALL}) - add_feature_info(OPUS_INSTALL_CMAKE_CONFIG_MODULE OPUS_INSTALL_CMAKE_CONFIG_MODULE ${OPUS_INSTALL_CMAKE_CONFIG_MODULE_HELP_STR}) - - set(OPUS_DRED_HELP_STR "enable DRED.") -@@ -613,53 +624,58 @@ if(OPUS_BUILD_FRAMEWORK) - OUTPUT_NAME Opus) - endif() - --install(TARGETS opus -- EXPORT OpusTargets -- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} -- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -- FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX} -- PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus) -- --if(OPUS_INSTALL_PKG_CONFIG_MODULE) -- set(prefix ${CMAKE_INSTALL_PREFIX}) -- set(exec_prefix ${CMAKE_INSTALL_PREFIX}) -- set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) -- set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) -- set(VERSION ${PACKAGE_VERSION}) -- if(HAVE_LIBM) -- set(LIBM "-lm") -+if (OPUS_INSTALL) -+ install(TARGETS opus -+ EXPORT OpusTargets -+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} -+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -+ FRAMEWORK DESTINATION ${CMAKE_INSTALL_PREFIX} -+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/opus) -+ -+ if(OPUS_INSTALL_PKG_CONFIG_MODULE) -+ set(prefix ${CMAKE_INSTALL_PREFIX}) -+ set(exec_prefix ${CMAKE_INSTALL_PREFIX}) -+ set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) -+ set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) -+ set(VERSION ${PACKAGE_VERSION}) -+ if(HAVE_LIBM) -+ set(LIBM "-lm") -+ endif() -+ configure_file(opus.pc.in opus.pc) -+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc -+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -+ endif() -+ -+ if(OPUS_INSTALL_CMAKE_CONFIG_MODULE) -+ set(CPACK_GENERATOR TGZ) -+ include(CPack) -+ set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) -+ install(EXPORT OpusTargets -+ NAMESPACE Opus:: -+ DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) -+ -+ include(CMakePackageConfigHelpers) -+ -+ set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) -+ configure_package_config_file( -+ ${PROJECT_SOURCE_DIR}/cmake/OpusConfig.cmake.in -+ OpusConfig.cmake -+ INSTALL_DESTINATION -+ ${CMAKE_INSTALL_PACKAGEDIR} -+ PATH_VARS -+ INCLUDE_INSTALL_DIR -+ INSTALL_PREFIX -+ ${CMAKE_INSTALL_PREFIX}) -+ -+ write_basic_package_version_file(OpusConfigVersion.cmake -+ VERSION ${PROJECT_VERSION} -+ COMPATIBILITY SameMajorVersion) -+ -+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake -+ ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake -+ DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) - endif() -- configure_file(opus.pc.in opus.pc) -- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/opus.pc -- DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) --endif() -- --if(OPUS_INSTALL_CMAKE_CONFIG_MODULE) -- set(CPACK_GENERATOR TGZ) -- include(CPack) -- set(CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) -- install(EXPORT OpusTargets -- NAMESPACE Opus:: -- DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) -- -- include(CMakePackageConfigHelpers) -- -- set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) -- configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/OpusConfig.cmake.in -- OpusConfig.cmake -- INSTALL_DESTINATION -- ${CMAKE_INSTALL_PACKAGEDIR} -- PATH_VARS -- INCLUDE_INSTALL_DIR -- INSTALL_PREFIX -- ${CMAKE_INSTALL_PREFIX}) -- write_basic_package_version_file(OpusConfigVersion.cmake -- VERSION ${PROJECT_VERSION} -- COMPATIBILITY SameMajorVersion) -- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/OpusConfig.cmake -- ${CMAKE_CURRENT_BINARY_DIR}/OpusConfigVersion.cmake -- DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) - endif() - - if(OPUS_BUILD_PROGRAMS) diff --git a/CMakeLists.txt b/CMakeLists.txt index 266331b0ac..f5c360b294 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,21 +464,6 @@ if (NOT YUZU_STATIC_ROOM) if (ZLIB_ADDED) add_library(ZLIB::ZLIB ALIAS zlibstatic) endif() - - # Opus - AddJsonPackage(opus) - - if (Opus_ADDED) - if (MSVC AND CXX_CLANG) - target_compile_options(opus PRIVATE - $<$:-Wno-implicit-function-declaration> - ) - endif() - endif() - - if (NOT TARGET Opus::opus) - add_library(Opus::opus ALIAS opus) - endif() endif() if(NOT TARGET Boost::headers) diff --git a/CMakeModules/find/FindOpus.cmake b/CMakeModules/find/FindOpus.cmake deleted file mode 100644 index 257642682e..0000000000 --- a/CMakeModules/find/FindOpus.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - -# SPDX-FileCopyrightText: 2022 yuzu Emulator Project -# SPDX-License-Identifier: GPL-2.0-or-later - -find_package(PkgConfig QUIET) -pkg_search_module(OPUS QUIET IMPORTED_TARGET opus) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Opus - REQUIRED_VARS OPUS_LINK_LIBRARIES - VERSION_VAR OPUS_VERSION -) - -if (MSYS2) - FixMsysPath(PkgConfig::OPUS) -endif() - -if (Opus_FOUND AND NOT TARGET Opus::opus) - add_library(Opus::opus ALIAS PkgConfig::OPUS) -endif() diff --git a/cpmfile.json b/cpmfile.json index 8b2099f40a..419c8d2d69 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -82,7 +82,7 @@ "name": "ffmpeg", "package": "FFmpeg", "repo": "crueter-ci/FFmpeg", - "version": "9.0.1-1788120736-bf1b838f2a" + "version": "9.0.1-1788303113-bf1b838f2a" }, "fmt": { "hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2", @@ -210,21 +210,6 @@ "repo": "jimmy-park/openssl-cmake", "version": "3.6.2" }, - "opus": { - "find_args": "MODULE", - "hash": "9506147b0de35befda8633ff272981cc2575c860874791bd455b752f797fd7dbd1079f0ba42ccdd7bb1fe6773fa5e84b3d75667c2883dd1fb2d0e4a5fa4f8387", - "min_version": "1.3", - "options": [ - "OPUS_PRESUME_NEON ON" - ], - "package": "Opus", - "patches": [ - "0001-disable-clang-runtime-neon.patch", - "0002-no-install.patch" - ], - "repo": "xiph/opus", - "version": "a3f0ec02b3" - }, "quazip": { "hash": "609c240c7f029ac26a37d8fbab51bc16284e05e128b78b9b9c0e95d083538c36047a67d682759ac990e4adb0eeb90f04f1ea7fe2253bbda7e7e3bcce32e53dd8", "min_version": "1.3", diff --git a/docs/Deps.md b/docs/Deps.md index 2b73ecb4ac..9a781ebdcd 100644 --- a/docs/Deps.md +++ b/docs/Deps.md @@ -60,7 +60,6 @@ All other dependencies will be downloaded and built by [CPM](https://github.com/ * [ZLIB](https://www.zlib.net/) 1.2+ * [zstd](https://facebook.github.io/zstd/) 1.5+ * [enet](http://enet.bespin.org/) 1.3+ -* [Opus](https://opus-codec.org/) 1.3+ Vulkan 1.3.274+ is also needed: @@ -121,7 +120,7 @@ sudo emerge -a \ dev-libs/boost dev-libs/openssl dev-libs/discord-rpc \ dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \ dev-util/vulkan-utility-libraries dev-util/glslang \ - media-gfx/renderdoc media-libs/libva media-libs/opus media-video/ffmpeg \ + media-gfx/renderdoc media-libs/libva media-video/ffmpeg \ media-libs/VulkanMemoryAllocator media-libs/libsdl3 media-libs/cubeb \ net-libs/enet \ sys-libs/zlib \ @@ -153,7 +152,7 @@ Required USE flags: Arch Linux ```sh -sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 ninja nlohmann-json openssl opus qt6-base qt6-multimedia qt6-charts sdl3 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers +sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 ninja nlohmann-json openssl qt6-base qt6-multimedia qt6-charts sdl3 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers ``` * Building with QT Web Engine requires `qt6-webengine` as well. @@ -166,7 +165,7 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl Ubuntu, Debian, Mint Linux ```sh -sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev qt6-charts-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl3-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev +sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev qt6-charts-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl3-dev libasound2t64 vulkan-utility-libraries-dev ``` * Ubuntu 26.04, Linux Mint 22.3, or Debian 13 or later is required. @@ -213,7 +212,7 @@ First, enable the community repository; [see here](https://wiki.alpinelinux.org/ # Enable the community repository setup-apkrepos -c # Install -apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev jq patch +apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev jq patch ``` @@ -261,7 +260,7 @@ brew install molten-vk As root run: ```sh -pkg install devel/cmake devel/sdl3 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base x11-toolkits/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib graphics/vulkan-utility-libraries graphics/vulkan-headers graphics/spirv-headers quazip-qt6 +pkg install devel/cmake devel/sdl3 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base x11-toolkits/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib graphics/vulkan-utility-libraries graphics/vulkan-headers graphics/spirv-headers quazip-qt6 ``` If using FreeBSD 12 or prior, use `devel/pkg-config` instead. @@ -275,7 +274,7 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead. For NetBSD +10.1: ```sh -pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6-qtbase qt6-qtcharts qt6-qtmultimedia qt6-qttools cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen +pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq qt6-qtbase qt6-qtcharts qt6-qtmultimedia qt6-qttools cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen ``` [Caveats](./Caveats.md#netbsd). @@ -306,7 +305,7 @@ pkg install gcc14 git cmake unzip nasm autoconf bash pkgconf ffmpeg glslang gmak OpenIndiana ```sh -sudo pkg install git cmake qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl3 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt +sudo pkg install git cmake qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl sdl3 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt ``` [Caveats](./Caveats.md#openindiana). @@ -330,7 +329,7 @@ sudo pkgin install git cmake autoconf build-essential libusb-1 nasm gcc13 ```sh BASE="git make autoconf libtool automake-wrapper jq patch" -MINGW="qt6-base qt6-charts qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus libusb openssl SDL3" +MINGW="qt6-base qt6-charts qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet libusb openssl SDL3" # Either x86_64 or clang-aarch64 (Windows on ARM) packages="$BASE" for pkg in $MINGW; do @@ -356,7 +355,7 @@ pacman -Syuu --needed --noconfirm $packages HaikuOS ```sh -pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel cubeb_devel simpleini quazip_qt6_devel +pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel cubeb_devel simpleini quazip_qt6_devel ``` [Caveats](./Caveats.md#haikuos). diff --git a/shell.nix b/shell.nix index 786b94ccb2..e4d57d7e5e 100755 --- a/shell.nix +++ b/shell.nix @@ -12,7 +12,7 @@ pkgs.mkShellNoCC { git cmake clang gnumake patch jq pkg-config # libraries openssl boost fmt nlohmann_json lz4 zlib zstd - enet libopus vulkan-headers vulkan-utility-libraries + enet vulkan-headers vulkan-utility-libraries spirv-tools spirv-headers vulkan-loader unzip glslang python3 httplib cpp-jwt ffmpeg-headless libusb1 cubeb diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt index 32b72fe38f..226edfa00c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt @@ -79,13 +79,6 @@ class LicensesFragment : Fragment() { R.string.license_ffmpeg_copyright, R.string.license_ffmpeg_text ), - License( - R.string.license_opus, - R.string.license_opus_description, - R.string.license_opus_link, - R.string.license_opus_copyright, - R.string.license_opus_text - ), License( R.string.license_sirit, R.string.license_sirit_description, diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index a9200bbca9..ca7263ead7 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -1783,51 +1783,6 @@ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - Opus - Modern audio compression for the internet - https://github.com/xiph/opus - Copyright 2001–2011 Xiph.Org, Skype Limited, Octasic, Jean-Marc Valin, Timothy B. Terriberry, CSIRO, Gregory Maxwell, Mark Borgerding, Erik de Castro Lopo - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met:\n\n - -- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer.\n\n - -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution.\n\n - -- Neither the name of Internet Society, IETF or IETF Trust, nor the -names of specific contributors, may be used to endorse or promote -products derived from this software without specific prior written -permission.\n\n - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n - -Opus is subject to the royalty-free patent licenses which are -specified at:\n\n - -Xiph.Org Foundation: -https://datatracker.ietf.org/ipr/1524/ \n\n - -Microsoft Corporation: -https://datatracker.ietf.org/ipr/1914/ \n\n - -Broadcom Corporation: -https://datatracker.ietf.org/ipr/1526/ Sirit A runtime SPIR-V assembler diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index b244d657a9..71a46a7b1e 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -15,10 +15,6 @@ add_library(audio_core STATIC adsp/apps/audio_renderer/command_list_processor.h adsp/apps/opus/opus_decoder.cpp adsp/apps/opus/opus_decoder.h - adsp/apps/opus/opus_decode_object.cpp - adsp/apps/opus/opus_decode_object.h - adsp/apps/opus/opus_multistream_decode_object.cpp - adsp/apps/opus/opus_multistream_decode_object.h adsp/apps/opus/shared_memory.h audio_core.cpp audio_core.h @@ -226,8 +222,14 @@ else() $<$:-Wno-sign-conversion>) endif() -target_include_directories(audio_core PRIVATE ${OPUS_INCLUDE_DIRS}) -target_link_libraries(audio_core PUBLIC common core Opus::opus) +if (YUZU_USE_EXTERNAL_FFMPEG) + add_dependencies(audio_core ffmpeg-build) +endif() +target_include_directories(audio_core PUBLIC ${FFmpeg_INCLUDE_DIR}) +target_link_libraries(audio_core PRIVATE ${FFmpeg_LIBRARIES}) +target_link_options(audio_core PRIVATE ${FFmpeg_LDFLAGS}) + +target_link_libraries(audio_core PUBLIC common core) if (ENABLE_CUBEB) target_sources(audio_core PRIVATE diff --git a/src/audio_core/adsp/apps/opus/opus_decode_object.cpp b/src/audio_core/adsp/apps/opus/opus_decode_object.cpp deleted file mode 100644 index e2b9eb566c..0000000000 --- a/src/audio_core/adsp/apps/opus/opus_decode_object.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "audio_core/adsp/apps/opus/opus_decode_object.h" -#include "common/assert.h" - -namespace AudioCore::ADSP::OpusDecoder { -namespace { -bool IsValidChannelCount(u32 channel_count) { - return channel_count == 1 || channel_count == 2; -} -} // namespace - -u32 OpusDecodeObject::GetWorkBufferSize(u32 channel_count) { - if (!IsValidChannelCount(channel_count)) { - return 0; - } - return static_cast(sizeof(OpusDecodeObject)) + opus_decoder_get_size(channel_count); -} - -OpusDecodeObject& OpusDecodeObject::Initialize(u64 buffer, u64 buffer2) { - auto* new_decoder = reinterpret_cast(buffer); - auto* comparison = reinterpret_cast(buffer2); - - if (new_decoder->magic == DecodeObjectMagic) { - if (!new_decoder->initialized || - (new_decoder->initialized && new_decoder->self == comparison)) { - new_decoder->state_valid = true; - } - } else { - new_decoder->initialized = false; - new_decoder->state_valid = true; - } - return *new_decoder; -} - -s32 OpusDecodeObject::InitializeDecoder(u32 sample_rate, u32 channel_count) { - if (!state_valid) { - return OPUS_INVALID_STATE; - } - - if (initialized) { - return OPUS_OK; - } - - // Unfortunately libopus does not expose the OpusDecoder struct publicly, so we can't include - // it in this class. Nintendo does not allocate memory, which is why we have a workbuffer - // provided. - // We could use _create and have libopus allocate it for us, but then we have to separately - // track which decoder is being used between this and multistream in order to call the correct - // destroy from the host side. - // This is a bit cringe, but is safe as these objects are only ever initialized inside the given - // workbuffer, and GetWorkBufferSize will guarantee there's enough space to follow. - decoder = (LibOpusDecoder*)(this + 1); - s32 ret = opus_decoder_init(decoder, sample_rate, channel_count); - if (ret == OPUS_OK) { - magic = DecodeObjectMagic; - initialized = true; - state_valid = true; - self = this; - final_range = 0; - } - return ret; -} - -s32 OpusDecodeObject::Shutdown() { - if (!state_valid) { - return OPUS_INVALID_STATE; - } - - if (initialized) { - magic = 0x0; - initialized = false; - state_valid = false; - self = nullptr; - final_range = 0; - decoder = nullptr; - } - return OPUS_OK; -} - -s32 OpusDecodeObject::ResetDecoder() { - return opus_decoder_ctl(decoder, OPUS_RESET_STATE); -} - -s32 OpusDecodeObject::Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, - u64 input_data, u64 input_data_size) { - ASSERT(initialized); - out_sample_count = 0; - - if (!state_valid) { - return OPUS_INVALID_STATE; - } - - auto ret_code_or_samples = opus_decode( - decoder, reinterpret_cast(input_data), static_cast(input_data_size), - reinterpret_cast(output_data), static_cast(output_data_size), 0); - - if (ret_code_or_samples < OPUS_OK) { - return ret_code_or_samples; - } - - out_sample_count = ret_code_or_samples; - return opus_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range); -} - -} // namespace AudioCore::ADSP::OpusDecoder diff --git a/src/audio_core/adsp/apps/opus/opus_decode_object.h b/src/audio_core/adsp/apps/opus/opus_decode_object.h deleted file mode 100644 index 6425f987c6..0000000000 --- a/src/audio_core/adsp/apps/opus/opus_decode_object.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "common/common_types.h" - -namespace AudioCore::ADSP::OpusDecoder { -using LibOpusDecoder = ::OpusDecoder; -static constexpr u32 DecodeObjectMagic = 0xDEADBEEF; - -class OpusDecodeObject { -public: - static u32 GetWorkBufferSize(u32 channel_count); - static OpusDecodeObject& Initialize(u64 buffer, u64 buffer2); - - s32 InitializeDecoder(u32 sample_rate, u32 channel_count); - s32 Shutdown(); - s32 ResetDecoder(); - s32 Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, u64 input_data, - u64 input_data_size); - u32 GetFinalRange() const noexcept { - return final_range; - } - -private: - u32 magic; - bool initialized; - bool state_valid; - OpusDecodeObject* self; - u32 final_range; - LibOpusDecoder* decoder; -}; -static_assert(std::is_trivially_constructible_v); - -} // namespace AudioCore::ADSP::OpusDecoder diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.cpp b/src/audio_core/adsp/apps/opus/opus_decoder.cpp index 8a009c04c7..0be0f774b1 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.cpp +++ b/src/audio_core/adsp/apps/opus/opus_decoder.cpp @@ -5,55 +5,388 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include -#include "audio_core/adsp/apps/opus/opus_decode_object.h" -#include "audio_core/adsp/apps/opus/opus_multistream_decode_object.h" +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +} + #include "audio_core/adsp/apps/opus/shared_memory.h" #include "audio_core/audio_core.h" -#include "audio_core/common/common.h" #include "common/logging.h" #include "common/thread.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hle/service/audio/errors.h" namespace AudioCore::ADSP::OpusDecoder { namespace { -constexpr size_t OpusStreamCountMax = 255; +constexpr u32 OPUS_STREAM_COUNT_MAX = 255; +// https://git.ffmpeg.org/gitweb/ffmpeg.git/blob_plain/HEAD:/libavcodec/libopusdec.c +constexpr u32 OPUS_HEAD_SIZE = 19; +constexpr u32 OPUS_MAX_CHANNELS = 2; bool IsValidChannelCount(u32 channel_count) { - return channel_count == 1 || channel_count == 2; + return channel_count >= 1 || channel_count <= OPUS_MAX_CHANNELS; } -bool IsValidMultiStreamChannelCount(u32 channel_count) { - return channel_count <= OpusStreamCountMax; +bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) { + return total_stream_count > 0 && total_stream_count <= OPUS_STREAM_COUNT_MAX + && s32(stereo_stream_count) >= 0 && stereo_stream_count <= total_stream_count; } -bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 stereo_stream_count) { - return IsValidMultiStreamChannelCount(total_stream_count) && total_stream_count > 0 && - stereo_stream_count >= 0 && stereo_stream_count <= total_stream_count; -} +class OpusGenericDecodeObject { +public: + static u32 GetWorkBufferSizeMultistream(u32 total_stream_count, u32 stereo_stream_count) { + if (IsValidStreamCounts(total_stream_count, stereo_stream_count)) + return 48 + 2556 * (total_stream_count * stereo_stream_count); + return 0; + } + + static u32 GetWorkBufferSize(u32 channel_count) { + if (channel_count == 1 || channel_count == 2) + return 48 + 16 * channel_count; + return 0; + } + + /// idempotency of initialize is guaranteed + Result InitializeDecoder(u32 sample_rate, u32 total_stream_count, u32 channel_count, u32 stereo_stream_count, u8 const* mappings) { + // prefer libopus, ffmpeg docs say to use libopus **if** available + // However, native opus can also work with swrescale: + // it uses planarfloat, we can resample to s16 + AVCodec const* codec = avcodec_find_decoder_by_name("libopus"); + bool is_libopus = codec != nullptr; + if (!codec) { + LOG_WARNING(Audio_DSP, "using ffmpeg native opus decoder"); + codec = avcodec_find_decoder(AV_CODEC_ID_OPUS); + } + if (codec) { + if ((avc = avc ? avc : avcodec_alloc_context3(codec))) { + if (is_libopus) { + const std::array mapping_arr{0, 1}; + mappings = mappings ? mappings : mapping_arr.data(); + + // freed by avcodec_context_free() + u8 *edata = reinterpret_cast(av_mallocz(OPUS_HEAD_SIZE + 2 * OPUS_MAX_CHANNELS + AV_INPUT_BUFFER_PADDING_SIZE)); + ASSERT(edata); + edata[9] = u8(channel_count); //channels + edata[10] = u8(0); //opus->pre_skip + edata[16] = u8(0); //gain_db + edata[18] = u8(0); //channel_map + edata[OPUS_HEAD_SIZE + 0] = u8(total_stream_count); + edata[OPUS_HEAD_SIZE + 1] = u8(stereo_stream_count); + if (channel_count >= 1) edata[OPUS_HEAD_SIZE + 2] = mappings[0]; + if (channel_count >= 2) edata[OPUS_HEAD_SIZE + 3] = mappings[1]; + avc->extradata = edata; + avc->extradata_size = OPUS_HEAD_SIZE + 2 * channel_count; + } + + + // FFmpeg hardcodes sample rate + avc->sample_rate = sample_rate; + avc->request_sample_fmt = AV_SAMPLE_FMT_S16; + av_channel_layout_default(&avc->ch_layout, channel_count); + if (avcodec_open2(avc, codec, nullptr) >= 0) { + avpkt = av_packet_alloc(); + frame = av_frame_alloc(); + return ResultSuccess; + } else { + avcodec_free_context(&avc); + } + } + } + return Service::Audio::ResultLibOpusInternalError; + } + + Result Shutdown() { + avcodec_free_context(&avc); + av_frame_free(&frame); + av_packet_free(&avpkt); + return ResultSuccess; + } + + Result ResetDecoder() { + if (avc) { + if (avcodec_is_open(avc)) avcodec_flush_buffers(avc); + return ResultSuccess; + } + return Service::Audio::ResultLibOpusInvalidState; + } + + Result Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, u64 input_data, u64 input_data_size) { + out_sample_count = 0; + if (avc) { + int rem_output_bytes = int(output_data_size); + while (rem_output_bytes > 0) { + int r = avcodec_receive_frame(avc, frame); + if (r == AVERROR(EAGAIN)) { + av_packet_unref(avpkt); + av_new_packet(avpkt, int(input_data_size)); + std::memcpy(avpkt->data, reinterpret_cast(input_data), input_data_size); + r = avcodec_send_packet(avc, avpkt); + ASSERT(r >= 0); + } else if (r == AVERROR_EOF) { + break; + } else if (r >= 0) { + auto const bsize = av_samples_get_buffer_size(nullptr, frame->ch_layout.nb_channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1); + if (frame->format == AV_SAMPLE_FMT_S16) { + std::memcpy(reinterpret_cast(output_data) + (int(output_data_size) - rem_output_bytes), frame->data[0], size_t(bsize)); + } else { + SwrContext *swr = nullptr; + if (swr_alloc_set_opts2( + &swr, + &avc->ch_layout, + AV_SAMPLE_FMT_S16, + 48000, + &avc->ch_layout, + (enum AVSampleFormat)frame->format, + 48000, + 0, + nullptr + ) >= 0) { + if (swr_init(swr) >= 0) { + AVFrame *s16_frame = av_frame_alloc(); + s16_frame->format = AV_SAMPLE_FMT_S16; + s16_frame->sample_rate = frame->sample_rate; + av_channel_layout_copy(&s16_frame->ch_layout, &frame->ch_layout); + s16_frame->nb_samples = frame->nb_samples; + av_frame_get_buffer(s16_frame, 0); + swr_convert(swr, s16_frame->data, s16_frame->nb_samples, (const uint8_t **)frame->data, frame->nb_samples); + std::memcpy(reinterpret_cast(output_data) + (int(output_data_size) - rem_output_bytes), s16_frame->data[0], size_t(bsize)); + swr_free(&swr); + } + } + } + out_sample_count += frame->nb_samples; + rem_output_bytes -= bsize; + } else { + LOG_ERROR(Audio_DSP, "{}", r); + break; + } + } + ASSERT(rem_output_bytes == 0 && "remaining bytes!"); + return ResultSuccess; + } + return Service::Audio::ResultLibOpusInvalidState; + } + + AVCodecContext* avc = nullptr; + AVPacket* avpkt = nullptr; + AVFrame* frame = nullptr; +}; } // namespace -OpusDecoder::OpusDecoder(Core::System& system_) : system{system_} { - init_thread = std::jthread([this](std::stop_token stop_token) { Init(stop_token); }); +OpusDecoder::OpusDecoder(Core::System& system) { + dsp_thread = std::jthread([this, &system](std::stop_token stop_token) { + Common::SetCurrentThreadName("DSP_OpusDecoder"); + if (Receive(Direction::DSP, stop_token) != Message::Start) { + LOG_ERROR(Service_Audio, "DSP OpusDecoder failed to receive Start message. Opus initialization failed."); + return; + } + Send(Direction::Host, Message::StartOK); + + // Main OpusDecoder thread, responsible for processing the incoming Opus packets. + ::Common::unordered_map decode_objects; + while (!stop_token.stop_requested()) { + auto msg = Receive(Direction::DSP, stop_token); + switch (msg) { + case Shutdown: + Send(Direction::Host, Message::ShutdownOK); + return; + case GetWorkBufferSize: { + auto channel_count = s32(shared_memory->host_send_data[0]); + + ASSERT(IsValidChannelCount(channel_count)); + + shared_memory->dsp_return_data[0] = OpusGenericDecodeObject::GetWorkBufferSize(channel_count); + Send(Direction::Host, Message::GetWorkBufferSizeOK); + break; + } + case InitializeDecodeObject: { + auto buffer = shared_memory->host_send_data[0]; + auto buffer_size = shared_memory->host_send_data[1]; + auto sample_rate = s32(shared_memory->host_send_data[2]); + auto channel_count = s32(shared_memory->host_send_data[3]); + + ASSERT(sample_rate >= 0); + ASSERT(IsValidChannelCount(channel_count)); + ASSERT(buffer_size >= OpusGenericDecodeObject::GetWorkBufferSize(channel_count)); + + if (auto const it = decode_objects.find(buffer); it != decode_objects.end()) { + it->second.Shutdown(); + shared_memory->dsp_return_data[0] = it->second.InitializeDecoder(sample_rate, 1, channel_count, channel_count == 2 ? 1 : 0, nullptr).raw; + } else { + OpusGenericDecodeObject obj{}; + shared_memory->dsp_return_data[0] = obj.InitializeDecoder(sample_rate, 1, channel_count, channel_count == 2 ? 1 : 0, nullptr).raw; + decode_objects.insert_or_assign(buffer, obj); + } + Send(Direction::Host, Message::InitializeDecodeObjectOK); + break; + } + case ShutdownDecodeObject: { + auto buffer = shared_memory->host_send_data[0]; + //[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; + if (auto const it = decode_objects.find(buffer); it != decode_objects.end()) { + shared_memory->dsp_return_data[0] = it->second.Shutdown().raw; + } else { + LOG_ERROR(Audio_DSP, "operating unregistered buffer {}", buffer); + shared_memory->dsp_return_data[0] = Service::Audio::ResultLibOpusInvalidState.raw; + } + Send(Direction::Host, Message::ShutdownDecodeObjectOK); + break; + } + case DecodeInterleaved: { + auto start_time = system.CoreTiming().GetGlobalTimeUs(); + + auto buffer = shared_memory->host_send_data[0]; + auto input_data = shared_memory->host_send_data[1]; + auto input_data_size = shared_memory->host_send_data[2]; + auto output_data = shared_memory->host_send_data[3]; + auto output_data_size = shared_memory->host_send_data[4]; + //auto final_range = static_cast(shared_memory->host_send_data[5]); + auto reset_requested = shared_memory->host_send_data[6]; + + u32 decoded_samples{0}; + + if (auto const it = decode_objects.find(buffer); it != decode_objects.end()) { + auto res = ResultSuccess; + if (reset_requested) + res = it->second.ResetDecoder(); + if (res == ResultSuccess) + res = it->second.Decode(decoded_samples, output_data, output_data_size, input_data, input_data_size); + + auto end_time = system.CoreTiming().GetGlobalTimeUs(); + shared_memory->dsp_return_data[0] = res.raw; + shared_memory->dsp_return_data[1] = decoded_samples; + shared_memory->dsp_return_data[2] = (end_time - start_time).count(); + } else { + LOG_ERROR(Audio_DSP, "operating unregistered buffer {}", buffer); + shared_memory->dsp_return_data[0] = Service::Audio::ResultLibOpusInvalidState.raw; + } + Send(Direction::Host, Message::DecodeInterleavedOK); + break; + } + case MapMemory: { + [[maybe_unused]] auto buffer = shared_memory->host_send_data[0]; + [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; + Send(Direction::Host, Message::MapMemoryOK); + break; + } + case UnmapMemory: { + [[maybe_unused]] auto buffer = shared_memory->host_send_data[0]; + [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; + Send(Direction::Host, Message::UnmapMemoryOK); + break; + } + case GetWorkBufferSizeForMultiStream: { + auto total_stream_count = s32(shared_memory->host_send_data[0]); + auto stereo_stream_count = s32(shared_memory->host_send_data[1]); + + ASSERT(IsValidStreamCounts(total_stream_count, stereo_stream_count)); + + shared_memory->dsp_return_data[0] = OpusGenericDecodeObject::GetWorkBufferSizeMultistream(total_stream_count, stereo_stream_count); + Send(Direction::Host, Message::GetWorkBufferSizeForMultiStreamOK); + break; + } + case InitializeMultiStreamDecodeObject: { + auto buffer = shared_memory->host_send_data[0]; + auto buffer_size = shared_memory->host_send_data[1]; + auto sample_rate = s32(shared_memory->host_send_data[2]); + auto channel_count = s32(shared_memory->host_send_data[3]); + auto total_stream_count = s32(shared_memory->host_send_data[4]); + auto stereo_stream_count = s32(shared_memory->host_send_data[5]); + // Nintendo seem to have a bug here, they try to use &host_send_data[6] for the channel + // mappings, but [6] is never set, and there is not enough room in the argument data for + // more than 40 channels, when 255 are possible. + // It also means the mapping values are undefined, though likely always 0, + // and the mappings given by the game are ignored. The mappings are copied to this + // dedicated buffer host side, so let's do as intended. + auto mappings = shared_memory->channel_mapping.data(); + + ASSERT(IsValidStreamCounts(total_stream_count, stereo_stream_count)); + ASSERT(sample_rate >= 0); + ASSERT(buffer_size >= OpusGenericDecodeObject::GetWorkBufferSizeMultistream(total_stream_count, stereo_stream_count)); + if (auto const it = decode_objects.find(buffer); it != decode_objects.end()) { + it->second.Shutdown(); + shared_memory->dsp_return_data[0] = it->second.InitializeDecoder(sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings).raw; + } else { + OpusGenericDecodeObject obj{}; + shared_memory->dsp_return_data[0] = obj.InitializeDecoder(sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings).raw; + decode_objects.insert_or_assign(buffer, obj); + } + Send(Direction::Host, Message::InitializeMultiStreamDecodeObjectOK); + break; + } + case ShutdownMultiStreamDecodeObject: { + auto buffer = shared_memory->host_send_data[0]; + //[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; + if (auto const it = decode_objects.find(buffer); it != decode_objects.end()) { + shared_memory->dsp_return_data[0] = it->second.Shutdown().raw; + } else { + LOG_ERROR(Audio_DSP, "operating unregistered buffer {}", buffer); + shared_memory->dsp_return_data[0] = Service::Audio::ResultLibOpusInvalidState.raw; + } + Send(Direction::Host, Message::ShutdownMultiStreamDecodeObjectOK); + break; + } + case DecodeInterleavedForMultiStream: { + auto start_time = system.CoreTiming().GetGlobalTimeUs(); + + auto buffer = shared_memory->host_send_data[0]; + auto input_data = shared_memory->host_send_data[1]; + auto input_data_size = shared_memory->host_send_data[2]; + auto output_data = shared_memory->host_send_data[3]; + auto output_data_size = shared_memory->host_send_data[4]; + //auto final_range = static_cast(shared_memory->host_send_data[5]); + auto reset_requested = shared_memory->host_send_data[6]; + + u32 decoded_samples{0}; + + if (auto const it = decode_objects.find(buffer); it != decode_objects.end()) { + auto res = ResultSuccess; + if (reset_requested) + res = it->second.ResetDecoder(); + if (res == ResultSuccess) + res = it->second.Decode(decoded_samples, output_data, output_data_size, input_data, input_data_size); + + auto end_time = system.CoreTiming().GetGlobalTimeUs(); + shared_memory->dsp_return_data[0] = res.raw; + shared_memory->dsp_return_data[1] = decoded_samples; + shared_memory->dsp_return_data[2] = (end_time - start_time).count(); + } else { + LOG_ERROR(Audio_DSP, "operating unregistered buffer {}", buffer); + shared_memory->dsp_return_data[0] = Service::Audio::ResultLibOpusInvalidState.raw; + } + Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK); + break; + } + default: + LOG_ERROR(Audio_DSP, "Invalid OpusDecoder command {}", msg); + continue; + } + } + for (auto e : decode_objects) + e.second.Shutdown(); + }); } OpusDecoder::~OpusDecoder() { - if (!running) { - init_thread.request_stop(); - return; + if (dsp_thread.joinable()) { + // Shutdown the thread + auto const stop_token = dsp_thread.get_stop_token(); + Send(Direction::DSP, Message::Shutdown); + auto msg = Receive(Direction::Host, stop_token); + ASSERT_MSG(msg == Message::ShutdownOK, "Expected Opus shutdown code {}, got {}", Message::ShutdownOK, msg); + dsp_thread.request_stop(); + dsp_thread.join(); } - - // Shutdown the thread - Send(Direction::DSP, Message::Shutdown); - auto msg = Receive(Direction::Host); - ASSERT_MSG(msg == Message::ShutdownOK, "Expected Opus shutdown code {}, got {}", - Message::ShutdownOK, msg); - main_thread.request_stop(); - main_thread.join(); - running = false; } void OpusDecoder::Send(Direction dir, u32 message) { @@ -64,206 +397,4 @@ u32 OpusDecoder::Receive(Direction dir, std::stop_token stop_token) { return mailbox.Receive(dir, stop_token); } -void OpusDecoder::Init(std::stop_token stop_token) { - Common::SetCurrentThreadName("DSP_OpusDecoder_Init"); - - if (Receive(Direction::DSP, stop_token) != Message::Start) { - LOG_ERROR(Service_Audio, - "DSP OpusDecoder failed to receive Start message. Opus initialization failed."); - return; - } - main_thread = std::jthread([this](std::stop_token st) { Main(st); }); - running = true; - Send(Direction::Host, Message::StartOK); -} - -void OpusDecoder::Main(std::stop_token stop_token) { - Common::SetCurrentThreadName("DSP_OpusDecoder_Main"); - - while (!stop_token.stop_requested()) { - auto msg = Receive(Direction::DSP, stop_token); - switch (msg) { - case Shutdown: - Send(Direction::Host, Message::ShutdownOK); - return; - - case GetWorkBufferSize: { - auto channel_count = static_cast(shared_memory->host_send_data[0]); - - ASSERT(IsValidChannelCount(channel_count)); - - shared_memory->dsp_return_data[0] = OpusDecodeObject::GetWorkBufferSize(channel_count); - Send(Direction::Host, Message::GetWorkBufferSizeOK); - } break; - - case InitializeDecodeObject: { - auto buffer = shared_memory->host_send_data[0]; - auto buffer_size = shared_memory->host_send_data[1]; - auto sample_rate = static_cast(shared_memory->host_send_data[2]); - auto channel_count = static_cast(shared_memory->host_send_data[3]); - - ASSERT(sample_rate >= 0); - ASSERT(IsValidChannelCount(channel_count)); - ASSERT(buffer_size >= OpusDecodeObject::GetWorkBufferSize(channel_count)); - - auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); - shared_memory->dsp_return_data[0] = - decoder_object.InitializeDecoder(sample_rate, channel_count); - - Send(Direction::Host, Message::InitializeDecodeObjectOK); - } break; - - case ShutdownDecodeObject: { - auto buffer = shared_memory->host_send_data[0]; - [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; - - auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); - shared_memory->dsp_return_data[0] = decoder_object.Shutdown(); - - Send(Direction::Host, Message::ShutdownDecodeObjectOK); - } break; - - case DecodeInterleaved: { - auto start_time = system.CoreTiming().GetGlobalTimeUs(); - - auto buffer = shared_memory->host_send_data[0]; - auto input_data = shared_memory->host_send_data[1]; - auto input_data_size = shared_memory->host_send_data[2]; - auto output_data = shared_memory->host_send_data[3]; - auto output_data_size = shared_memory->host_send_data[4]; - auto final_range = static_cast(shared_memory->host_send_data[5]); - auto reset_requested = shared_memory->host_send_data[6]; - - u32 decoded_samples{0}; - - auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer); - s32 error_code{OPUS_OK}; - if (reset_requested) { - error_code = decoder_object.ResetDecoder(); - } - - if (error_code == OPUS_OK) { - error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, - input_data, input_data_size); - } - - if (error_code == OPUS_OK) { - if (final_range && decoder_object.GetFinalRange() != final_range) { - error_code = OPUS_INVALID_PACKET; - } - } - - auto end_time = system.CoreTiming().GetGlobalTimeUs(); - shared_memory->dsp_return_data[0] = error_code; - shared_memory->dsp_return_data[1] = decoded_samples; - shared_memory->dsp_return_data[2] = (end_time - start_time).count(); - - Send(Direction::Host, Message::DecodeInterleavedOK); - } break; - - case MapMemory: { - [[maybe_unused]] auto buffer = shared_memory->host_send_data[0]; - [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; - Send(Direction::Host, Message::MapMemoryOK); - } break; - - case UnmapMemory: { - [[maybe_unused]] auto buffer = shared_memory->host_send_data[0]; - [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; - Send(Direction::Host, Message::UnmapMemoryOK); - } break; - - case GetWorkBufferSizeForMultiStream: { - auto total_stream_count = static_cast(shared_memory->host_send_data[0]); - auto stereo_stream_count = static_cast(shared_memory->host_send_data[1]); - - ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count)); - - shared_memory->dsp_return_data[0] = OpusMultiStreamDecodeObject::GetWorkBufferSize( - total_stream_count, stereo_stream_count); - Send(Direction::Host, Message::GetWorkBufferSizeForMultiStreamOK); - } break; - - case InitializeMultiStreamDecodeObject: { - auto buffer = shared_memory->host_send_data[0]; - auto buffer_size = shared_memory->host_send_data[1]; - auto sample_rate = static_cast(shared_memory->host_send_data[2]); - auto channel_count = static_cast(shared_memory->host_send_data[3]); - auto total_stream_count = static_cast(shared_memory->host_send_data[4]); - auto stereo_stream_count = static_cast(shared_memory->host_send_data[5]); - // Nintendo seem to have a bug here, they try to use &host_send_data[6] for the channel - // mappings, but [6] is never set, and there is not enough room in the argument data for - // more than 40 channels, when 255 are possible. - // It also means the mapping values are undefined, though likely always 0, - // and the mappings given by the game are ignored. The mappings are copied to this - // dedicated buffer host side, so let's do as intended. - auto mappings = shared_memory->channel_mapping.data(); - - ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count)); - ASSERT(sample_rate >= 0); - ASSERT(buffer_size >= OpusMultiStreamDecodeObject::GetWorkBufferSize( - total_stream_count, stereo_stream_count)); - - auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); - shared_memory->dsp_return_data[0] = decoder_object.InitializeDecoder( - sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings); - - Send(Direction::Host, Message::InitializeMultiStreamDecodeObjectOK); - } break; - - case ShutdownMultiStreamDecodeObject: { - auto buffer = shared_memory->host_send_data[0]; - [[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1]; - - auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); - shared_memory->dsp_return_data[0] = decoder_object.Shutdown(); - - Send(Direction::Host, Message::ShutdownMultiStreamDecodeObjectOK); - } break; - - case DecodeInterleavedForMultiStream: { - auto start_time = system.CoreTiming().GetGlobalTimeUs(); - - auto buffer = shared_memory->host_send_data[0]; - auto input_data = shared_memory->host_send_data[1]; - auto input_data_size = shared_memory->host_send_data[2]; - auto output_data = shared_memory->host_send_data[3]; - auto output_data_size = shared_memory->host_send_data[4]; - auto final_range = static_cast(shared_memory->host_send_data[5]); - auto reset_requested = shared_memory->host_send_data[6]; - - u32 decoded_samples{0}; - - auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer); - s32 error_code{OPUS_OK}; - if (reset_requested) { - error_code = decoder_object.ResetDecoder(); - } - - if (error_code == OPUS_OK) { - error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size, - input_data, input_data_size); - } - - if (error_code == OPUS_OK) { - if (final_range && decoder_object.GetFinalRange() != final_range) { - error_code = OPUS_INVALID_PACKET; - } - } - - auto end_time = system.CoreTiming().GetGlobalTimeUs(); - shared_memory->dsp_return_data[0] = error_code; - shared_memory->dsp_return_data[1] = decoded_samples; - shared_memory->dsp_return_data[2] = (end_time - start_time).count(); - - Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK); - } break; - - default: - LOG_ERROR(Service_Audio, "Invalid OpusDecoder command {}", msg); - continue; - } - } -} - } // namespace AudioCore::ADSP::OpusDecoder diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.h b/src/audio_core/adsp/apps/opus/opus_decoder.h index 5b3f22bf4c..dd87b473d1 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.h +++ b/src/audio_core/adsp/apps/opus/opus_decoder.h @@ -6,12 +6,13 @@ #pragma once -#include #include +#include "common/container/unordered_map.h" #include "audio_core/adsp/apps/opus/shared_memory.h" #include "audio_core/adsp/mailbox.h" #include "common/common_types.h" +#include "core/hle/result.h" namespace Core { class System; @@ -48,16 +49,14 @@ enum Message : u32 { DecodeInterleavedForMultiStreamOK = 50, }; -/** - * The AudioRenderer application running on the ADSP. - */ +/// @brief The AudioRenderer application running on the ADSP. class OpusDecoder { public: explicit OpusDecoder(Core::System& system); ~OpusDecoder(); bool IsRunning() const noexcept { - return running; + return dsp_thread.joinable(); } void Send(Direction dir, u32 message); @@ -68,28 +67,12 @@ public: } private: - /** - * Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread. - */ - void Init(std::stop_token stop_token); - /** - * Main OpusDecoder thread, responsible for processing the incoming Opus packets. - */ - void Main(std::stop_token stop_token); - - /// Core system - Core::System& system; /// Mailbox to communicate messages with the host, drives the main thread Mailbox mailbox; - /// Init thread - std::jthread init_thread{}; - /// Main thread - std::jthread main_thread{}; - /// The current state - bool running{}; /// Structure shared with the host, input data set by the host before sending a mailbox message, /// and the responses are written back by the OpusDecoder. SharedMemory* shared_memory{}; + std::jthread dsp_thread{}; }; } // namespace AudioCore::ADSP::OpusDecoder diff --git a/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp b/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp deleted file mode 100644 index 6fecd63309..0000000000 --- a/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "audio_core/adsp/apps/opus/opus_multistream_decode_object.h" -#include "common/assert.h" - -namespace AudioCore::ADSP::OpusDecoder { - -namespace { -constexpr u32 OpusStreamCountMax = 255; - -bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) { - return total_stream_count > 0 && total_stream_count <= OpusStreamCountMax && - static_cast(stereo_stream_count) >= 0 && - stereo_stream_count <= total_stream_count; -} -} // namespace - -u32 OpusMultiStreamDecodeObject::GetWorkBufferSize(u32 total_stream_count, - u32 stereo_stream_count) { - if (IsValidStreamCounts(total_stream_count, stereo_stream_count)) { - return static_cast(sizeof(OpusMultiStreamDecodeObject)) + - opus_multistream_decoder_get_size(total_stream_count, stereo_stream_count); - } - return 0; -} - -OpusMultiStreamDecodeObject& OpusMultiStreamDecodeObject::Initialize(u64 buffer, u64 buffer2) { - auto* new_decoder = reinterpret_cast(buffer); - auto* comparison = reinterpret_cast(buffer2); - - if (new_decoder->magic == DecodeMultiStreamObjectMagic) { - if (!new_decoder->initialized || - (new_decoder->initialized && new_decoder->self == comparison)) { - new_decoder->state_valid = true; - } - } else { - new_decoder->initialized = false; - new_decoder->state_valid = true; - } - return *new_decoder; -} - -s32 OpusMultiStreamDecodeObject::InitializeDecoder(u32 sample_rate, u32 total_stream_count, - u32 channel_count, u32 stereo_stream_count, - u8* mappings) { - if (!state_valid) { - return OPUS_INVALID_STATE; - } - - if (initialized) { - return OPUS_OK; - } - - // See OpusDecodeObject::InitializeDecoder for an explanation of this - decoder = (LibOpusMSDecoder*)(this + 1); - s32 ret = opus_multistream_decoder_init(decoder, sample_rate, channel_count, total_stream_count, - stereo_stream_count, mappings); - if (ret == OPUS_OK) { - magic = DecodeMultiStreamObjectMagic; - initialized = true; - state_valid = true; - self = this; - final_range = 0; - } - return ret; -} - -s32 OpusMultiStreamDecodeObject::Shutdown() { - if (!state_valid) { - return OPUS_INVALID_STATE; - } - - if (initialized) { - magic = 0x0; - initialized = false; - state_valid = false; - self = nullptr; - final_range = 0; - decoder = nullptr; - } - return OPUS_OK; -} - -s32 OpusMultiStreamDecodeObject::ResetDecoder() { - return opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE); -} - -s32 OpusMultiStreamDecodeObject::Decode(u32& out_sample_count, u64 output_data, - u64 output_data_size, u64 input_data, u64 input_data_size) { - ASSERT(initialized); - out_sample_count = 0; - - if (!state_valid) { - return OPUS_INVALID_STATE; - } - - auto ret_code_or_samples = opus_multistream_decode( - decoder, reinterpret_cast(input_data), static_cast(input_data_size), - reinterpret_cast(output_data), static_cast(output_data_size), 0); - - if (ret_code_or_samples < OPUS_OK) { - return ret_code_or_samples; - } - - out_sample_count = ret_code_or_samples; - return opus_multistream_decoder_ctl(decoder, OPUS_GET_FINAL_RANGE_REQUEST, &final_range); -} - -} // namespace AudioCore::ADSP::OpusDecoder diff --git a/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.h b/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.h deleted file mode 100644 index 93558ded5d..0000000000 --- a/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.h +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include "common/common_types.h" - -namespace AudioCore::ADSP::OpusDecoder { -using LibOpusMSDecoder = ::OpusMSDecoder; -static constexpr u32 DecodeMultiStreamObjectMagic = 0xDEADBEEF; - -class OpusMultiStreamDecodeObject { -public: - static u32 GetWorkBufferSize(u32 total_stream_count, u32 stereo_stream_count); - static OpusMultiStreamDecodeObject& Initialize(u64 buffer, u64 buffer2); - - s32 InitializeDecoder(u32 sample_rate, u32 total_stream_count, u32 channel_count, - u32 stereo_stream_count, u8* mappings); - s32 Shutdown(); - s32 ResetDecoder(); - s32 Decode(u32& out_sample_count, u64 output_data, u64 output_data_size, u64 input_data, - u64 input_data_size); - u32 GetFinalRange() const noexcept { - return final_range; - } - -private: - u32 magic; - bool initialized; - bool state_valid; - OpusMultiStreamDecodeObject* self; - u32 final_range; - LibOpusMSDecoder* decoder; -}; -static_assert(std::is_trivially_constructible_v); - -} // namespace AudioCore::ADSP::OpusDecoder diff --git a/src/audio_core/adsp/apps/opus/opus_types.h b/src/audio_core/adsp/apps/opus/opus_types.h new file mode 100644 index 0000000000..bacfb30338 --- /dev/null +++ b/src/audio_core/adsp/apps/opus/opus_types.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" + +namespace AudioCore::ADSP { + +static constexpr u32 DECODE_OBJECT_MAGIC = 0xDEADBEEF; +struct LibOpusDecoder { + u32 magic; + bool initialized; + bool state_valid; + LibOpusDecoder* self; + u32 final_range; + void* decoder; +}; +static_assert(sizeof(LibOpusDecoder) == 32); + +static constexpr u32 DECODE_MULTISTREAM_OBJECT_MAGIC = 0xDEADBEEF; +struct LibOpusMultistreamDecoder { + u32 magic; + bool initialized; + bool state_valid; + LibOpusMultistreamDecoder* self; + u32 final_range; + void* decoder; +}; +static_assert(sizeof(LibOpusMultistreamDecoder) == 32); + +} diff --git a/src/audio_core/adsp/apps/opus/shared_memory.h b/src/audio_core/adsp/apps/opus/shared_memory.h index c696731ed8..45079c6292 100644 --- a/src/audio_core/adsp/apps/opus/shared_memory.h +++ b/src/audio_core/adsp/apps/opus/shared_memory.h @@ -1,9 +1,11 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#include "common/common_funcs.h" #include "common/common_types.h" namespace AudioCore::ADSP::OpusDecoder { diff --git a/src/audio_core/opus/hardware_opus.cpp b/src/audio_core/opus/hardware_opus.cpp index 04591c10b6..c07a358168 100644 --- a/src/audio_core/opus/hardware_opus.cpp +++ b/src/audio_core/opus/hardware_opus.cpp @@ -10,39 +10,18 @@ #include "audio_core/audio_core.h" #include "audio_core/opus/hardware_opus.h" #include "core/core.h" +#include "core/hle/result.h" namespace AudioCore::OpusDecoder { + namespace { using namespace Service::Audio; - -static constexpr Result ResultCodeFromLibOpusErrorCode(u64 error_code) { - s32 error{static_cast(error_code)}; - ASSERT(error <= OPUS_OK); - switch (error) { - case OPUS_ALLOC_FAIL: - R_THROW(ResultLibOpusAllocFail); - case OPUS_INVALID_STATE: - R_THROW(ResultLibOpusInvalidState); - case OPUS_UNIMPLEMENTED: - R_THROW(ResultLibOpusUnimplemented); - case OPUS_INVALID_PACKET: - R_THROW(ResultLibOpusInvalidPacket); - case OPUS_INTERNAL_ERROR: - R_THROW(ResultLibOpusInternalError); - case OPUS_BUFFER_TOO_SMALL: - R_THROW(ResultBufferTooSmall); - case OPUS_BAD_ARG: - R_THROW(ResultLibOpusBadArg); - case OPUS_OK: - R_RETURN(ResultSuccess); - } - UNREACHABLE(); -} - } // namespace HardwareOpus::HardwareOpus(Core::System& system_) - : system{system_}, opus_decoder{system.AudioCore().ADSP().OpusDecoder()} { + : system{system_} + , opus_decoder{system.AudioCore().ADSP().OpusDecoder()} +{ opus_decoder.SetSharedMemory(shared_memory); } @@ -112,7 +91,7 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, R_THROW(ResultInvalidOpusDSPReturnCode); } - R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); + R_RETURN(Result(u32(shared_memory.dsp_return_data[0]))); } Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, @@ -140,7 +119,7 @@ Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 chan R_THROW(ResultInvalidOpusDSPReturnCode); } - R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); + R_RETURN(Result(u32(shared_memory.dsp_return_data[0]))); } Result HardwareOpus::ShutdownDecodeObject(void* buffer, u64 buffer_size) { @@ -154,7 +133,7 @@ Result HardwareOpus::ShutdownDecodeObject(void* buffer, u64 buffer_size) { "Expected Opus shutdown code {}, got {}", ADSP::OpusDecoder::Message::ShutdownDecodeObjectOK, msg); - R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); + R_RETURN(Result(u32(shared_memory.dsp_return_data[0]))); } Result HardwareOpus::ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size) { @@ -169,7 +148,7 @@ Result HardwareOpus::ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_si "Expected Opus shutdown code {}, got {}", ADSP::OpusDecoder::Message::ShutdownMultiStreamDecodeObjectOK, msg); - R_RETURN(ResultCodeFromLibOpusErrorCode(shared_memory.dsp_return_data[0])); + R_RETURN(Result(u32(shared_memory.dsp_return_data[0]))); } Result HardwareOpus::DecodeInterleaved(u32& out_sample_count, void* output_data, @@ -193,12 +172,12 @@ Result HardwareOpus::DecodeInterleaved(u32& out_sample_count, void* output_data, R_THROW(ResultInvalidOpusDSPReturnCode); } - auto error_code{static_cast(shared_memory.dsp_return_data[0])}; - if (error_code == OPUS_OK) { - out_sample_count = static_cast(shared_memory.dsp_return_data[1]); + auto error_code = s32(shared_memory.dsp_return_data[0]); + if (error_code == ResultSuccess.raw) { + out_sample_count = u32(shared_memory.dsp_return_data[1]); out_time_taken = 1000 * shared_memory.dsp_return_data[2]; } - R_RETURN(ResultCodeFromLibOpusErrorCode(error_code)); + R_RETURN(Result(u32(error_code))); } Result HardwareOpus::DecodeInterleavedForMultiStream(u32& out_sample_count, void* output_data, @@ -207,29 +186,27 @@ Result HardwareOpus::DecodeInterleavedForMultiStream(u32& out_sample_count, void void* buffer, u64& out_time_taken, bool reset) { std::scoped_lock l{mutex}; - shared_memory.host_send_data[0] = (u64)buffer; - shared_memory.host_send_data[1] = (u64)input_data; + shared_memory.host_send_data[0] = u64(buffer); + shared_memory.host_send_data[1] = u64(input_data); shared_memory.host_send_data[2] = input_data_size; - shared_memory.host_send_data[3] = (u64)output_data; + shared_memory.host_send_data[3] = u64(output_data); shared_memory.host_send_data[4] = output_data_size; shared_memory.host_send_data[5] = 0; shared_memory.host_send_data[6] = reset; - opus_decoder.Send(ADSP::Direction::DSP, - ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStream); + opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStream); auto msg = opus_decoder.Receive(ADSP::Direction::Host); if (msg != ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK) { - LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", - ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK, msg); + LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", ADSP::OpusDecoder::Message::DecodeInterleavedForMultiStreamOK, msg); R_THROW(ResultInvalidOpusDSPReturnCode); } - auto error_code{static_cast(shared_memory.dsp_return_data[0])}; - if (error_code == OPUS_OK) { + auto const error_code = shared_memory.dsp_return_data[0]; + if (error_code == ResultSuccess.raw) { out_sample_count = static_cast(shared_memory.dsp_return_data[1]); out_time_taken = 1000 * shared_memory.dsp_return_data[2]; } - R_RETURN(ResultCodeFromLibOpusErrorCode(error_code)); + R_RETURN(Result(u32(shared_memory.dsp_return_data[0]))); } Result HardwareOpus::MapMemory(void* buffer, u64 buffer_size) { @@ -240,8 +217,7 @@ Result HardwareOpus::MapMemory(void* buffer, u64 buffer_size) { opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::MapMemory); auto msg = opus_decoder.Receive(ADSP::Direction::Host); if (msg != ADSP::OpusDecoder::Message::MapMemoryOK) { - LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", - ADSP::OpusDecoder::Message::MapMemoryOK, msg); + LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", ADSP::OpusDecoder::Message::MapMemoryOK, msg); R_THROW(ResultInvalidOpusDSPReturnCode); } R_SUCCEED(); @@ -255,8 +231,7 @@ Result HardwareOpus::UnmapMemory(void* buffer, u64 buffer_size) { opus_decoder.Send(ADSP::Direction::DSP, ADSP::OpusDecoder::Message::UnmapMemory); auto msg = opus_decoder.Receive(ADSP::Direction::Host); if (msg != ADSP::OpusDecoder::Message::UnmapMemoryOK) { - LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", - ADSP::OpusDecoder::Message::UnmapMemoryOK, msg); + LOG_ERROR(Service_Audio, "OpusDecoder returned invalid message. Expected {} got {}", ADSP::OpusDecoder::Message::UnmapMemoryOK, msg); R_THROW(ResultInvalidOpusDSPReturnCode); } R_SUCCEED(); diff --git a/src/audio_core/opus/hardware_opus.h b/src/audio_core/opus/hardware_opus.h index b6c7fbe6c8..26c96e00c0 100644 --- a/src/audio_core/opus/hardware_opus.h +++ b/src/audio_core/opus/hardware_opus.h @@ -8,8 +8,6 @@ #include #include -#include - #include "audio_core/adsp/apps/opus/opus_decoder.h" #include "audio_core/adsp/apps/opus/shared_memory.h" #include "audio_core/adsp/mailbox.h" diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 508ace3501..e72fd791b9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1199,7 +1199,6 @@ else() endif() endif() -target_include_directories(core PRIVATE ${OPUS_INCLUDE_DIRS}) target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz) if (BOOST_NO_HEADERS) diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 64d14ab2a6..06b77a2a8f 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -414,9 +414,7 @@ endif() if (YUZU_USE_EXTERNAL_FFMPEG) add_dependencies(video_core ffmpeg-build) endif() - target_include_directories(video_core PUBLIC ${FFmpeg_INCLUDE_DIR}) - target_link_libraries(video_core PRIVATE ${FFmpeg_LIBRARIES}) target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})