diff --git a/nx/include/switch/services/audin.h b/nx/include/switch/services/audin.h index a3d52a88..bd54c3ac 100644 --- a/nx/include/switch/services/audin.h +++ b/nx/include/switch/services/audin.h @@ -6,7 +6,9 @@ */ #pragma once +#include "../types.h" #include "../audio/audio.h" +#include "../sf/service.h" typedef enum { AudioInState_Started = 0, @@ -25,10 +27,19 @@ struct AudioInBuffer u64 data_offset; ///< Offset of data inside the buffer. (Unused?) }; +/// Initialize audin. Result audinInitialize(void); + +/// Exit audin. void audinExit(void); -Result audinListAudioIns(char *DeviceNames, u32 *DeviceNamesCount); +/// Gets the Service object for the actual audin service session. +Service* audinGetServiceSession(void); + +/// Gets the Service object for IAudioIn. +Service* audinGetServiceSession_AudioIn(void); + +Result audinListAudioIns(char *DeviceNames, s32 count, u32 *DeviceNamesCount); Result audinOpenAudioIn(const char *DeviceNameIn, char *DeviceNameOut, u32 SampleRateIn, u32 ChannelCountIn, u32 *SampleRateOut, u32 *ChannelCountOut, PcmFormat *Format, AudioInState *State); Result audinGetAudioInState(AudioInState *State); Result audinStartAudioIn(void); diff --git a/nx/source/services/audin.c b/nx/source/services/audin.c index 650adddf..45abfc46 100644 --- a/nx/source/services/audin.c +++ b/nx/source/services/audin.c @@ -1,11 +1,8 @@ -#include -#include "types.h" -#include "result.h" -#include "arm/atomics.h" -#include "kernel/ipc.h" +#define NX_SERVICE_ASSUME_NON_DOMAIN +#include "service_guard.h" #include "kernel/event.h" #include "services/audin.h" -#include "services/sm.h" +#include "runtime/hosversion.h" #define DEVICE_NAME_LENGTH 0x100 #define DEFAULT_SAMPLE_RATE 0xBB80 @@ -13,7 +10,6 @@ static Service g_audinSrv; static Service g_audinIAudioIn; -static u64 g_refCnt; static Event g_audinBufferEvent; @@ -24,19 +20,14 @@ static AudioInState g_deviceState = AudioInState_Stopped; static Result _audinRegisterBufferEvent(Event *BufferEvent); -Result audinInitialize(void) -{ - atomicIncrement64(&g_refCnt); - - if (serviceIsActive(&g_audinSrv)) - return 0; +NX_GENERATE_SERVICE_GUARD(audin); +Result _audinInitialize(void) { Result rc = 0; rc = smGetService(&g_audinSrv, "audin:u"); // Setup the default device - if (R_SUCCEEDED(rc)) - { + if (R_SUCCEEDED(rc)) { // Passing an empty device name will open the default "BuiltInHeadset" char DeviceNameIn[DEVICE_NAME_LENGTH] = {0}; char DeviceNameOut[DEVICE_NAME_LENGTH] = {0}; @@ -49,26 +40,27 @@ Result audinInitialize(void) if (R_SUCCEEDED(rc)) rc = _audinRegisterBufferEvent(&g_audinBufferEvent); - if (R_FAILED(rc)) - audinExit(); - return rc; } -void audinExit(void) -{ - if (atomicDecrement64(&g_refCnt) == 0) - { - eventClose(&g_audinBufferEvent); +void _audinCleanup(void) { + eventClose(&g_audinBufferEvent); - g_sampleRate = 0; - g_channelCount = 0; - g_pcmFormat = PcmFormat_Invalid; - g_deviceState = AudioInState_Stopped; + g_sampleRate = 0; + g_channelCount = 0; + g_pcmFormat = PcmFormat_Invalid; + g_deviceState = AudioInState_Stopped; - serviceClose(&g_audinIAudioIn); - serviceClose(&g_audinSrv); - } + serviceClose(&g_audinIAudioIn); + serviceClose(&g_audinSrv); +} + +Service* audinGetServiceSession(void) { + return &g_audinSrv; +} + +Service* audinGetServiceSession_AudioIn(void) { + return &g_audinIAudioIn; } u32 audinGetSampleRate(void) { @@ -87,12 +79,35 @@ AudioInState audinGetDeviceState(void) { return g_deviceState; } +static Result _audinCmdGetHandle(Service* srv, Handle* handle_out, u32 cmd_id) { + return serviceDispatch(srv, cmd_id, + .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, + .out_handles = handle_out, + ); +} + +static Result _audinCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u32 cmd_id) { + Handle tmp_handle = INVALID_HANDLE; + Result rc = 0; + + rc = _audinCmdGetHandle(srv, &tmp_handle, cmd_id); + if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, autoclear); + return rc; +} + +static Result _audinCmdNoIO(Service* srv, u32 cmd_id) { + return serviceDispatch(srv, cmd_id); +} + +static Result _audinCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) { + return serviceDispatchOut(srv, cmd_id, *out); +} + Result audinWaitCaptureFinish(AudioInBuffer **released, u32* released_count, u64 timeout) { // Wait on the buffer event handle Result rc = eventWait(&g_audinBufferEvent, timeout); - if (R_SUCCEEDED(rc)) - { + if (R_SUCCEEDED(rc)) { // Grab the released buffer rc = audinGetReleasedAudioInBuffer(released, released_count); } @@ -113,341 +128,95 @@ Result audinCaptureBuffer(AudioInBuffer *source, AudioInBuffer **released) { return rc; } -Result audinListAudioIns(char *DeviceNames, u32 *DeviceNamesCount) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - ipcAddRecvBuffer(&c, DeviceNames, DEVICE_NAME_LENGTH, 0); - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 0; - - Result rc = serviceIpcDispatch(&g_audinSrv); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 DeviceNamesCount; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc) && DeviceNamesCount) - *DeviceNamesCount = resp->DeviceNamesCount; - } - - return rc; +Result audinListAudioIns(char *DeviceNames, s32 count, u32 *DeviceNamesCount) { + bool new_cmd = hosversionAtLeast(3,0,0); + return serviceDispatchOut(&g_audinSrv, new_cmd==0 ? 0 : 2, *DeviceNamesCount, + .buffer_attrs = { (new_cmd==0 ? SfBufferAttr_HipcMapAlias : SfBufferAttr_HipcAutoSelect) | SfBufferAttr_Out }, + .buffers = { { DeviceNames, count*DEVICE_NAME_LENGTH } }, + ); } Result audinOpenAudioIn(const char *DeviceNameIn, char *DeviceNameOut, u32 SampleRateIn, u32 ChannelCountIn, u32 *SampleRateOut, u32 *ChannelCountOut, PcmFormat *Format, AudioInState *State) { - IpcCommand c; - ipcInitialize(&c); + bool new_cmd = hosversionAtLeast(3,0,0); - struct { - u64 magic; - u64 cmd_id; + const struct { u32 sample_rate; u32 channel_count; u64 client_pid; - } *raw; + } in = { SampleRateIn, ChannelCountIn, 0 }; - ipcSendPid(&c); - ipcSendHandleCopy(&c, CUR_PROCESS_HANDLE); - ipcAddSendBuffer(&c, DeviceNameIn, DEVICE_NAME_LENGTH, 0); - ipcAddRecvBuffer(&c, DeviceNameOut, DEVICE_NAME_LENGTH, 0); - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 1; - raw->sample_rate = SampleRateIn; - raw->channel_count = ChannelCountIn; - raw->client_pid = 0; - - Result rc = serviceIpcDispatch(&g_audinSrv); + struct { + u32 sample_rate; + u32 channel_count; + u32 pcm_format; + u32 state; + } out; + u32 tmpattr = new_cmd==0 ? SfBufferAttr_HipcMapAlias : SfBufferAttr_HipcAutoSelect; + Result rc = serviceDispatchInOut(&g_audinSrv, new_cmd==0 ? 1 : 3, in, out, + .buffer_attrs = { + tmpattr | SfBufferAttr_In, + tmpattr | SfBufferAttr_Out, + }, + .buffers = { + { DeviceNameIn, DEVICE_NAME_LENGTH }, + { DeviceNameOut, DEVICE_NAME_LENGTH }, + }, + .in_send_pid = true, + .in_num_handles = 1, + .in_handles = { CUR_PROCESS_HANDLE }, + .out_num_objects = 1, + .out_objects = &g_audinIAudioIn, + ); if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 sample_rate; - u32 channel_count; - u32 pcm_format; - u32 state; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - serviceCreate(&g_audinIAudioIn, r.Handles[0]); - - if (SampleRateOut) - *SampleRateOut = resp->sample_rate; - - if (ChannelCountOut) - *ChannelCountOut = resp->channel_count; - - if (Format) - *Format = resp->pcm_format; - - if (State) - *State = resp->state; - } + if (SampleRateOut) *SampleRateOut = out.sample_rate; + if (ChannelCountOut) *ChannelCountOut = out.channel_count; + if (Format) *Format = out.pcm_format; + if (State) *State = out.state; } - return rc; } Result audinGetAudioInState(AudioInState *State) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 0; - - Result rc = serviceIpcDispatch(&g_audinIAudioIn); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 state; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc) && State) - *State = resp->state; - } - + u32 tmp=0; + Result rc = _audinCmdNoInOutU32(&g_audinIAudioIn, &tmp, 0); + if (R_SUCCEEDED(rc) && State) *State = tmp; return rc; } Result audinStartAudioIn(void) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 1; - - Result rc = serviceIpcDispatch(&g_audinIAudioIn); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; + return _audinCmdNoIO(&g_audinIAudioIn, 1); } Result audinStopAudioIn(void) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 2; - - Result rc = serviceIpcDispatch(&g_audinIAudioIn); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; + return _audinCmdNoIO(&g_audinIAudioIn, 2); } Result audinAppendAudioInBuffer(AudioInBuffer *Buffer) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u64 tag; - } *raw; - - ipcAddSendBuffer(&c, Buffer, sizeof(*Buffer), 0); - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 3; - raw->tag = (u64)Buffer; - - Result rc = serviceIpcDispatch(&g_audinIAudioIn); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - } - - return rc; + bool new_cmd = hosversionAtLeast(3,0,0); + u64 tmp = (u64)Buffer; + return serviceDispatchIn(&g_audinIAudioIn, new_cmd==0 ? 3 : 8, tmp, + .buffer_attrs = { (new_cmd==0 ? SfBufferAttr_HipcMapAlias : SfBufferAttr_HipcAutoSelect) | SfBufferAttr_In }, + .buffers = { { Buffer, sizeof(*Buffer) } }, + ); } static Result _audinRegisterBufferEvent(Event *BufferEvent) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 4; - - Result rc = serviceIpcDispatch(&g_audinIAudioIn); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc) && BufferEvent) - eventLoadRemote(BufferEvent, r.Handles[0], true); - } - - return rc; + return _audinCmdGetEvent(&g_audinIAudioIn, BufferEvent, true, 4); } Result audinGetReleasedAudioInBuffer(AudioInBuffer **Buffer, u32 *ReleasedBuffersCount) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - ipcAddRecvBuffer(&c, Buffer, sizeof(*Buffer), 0); - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 5; - - Result rc = serviceIpcDispatch(&g_audinIAudioIn); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 released_buffers_count; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc) && ReleasedBuffersCount) - *ReleasedBuffersCount = resp->released_buffers_count; - } - - return rc; + bool new_cmd = hosversionAtLeast(3,0,0); + return serviceDispatchOut(&g_audinIAudioIn, new_cmd==0 ? 5 : 9, *ReleasedBuffersCount, + .buffer_attrs = { (new_cmd==0 ? SfBufferAttr_HipcMapAlias : SfBufferAttr_HipcAutoSelect) | SfBufferAttr_Out }, + .buffers = { { Buffer, sizeof(*Buffer) } }, + ); } Result audinContainsAudioInBuffer(AudioInBuffer *Buffer, bool *ContainsBuffer) { - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - u64 tag; - } *raw; - - raw = ipcPrepareHeader(&c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 6; - raw->tag = (u64)Buffer; - - Result rc = serviceIpcDispatch(&g_audinIAudioIn); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 contains_buffer; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc) && ContainsBuffer) - *ContainsBuffer = (resp->contains_buffer & 0x01); - } - + u64 tmp = (u64)Buffer; + u8 out=0; + Result rc = serviceDispatchInOut(&g_audinIAudioIn, 6, tmp, out); + if (R_SUCCEEDED(rc) && ContainsBuffer) *ContainsBuffer = out!=0; return rc; }