From 6ce881b0139ed80dbf26be445cc78642d3f18fcc Mon Sep 17 00:00:00 2001 From: plutoo Date: Sun, 30 May 2021 17:33:26 -0700 Subject: [PATCH] audrec: Initial commit --- nx/include/switch/services/audrec.h | 47 +++++++++++ nx/source/services/audrec.c | 123 ++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 nx/include/switch/services/audrec.h create mode 100644 nx/source/services/audrec.c diff --git a/nx/include/switch/services/audrec.h b/nx/include/switch/services/audrec.h new file mode 100644 index 00000000..a9e2307d --- /dev/null +++ b/nx/include/switch/services/audrec.h @@ -0,0 +1,47 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + u64 released_ns; + u64 next_buffer_ptr; + u64 sample_buffer_ptr; + u64 sample_buffer_capacity; + u64 data_size; + u64 data_offset; +} FinalOutputRecorderBuffer; + +typedef struct { + u32 sample_rate; + u32 channel_count; +} FinalOutputRecorderParameter; + +typedef struct { + u32 sample_rate; + u32 channel_count; + u32 sample_format; + u32 state; +} FinalOutputRecorderParameterInternal; + +typedef struct { + Service s; +} AudrecRecorder; + +Result audrecInitialize(void); +void audrecExit(void); +Service* audrecGetServiceSession(void); + +Result audrecOpenFinalOutputRecorder(AudrecRecorder* recorder_out, FinalOutputRecorderParameter* param_in, u64 aruid, FinalOutputRecorderParameterInternal* param_out); + +Result audrecRecorderStart(AudrecRecorder* recorder); +Result audrecRecorderStop(AudrecRecorder* recorder); +Result audrecRecorderRegisterBufferEvent(AudrecRecorder* recorder, Event* out_event); +Result audrecRecorderAppendFinalOutputRecorderBuffer(AudrecRecorder* recorder, u64 buffer_client_ptr, FinalOutputRecorderBuffer* param); +Result audrecRecorderGetReleasedFinalOutputRecorderBuffers(AudrecRecorder* recorder, u64* out_buffers, u64* inout_count, u64* out_released); +void audrecRecorderClose(AudrecRecorder* recorder); + +#ifdef __cplusplus +}; +#endif \ No newline at end of file diff --git a/nx/source/services/audrec.c b/nx/source/services/audrec.c new file mode 100644 index 00000000..111c2040 --- /dev/null +++ b/nx/source/services/audrec.c @@ -0,0 +1,123 @@ +#define NX_SERVICE_ASSUME_NON_DOMAIN +#include "service_guard.h" +#include "kernel/event.h" +#include "runtime/hosversion.h" +#include "services/audrec.h" + +NX_GENERATE_SERVICE_GUARD(audrec); +static Service g_audrecUserSrv; + +Result _audrecInitialize(void) { + return smGetService(&g_audrecUserSrv, "audrec:u"); +} + +void _audrecCleanup(void) { + serviceClose(&g_audrecUserSrv); +} + +Service* audrecGetServiceSession(void) { + return &g_audrecUserSrv; +} + +Result audrecOpenFinalOutputRecorder(AudrecRecorder* recorder_out, FinalOutputRecorderParameter* param_in, u64 aruid, FinalOutputRecorderParameterInternal* param_out) { + const struct { + FinalOutputRecorderParameter param; + u64 aruid; + } in = { *param_in, aruid }; + + struct { + FinalOutputRecorderParameterInternal param; + } out; + + Result rc = serviceDispatchInOut(&g_audrecUserSrv, 0, in, out, + .in_num_handles = 1, + .in_handles = { CUR_PROCESS_HANDLE }, + .out_num_objects = 1, + .out_objects = &recorder_out->s, + ); + + if (R_SUCCEEDED(rc)) { + *param_out = out.param; + } + + return rc; +} + +Result audrecRecorderStart(AudrecRecorder* recorder) { + return serviceDispatch(&recorder->s, 1); +} + +Result audrecRecorderStop(AudrecRecorder* recorder) { + return serviceDispatch(&recorder->s, 2); +} + +Result audrecRecorderRegisterBufferEvent(AudrecRecorder* recorder, Event* out_event) { + Handle tmp_handle; + + Result rc = serviceDispatch(&recorder->s, 4, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = &tmp_handle, + ); + + if (R_SUCCEEDED(rc)) { + eventLoadRemote(out_event, tmp_handle, 1); + } + + return rc; +} + +Result audrecRecorderAppendFinalOutputRecorderBuffer(AudrecRecorder* recorder, u64 buffer_client_ptr, FinalOutputRecorderBuffer* param) { + const struct { + u64 buffer_client_ptr; + } in = { buffer_client_ptr }; + + if (hosversionAtLeast(3,0,0)) { + return serviceDispatchIn(&recorder->s, 8, in, + .buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In }, + .buffers = { { param, sizeof(*param) } }, + ); + } + else { + return serviceDispatchIn(&recorder->s, 3, in, + .buffer_attrs = { SfBufferAttr_In }, + .buffers = { { param, sizeof(*param) } }, + ); + } +} + +Result audrecRecorderGetReleasedFinalOutputRecorderBuffers(AudrecRecorder* recorder, u64* out_buffers, u64* inout_count, u64* out_released) { + struct { + u32 count; + u32 padding; + u64 released; + } out; + + const struct { + } in; + + Result rc; + + if (hosversionAtLeast(3,0,0)) { + rc = serviceDispatchInOut(&recorder->s, 9, in, out, + .buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out }, + .buffers = { { out_buffers, sizeof(u64) * (*inout_count) } }, + ); + } + else { + rc = serviceDispatchInOut(&recorder->s, 5, in, out, + .buffer_attrs = { SfBufferAttr_Out }, + .buffers = { { out_buffers, sizeof(u64) * (*inout_count) } }, + ); + } + + if (R_SUCCEEDED(rc)) { + *inout_count = out.count; + *out_released = out.released; + } + + return rc; +} + +void audrecRecorderClose(AudrecRecorder* recorder) { + serviceClose(&recorder->s); +}