diff --git a/nx/include/switch/services/aud.h b/nx/include/switch/services/aud.h new file mode 100644 index 000000000..b282a6a37 --- /dev/null +++ b/nx/include/switch/services/aud.h @@ -0,0 +1,47 @@ +/** + * @file aud.h + * @brief Only available on [11.0.0+]. + * @note Only one session may be open at once. + * @author TotalJustice + * @copyright libnx Authors + */ + +#pragma once + +#include "../types.h" +#include "../sf/service.h" + +#define AUD_MAX_DELAY (1000000000ULL) + +/// Initialize aud:a. Only available on [11.0.0+]. +Result audaInitialize(void); + +/// Exit aud:a. +void audaExit(void); + +/// Initialize aud:d. Only available on [11.0.0+]. +Result auddInitialize(void); + +/// Exit aud:d. +void auddExit(void); + +/// Gets the Service for aud:a. +Service* audaGetServiceSession(void); + +/// Gets the Service for aud:d. +Service* auddGetServiceSession(void); + +Result audaRequestSuspendAudio(u64 pid, u64 delay); +Result audaRequestResumeAudio(u64 pid, u64 delay); +Result audaGetAudioOutputProcessMasterVolume(u64 pid, float* volume_out); + +Result audaSetAudioOutputProcessMasterVolume(u64 pid, u64 delay, float volume); +Result audaGetAudioInputProcessMasterVolume(u64 pid, float* volume_out); + +// Sets both Output and Input volume +Result audaSetAudioInputProcessMasterVolume(u64 pid, u64 delay, float volume); +Result audaGetAudioOutputProcessRecordVolume(u64 pid, float* volume_out); +Result audaSetAudioOutputProcessRecordVolume(u64 pid, u64 delay, float volume); + +Result auddRequestSuspendAudioForDebug(u64 pid, u64 delay); +Result auddRequestResumeAudioForDebug(u64 pid, u64 delay); diff --git a/nx/include/switch/services/audout.h b/nx/include/switch/services/audout.h index 8a49a9b2b..c996066ff 100644 --- a/nx/include/switch/services/audout.h +++ b/nx/include/switch/services/audout.h @@ -10,6 +10,8 @@ #include "../audio/audio.h" #include "../sf/service.h" +#define AUDOUT_MAX_DELAY (1000000000ULL) + typedef enum { AudioOutState_Started = 0, AudioOutState_Stopped = 1, @@ -33,12 +35,30 @@ Result audoutInitialize(void); /// Exit audout. void audoutExit(void); +/// Initialize audout:a. Removed in [11.0.0]. +Result audoutaInitialize(void); + +/// Exit audout:a. +void audoutaExit(void); + +/// Initialize audout:d. Removed in [11.0.0]. +Result audoutdInitialize(void); + +/// Exit audout:d. +void audoutdExit(void); + /// Gets the Service object for the actual audout service session. Service* audoutGetServiceSession(void); /// Gets the Service object for IAudioOut. Service* audoutGetServiceSession_AudioOut(void); +/// Gets the Service for audout:a. +Service* audoutaGetServiceSession(void); + +/// Gets the Service for audout:d. +Service* audoutdGetServiceSession(void); + Result audoutListAudioOuts(char *DeviceNames, s32 count, u32 *DeviceNamesCount); Result audoutOpenAudioOut(const char *DeviceNameIn, char *DeviceNameOut, u32 SampleRateIn, u32 ChannelCountIn, u32 *SampleRateOut, u32 *ChannelCountOut, PcmFormat *Format, AudioOutState *State); Result audoutGetAudioOutState(AudioOutState *State); @@ -83,3 +103,15 @@ u32 audoutGetSampleRate(void); ///< Supported sample rate ( u32 audoutGetChannelCount(void); ///< Supported channel count (2 channels). PcmFormat audoutGetPcmFormat(void); ///< Supported PCM format (Int16). AudioOutState audoutGetDeviceState(void); ///< Initial device state (stopped). + +Result audoutaRequestSuspendOld(u64 pid, u64 delay, Handle* handle_out); // [1.0.0] - [4.0.0] +Result audoutaRequestResumeOld(u64 pid, u64 delay, Handle* handle_out); // [1.0.0] - [4.0.0] +Result audoutaRequestSuspend(u64 pid, u64 delay); // [4.0.0]+ +Result audoutaRequestResume(u64 pid, u64 delay); // [4.0.0]+ +Result audoutaGetProcessMasterVolume(u64 pid, float* volume_out); +Result audoutaSetProcessMasterVolume(u64 pid, u64 delay, float volume); +Result audoutaGetProcessRecordVolume(u64 pid, float* volume_out); +Result audoutaSetProcessRecordVolume(u64 pid, u64 delay, float volume); + +Result audoutdRequestSuspendForDebug(u64 pid, u64 delay); +Result audoutdRequestResumeForDebug(u64 pid, u64 delay); diff --git a/nx/source/services/aud.c b/nx/source/services/aud.c new file mode 100644 index 000000000..018091337 --- /dev/null +++ b/nx/source/services/aud.c @@ -0,0 +1,115 @@ +#define NX_SERVICE_ASSUME_NON_DOMAIN +#include "service_guard.h" +#include "services/aud.h" +#include "runtime/hosversion.h" + +static Service g_audaSrv; +static Service g_auddSrv; + +NX_GENERATE_SERVICE_GUARD(auda); +NX_GENERATE_SERVICE_GUARD(audd); + +Result _audaInitialize(void) { + if (hosversionBefore(11,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return smGetService(&g_audaSrv, "aud:a"); +} + +void _audaCleanup(void) { + serviceClose(&g_audaSrv); +} + +Result _auddInitialize(void) { + return smGetService(&g_auddSrv, "aud:d"); +} + +void _auddCleanup(void) { + serviceClose(&g_auddSrv); +} + +Service* audaGetServiceSession(void) { + return &g_audaSrv; +} + +Service* auddGetServiceSession(void) { + return &g_auddSrv; +} + +Result audaRequestSuspendAudio(u64 pid, u64 delay) { + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchIn(&g_audaSrv, 2, in); +} + +Result audaRequestResumeAudio(u64 pid, u64 delay) { + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchIn(&g_audaSrv, 3, in); +} + +Result audaGetAudioOutputProcessMasterVolume(u64 pid, float* volume_out) { + return serviceDispatchInOut(&g_audaSrv, 4, pid, *volume_out); +} + +Result audaSetAudioOutputProcessMasterVolume(u64 pid, u64 delay, float volume) { + const struct { + float volume; + u64 pid; + u64 delay; + } in = { volume, pid, delay }; + + return serviceDispatchIn(&g_audaSrv, 5, in); +} + +Result audaGetAudioInputProcessMasterVolume(u64 pid, float* volume_out) { + return serviceDispatchInOut(&g_audaSrv, 6, pid, *volume_out); +} + +Result audaSetAudioInputProcessMasterVolume(u64 pid, u64 delay, float volume) { + const struct { + float volume; + u64 pid; + u64 delay; + } in = { volume, pid, delay }; + + return serviceDispatchIn(&g_audaSrv, 7, in); +} + +Result audaGetAudioOutputProcessRecordVolume(u64 pid, float* volume_out) { + return serviceDispatchInOut(&g_audaSrv, 8, pid, *volume_out); +} + +Result audaSetAudioOutputProcessRecordVolume(u64 pid, u64 delay, float volume) { + const struct { + float volume; + u64 pid; + u64 delay; + } in = { volume, pid, delay }; + + return serviceDispatchIn(&g_audaSrv, 9, in); +} + +Result auddRequestSuspendAudioForDebug(u64 pid, u64 delay) { + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchIn(&g_auddSrv, 0, in); +} + +Result auddRequestResumeAudioForDebug(u64 pid, u64 delay) { + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchIn(&g_auddSrv, 1, in); +} diff --git a/nx/source/services/audout.c b/nx/source/services/audout.c index c1d6ac8c3..5f685fccd 100644 --- a/nx/source/services/audout.c +++ b/nx/source/services/audout.c @@ -11,6 +11,8 @@ static Service g_audoutSrv; static Service g_audoutIAudioOut; +static Service g_audoutaSrv; +static Service g_audoutdSrv; static Event g_audoutBufferEvent; @@ -22,6 +24,8 @@ static AudioOutState g_deviceState = AudioOutState_Stopped; static Result _audoutRegisterBufferEvent(Event *BufferEvent); NX_GENERATE_SERVICE_GUARD(audout); +NX_GENERATE_SERVICE_GUARD(audouta); +NX_GENERATE_SERVICE_GUARD(audoutd); Result _audoutInitialize(void) { Result rc = 0; @@ -56,6 +60,28 @@ void _audoutCleanup(void) { serviceClose(&g_audoutSrv); } +Result _audoutaInitialize(void) { + if (hosversionAtLeast(11,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return smGetService(&g_audoutaSrv, "audout:a"); +} + +void _audoutaCleanup(void) { + serviceClose(&g_audoutaSrv); +} + +Result _audoutdInitialize(void) { + if (hosversionAtLeast(11,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return smGetService(&g_audoutdSrv, "audout:d"); +} + +void _audoutdCleanup(void) { + serviceClose(&g_audoutdSrv); +} + Service* audoutGetServiceSession(void) { return &g_audoutSrv; } @@ -64,6 +90,14 @@ Service* audoutGetServiceSession_AudioOut(void) { return &g_audoutIAudioOut; } +Service* audoutaGetServiceSession(void) { + return &g_audoutaSrv; +} + +Service* audoutdGetServiceSession(void) { + return &g_audoutdSrv; +} + u32 audoutGetSampleRate(void) { return g_sampleRate; } @@ -259,3 +293,103 @@ Result audoutGetAudioOutVolume(float *volume) { return serviceDispatchOut(&g_audoutIAudioOut, 13, *volume); } + +Result audoutaRequestSuspendOld(u64 pid, u64 delay, Handle* handle_out) { + if (hosversionAtLeast(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchInOut(&g_audoutaSrv, 0, in, *handle_out); +} + +Result audoutaRequestResumeOld(u64 pid, u64 delay, Handle* handle_out) { + if (hosversionAtLeast(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchInOut(&g_audoutaSrv, 1, in, *handle_out); +} + +Result audoutaRequestSuspend(u64 pid, u64 delay) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchIn(&g_audoutaSrv, 0, in); +} + +Result audoutaRequestResume(u64 pid, u64 delay) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchIn(&g_audoutaSrv, 1, in); +} + +Result audoutaGetProcessMasterVolume(u64 pid, float* volume_out) { + return serviceDispatchInOut(&g_audoutaSrv, 2, pid, *volume_out); +} + +Result audoutaSetProcessMasterVolume(u64 pid, u64 delay, float volume) { + const struct { + float volume; + u64 pid; + u64 delay; + } in = { volume, pid, delay }; + + return serviceDispatchIn(&g_audoutaSrv, 3, in); +} + +Result audoutaGetProcessRecordVolume(u64 pid, float* volume_out) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return serviceDispatchInOut(&g_audoutaSrv, 4, pid, *volume_out); +} + +Result audoutaSetProcessRecordVolume(u64 pid, u64 delay, float volume) { + if (hosversionBefore(4,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + const struct { + float volume; + u64 pid; + u64 delay; + } in = { volume, pid, delay }; + + return serviceDispatchIn(&g_audoutaSrv, 5, in); +} + +Result audoutdRequestSuspendForDebug(u64 pid, u64 delay) { + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchIn(&g_audoutdSrv, 0, in); +} + +Result audoutdRequestResumeForDebug(u64 pid, u64 delay) { + const struct { + u64 pid; + u64 delay; + } in = { pid, delay }; + + return serviceDispatchIn(&g_audoutdSrv, 1, in); +}