From 34e99d53c2609a7bd40da94d36c3d6b6215df6da Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sun, 4 Nov 2018 18:39:04 -0500 Subject: [PATCH] Added hwopus. --- nx/include/switch.h | 1 + nx/include/switch/services/hwopus.h | 21 ++++ nx/source/services/hwopus.c | 161 ++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 nx/include/switch/services/hwopus.h create mode 100644 nx/source/services/hwopus.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 1085a573..800551cb 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -48,6 +48,7 @@ extern "C" { #include "switch/services/audout.h" #include "switch/services/audren.h" #include "switch/services/auddev.h" +#include "switch/services/hwopus.h" #include "switch/services/csrng.h" #include "switch/services/bpc.h" #include "switch/services/psm.h" diff --git a/nx/include/switch/services/hwopus.h b/nx/include/switch/services/hwopus.h new file mode 100644 index 00000000..30f4960e --- /dev/null +++ b/nx/include/switch/services/hwopus.h @@ -0,0 +1,21 @@ +/** + * @file hwopus.h + * @brief Hardware Opus audio service. + * @author yellows8 + * @copyright libnx Authors + */ +#pragma once + +#include "../services/sm.h" +#include "../kernel/tmem.h" + +typedef struct { + Service s; + TransferMemory tmem; +} HwopusDecoder; + +Result hwopusDecoderInitialize(HwopusDecoder* decoder, s32 SampleRate, s32 ChannelCount); +void hwopusDecoderExit(HwopusDecoder* decoder); + +Result hwopusDecodeInterleaved(HwopusDecoder* decoder, s32 *DecodedSampleCount, u32 *DecodedDataSize, const void* opusin, size_t opusin_size, s16 *pcmbuf, size_t pcmbuf_size); + diff --git a/nx/source/services/hwopus.c b/nx/source/services/hwopus.c new file mode 100644 index 00000000..78f6b85b --- /dev/null +++ b/nx/source/services/hwopus.c @@ -0,0 +1,161 @@ +#include "types.h" +#include "result.h" +#include "arm/atomics.h" +#include "kernel/ipc.h" +#include "kernel/detect.h" +#include "kernel/tmem.h" +#include "services/hwopus.h" +#include "services/sm.h" + +static Result _hwopusInitialize(Service* srv, Service* out_srv, TransferMemory *tmem, s32 SampleRate, s32 ChannelCount); +static Result _hwopusGetWorkBufferSize(Service* srv, u32 *size, s32 SampleRate, s32 ChannelCount); + +Result hwopusDecoderInitialize(HwopusDecoder* decoder, s32 SampleRate, s32 ChannelCount) { + Result rc=0; + u32 size=0; + + if (serviceIsActive(&decoder->s)) + return 0; + + Service hwopusMgrSrv; + rc = smGetService(&hwopusMgrSrv, "hwopus"); + if (R_SUCCEEDED(rc)) { + rc = _hwopusGetWorkBufferSize(&hwopusMgrSrv, &size, SampleRate, ChannelCount); + if (R_SUCCEEDED(rc)) size = (size + 0xfff) & ~0xfff; + + if (R_SUCCEEDED(rc)) rc = tmemCreate(&decoder->tmem, size, Perm_None); + + if (R_SUCCEEDED(rc)) { + rc = _hwopusInitialize(&hwopusMgrSrv, &decoder->s, &decoder->tmem, SampleRate, ChannelCount); + if (R_FAILED(rc)) tmemClose(&decoder->tmem); + } + + serviceClose(&hwopusMgrSrv); + } + + return rc; +} + +void hwopusDecoderExit(HwopusDecoder* decoder) { + serviceClose(&decoder->s); + tmemClose(&decoder->tmem); +} + +static Result _hwopusInitialize(Service* srv, Service* out_srv, TransferMemory *tmem, s32 SampleRate, s32 ChannelCount) { + IpcCommand c; + ipcInitialize(&c); + + ipcSendHandleCopy(&c, tmem->handle); + + struct { + u64 magic; + u64 cmd_id; + u64 val; + u32 size; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + raw->val = (u64)SampleRate | ((u64)ChannelCount<<32); + raw->size = tmem->size; + + 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; +} + +static Result _hwopusGetWorkBufferSize(Service* srv, u32 *size, s32 SampleRate, s32 ChannelCount) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u64 val; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 1; + raw->val = (u64)SampleRate | ((u64)ChannelCount<<32); + + Result rc = serviceIpcDispatch(srv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u32 size; + } *resp; + + serviceIpcParse(srv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && size) *size = resp->size; + } + + return rc; +} + +Result hwopusDecodeInterleaved(HwopusDecoder* decoder, s32 *DecodedSampleCount, u32 *DecodedDataSize, const void* opusin, size_t opusin_size, s16 *pcmbuf, size_t pcmbuf_size) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendBuffer(&c, opusin, opusin_size, BufferType_Normal); + ipcAddRecvBuffer(&c, pcmbuf, pcmbuf_size, BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&decoder->s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + + Result rc = serviceIpcDispatch(&decoder->s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + s32 DecodedSampleCount; + u32 DecodedDataSize; + } *resp; + + serviceIpcParse(&decoder->s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && DecodedSampleCount) *DecodedSampleCount = resp->DecodedSampleCount; + if (R_SUCCEEDED(rc) && DecodedDataSize) *DecodedDataSize = resp->DecodedDataSize; + } + + return rc; +}