diff --git a/nx/include/switch.h b/nx/include/switch.h index 467736f8..e9fbd656 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -90,6 +90,7 @@ extern "C" { #include "switch/services/nfc.h" #include "switch/services/wlaninf.h" #include "switch/services/pctl.h" +#include "switch/services/pdm.h" #include "switch/display/binder.h" #include "switch/display/parcel.h" diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index 53f6a7d8..7daad349 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -9,6 +9,7 @@ #include "../types.h" #include "../services/sm.h" #include "../services/apm.h" +#include "../services/pdm.h" #include "../kernel/tmem.h" #include "../kernel/event.h" @@ -135,11 +136,6 @@ typedef struct { LibAppletExitReason exitreason; ///< Set by \ref appletHolderJoin using the output from cmd GetResult, see \ref LibAppletExitReason. } AppletHolder; -/// 'pdm' ApplicationPlayStatistics -typedef struct { - u8 unk_x0[0x8]; -} AppletApplicationPlayStatistics; - /// Attributes for launching applications for Quest. typedef struct { u32 unk_x0; @@ -226,13 +222,24 @@ Result appletEndBlockingHomeButton(void); /** * @brief Gets ApplicationPlayStatistics. * @note Only available with AppletType_*Application on 5.0.0+. - * @note This may return no output in some cases. - * @param stats Output \ref AppletApplicationPlayStatistics array. + * @note The input titleIDs must be allowed via control.nacp with the current host title. The minimum allowed titleID is the titleID for the current-process. + * @param stats Output \ref PdmApplicationPlayStatistics array. * @param titleIDs Input titleIDs array. * @param count Total entries in the input/output arrays. - * @param out Output s32. + * @param total_out Total output entries. */ -Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *out); +Result appletQueryApplicationPlayStatistics(PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out); + +/** + * @brief Same as \ref appletQueryApplicationPlayStatistics except this gets playstats specific to the input userID. + * @note Only available with AppletType_*Application on 6.0.0+. + * @param userID userID + * @param stats Output \ref PdmApplicationPlayStatistics array. + * @param titleIDs Input titleIDs array. + * @param count Total entries in the input/output arrays. + * @param total_out Total output entries. + */ +Result appletQueryApplicationPlayStatisticsByUid(u128 userID, PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out); /** * @brief Delay exiting until \ref appletUnlockExit is called, with a 15 second timeout once exit is requested. diff --git a/nx/include/switch/services/pdm.h b/nx/include/switch/services/pdm.h new file mode 100644 index 00000000..d66c4270 --- /dev/null +++ b/nx/include/switch/services/pdm.h @@ -0,0 +1,16 @@ +/** + * @file pdm.h + * @brief PDM (pdm:*) service IPC wrapper. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once +#include "../types.h" +#include "../services/sm.h" + +/// ApplicationPlayStatistics +typedef struct { + u64 titleID; ///< titleID + u8 unk_x8[0x10]; ///< Unknown +} PdmApplicationPlayStatistics; + diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index 0ee932b8..d270f4c7 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -1445,8 +1445,8 @@ Result appletInitializeGamePlayRecording(void) { return rc; } -//Official sw has this under 'pdm'. -Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *out) { +//Official sw has these under 'pdm'. +Result appletQueryApplicationPlayStatistics(PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out) { IpcCommand c; ipcInitialize(&c); @@ -1456,8 +1456,8 @@ Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *sta if (hosversionBefore(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - ipcAddRecvBuffer(&c, stats, count*sizeof(AppletApplicationPlayStatistics), BufferType_Normal); ipcAddSendBuffer(&c, titleIDs, count*sizeof(u64), BufferType_Normal); + ipcAddRecvBuffer(&c, stats, count*sizeof(PdmApplicationPlayStatistics), BufferType_Normal); struct { u64 magic; @@ -1476,7 +1476,7 @@ Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *sta struct { u64 magic; u64 result; - s32 out; + s32 total_out; } *resp; serviceIpcParse(&g_appletIFunctions, &r, sizeof(*resp)); @@ -1484,7 +1484,53 @@ Result appletQueryApplicationPlayStatistics(AppletApplicationPlayStatistics *sta rc = resp->result; - if (R_SUCCEEDED(rc) && out) *out = resp->out; + if (R_SUCCEEDED(rc) && total_out) *total_out = resp->total_out; + } + + return rc; +} + +Result appletQueryApplicationPlayStatisticsByUid(u128 userID, PdmApplicationPlayStatistics *stats, const u64 *titleIDs, s32 count, s32 *total_out) { + IpcCommand c; + ipcInitialize(&c); + + if (!serviceIsActive(&g_appletSrv) || !_appletIsRegularApplication()) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + if (hosversionBefore(6,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + ipcAddSendBuffer(&c, titleIDs, count*sizeof(u64), BufferType_Normal); + ipcAddRecvBuffer(&c, stats, count*sizeof(PdmApplicationPlayStatistics), BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + u128 userID; + } *raw; + + raw = serviceIpcPrepareHeader(&g_appletIFunctions, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 111; + raw->userID = userID; + + Result rc = serviceIpcDispatch(&g_appletIFunctions); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + s32 total_out; + } *resp; + + serviceIpcParse(&g_appletIFunctions, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && total_out) *total_out = resp->total_out; } return rc;