From 576302444d35e6015175fa85075e0ad44464c060 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 2 Nov 2018 16:03:36 -0400 Subject: [PATCH] Added auddev and AudioDeviceName. --- nx/include/switch.h | 1 + nx/include/switch/audio/audio.h | 4 + nx/include/switch/services/auddev.h | 17 +++ nx/source/services/auddev.c | 209 ++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 nx/include/switch/services/auddev.h create mode 100644 nx/source/services/auddev.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 6c5d8423..353c83b0 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -47,6 +47,7 @@ extern "C" { #include "switch/services/audin.h" #include "switch/services/audout.h" #include "switch/services/audren.h" +#include "switch/services/auddev.h" #include "switch/services/csrng.h" #include "switch/services/bpc.h" #include "switch/services/psm.h" diff --git a/nx/include/switch/audio/audio.h b/nx/include/switch/audio/audio.h index cbea7cb9..13a65825 100644 --- a/nx/include/switch/audio/audio.h +++ b/nx/include/switch/audio/audio.h @@ -17,3 +17,7 @@ typedef enum { PcmFormat_Float = 5, PcmFormat_Adpcm = 6, } PcmFormat; + +typedef struct { + char name[0x100]; +} AudioDeviceName; diff --git a/nx/include/switch/services/auddev.h b/nx/include/switch/services/auddev.h new file mode 100644 index 00000000..6dccabec --- /dev/null +++ b/nx/include/switch/services/auddev.h @@ -0,0 +1,17 @@ +/** + * @file auddev.h + * @brief Audio device. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once + +#include "../audio/audio.h" + +Result auddevInitialize(void); +void auddevExit(void); + +Result auddevListAudioDeviceName(AudioDeviceName *DeviceNames, s32 max_names, s32 *total_names); +Result auddevSetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float volume); +Result auddevGetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float *volume); + diff --git a/nx/source/services/auddev.c b/nx/source/services/auddev.c new file mode 100644 index 00000000..91290ae6 --- /dev/null +++ b/nx/source/services/auddev.c @@ -0,0 +1,209 @@ +#include +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/event.h" +#include "kernel/detect.h" +#include "services/auddev.h" +#include "services/applet.h" +#include "services/sm.h" + +static Service g_auddevIAudioDevice; +static u64 g_auddevRefCnt; +static size_t g_auddevIpcBufferSize; + +static Result _auddevGetAudioDeviceService(Service* srv, Service* out_srv, u64 aruid); + +Result auddevInitialize(void) { + Result rc=0; + + atomicIncrement64(&g_auddevRefCnt); + + if (serviceIsActive(&g_auddevIAudioDevice)) + return 0; + + u64 aruid = 0; + rc = appletGetAppletResourceUserId(&aruid); + + Service audrenMgrSrv; + rc = smGetService(&audrenMgrSrv, "audren:u"); + if (R_SUCCEEDED(rc)) { + rc = _auddevGetAudioDeviceService(&audrenMgrSrv, &g_auddevIAudioDevice, aruid); + + serviceClose(&audrenMgrSrv); + + if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_auddevIAudioDevice.handle, &g_auddevIpcBufferSize); + } + + if (R_FAILED(rc)) auddevExit(); + + return rc; +} + +void auddevExit(void) { + if (atomicDecrement64(&g_auddevRefCnt) == 0) { + serviceClose(&g_auddevIAudioDevice); + } +} + +static Result _auddevGetAudioDeviceService(Service* srv, Service* out_srv, u64 aruid) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 aruid; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2; + raw->aruid = aruid; + + Result rc = serviceIpcDispatch(srv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(srv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + serviceCreateSubservice(out_srv, srv, &r, 0); + } + } + + return rc; +} + +Result auddevListAudioDeviceName(AudioDeviceName *DeviceNames, s32 max_names, s32 *total_names) { + bool new_cmd = kernelAbove300(); + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + if (!new_cmd) ipcAddRecvBuffer(&c, DeviceNames, sizeof(AudioDeviceName) * max_names, 0); + if (new_cmd) ipcAddRecvSmart(&c, g_auddevIpcBufferSize, DeviceNames, sizeof(AudioDeviceName) * max_names, 0); + + raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = new_cmd==0 ? 0 : 6; + + Result rc = serviceIpcDispatch(&g_auddevIAudioDevice); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + + struct { + u64 magic; + u64 result; + s32 total_names; + } *resp; + + serviceIpcParse(&g_auddevIAudioDevice, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && total_names) *total_names = resp->total_names; + } + + return rc; +} + +Result auddevSetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float volume) { + bool new_cmd = kernelAbove300(); + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + float volume; + } *raw; + + if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), 0); + if (new_cmd) ipcAddSendSmart(&c, g_auddevIpcBufferSize, DeviceName, sizeof(AudioDeviceName), 0); + + raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = new_cmd==0 ? 1 : 7; + raw->volume = volume; + + Result rc = serviceIpcDispatch(&g_auddevIAudioDevice); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_auddevIAudioDevice, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result auddevGetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float *volume) { + bool new_cmd = kernelAbove300(); + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), 0); + if (new_cmd) ipcAddSendSmart(&c, g_auddevIpcBufferSize, DeviceName, sizeof(AudioDeviceName), 0); + + raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = new_cmd==0 ? 2 : 8; + + Result rc = serviceIpcDispatch(&g_auddevIAudioDevice); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + + struct { + u64 magic; + u64 result; + float volume; + } *resp; + + serviceIpcParse(&g_auddevIAudioDevice, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && volume) *volume = resp->volume; + } + + return rc; +}