Add ability to force routing audio to headphones...
... even when HPs aren't inserted. This is aimed at people using Bluetooth audio hw mods. There are some software limitations, please read the INI/option description. Closes #1828.
This commit is contained in:
parent
dfeda19451
commit
1888e17b22
Binary file not shown.
@ -65,6 +65,7 @@ static const char *singleOptionIniNamesBoot[] = {
|
|||||||
"app_syscore_threads_on_core_2",
|
"app_syscore_threads_on_core_2",
|
||||||
"show_system_settings_string",
|
"show_system_settings_string",
|
||||||
"show_gba_boot_screen",
|
"show_gba_boot_screen",
|
||||||
|
"force_headphone_output",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *singleOptionIniNamesMisc[] = {
|
static const char *singleOptionIniNamesMisc[] = {
|
||||||
@ -581,7 +582,7 @@ static size_t saveLumaIniConfigToStr(char *out)
|
|||||||
(int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM),
|
(int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM),
|
||||||
(int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES),
|
(int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES),
|
||||||
(int)CONFIG(REDIRECTAPPTHREADS), (int)CONFIG(PATCHVERSTRING),
|
(int)CONFIG(REDIRECTAPPTHREADS), (int)CONFIG(PATCHVERSTRING),
|
||||||
(int)CONFIG(SHOWGBABOOT),
|
(int)CONFIG(SHOWGBABOOT), (int)CONFIG(FORCEHEADPHONEOUTPUT),
|
||||||
|
|
||||||
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
|
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
|
||||||
splashPosStr, (unsigned int)cfg->splashDurationMsec,
|
splashPosStr, (unsigned int)cfg->splashDurationMsec,
|
||||||
@ -759,6 +760,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
"( ) Redirect app. syscore threads to core2",
|
"( ) Redirect app. syscore threads to core2",
|
||||||
"( ) Show NAND or user string in System Settings",
|
"( ) Show NAND or user string in System Settings",
|
||||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||||
|
"( ) Force routing audio output to headphones"
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
|
static const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
|
||||||
@ -830,8 +832,8 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
"of patched code binaries, exHeaders,\n"
|
"of patched code binaries, exHeaders,\n"
|
||||||
"IPS code patches and LayeredFS\n"
|
"IPS code patches and LayeredFS\n"
|
||||||
"for specific games.\n\n"
|
"for specific games.\n\n"
|
||||||
"Also makes certain DLCs\n"
|
"Also makes certain DLCs for out-of-\n"
|
||||||
"for out-of-region games work.\n\n"
|
"region games work.\n\n"
|
||||||
"Refer to the wiki for instructions.",
|
"Refer to the wiki for instructions.",
|
||||||
|
|
||||||
"Redirect app. threads that would spawn\n"
|
"Redirect app. threads that would spawn\n"
|
||||||
@ -857,6 +859,15 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
|
|
||||||
"Enable showing the GBA boot screen\n"
|
"Enable showing the GBA boot screen\n"
|
||||||
"when booting GBA games.",
|
"when booting GBA games.",
|
||||||
|
|
||||||
|
"Force audio output to headphones.\n\n"
|
||||||
|
"Currently only for NATIVE_FIRM.\n\n"
|
||||||
|
"Due to software limitations, this gets\n"
|
||||||
|
"undone if you actually insert then\n"
|
||||||
|
"remove HPs (just enter then exit sleep\n"
|
||||||
|
"mode if this happens).\n\n"
|
||||||
|
"Also gets bypassed for camera shutter\n"
|
||||||
|
"sound.",
|
||||||
};
|
};
|
||||||
|
|
||||||
FirmwareSource nandType = FIRMWARE_SYSNAND;
|
FirmwareSource nandType = FIRMWARE_SYSNAND;
|
||||||
@ -892,6 +903,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
{ .visible = ISN3DS },
|
{ .visible = ISN3DS },
|
||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
|
{ .visible = true },
|
||||||
};
|
};
|
||||||
|
|
||||||
//Calculate the amount of the various kinds of options and pre-select the first single one
|
//Calculate the amount of the various kinds of options and pre-select the first single one
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#define CONFIG_FILE "config.bin"
|
#define CONFIG_FILE "config.bin"
|
||||||
#define CONFIG_VERSIONMAJOR 3
|
#define CONFIG_VERSIONMAJOR 3
|
||||||
#define CONFIG_VERSIONMINOR 4
|
#define CONFIG_VERSIONMINOR 5
|
||||||
|
|
||||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||||
@ -62,6 +62,7 @@ enum singleOptions
|
|||||||
REDIRECTAPPTHREADS,
|
REDIRECTAPPTHREADS,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
|
FORCEHEADPHONEOUTPUT,
|
||||||
PATCHUNITINFO,
|
PATCHUNITINFO,
|
||||||
DISABLEARM11EXCHANDLERS,
|
DISABLEARM11EXCHANDLERS,
|
||||||
ENABLESAFEFIRMROSALINA,
|
ENABLESAFEFIRMROSALINA,
|
||||||
|
@ -33,6 +33,7 @@ enum singleOptions
|
|||||||
REDIRECTAPPTHREADS,
|
REDIRECTAPPTHREADS,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
|
FORCEHEADPHONEOUTPUT,
|
||||||
PATCHUNITINFO,
|
PATCHUNITINFO,
|
||||||
DISABLEARM11EXCHANDLERS,
|
DISABLEARM11EXCHANDLERS,
|
||||||
ENABLESAFEFIRMROSALINA,
|
ENABLESAFEFIRMROSALINA,
|
||||||
|
@ -36,6 +36,7 @@ enum singleOptions
|
|||||||
REDIRECTAPPTHREADS,
|
REDIRECTAPPTHREADS,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
|
FORCEHEADPHONEOUTPUT,
|
||||||
PATCHUNITINFO,
|
PATCHUNITINFO,
|
||||||
DISABLEARM11EXCHANDLERS,
|
DISABLEARM11EXCHANDLERS,
|
||||||
ENABLESAFEFIRMROSALINA,
|
ENABLESAFEFIRMROSALINA,
|
||||||
|
@ -30,6 +30,7 @@ enum singleOptions
|
|||||||
REDIRECTAPPTHREADS,
|
REDIRECTAPPTHREADS,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
|
FORCEHEADPHONEOUTPUT,
|
||||||
PATCHUNITINFO,
|
PATCHUNITINFO,
|
||||||
DISABLEARM11EXCHANDLERS,
|
DISABLEARM11EXCHANDLERS,
|
||||||
ENABLESAFEFIRMROSALINA,
|
ENABLESAFEFIRMROSALINA,
|
||||||
|
Binary file not shown.
@ -39,6 +39,7 @@ enum singleOptions
|
|||||||
REDIRECTAPPTHREADS,
|
REDIRECTAPPTHREADS,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
|
FORCEHEADPHONEOUTPUT,
|
||||||
PATCHUNITINFO,
|
PATCHUNITINFO,
|
||||||
DISABLEARM11EXCHANDLERS,
|
DISABLEARM11EXCHANDLERS,
|
||||||
ENABLESAFEFIRMROSALINA,
|
ENABLESAFEFIRMROSALINA,
|
||||||
|
29
sysmodules/rosalina/include/shell.h
Normal file
29
sysmodules/rosalina/include/shell.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2023 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||||
|
* * Requiring preservation of specified reasonable legal notices or
|
||||||
|
* author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
* * Prohibiting misrepresentation of the origin of that material,
|
||||||
|
* or requiring that modified versions of such material be marked in
|
||||||
|
* reasonable ways as different from the original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <3ds/types.h>
|
||||||
|
|
||||||
|
void handleShellOpened(void);
|
@ -150,7 +150,7 @@ static size_t LumaConfig_SaveLumaIniConfigToStr(char *out, const CfgData *cfg)
|
|||||||
(int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM),
|
(int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM),
|
||||||
(int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES),
|
(int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES),
|
||||||
(int)CONFIG(REDIRECTAPPTHREADS), (int)CONFIG(PATCHVERSTRING),
|
(int)CONFIG(REDIRECTAPPTHREADS), (int)CONFIG(PATCHVERSTRING),
|
||||||
(int)CONFIG(SHOWGBABOOT),
|
(int)CONFIG(SHOWGBABOOT), (int)CONFIG(FORCEHEADPHONEOUTPUT),
|
||||||
|
|
||||||
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
|
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
|
||||||
splashPosStr, (unsigned int)cfg->splashDurationMsec,
|
splashPosStr, (unsigned int)cfg->splashDurationMsec,
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "minisoc.h"
|
#include "minisoc.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "bootdiag.h"
|
#include "bootdiag.h"
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
#include "task_runner.h"
|
#include "task_runner.h"
|
||||||
|
|
||||||
@ -165,13 +166,7 @@ static void handleShellNotification(u32 notificationId)
|
|||||||
// Note that this notification is also fired on system init.
|
// Note that this notification is also fired on system init.
|
||||||
// Sequence goes like this: MCU fires notif. 0x200 on shell open
|
// Sequence goes like this: MCU fires notif. 0x200 on shell open
|
||||||
// and shell close, then NS demuxes it and fires 0x213 and 0x214.
|
// and shell close, then NS demuxes it and fires 0x213 and 0x214.
|
||||||
|
handleShellOpened();
|
||||||
// We need to check here if GSP has done its init stuff, in particular
|
|
||||||
// clock and reset, otherwise we'll cause core1 to be in a waitstate
|
|
||||||
// forever (if we access a GPU reg while the GPU block's clock is off).
|
|
||||||
// (GSP does its init before registering its services)
|
|
||||||
if (isServiceUsable("gsp::Gpu"))
|
|
||||||
ScreenFiltersMenu_RestoreSettings();
|
|
||||||
menuShouldExit = false;
|
menuShouldExit = false;
|
||||||
} else {
|
} else {
|
||||||
// Shell closed
|
// Shell closed
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "menus/cheats.h"
|
#include "menus/cheats.h"
|
||||||
#include "minisoc.h"
|
#include "minisoc.h"
|
||||||
#include "menus/screen_filters.h"
|
#include "menus/screen_filters.h"
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
u32 menuCombo = 0;
|
u32 menuCombo = 0;
|
||||||
bool isHidInitialized = false;
|
bool isHidInitialized = false;
|
||||||
@ -261,10 +262,11 @@ void menuThreadMain(void)
|
|||||||
if(isN3DS)
|
if(isN3DS)
|
||||||
N3DSMenu_UpdateStatus();
|
N3DSMenu_UpdateStatus();
|
||||||
|
|
||||||
while (!isServiceUsable("ac:u") || !isServiceUsable("hid:USER") || !isServiceUsable("gsp::Gpu"))
|
while (!isServiceUsable("ac:u") || !isServiceUsable("hid:USER") || !isServiceUsable("gsp::Gpu") || !isServiceUsable("cdc:CHK"))
|
||||||
svcSleepThread(250 * 1000 * 1000LL);
|
svcSleepThread(250 * 1000 * 1000LL);
|
||||||
|
|
||||||
ScreenFiltersMenu_LoadConfig();
|
ScreenFiltersMenu_LoadConfig();
|
||||||
|
handleShellOpened();
|
||||||
|
|
||||||
hidInit(); // assume this doesn't fail
|
hidInit(); // assume this doesn't fail
|
||||||
isHidInitialized = true;
|
isHidInitialized = true;
|
||||||
|
@ -227,8 +227,6 @@ void ScreenFiltersMenu_LoadConfig(void)
|
|||||||
|
|
||||||
svcGetSystemInfo(&out, 0x10000, 0x10C);
|
svcGetSystemInfo(&out, 0x10000, 0x10C);
|
||||||
bottomScreenFilter.invert = (bool)out;
|
bottomScreenFilter.invert = (bool)out;
|
||||||
|
|
||||||
ScreenFiltersMenu_RestoreSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEF_CCT_SETTER(6500, Default)
|
DEF_CCT_SETTER(6500, Default)
|
||||||
|
82
sysmodules/rosalina/source/shell.c
Normal file
82
sysmodules/rosalina/source/shell.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Luma3DS
|
||||||
|
* Copyright (C) 2023 Aurora Wright, TuxSH
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||||
|
* * Requiring preservation of specified reasonable legal notices or
|
||||||
|
* author attributions in that material or in the Appropriate Legal
|
||||||
|
* Notices displayed by works containing it.
|
||||||
|
* * Prohibiting misrepresentation of the origin of that material,
|
||||||
|
* or requiring that modified versions of such material be marked in
|
||||||
|
* reasonable ways as different from the original version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
#include "shell.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "screen_filters.h"
|
||||||
|
#include "luma_config.h"
|
||||||
|
|
||||||
|
static void forceHeadphoneOutput(void)
|
||||||
|
{
|
||||||
|
// DSP/Codec sysmodule already have a way to force headphone output,
|
||||||
|
// but it's only for when the shell is closed (applied on shell close,
|
||||||
|
// cleared on shell opened); that mechanism is usually used by apps
|
||||||
|
// which have a "jukebox" feature (e.g Pokémon SMD).
|
||||||
|
|
||||||
|
// This whole thing here is fragile and doesn't mesh well with the "codec"
|
||||||
|
// sysmodule. For example, inserting then removing HPs will undo what this
|
||||||
|
// function does.
|
||||||
|
|
||||||
|
// TODO: stop opening and closing cdc:CHK (and mcu::HWC), which
|
||||||
|
// unecessarily spawns and despawns threads.
|
||||||
|
|
||||||
|
// Wait for CSND to do its job
|
||||||
|
svcSleepThread(20 * 1000 * 1000LL);
|
||||||
|
|
||||||
|
Handle *cdcChkHandlePtr = cdcChkGetSessionHandle();
|
||||||
|
*cdcChkHandlePtr = 0;
|
||||||
|
|
||||||
|
Result res = srvGetServiceHandle(cdcChkHandlePtr, "cdc:CHK");
|
||||||
|
// Try to steal the handle if some other process is using the service (custom SVC)
|
||||||
|
if (R_FAILED(res))
|
||||||
|
res = svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, cdcChkHandlePtr, "cdc:CHK");
|
||||||
|
|
||||||
|
if (R_FAILED(res))
|
||||||
|
return;
|
||||||
|
|
||||||
|
u8 reg = 0x30; // Enable override selection (always set), then select HP.
|
||||||
|
res = CDCCHK_WriteRegisters2(100, 69, ®, 1);
|
||||||
|
|
||||||
|
svcCloseHandle(*cdcChkHandlePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleShellOpened(void)
|
||||||
|
{
|
||||||
|
s64 out = 0;
|
||||||
|
svcGetSystemInfo(&out, 0x10000, 3);
|
||||||
|
u32 config = (u32)out;
|
||||||
|
|
||||||
|
// We need to check here if GSP has done its init stuff, in particular
|
||||||
|
// clock and reset, otherwise we'll cause core1 to be in a waitstate
|
||||||
|
// forever (if we access a GPU reg while the GPU block's clock is off).
|
||||||
|
// (GSP does its init before registering its services)
|
||||||
|
if (isServiceUsable("gsp::Gpu"))
|
||||||
|
ScreenFiltersMenu_RestoreSettings();
|
||||||
|
|
||||||
|
if ((config & BIT(FORCEHEADPHONEOUTPUT)) != 0 && isServiceUsable("cdc:CHK"))
|
||||||
|
forceHeadphoneOutput();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user