mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
Added support for applet video-recording, currently not usable. In appletExit, only call appletSetFocusHandlingMode when g_appletExitProcessFlag is zero, so that it isn't called twice during proc-exit.
This commit is contained in:
parent
cfbc3e9278
commit
a62e29d5cf
@ -55,6 +55,20 @@ Result appletCreateManagedDisplayLayer(u64 *out);
|
||||
|
||||
Result appletGetDesiredLanguage(u64 *LanguageCode);
|
||||
|
||||
/// Gets whether video recording is supported.
|
||||
/// See also \ref appletInitializeGamePlayRecording.
|
||||
Result appletIsGamePlayRecordingSupported(bool *flag);
|
||||
|
||||
/// Disable/enable video recording. Only available after \ref appletInitializeGamePlayRecording was used.
|
||||
/// See also \ref appletInitializeGamePlayRecording.
|
||||
Result appletSetGamePlayRecordingState(bool state);
|
||||
|
||||
/// This is currently not usable.
|
||||
/// Initializes video recording. When size is 0, the default size of 0x6000000 is used.
|
||||
/// Only available with AppletType_*Application on 3.0.0+, hence errors from this can be ignored.
|
||||
/// Video recording is only fully available system-side with 4.0.0+.
|
||||
Result appletInitializeGamePlayRecording(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Blocks the usage of the home button.
|
||||
* @param val Unknown nanoseconds. Value 0 can be used.
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "kernel/detect.h"
|
||||
#include "kernel/tmem.h"
|
||||
#include "services/fatal.h"
|
||||
#include "services/applet.h"
|
||||
#include "services/apm.h"
|
||||
@ -50,6 +51,9 @@ static bool g_appletNotifiedRunning = 0;
|
||||
|
||||
static AppletHookCookie g_appletFirstHook;
|
||||
|
||||
static TransferMemory g_appletRecordingTmem;
|
||||
static u32 g_appletRecordingInitialized;
|
||||
|
||||
static Result _appletGetHandle(Service* srv, Handle* handle_out, u64 cmd_id);
|
||||
static Result _appletGetSession(Service* srv, Service* srv_out, u64 cmd_id);
|
||||
static Result _appletGetSessionProxy(Service* srv_out, u64 cmd_id, Handle prochandle, u8 *AppletAttribute);
|
||||
@ -93,6 +97,7 @@ Result appletInitialize(void)
|
||||
g_appletResourceUserId = 0;
|
||||
g_appletNotifiedRunning = 0;
|
||||
g_appletExitProcessFlag = 0;
|
||||
g_appletRecordingInitialized = 0;
|
||||
|
||||
switch (__nx_applet_type) {
|
||||
case AppletType_Default:
|
||||
@ -270,7 +275,13 @@ void appletExit(void)
|
||||
{
|
||||
if (atomicDecrement64(&g_refCnt) == 0)
|
||||
{
|
||||
if (!g_appletExitProcessFlag) {
|
||||
if (g_appletRecordingInitialized > 0) {
|
||||
if (g_appletRecordingInitialized == 2) appletSetGamePlayRecordingState(0);
|
||||
}
|
||||
|
||||
if (__nx_applet_type == AppletType_Application) appletSetFocusHandlingMode(1);
|
||||
}
|
||||
|
||||
if ((envIsNso() && __nx_applet_exit_mode==0) || __nx_applet_exit_mode==1) {
|
||||
if (_appletIsApplication() ||
|
||||
@ -323,6 +334,11 @@ void appletExit(void)
|
||||
g_appletResourceUserId = 0;
|
||||
|
||||
apmExit();
|
||||
|
||||
if (g_appletRecordingInitialized > 0) {
|
||||
tmemClose(&g_appletRecordingTmem);
|
||||
g_appletRecordingInitialized = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -715,6 +731,156 @@ void appletNotifyRunning(u8 *out) {
|
||||
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadAppletNotifyRunning));
|
||||
}
|
||||
|
||||
Result appletIsGamePlayRecordingSupported(bool *flag) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
if (flag) *flag = 0;
|
||||
|
||||
if (!serviceIsActive(&g_appletSrv) || !_appletIsApplication())
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
if (!kernelAbove300())
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 65;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_appletIFunctions);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 flag;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc) && flag) *flag = resp->flag & 1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _appletInitializeGamePlayRecording(TransferMemory *tmem) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
if (!serviceIsActive(&g_appletSrv) || !_appletIsApplication())
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
if (!kernelAbove300())
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
ipcSendHandleCopy(&c, tmem->handle);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 size;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 66;
|
||||
raw->size = tmem->size;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_appletIFunctions);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result appletSetGamePlayRecordingState(bool state) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
if (!serviceIsActive(&g_appletSrv) || !_appletIsApplication() || g_appletRecordingInitialized==0)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
if (!kernelAbove300())
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 state;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 67;
|
||||
raw->state = state==0 ? 0 : 1;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_appletIFunctions);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result appletInitializeGamePlayRecording(size_t size) {
|
||||
Result rc=0;
|
||||
|
||||
g_appletRecordingInitialized = 0;
|
||||
|
||||
//These checks are done in the called applet funcs, but do it here too so that tmemCreate() doesn't run when it's not needed.
|
||||
if (!serviceIsActive(&g_appletSrv) || !_appletIsApplication())
|
||||
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
if (!kernelAbove300())
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||
|
||||
if (size==0) size = 0x6000000;
|
||||
rc = tmemCreate(&g_appletRecordingTmem, size, Perm_None);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
rc = _appletInitializeGamePlayRecording(&g_appletRecordingTmem);
|
||||
if (R_FAILED(rc)) {
|
||||
tmemClose(&g_appletRecordingTmem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
g_appletRecordingInitialized = 1;
|
||||
|
||||
rc = appletSetGamePlayRecordingState(1);
|
||||
if (R_SUCCEEDED(rc)) g_appletRecordingInitialized = 2;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _appletReceiveMessage(u32 *out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
Loading…
Reference in New Issue
Block a user