From 8a92b3edff9bb80c98f8ad9020a3ae260e8abfd4 Mon Sep 17 00:00:00 2001 From: izzy2lost Date: Fri, 20 Mar 2026 14:43:29 -0400 Subject: [PATCH] HRTF 3d audio now set to off by default --- android/app/src/main/cpp/xemu_android.cpp | 138 +++++++++++++++++- .../app/src/main/cpp/xemu_settings_android.cc | 2 +- .../com/izzy2lost/x1box/SettingsActivity.kt | 21 ++- 3 files changed, 155 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/cpp/xemu_android.cpp b/android/app/src/main/cpp/xemu_android.cpp index e719d09fab..bd95fd2c16 100644 --- a/android/app/src/main/cpp/xemu_android.cpp +++ b/android/app/src/main/cpp/xemu_android.cpp @@ -39,6 +39,9 @@ namespace { constexpr const char* kLogTag = "xemu-android"; constexpr const char* kPrefsName = "x1box_prefs"; constexpr const char* kDebugLogPrefKey = "setting_debug_logs_enabled"; +constexpr const char* kHrtfPrefKey = "setting_hrtf"; +constexpr const char* kHrtfDefaultOffMigrationPrefKey = + "setting_hrtf_default_off_migrated_v1"; constexpr const char* kDebugLogRelativeDir = "x1box/debug-logs"; constexpr const char* kNativeDebugLogFileName = "xemu-debug.log"; constexpr off_t kMaxDebugLogBytes = 4 * 1024 * 1024; @@ -52,6 +55,7 @@ static jobject GetActivity(JNIEnv* env); static bool HasException(JNIEnv* env, const char* context); static std::string GetFilesDirPath(JNIEnv* env, jobject activity); static void ConfigureNativeDebugLogging(JNIEnv* env, jobject activity); +static void ApplyHrtfDefaultOffMigration(JNIEnv* env, jobject activity); static bool NativeDebugLoggingEnabled(); static void AppendNativeDebugLog(const char* level, const char* message); @@ -518,6 +522,134 @@ static bool GetPrefBool(JNIEnv* env, jobject activity, const char* key, bool def return out; } +static void ApplyHrtfDefaultOffMigration(JNIEnv* env, jobject activity) { + if (!env || !activity) { + return; + } + + jclass activityClass = env->GetObjectClass(activity); + if (!activityClass) { + return; + } + + jmethodID getPrefs = env->GetMethodID( + activityClass, "getSharedPreferences", + "(Ljava/lang/String;I)Landroid/content/SharedPreferences;"); + env->DeleteLocalRef(activityClass); + if (!getPrefs) { + return; + } + + jstring prefsName = env->NewStringUTF(kPrefsName); + if (!prefsName) { + return; + } + + jobject prefs = env->CallObjectMethod(activity, getPrefs, prefsName, 0); + env->DeleteLocalRef(prefsName); + if (HasException(env, "getSharedPreferences") || !prefs) { + return; + } + + jclass prefsClass = env->GetObjectClass(prefs); + if (!prefsClass) { + env->DeleteLocalRef(prefs); + return; + } + + jmethodID getBool = + env->GetMethodID(prefsClass, "getBoolean", "(Ljava/lang/String;Z)Z"); + jmethodID edit = + env->GetMethodID(prefsClass, "edit", + "()Landroid/content/SharedPreferences$Editor;"); + if (!getBool || !edit) { + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); + return; + } + + jstring migrationKey = env->NewStringUTF(kHrtfDefaultOffMigrationPrefKey); + if (!migrationKey) { + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); + return; + } + + const jboolean migrated = + env->CallBooleanMethod(prefs, getBool, migrationKey, JNI_FALSE); + if (HasException(env, "SharedPreferences.getBoolean")) { + env->DeleteLocalRef(migrationKey); + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); + return; + } + + if (migrated == JNI_TRUE) { + env->DeleteLocalRef(migrationKey); + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); + return; + } + + jobject editor = env->CallObjectMethod(prefs, edit); + if (HasException(env, "SharedPreferences.edit") || !editor) { + env->DeleteLocalRef(migrationKey); + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); + return; + } + + jclass editorClass = env->GetObjectClass(editor); + if (!editorClass) { + env->DeleteLocalRef(editor); + env->DeleteLocalRef(migrationKey); + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); + return; + } + + jmethodID putBool = env->GetMethodID( + editorClass, "putBoolean", + "(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor;"); + jmethodID apply = env->GetMethodID(editorClass, "apply", "()V"); + if (!putBool || !apply) { + env->DeleteLocalRef(editorClass); + env->DeleteLocalRef(editor); + env->DeleteLocalRef(migrationKey); + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); + return; + } + + jstring hrtfKey = env->NewStringUTF(kHrtfPrefKey); + if (!hrtfKey) { + env->DeleteLocalRef(editorClass); + env->DeleteLocalRef(editor); + env->DeleteLocalRef(migrationKey); + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); + return; + } + + env->CallObjectMethod(editor, putBool, hrtfKey, JNI_FALSE); + if (!HasException(env, "Editor.putBoolean")) { + env->CallObjectMethod(editor, putBool, migrationKey, JNI_TRUE); + if (!HasException(env, "Editor.putBoolean")) { + env->CallVoidMethod(editor, apply); + if (!HasException(env, "Editor.apply")) { + LogInfo("Applied one-time Android HRTF default-off migration"); + } + } + } + + env->DeleteLocalRef(hrtfKey); + env->DeleteLocalRef(editorClass); + env->DeleteLocalRef(editor); + env->DeleteLocalRef(migrationKey); + env->DeleteLocalRef(prefsClass); + env->DeleteLocalRef(prefs); +} + static int GetPrefInt(JNIEnv* env, jobject activity, const char* key, int defValue) { if (!env || !activity || !key || key[0] == '\0') { return defValue; @@ -873,7 +1005,7 @@ struct EmulatorSettings { std::string renderer = "opengl"; // "vulkan" or "opengl" std::string filtering = "linear"; // "linear" or "nearest" bool use_dsp = false; - bool hrtf = true; + bool hrtf = false; bool cache_shaders = true; bool hard_fpu = true; bool vsync = false; @@ -1029,6 +1161,8 @@ static SetupFiles SyncSetupFiles() { } LogInfoFmt("SyncSetupFiles: base path %s", basePath); + ApplyHrtfDefaultOffMigration(env, activity); + std::string base = std::string(basePath) + "/x1box"; EnsureDirExists(base); out.eeprom = base + "/eeprom.bin"; @@ -1118,7 +1252,7 @@ static SetupFiles SyncSetupFiles() { emuSettings.system_memory_mib = 64; } emuSettings.use_dsp = GetPrefBool(env, activity, "setting_use_dsp", false); - emuSettings.hrtf = GetPrefBool(env, activity, "setting_hrtf", true); + emuSettings.hrtf = GetPrefBool(env, activity, kHrtfPrefKey, false); emuSettings.cache_shaders = GetPrefBool(env, activity, "setting_cache_shaders", true); emuSettings.hard_fpu = GetPrefBool(env, activity, "setting_hard_fpu", true); emuSettings.skip_boot_anim = diff --git a/android/app/src/main/cpp/xemu_settings_android.cc b/android/app/src/main/cpp/xemu_settings_android.cc index 41beaf0947..b61dba0205 100644 --- a/android/app/src/main/cpp/xemu_settings_android.cc +++ b/android/app/src/main/cpp/xemu_settings_android.cc @@ -94,7 +94,7 @@ static void xemu_settings_apply_defaults(void) g_config.audio.vp.num_workers = 0; g_config.audio.use_dsp = false; - g_config.audio.hrtf = true; + g_config.audio.hrtf = false; g_config.audio.volume_limit = 1.0; g_config.net.enable = false; diff --git a/android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt b/android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt index e124c56dd1..f28e82b440 100644 --- a/android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt +++ b/android/app/src/main/java/com/izzy2lost/x1box/SettingsActivity.kt @@ -33,7 +33,10 @@ class SettingsActivity : AppCompatActivity() { companion object { const val EXTRA_INITIAL_ORIENTATION = "com.izzy2lost.x1box.extra.INITIAL_ORIENTATION" + private const val PREFS_NAME = "x1box_prefs" private const val PREF_ADVANCED_EXPERIMENTAL_EXPANDED = "settings_advanced_experimental_expanded" + private const val PREF_HRTF = "setting_hrtf" + private const val PREF_HRTF_DEFAULT_OFF_MIGRATED = "setting_hrtf_default_off_migrated_v1" private const val PREF_INSIGNIA_SETUP_URI = "setting_insignia_setup_assistant_uri" private const val PREF_INSIGNIA_SETUP_NAME = "setting_insignia_setup_assistant_name" private const val PREF_VULKAN_DRIVER_URI = "setting_vulkan_driver_uri" @@ -44,7 +47,7 @@ class SettingsActivity : AppCompatActivity() { private const val VULKAN_DRIVER_FILE_NAME = "vulkan_driver.so" } - private val prefs by lazy { getSharedPreferences("x1box_prefs", Context.MODE_PRIVATE) } + private val prefs by lazy { getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) } private data class EepromLanguageOption( val value: XboxEepromEditor.Language, @@ -234,6 +237,7 @@ class SettingsActivity : AppCompatActivity() { applyInitialOrientationFromIntent() OrientationLocker(this).enable() DebugLog.initialize(this) + applyHrtfDefaultOffMigration() setContentView(R.layout.activity_settings) EdgeToEdgeHelper.enable(this) EdgeToEdgeHelper.applySystemBarPadding(findViewById(R.id.settings_scroll)) @@ -343,7 +347,7 @@ class SettingsActivity : AppCompatActivity() { } switchDsp.isChecked = prefs.getBoolean("setting_use_dsp", false) - switchHrtf.isChecked = prefs.getBoolean("setting_hrtf", true) + switchHrtf.isChecked = prefs.getBoolean(PREF_HRTF, false) switchShaders.isChecked = prefs.getBoolean("setting_cache_shaders", true) switchFpu.isChecked = prefs.getBoolean("setting_hard_fpu", true) switchVsync.isChecked = prefs.getBoolean("setting_vsync", false) @@ -463,7 +467,7 @@ class SettingsActivity : AppCompatActivity() { .putInt("setting_system_memory_mib", selectedSystemMemoryMiB) .putString("setting_tcg_thread", selectedThread) .putBoolean("setting_use_dsp", switchDsp.isChecked) - .putBoolean("setting_hrtf", switchHrtf.isChecked) + .putBoolean(PREF_HRTF, switchHrtf.isChecked) .putBoolean("setting_cache_shaders", switchShaders.isChecked) .putBoolean("setting_hard_fpu", switchFpu.isChecked) .putBoolean("setting_vsync", switchVsync.isChecked) @@ -528,6 +532,17 @@ class SettingsActivity : AppCompatActivity() { } } + private fun applyHrtfDefaultOffMigration() { + if (prefs.getBoolean(PREF_HRTF_DEFAULT_OFF_MIGRATED, false)) { + return + } + + prefs.edit() + .putBoolean(PREF_HRTF, false) + .putBoolean(PREF_HRTF_DEFAULT_OFF_MIGRATED, true) + .apply() + } + private fun applyInitialOrientationFromIntent() { val initialOrientation = intent.getIntExtra(EXTRA_INITIAL_ORIENTATION, Int.MIN_VALUE) if (initialOrientation == android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ||