From 6a8dba4eb4fcb82dca36e19a03434c74c345744b Mon Sep 17 00:00:00 2001 From: yellows8 Date: Tue, 6 Nov 2018 15:10:54 -0500 Subject: [PATCH] Added support for hwopus multistream. Minor adjustments in hwopus.h. --- nx/include/switch/services/hwopus.h | 17 +++- nx/source/services/hwopus.c | 124 ++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/nx/include/switch/services/hwopus.h b/nx/include/switch/services/hwopus.h index 4e6abfa3..fd76ebce 100644 --- a/nx/include/switch/services/hwopus.h +++ b/nx/include/switch/services/hwopus.h @@ -15,15 +15,28 @@ typedef struct { bool multistream; } HwopusDecoder; -///< This structure is the start of opusin for \ref hwopusDecodeInterleaved, with the actual opus packet following this. -///< These fields are big-endian. +/// This structure is the start of opusin for \ref hwopusDecodeInterleaved, with the actual opus packet following this. +/// These fields are big-endian. typedef struct { u32 size; ///< Size of the packet following this header. u32 unk; ///< Unknown, can be left at zero. } HwopusHeader; +/// Used internally. +typedef struct { + s32 SampleRate; + s32 ChannelCount; + s32 TotalStreamCount; + s32 StereoStreamCount; + u8 channel_mapping[256]; +} HwopusMultistreamState; + Result hwopusDecoderInitialize(HwopusDecoder* decoder, s32 SampleRate, s32 ChannelCount); void hwopusDecoderExit(HwopusDecoder* decoder); +/// Only available on 3.0.0+. +/// See libopus multistream docs. +Result hwopusDecoderMultistreamInitialize(HwopusDecoder* decoder, s32 SampleRate, s32 ChannelCount, s32 TotalStreamCount, s32 StereoStreamCount, u8 *channel_mapping); + Result hwopusDecodeInterleaved(HwopusDecoder* decoder, s32 *DecodedDataSize, s32 *DecodedSampleCount, 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 index 88cb9098..c7b2d572 100644 --- a/nx/source/services/hwopus.c +++ b/nx/source/services/hwopus.c @@ -1,3 +1,4 @@ +#include #include "types.h" #include "result.h" #include "arm/atomics.h" @@ -9,6 +10,8 @@ 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); +static Result _hwopusOpenHardwareOpusDecoderForMultiStream(Service* srv, Service* out_srv, TransferMemory *tmem, HwopusMultistreamState *state); +static Result _hwopusGetWorkBufferSizeForMultiStream(Service* srv, u32 *size, HwopusMultistreamState *state); static Result _hwopusDecodeInterleavedWithPerfOld(HwopusDecoder* decoder, s32 *DecodedDataSize, s32 *DecodedSampleCount, u64 *perf, const void* opusin, size_t opusin_size, s16 *pcmbuf, size_t pcmbuf_size); @@ -40,6 +43,49 @@ Result hwopusDecoderInitialize(HwopusDecoder* decoder, s32 SampleRate, s32 Chann return rc; } +Result hwopusDecoderMultistreamInitialize(HwopusDecoder* decoder, s32 SampleRate, s32 ChannelCount, s32 TotalStreamCount, s32 StereoStreamCount, u8 *channel_mapping) { + Result rc=0; + u32 size=0; + HwopusMultistreamState state; + + if (serviceIsActive(&decoder->s)) + return 0; + + if (!kernelAbove300()) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + if (ChannelCount < 0 || ChannelCount > sizeof(state.channel_mapping)) + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + + decoder->multistream = true; + + memset(&state, 0, sizeof(HwopusMultistreamState)); + state.SampleRate = SampleRate; + state.ChannelCount = ChannelCount; + state.TotalStreamCount = TotalStreamCount; + state.StereoStreamCount = StereoStreamCount; + + Service hwopusMgrSrv; + rc = smGetService(&hwopusMgrSrv, "hwopus"); + if (R_SUCCEEDED(rc)) { + rc = _hwopusGetWorkBufferSizeForMultiStream(&hwopusMgrSrv, &size, &state); + if (R_SUCCEEDED(rc)) size = (size + 0xfff) & ~0xfff; + + if (R_SUCCEEDED(rc)) rc = tmemCreate(&decoder->tmem, size, Perm_None); + + if (R_SUCCEEDED(rc)) { + memcpy(state.channel_mapping, channel_mapping, ChannelCount); + + rc = _hwopusOpenHardwareOpusDecoderForMultiStream(&hwopusMgrSrv, &decoder->s, &decoder->tmem, &state); + if (R_FAILED(rc)) tmemClose(&decoder->tmem); + } + + serviceClose(&hwopusMgrSrv); + } + + return rc; +} + void hwopusDecoderExit(HwopusDecoder* decoder) { serviceClose(&decoder->s); tmemClose(&decoder->tmem); @@ -124,6 +170,84 @@ static Result _hwopusGetWorkBufferSize(Service* srv, u32 *size, s32 SampleRate, return rc; } +static Result _hwopusOpenHardwareOpusDecoderForMultiStream(Service* srv, Service* out_srv, TransferMemory *tmem, HwopusMultistreamState *state) { + IpcCommand c; + ipcInitialize(&c); + + ipcSendHandleCopy(&c, tmem->handle); + ipcAddSendStatic(&c, state, sizeof(HwopusMultistreamState), 0); + + struct { + u64 magic; + u64 cmd_id; + u32 size; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 2; + 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 _hwopusGetWorkBufferSizeForMultiStream(Service* srv, u32 *size, HwopusMultistreamState *state) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendStatic(&c, state, sizeof(HwopusMultistreamState), 0); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 3; + + 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 *DecodedDataSize, s32 *DecodedSampleCount, const void* opusin, size_t opusin_size, s16 *pcmbuf, size_t pcmbuf_size) { if (kernelAbove400()) return _hwopusDecodeInterleavedWithPerfOld(decoder, DecodedDataSize, DecodedSampleCount, NULL, opusin, opusin_size, pcmbuf, pcmbuf_size);