aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrueter <crueter@eden-emu.dev>2026-09-02 00:29:58 +0200
committercrueter <crueter@eden-emu.dev>2026-09-02 00:29:58 +0200
commitaa4e494c08075f5d048e8e3d6e0f7426d88d0f0a (patch)
tree3055c96bf4c84efcc24f768acc4545c1147f5c2d
parent858f9e5aeac89503c331dfe4588cc3c83ab2223b (diff)
[android] Replace Oboe audio with SDL3 audio (#4338)
Supersedes #4335. Replaces the Oboe audio backend with SDL3, since we already support it. A few caveats: - SDL defines a JVM OnLoad method already, so we have to instead hijack NativeLibrary for id_cache initialization - This also means some internal fields in Double/Integer/Boolean (namely `value`) can't be accessed, so I switched those to methods for now. - SDL Java sources are pulled in from the CI package. - Since we can't use SDLActivity, `SDL.setupJNI()` handles everything Signed-off-by: crueter <crueter@eden-emu.dev> - [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md) - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4338 Reviewed-by: Lizzie and Samuel <lizzie@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev>
-rw-r--r--.gitignore3
-rw-r--r--CMakeLists.txt4
-rw-r--r--cpmfile.json6
-rw-r--r--externals/CMakeLists.txt80
-rw-r--r--src/android/app/build.gradle.kts7
-rw-r--r--src/android/app/proguard-rules.pro3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt4
-rw-r--r--src/android/app/src/main/jni/CMakeLists.txt2
-rw-r--r--src/android/app/src/main/jni/native.cpp9
-rw-r--r--src/android/app/src/main/res/values-fa/strings.xml1
-rw-r--r--src/android/app/src/main/res/values/arrays.xml4
-rw-r--r--src/android/app/src/main/res/values/strings.xml2
-rw-r--r--src/audio_core/CMakeLists.txt19
-rw-r--r--src/audio_core/sink/oboe_sink.cpp230
-rw-r--r--src/audio_core/sink/oboe_sink.h75
-rw-r--r--src/audio_core/sink/sink_details.cpp19
-rw-r--r--src/common/android/android_common.cpp8
-rw-r--r--src/common/android/id_cache.cpp380
-rw-r--r--src/common/android/id_cache.h7
-rw-r--r--src/common/settings_enums.h6
-rw-r--r--src/input_common/drivers/android.cpp2
21 files changed, 274 insertions, 597 deletions
diff --git a/.gitignore b/.gitignore
index 75e728babe..20ed5e93c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,3 +63,6 @@ artifacts
/install*
vulkansdk*.exe
*.tar.zst
+
+# Build-time generated external sources
+externals/generated
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 477e7c636d..bc4b991b4a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -214,8 +214,6 @@ if(MSVC)
endif()
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
-cmake_dependent_option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" "${MSVC}" "NOT ANDROID" OFF)
-
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
set(EXT_DEFAULT OFF)
@@ -223,6 +221,8 @@ if (MSVC OR ANDROID)
set(EXT_DEFAULT ON)
endif()
+option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" ${EXT_DEFAULT})
+
# ffmpeg
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${SOLARIS}" "NOT WIN32 AND NOT ANDROID" OFF)
diff --git a/cpmfile.json b/cpmfile.json
index c0d879f838..c5ea35c955 100644
--- a/cpmfile.json
+++ b/cpmfile.json
@@ -186,12 +186,6 @@
"repo": "eden-emulator/oaknut",
"version": "v2.0.3"
},
- "oboe": {
- "bundled": true,
- "hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
- "repo": "google/oboe",
- "version": "1.10.0"
- },
"openssl": {
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
"min_version": "3.0.0",
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 6e324ce9f6..0682f643e2 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -136,48 +136,49 @@ if(ENABLE_CUBEB)
endif()
endif()
-if (NOT ANDROID)
- if (NOT YUZU_USE_BUNDLED_SDL3)
- if (NOT WIN32)
- # Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
- # Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
- # Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
- # CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
- set(SDL_UNUSED_SUBSYSTEMS
- File Filesystem
- Locale Power Render)
- foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
- string(TOUPPER ${_SUB} _OPT)
- set(SDL_${_OPT} OFF)
- endforeach()
-
- set(HIDAPI ON)
- endif()
-
- if (APPLE)
- set(SDL_FILE ON)
- endif()
+if (NOT YUZU_USE_BUNDLED_SDL3)
+ if (NOT WIN32)
+ # Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
+ # Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
+ # Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
+ # CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
+ set(SDL_UNUSED_SUBSYSTEMS
+ File Filesystem
+ Locale Power Render)
+ foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
+ string(TOUPPER ${_SUB} _OPT)
+ set(SDL_${_OPT} OFF)
+ endforeach()
+
+ set(HIDAPI ON)
+ endif()
- AddJsonPackage(sdl3)
- else()
- message(STATUS "Using bundled SDL3")
- AddJsonPackage(sdl3-ci)
+ if (APPLE)
+ set(SDL_FILE ON)
endif()
- # Normalize SDL3 link target across package variants.
- # Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
- if (NOT TARGET SDL3::SDL3)
- if (TARGET SDL3::SDL3-shared)
- add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
- elseif (TARGET SDL3::SDL3-static)
- add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
- else()
- message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
- endif()
+ AddJsonPackage(sdl3)
+else()
+ message(STATUS "Using bundled SDL3")
+ AddJsonPackage(sdl3-ci)
+
+ # copy sdl java sources for consumption by Gradle
+ if (ANDROID)
+ file(COPY ${SDL3_SOURCE_DIR}/java DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/generated/sdl)
endif()
endif()
-set(BUILD_SHARED_LIBS OFF)
+# Normalize SDL3 link target across package variants.
+# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
+if (NOT TARGET SDL3::SDL3)
+ if (TARGET SDL3::SDL3-shared)
+ add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
+ elseif (TARGET SDL3::SDL3-static)
+ add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
+ else()
+ message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
+ endif()
+endif()
# SPIRV Headers
AddJsonPackage(spirv-headers)
@@ -385,13 +386,6 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
endif()
endif()
-# oboe
-if (ANDROID)
- AddJsonPackage(oboe)
-
- add_library(oboe::oboe ALIAS oboe)
-endif()
-
if (APPLE)
# moltenvk
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts
index 0cef7e7196..3ae6d73994 100644
--- a/src/android/app/build.gradle.kts
+++ b/src/android/app/build.gradle.kts
@@ -272,6 +272,13 @@ android {
resValue("string", "app_name_suffixed", "$currentName$suffix")
resValue("string", "app_name", "Eden$suffix")
}
+
+ sourceSets {
+ named("main") {
+ java.srcDir("${edenDir}/externals/generated/sdl/java")
+ kotlin.srcDir("${edenDir}/externals/generated/sdl/java")
+ }
+ }
}
idea {
diff --git a/src/android/app/proguard-rules.pro b/src/android/app/proguard-rules.pro
index 691e08fd03..91f63bbb84 100644
--- a/src/android/app/proguard-rules.pro
+++ b/src/android/app/proguard-rules.pro
@@ -9,6 +9,9 @@
-keep class org.ini4j.spi.IniBuilder
-keep class org.ini4j.spi.IniFormatter
+-keep class org.libsdl.app.** { *; }
+-keepclassmembers class org.libsdl.app.** { *; }
+
# Suppress warnings for R8
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 4b46dd76a2..77222884c6 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -16,6 +16,7 @@ import android.widget.TextView
import androidx.annotation.Keep
import androidx.core.net.toUri
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import org.libsdl.app.SDL
import java.lang.ref.WeakReference
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
@@ -52,6 +53,8 @@ object NativeLibrary {
init {
try {
System.loadLibrary("yuzu-android")
+ SDL.setupJNI()
+ initJvm()
} catch (ex: UnsatisfiedLinkError) {
error("[NativeLibrary] $ex")
}
@@ -367,6 +370,7 @@ object NativeLibrary {
NetPlayManager.clearChat()
}
+ external fun initJvm()
external fun initMultiplayer()
@Keep
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt
index 7013691765..86c05d7c0d 100644
--- a/src/android/app/src/main/jni/CMakeLists.txt
+++ b/src/android/app/src/main/jni/CMakeLists.txt
@@ -22,7 +22,7 @@ add_library(yuzu-android SHARED
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common video_core)
-target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log)
+target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log GLESv2)
if (ARCHITECTURE_arm64)
target_link_libraries(yuzu-android PRIVATE adrenotools)
endif()
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 9fc550985a..423edc2c1b 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -1730,6 +1730,15 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_loadAmiibo(JNIEnv* env, jobject jobj,
return static_cast<jint>(info);
}
+extern "C" JNIEXPORT void JNICALL
+Java_org_yuzu_yuzu_1emu_NativeLibrary_initJvm(JNIEnv *env, jclass clazz) {
+ JavaVM *vm;
+ if (env->GetJavaVM(&vm) != JNI_OK)
+ return;
+
+ Common::Android::Initialize(vm, env);
+}
+
JNIEXPORT void JNICALL
Java_org_yuzu_yuzu_1emu_NativeLibrary_initMultiplayer(
JNIEnv* env, [[maybe_unused]] jobject obj) {
diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml
index 98b94d166d..6b40d97f2a 100644
--- a/src/android/app/src/main/res/values-fa/strings.xml
+++ b/src/android/app/src/main/res/values-fa/strings.xml
@@ -800,7 +800,6 @@
<string name="theme_mode_dark">تاریک</string>
<!-- Audio output engines -->
- <string name="oboe">oboe</string>
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml
index b1c0a98a61..931cf2bfa7 100644
--- a/src/android/app/src/main/res/values/arrays.xml
+++ b/src/android/app/src/main/res/values/arrays.xml
@@ -465,13 +465,13 @@
<string-array name="outputEngineEntries">
<item>@string/auto</item>
- <item>@string/oboe</item>
+ <item>@string/sdl3</item>
<item>@string/cubeb</item>
<item>@string/string_null</item>
</string-array>
<integer-array name="outputEngineValues">
<item>0</item>
- <item>4</item>
+ <item>2</item>
<item>1</item>
<item>3</item>
</integer-array>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 3f6d1889ff..55783f6e43 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -1240,7 +1240,7 @@
<string name="theme_mode_dark">Dark</string>
<!-- Audio output engines -->
- <string name="oboe" translatable="false">oboe</string>
+ <string name="sdl3" translatable="false">SDL3</string>
<string name="cubeb" translatable="false">cubeb</string>
<!-- Anisotropic filtering options -->
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index b186edaab4..b244d657a9 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -238,20 +238,11 @@ if (ENABLE_CUBEB)
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
endif()
-if(ANDROID)
- target_sources(audio_core PRIVATE
- sink/oboe_sink.cpp
- sink/oboe_sink.h)
+target_sources(audio_core PRIVATE
+ sink/sdl3_sink.cpp
+ sink/sdl3_sink.h)
- target_link_libraries(audio_core PRIVATE oboe)
- target_compile_definitions(audio_core PUBLIC HAVE_OBOE)
-else()
- target_sources(audio_core PRIVATE
- sink/sdl3_sink.cpp
- sink/sdl3_sink.h)
-
- target_link_libraries(audio_core PRIVATE SDL3::SDL3)
- target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
-endif()
+target_link_libraries(audio_core PRIVATE SDL3::SDL3)
+target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
create_target_directory_groups(audio_core)
diff --git a/src/audio_core/sink/oboe_sink.cpp b/src/audio_core/sink/oboe_sink.cpp
deleted file mode 100644
index d1ead7d880..0000000000
--- a/src/audio_core/sink/oboe_sink.cpp
+++ /dev/null
@@ -1,230 +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 <span>
-#include <vector>
-
-#include <oboe/Oboe.h>
-
-#include "audio_core/common/common.h"
-#include "audio_core/sink/oboe_sink.h"
-#include "audio_core/sink/sink_stream.h"
-#include "common/logging.h"
-#include "common/scope_exit.h"
-#include "core/core.h"
-
-namespace AudioCore::Sink {
-
-class OboeSinkStream final : public SinkStream,
- public oboe::AudioStreamDataCallback,
- public oboe::AudioStreamErrorCallback {
-public:
- explicit OboeSinkStream(Core::System& system_, StreamType type_, const std::string& name_,
- u32 system_channels_)
- : SinkStream(system_, type_) {
- name = name_;
- system_channels = system_channels_;
-
- this->OpenStream();
- }
-
- ~OboeSinkStream() override {
- LOG_INFO(Audio_Sink, "Destroyed Oboe stream");
- }
-
- void Finalize() override {
- this->Stop();
- m_stream.reset();
- }
-
- void Start(bool resume = false) override {
- if (!m_stream || !paused) {
- return;
- }
-
- paused = false;
-
- if (m_stream->start() != oboe::Result::OK) {
- LOG_CRITICAL(Audio_Sink, "Error starting Oboe stream");
- }
- }
-
- void Stop() override {
- if (!m_stream || paused) {
- return;
- }
-
- this->SignalPause();
-
- if (m_stream->stop() != oboe::Result::OK) {
- LOG_CRITICAL(Audio_Sink, "Error stopping Oboe stream");
- }
- }
-
-public:
- static s32 QueryChannelCount(oboe::Direction direction) {
- std::shared_ptr<oboe::AudioStream> temp_stream;
- oboe::AudioStreamBuilder builder;
-
- const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
- if (result == oboe::Result::OK) {
- return temp_stream->getChannelCount() >= 6 ? 6 : 2;
- }
-
- LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
- direction == oboe::Direction::Output ? "output" : "input");
- return 2;
- }
-
-protected:
- oboe::DataCallbackResult onAudioReady(oboe::AudioStream*, void* audio_data,
- s32 num_buffer_frames) override {
- const size_t num_channels = this->GetDeviceChannels();
- const size_t frame_size = num_channels;
- const size_t num_frames = static_cast<size_t>(num_buffer_frames);
-
- if (type == StreamType::In) {
- std::span<const s16> input_buffer{reinterpret_cast<const s16*>(audio_data),
- num_frames * frame_size};
- this->ProcessAudioIn(input_buffer, num_frames);
- } else {
- std::span<s16> output_buffer{reinterpret_cast<s16*>(audio_data),
- num_frames * frame_size};
- this->ProcessAudioOutAndRender(output_buffer, num_frames);
- }
-
- return oboe::DataCallbackResult::Continue;
- }
-
- void onErrorAfterClose(oboe::AudioStream*, oboe::Result) override {
- LOG_INFO(Audio_Sink, "Audio stream closed, reinitializing");
-
- if (this->OpenStream()) {
- m_stream->start();
- }
- }
-
-private:
- static oboe::AudioStreamBuilder* ConfigureBuilder(oboe::AudioStreamBuilder& builder,
- oboe::Direction direction) {
- // TODO: investigate callback delay issues when using AAudio
- return builder.setPerformanceMode(oboe::PerformanceMode::LowLatency)
- ->setAudioApi(oboe::AudioApi::OpenSLES)
- ->setDirection(direction)
- ->setSampleRate(TargetSampleRate)
- ->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
- ->setFormat(oboe::AudioFormat::I16)
- ->setFormatConversionAllowed(true)
- ->setUsage(oboe::Usage::Game)
- ->setBufferCapacityInFrames(TargetSampleCount * 2);
- }
-
- bool OpenStream() {
- const auto direction = [&]() {
- switch (type) {
- case StreamType::In:
- return oboe::Direction::Input;
- case StreamType::Out:
- case StreamType::Render:
- return oboe::Direction::Output;
- default:
- ASSERT(false);
- return oboe::Direction::Output;
- }
- }();
-
- const auto expected_channels = QueryChannelCount(direction);
- const auto expected_mask = [&]() {
- switch (expected_channels) {
- case 1:
- return oboe::ChannelMask::Mono;
- case 2:
- return oboe::ChannelMask::Stereo;
- case 6:
- return oboe::ChannelMask::CM5Point1;
- default:
- ASSERT(false);
- return oboe::ChannelMask::Unspecified;
- }
- }();
-
- oboe::AudioStreamBuilder builder;
- const auto result = ConfigureBuilder(builder, direction)
- ->setChannelCount(expected_channels)
- ->setChannelMask(expected_mask)
- ->setChannelConversionAllowed(true)
- ->setDataCallback(this)
- ->setErrorCallback(this)
- ->openStream(m_stream);
- ASSERT(result == oboe::Result::OK);
- return result == oboe::Result::OK && this->SetStreamProperties();
- }
-
- bool SetStreamProperties() {
- ASSERT(m_stream);
-
- m_stream->setBufferSizeInFrames(TargetSampleCount * 2);
- device_channels = m_stream->getChannelCount();
-
- const auto sample_rate = m_stream->getSampleRate();
- const auto buffer_capacity = m_stream->getBufferCapacityInFrames();
- const auto stream_backend =
- m_stream->getAudioApi() == oboe::AudioApi::AAudio ? "AAudio" : "OpenSLES";
-
- LOG_INFO(Audio_Sink, "Opened Oboe {} stream with {} channels sample rate {} capacity {}",
- stream_backend, device_channels, sample_rate, buffer_capacity);
-
- return true;
- }
-
- std::shared_ptr<oboe::AudioStream> m_stream{};
-};
-
-OboeSink::OboeSink() {
- // TODO: This is not generally knowable
- // The channel count is distinct based on direction and can change
- device_channels = OboeSinkStream::QueryChannelCount(oboe::Direction::Output);
-}
-
-OboeSink::~OboeSink() = default;
-
-SinkStream* OboeSink::AcquireSinkStream(Core::System& system, u32 system_channels,
- const std::string& name, StreamType type) {
- SinkStreamPtr& stream = sink_streams.emplace_back(
- std::make_unique<OboeSinkStream>(system, type, name, system_channels));
-
- return stream.get();
-}
-
-void OboeSink::CloseStream(SinkStream* to_remove) {
- sink_streams.remove_if([&](auto& stream) { return stream.get() == to_remove; });
-}
-
-void OboeSink::CloseStreams() {
- sink_streams.clear();
-}
-
-f32 OboeSink::GetDeviceVolume() const {
- if (sink_streams.empty()) {
- return 1.0f;
- }
-
- return sink_streams.front()->GetDeviceVolume();
-}
-
-void OboeSink::SetDeviceVolume(f32 volume) {
- for (auto& stream : sink_streams) {
- stream->SetDeviceVolume(volume);
- }
-}
-
-void OboeSink::SetSystemVolume(f32 volume) {
- for (auto& stream : sink_streams) {
- stream->SetSystemVolume(volume);
- }
-}
-
-} // namespace AudioCore::Sink
diff --git a/src/audio_core/sink/oboe_sink.h b/src/audio_core/sink/oboe_sink.h
deleted file mode 100644
index 8f6f54ab53..0000000000
--- a/src/audio_core/sink/oboe_sink.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <list>
-#include <string>
-
-#include "audio_core/sink/sink.h"
-
-namespace Core {
-class System;
-}
-
-namespace AudioCore::Sink {
-class SinkStream;
-
-class OboeSink final : public Sink {
-public:
- explicit OboeSink();
- ~OboeSink() override;
-
- /**
- * Create a new sink stream.
- *
- * @param system - Core system.
- * @param system_channels - Number of channels the audio system expects.
- * May differ from the device's channel count.
- * @param name - Name of this stream.
- * @param type - Type of this stream, render/in/out.
- *
- * @return A pointer to the created SinkStream
- */
- SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
- const std::string& name, StreamType type) override;
-
- /**
- * Close a given stream.
- *
- * @param stream - The stream to close.
- */
- void CloseStream(SinkStream* stream) override;
-
- /**
- * Close all streams.
- */
- void CloseStreams() override;
-
- /**
- * Get the device volume. Set from calls to the IAudioDevice service.
- *
- * @return Volume of the device.
- */
- f32 GetDeviceVolume() const override;
-
- /**
- * Set the device volume. Set from calls to the IAudioDevice service.
- *
- * @param volume - New volume of the device.
- */
- void SetDeviceVolume(f32 volume) override;
-
- /**
- * Set the system volume. Comes from the audio system using this stream.
- *
- * @param volume - New volume of the system.
- */
- void SetSystemVolume(f32 volume) override;
-
-private:
- /// List of streams managed by this sink
- std::list<SinkStreamPtr> sink_streams{};
-};
-
-} // namespace AudioCore::Sink
diff --git a/src/audio_core/sink/sink_details.cpp b/src/audio_core/sink/sink_details.cpp
index 1b737eb12e..efd8fceb32 100644
--- a/src/audio_core/sink/sink_details.cpp
+++ b/src/audio_core/sink/sink_details.cpp
@@ -10,9 +10,6 @@
#include <vector>
#include "audio_core/sink/sink_details.h"
-#ifdef HAVE_OBOE
-#include "audio_core/sink/oboe_sink.h"
-#endif
#ifdef HAVE_CUBEB
#include "audio_core/sink/cubeb_sink.h"
#endif
@@ -43,24 +40,8 @@ struct SinkDetails {
/// SuitableFn is_suitable; // REVERTED FOR LatencyFn latency ABOVE - DIABLO 3 FIX
};
-// NOTE TO PROBABLY FIX LATER FOR ANDROID - the return value "0u" for the first HAVE_OBOE
-// section below was just copied from the null section so there's a somewhat valid value
-// being returned, since the previous "true" value probably isn't compatible with the
-// previous EA-3833 code. (HAVE_OBOE was introduced in a later release.) Eventually need
-// to change "0u" for something else directly from the oboe_sink.cpp functions.
-
// sink_details is ordered in terms of desirability, with the best choice at the top.
constexpr SinkDetails sink_details[] = {
-#ifdef HAVE_OBOE
- SinkDetails{
- Settings::AudioEngine::Oboe,
- [](std::string_view device_id) -> std::unique_ptr<Sink> {
- return std::make_unique<OboeSink>();
- },
- [](bool capture) { return std::vector<std::string>{"Default"}; },
- []() { return 0u; },
- },
-#endif
#ifdef HAVE_CUBEB
SinkDetails{
Settings::AudioEngine::Cubeb,
diff --git a/src/common/android/android_common.cpp b/src/common/android/android_common.cpp
index a1cf081695..5041579e0e 100644
--- a/src/common/android/android_common.cpp
+++ b/src/common/android/android_common.cpp
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-// SPDX-FileCopyrightText: 2025 Eden Emulator Project
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "android_common.h"
@@ -51,7 +51,7 @@ jstring ToJString(JNIEnv* env, std::u16string_view str) {
}
double GetJDouble(JNIEnv* env, jobject jdouble) {
- return env->GetDoubleField(jdouble, GetDoubleValueField());
+ return env->CallDoubleMethod(jdouble, GetDoubleValueMethod());
}
jobject ToJDouble(JNIEnv* env, double value) {
@@ -59,7 +59,7 @@ jobject ToJDouble(JNIEnv* env, double value) {
}
s32 GetJInteger(JNIEnv* env, jobject jinteger) {
- return env->GetIntField(jinteger, GetIntegerValueField());
+ return env->CallIntMethod(jinteger, GetIntegerValueMethod());
}
jobject ToJInteger(JNIEnv* env, s32 value) {
@@ -67,7 +67,7 @@ jobject ToJInteger(JNIEnv* env, s32 value) {
}
bool GetJBoolean(JNIEnv* env, jobject jboolean) {
- return env->GetBooleanField(jboolean, GetBooleanValueField());
+ return env->CallBooleanMethod(jboolean, GetBooleanValueMethod());
}
jobject ToJBoolean(JNIEnv* env, bool value) {
diff --git a/src/common/android/id_cache.cpp b/src/common/android/id_cache.cpp
index 0fb358f6e4..3da532703a 100644
--- a/src/common/android/id_cache.cpp
+++ b/src/common/android/id_cache.cpp
@@ -63,15 +63,15 @@ static jfieldID s_patch_title_id_field;
static jclass s_double_class;
static jmethodID s_double_constructor;
-static jfieldID s_double_value_field;
+static jmethodID s_double_value_method;
static jclass s_integer_class;
static jmethodID s_integer_constructor;
-static jfieldID s_integer_value_field;
+static jmethodID s_integer_value_method;
static jclass s_boolean_class;
static jmethodID s_boolean_constructor;
-static jfieldID s_boolean_value_field;
+static jmethodID s_boolean_value_method;
static jclass s_player_input_class;
static jmethodID s_player_input_constructor;
@@ -103,7 +103,6 @@ static jmethodID s_clear_chat;
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
namespace Common::Android {
-
JNIEnv *GetEnvForThread() {
thread_local static struct OwnedEnv {
OwnedEnv() {
@@ -299,8 +298,8 @@ namespace Common::Android {
return s_double_constructor;
}
- jfieldID GetDoubleValueField() {
- return s_double_value_field;
+ jmethodID GetDoubleValueMethod() {
+ return s_double_value_method;
}
jclass GetIntegerClass() {
@@ -311,8 +310,8 @@ namespace Common::Android {
return s_integer_constructor;
}
- jfieldID GetIntegerValueField() {
- return s_integer_value_field;
+ jmethodID GetIntegerValueMethod() {
+ return s_integer_value_method;
}
jclass GetBooleanClass() {
@@ -323,8 +322,8 @@ namespace Common::Android {
return s_boolean_constructor;
}
- jfieldID GetBooleanValueField() {
- return s_boolean_value_field;
+ jmethodID GetBooleanValueMethod() {
+ return s_boolean_value_method;
}
jclass GetPlayerInputClass() {
@@ -429,188 +428,6 @@ namespace Common::Android {
jint InitFFmpegOnLoad(JavaVM *vm);
- jint JNI_OnLoad(JavaVM *vm, void *reserved) {
- s_java_vm = vm;
- InitFFmpegOnLoad(vm);
-
- JNIEnv *env;
- if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK)
- return JNI_ERR;
-
- // Initialize Java classes
- const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
- s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
- s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
- env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
- s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
- "org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
-
- const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
- s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
- s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
- "(Ljava/lang/String;Z)V");
- env->DeleteLocalRef(game_dir_class);
-
- // Initialize methods
- s_exit_emulation_activity =
- env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
- s_disk_cache_load_progress =
- env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
- s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
- "(Ljava/lang/String;Ljava/lang/String;)Z");
- s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
- "(Ljava/lang/String;)Z");
- s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
- "(Ljava/lang/String;)Ljava/lang/String;");
- s_on_emulation_started =
- env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
- s_on_emulation_stopped =
- env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
- s_on_program_changed =
- env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
-
- const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
- s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
- s_game_constructor = env->GetMethodID(game_class, "<init>",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
- "String;Ljava/lang/String;Ljava/lang/String;Z)V");
- s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
- s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
- s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
- s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
- s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
- s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
- env->DeleteLocalRef(game_class);
-
- const jclass string_class = env->FindClass("java/lang/String");
- s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
- env->DeleteLocalRef(string_class);
-
- const jclass pair_class = env->FindClass("kotlin/Pair");
- s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
- s_pair_constructor =
- env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
- s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
- s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
- env->DeleteLocalRef(pair_class);
-
- const jclass overlay_control_data_class =
- env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
- s_overlay_control_data_class =
- reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
- s_overlay_control_data_constructor =
- env->GetMethodID(overlay_control_data_class, "<init>",
- "(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
- s_overlay_control_data_id_field =
- env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
- s_overlay_control_data_enabled_field =
- env->GetFieldID(overlay_control_data_class, "enabled", "Z");
- s_overlay_control_data_landscape_position_field =
- env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
- s_overlay_control_data_portrait_position_field =
- env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
- s_overlay_control_data_foldable_position_field =
- env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
- s_overlay_control_data_individual_scale_field =
- env->GetFieldID(overlay_control_data_class, "individualScale", "F");
- env->DeleteLocalRef(overlay_control_data_class);
-
- const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
- s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
- s_patch_constructor = env->GetMethodID(
- patch_class, "<init>",
- "(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
- s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
- s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
- s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
- s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
- s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
- s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
- env->DeleteLocalRef(patch_class);
-
- const jclass double_class = env->FindClass("java/lang/Double");
- s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
- s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
- s_double_value_field = env->GetFieldID(double_class, "value", "D");
- env->DeleteLocalRef(double_class);
-
- const jclass int_class = env->FindClass("java/lang/Integer");
- s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
- s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
- s_integer_value_field = env->GetFieldID(int_class, "value", "I");
- env->DeleteLocalRef(int_class);
-
- const jclass boolean_class = env->FindClass("java/lang/Boolean");
- s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
- s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
- s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z");
- env->DeleteLocalRef(boolean_class);
-
- const jclass player_input_class =
- env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
- s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
- s_player_input_constructor = env->GetMethodID(
- player_input_class, "<init>",
- "(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
- s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
- s_player_input_buttons_field =
- env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
- s_player_input_analogs_field =
- env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
- s_player_input_motions_field =
- env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
- s_player_input_vibration_enabled_field =
- env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
- s_player_input_vibration_strength_field =
- env->GetFieldID(player_input_class, "vibrationStrength", "I");
- s_player_input_body_color_left_field =
- env->GetFieldID(player_input_class, "bodyColorLeft", "J");
- s_player_input_body_color_right_field =
- env->GetFieldID(player_input_class, "bodyColorRight", "J");
- s_player_input_button_color_left_field =
- env->GetFieldID(player_input_class, "buttonColorLeft", "J");
- s_player_input_button_color_right_field =
- env->GetFieldID(player_input_class, "buttonColorRight", "J");
- s_player_input_profile_name_field =
- env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
- s_player_input_use_system_vibrator_field =
- env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
- env->DeleteLocalRef(player_input_class);
-
- const jclass yuzu_input_device_interface =
- env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
- s_yuzu_input_device_interface =
- reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
- s_yuzu_input_device_get_name =
- env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
- s_yuzu_input_device_get_guid =
- env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
- s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
- "()I");
- s_yuzu_input_device_get_supports_vibration =
- env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
- s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
- "(F)V");
- s_yuzu_input_device_get_axes =
- env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
- s_yuzu_input_device_has_keys =
- env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
- env->DeleteLocalRef(yuzu_input_device_interface);
- s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
- "(ILjava/lang/String;)V");
- s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
-
-
- // Initialize Android Storage
- Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
-
- // Initialize applets
- Common::Android::SoftwareKeyboard::InitJNI(env);
- Common::Android::WebBrowser::InitJNI(env);
-
- return JNI_VERSION;
- }
-
void JNI_OnUnload(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK) {
@@ -645,4 +462,183 @@ namespace Common::Android {
}
#endif
+void Initialize(JavaVM* vm, JNIEnv *env) {
+ s_java_vm = vm;
+ InitFFmpegOnLoad(vm);
+
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ }
+
+ // Initialize Java classes
+ const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
+ s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
+ s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
+ env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
+ s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
+ "org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
+
+ const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
+ s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
+ s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
+ "(Ljava/lang/String;Z)V");
+ env->DeleteLocalRef(game_dir_class);
+
+ // Initialize methods
+ s_exit_emulation_activity =
+ env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
+ s_disk_cache_load_progress =
+ env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
+ s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
+ "(Ljava/lang/String;Ljava/lang/String;)Z");
+ s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
+ "(Ljava/lang/String;)Z");
+ s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
+ "(Ljava/lang/String;)Ljava/lang/String;");
+ s_on_emulation_started =
+ env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
+ s_on_emulation_stopped =
+ env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
+ s_on_program_changed =
+ env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
+
+ const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
+ s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
+ s_game_constructor = env->GetMethodID(game_class, "<init>",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
+ "String;Ljava/lang/String;Ljava/lang/String;Z)V");
+ s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
+ s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
+ s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
+ s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
+ s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
+ s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
+ env->DeleteLocalRef(game_class);
+
+ const jclass string_class = env->FindClass("java/lang/String");
+ s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
+ env->DeleteLocalRef(string_class);
+
+ const jclass pair_class = env->FindClass("kotlin/Pair");
+ s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
+ s_pair_constructor =
+ env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
+ s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
+ s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
+ env->DeleteLocalRef(pair_class);
+
+ const jclass overlay_control_data_class =
+ env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
+ s_overlay_control_data_class =
+ reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
+ s_overlay_control_data_constructor =
+ env->GetMethodID(overlay_control_data_class, "<init>",
+ "(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
+ s_overlay_control_data_id_field =
+ env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
+ s_overlay_control_data_enabled_field =
+ env->GetFieldID(overlay_control_data_class, "enabled", "Z");
+ s_overlay_control_data_landscape_position_field =
+ env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
+ s_overlay_control_data_portrait_position_field =
+ env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
+ s_overlay_control_data_foldable_position_field =
+ env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
+ s_overlay_control_data_individual_scale_field =
+ env->GetFieldID(overlay_control_data_class, "individualScale", "F");
+ env->DeleteLocalRef(overlay_control_data_class);
+
+ const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
+ s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
+ s_patch_constructor = env->GetMethodID(
+ patch_class, "<init>",
+ "(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
+ s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
+ s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
+ s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
+ s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
+ s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
+ s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
+ env->DeleteLocalRef(patch_class);
+
+ const jclass double_class = env->FindClass("java/lang/Double");
+ s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
+ s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
+ s_double_value_method = env->GetMethodID(double_class, "doubleValue", "()D");
+ env->DeleteLocalRef(double_class);
+
+ const jclass int_class = env->FindClass("java/lang/Integer");
+ s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
+ s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
+ s_integer_value_method = env->GetMethodID(int_class, "intValue", "()I");
+ env->DeleteLocalRef(int_class);
+
+ const jclass boolean_class = env->FindClass("java/lang/Boolean");
+ s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
+ s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
+ s_boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z");
+ env->DeleteLocalRef(boolean_class);
+
+ const jclass player_input_class =
+ env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
+ s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
+ s_player_input_constructor = env->GetMethodID(
+ player_input_class, "<init>",
+ "(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
+ s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
+ s_player_input_buttons_field =
+ env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
+ s_player_input_analogs_field =
+ env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
+ s_player_input_motions_field =
+ env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
+ s_player_input_vibration_enabled_field =
+ env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
+ s_player_input_vibration_strength_field =
+ env->GetFieldID(player_input_class, "vibrationStrength", "I");
+ s_player_input_body_color_left_field =
+ env->GetFieldID(player_input_class, "bodyColorLeft", "J");
+ s_player_input_body_color_right_field =
+ env->GetFieldID(player_input_class, "bodyColorRight", "J");
+ s_player_input_button_color_left_field =
+ env->GetFieldID(player_input_class, "buttonColorLeft", "J");
+ s_player_input_button_color_right_field =
+ env->GetFieldID(player_input_class, "buttonColorRight", "J");
+ s_player_input_profile_name_field =
+ env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
+ s_player_input_use_system_vibrator_field =
+ env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
+ env->DeleteLocalRef(player_input_class);
+
+ const jclass yuzu_input_device_interface =
+ env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
+ s_yuzu_input_device_interface =
+ reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
+ s_yuzu_input_device_get_name =
+ env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
+ s_yuzu_input_device_get_guid =
+ env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
+ s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
+ "()I");
+ s_yuzu_input_device_get_supports_vibration =
+ env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
+ s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
+ "(F)V");
+ s_yuzu_input_device_get_axes =
+ env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
+ s_yuzu_input_device_has_keys =
+ env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
+ env->DeleteLocalRef(yuzu_input_device_interface);
+ s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
+ "(ILjava/lang/String;)V");
+ s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
+
+ // Initialize Android Storage
+ Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
+
+ // Initialize applets
+ Common::Android::SoftwareKeyboard::InitJNI(env);
+ Common::Android::WebBrowser::InitJNI(env);
+}
+
} // namespace Common::Android
diff --git a/src/common/android/id_cache.h b/src/common/android/id_cache.h
index 6e47acb746..6da385d521 100644
--- a/src/common/android/id_cache.h
+++ b/src/common/android/id_cache.h
@@ -11,6 +11,7 @@
namespace Common::Android {
+void Initialize(JavaVM* vm, JNIEnv *env);
JNIEnv* GetEnvForThread();
/**
@@ -80,15 +81,15 @@ jfieldID GetPatchTitleIdField();
jclass GetDoubleClass();
jmethodID GetDoubleConstructor();
-jfieldID GetDoubleValueField();
+jmethodID GetDoubleValueMethod();
jclass GetIntegerClass();
jmethodID GetIntegerConstructor();
-jfieldID GetIntegerValueField();
+jmethodID GetIntegerValueMethod();
jclass GetBooleanClass();
jmethodID GetBooleanConstructor();
-jfieldID GetBooleanValueField();
+jmethodID GetBooleanValueMethod();
jclass GetPlayerInputClass();
jmethodID GetPlayerInputConstructor();
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
index a43df6924c..4b406f4c35 100644
--- a/src/common/settings_enums.h
+++ b/src/common/settings_enums.h
@@ -92,14 +92,14 @@ struct EnumMetadata {
// AudioEngine must be specified discretely due to having existing but slightly different
// canonicalizations
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
-enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, };
+enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, };
template<>
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
return {
{"auto", AudioEngine::Auto},
{"cubeb", AudioEngine::Cubeb},
{"sdl3", AudioEngine::Sdl3},
- {"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
+ {"null", AudioEngine::Null},
};
}
/// @brief This is just a sufficiently large number that is more than the number of other enums declared here
@@ -113,7 +113,7 @@ inline AudioEngine EnumMetadata<AudioEngine>::GetFirst() {
}
template<>
inline AudioEngine EnumMetadata<AudioEngine>::GetLast() {
- return AudioEngine::Oboe;
+ return AudioEngine::Null;
}
ENUM(AudioMode, Mono, Stereo, Surround);
diff --git a/src/input_common/drivers/android.cpp b/src/input_common/drivers/android.cpp
index 6ab12dfe0e..966abbef94 100644
--- a/src/input_common/drivers/android.cpp
+++ b/src/input_common/drivers/android.cpp
@@ -114,7 +114,7 @@ std::set<s32> Android::GetDeviceAxes(JNIEnv* env, jobject& j_device) const {
std::set<s32> axes;
for (int i = 0; i < env->GetArrayLength(j_axes); ++i) {
jobject axis = env->GetObjectArrayElement(j_axes, i);
- axes.insert(env->GetIntField(axis, Common::Android::GetIntegerValueField()));
+ axes.insert(env->CallIntMethod(axis, Common::Android::GetIntegerValueMethod()));
}
return axes;
}