mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 20:42:44 +02:00
Add audren:u IPC service wrapper with structure definitions
This commit is contained in:
parent
80439a186b
commit
6fbf25fb62
@ -44,6 +44,7 @@ extern "C" {
|
||||
#include "switch/services/applet.h"
|
||||
#include "switch/services/audin.h"
|
||||
#include "switch/services/audout.h"
|
||||
#include "switch/services/audren.h"
|
||||
#include "switch/services/csrng.h"
|
||||
#include "switch/services/bpc.h"
|
||||
//#include "switch/services/bsd.h" Use switch/runtime/devices/socket.h instead
|
||||
|
327
nx/include/switch/services/audren.h
Normal file
327
nx/include/switch/services/audren.h
Normal file
@ -0,0 +1,327 @@
|
||||
/**
|
||||
* @file audren.h
|
||||
* @brief Audio renderer service.
|
||||
* @author fincs
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../audio/audio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define AUDREN_CONSTEXPR constexpr
|
||||
#else
|
||||
#define AUDREN_CONSTEXPR static inline
|
||||
#endif
|
||||
|
||||
#define AUDREN_TIMER_FREQ_HZ 200.0f
|
||||
#define AUDREN_TIMER_PERIOD_MS 5.0f
|
||||
#define AUDREN_SAMPLES_PER_FRAME_32KHZ 160
|
||||
#define AUDREN_SAMPLES_PER_FRAME_48KHZ 240
|
||||
|
||||
#define AUDREN_INPUT_PARAM_ALIGNMENT 0x1000
|
||||
#define AUDREN_OUTPUT_PARAM_ALIGNMENT 0x10
|
||||
#define AUDREN_MEMPOOL_ALIGNMENT 0x1000
|
||||
#define AUDREN_BUFFER_ALIGNMENT 0x40
|
||||
|
||||
#define AUDREN_REVISION_1 0x31564552 // REV1 [1.0.0+?]
|
||||
#define AUDREN_REVISION_2 0x32564552 // REV2 [2.0.0+?]
|
||||
#define AUDREN_REVISION_3 0x33564552 // REV3 [3.0.0+?]
|
||||
#define AUDREN_REVISION_4 0x34564552 // REV4 [somewhere after 3.0.0, possibly 4.0.0+?]
|
||||
|
||||
#define AUDREN_NODEID(_a,_b,_c) ((((u32)(_a) & 0xF) << 28) | (((u32)(_b) & 0xFFF) << 16) | ((u32)(_c) & 0xFFFF))
|
||||
#define AUDREN_FINAL_MIX_ID 0
|
||||
#define AUDREN_UNUSED_MIX_ID 0x7FFFFFFF
|
||||
#define AUDREN_UNUSED_SPLITTER_ID 0xFFFFFFFF
|
||||
|
||||
#define AUDREN_DEFAULT_DEVICE_NAME "MainAudioOut"
|
||||
|
||||
typedef enum {
|
||||
AudioRendererOutputRate_32kHz,
|
||||
AudioRendererOutputRate_48kHz,
|
||||
} AudioRendererOutputRate;
|
||||
|
||||
typedef struct {
|
||||
AudioRendererOutputRate output_rate;
|
||||
int num_voices;
|
||||
int num_effects;
|
||||
int num_sinks;
|
||||
int num_mix_objs;
|
||||
int num_mix_buffers;
|
||||
} AudioRendererConfig;
|
||||
|
||||
/*
|
||||
Input buffer layout:
|
||||
|
||||
AudioRendererUpdateDataHeader
|
||||
AudioRendererBehaviorInfoIn
|
||||
AudioRendererMemPoolInfoIn * mempool_count
|
||||
AudioRendererChannelInfoIn * channel_count
|
||||
AudioRendererVoiceInfoIn * voice_count
|
||||
(effects would go here)
|
||||
(splitters would go here)
|
||||
AudioRendererMixInfoIn * mix_count (i.e. submix_count+1)
|
||||
AudioRendererSinkInfoIn * sink_count
|
||||
AudioRendererPerformanceBufferInfoIn
|
||||
*/
|
||||
|
||||
/*
|
||||
Output buffer layout:
|
||||
|
||||
AudioRendererUpdateDataHeader
|
||||
AudioRendererMemPoolInfoOut * mempool_count
|
||||
AudioRendererVoiceInfoOut * voice_count
|
||||
(effects would go here)
|
||||
AudioRendererSinkInfoOut * sink_count
|
||||
AudioRendererPerformanceBufferInfoOut
|
||||
AudioRendererBehaviorInfoOut
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u32 revision;
|
||||
u32 behavior_sz;
|
||||
u32 mempools_sz;
|
||||
u32 voices_sz;
|
||||
u32 channels_sz;
|
||||
u32 effects_sz;
|
||||
u32 mixes_sz;
|
||||
u32 sinks_sz;
|
||||
u32 perfmgr_sz;
|
||||
u32 _padding[6];
|
||||
u32 total_sz;
|
||||
} AudioRendererUpdateDataHeader;
|
||||
|
||||
typedef struct {
|
||||
u32 revision;
|
||||
u32 _padding1;
|
||||
u64 flags;
|
||||
} AudioRendererBehaviorInfoIn;
|
||||
|
||||
typedef struct {
|
||||
u64 unknown[20];
|
||||
u64 _padding1[2];
|
||||
} AudioRendererBehaviorInfoOut;
|
||||
|
||||
typedef enum {
|
||||
AudioRendererMemPoolState_Invalid,
|
||||
AudioRendererMemPoolState_New,
|
||||
AudioRendererMemPoolState_RequestDetach,
|
||||
AudioRendererMemPoolState_Detached,
|
||||
AudioRendererMemPoolState_RequestAttach,
|
||||
AudioRendererMemPoolState_Attached,
|
||||
AudioRendererMemPoolState_Released,
|
||||
} AudioRendererMemPoolState;
|
||||
|
||||
typedef struct {
|
||||
const void* address;
|
||||
u64 size;
|
||||
AudioRendererMemPoolState state;
|
||||
u32 _padding2[3];
|
||||
} AudioRendererMemPoolInfoIn;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AudioRendererMemPoolState new_state;
|
||||
u32 _padding2[3];
|
||||
} AudioRendererMemPoolInfoOut;
|
||||
|
||||
typedef struct {
|
||||
u32 id;
|
||||
float mix[24];
|
||||
bool is_used;
|
||||
u8 _padding1[11];
|
||||
} AudioRendererChannelInfoIn;
|
||||
|
||||
typedef struct {
|
||||
bool enable;
|
||||
u8 _padding;
|
||||
s16 numerator[3];
|
||||
s16 denominator[2];
|
||||
} AudioRendererBiquadFilter;
|
||||
|
||||
typedef struct {
|
||||
u16 coefficients[16];
|
||||
} AudioRendererAdpcmParameters;
|
||||
|
||||
typedef struct {
|
||||
u16 index;
|
||||
s16 history0;
|
||||
s16 history1;
|
||||
} AudioRendererAdpcmContext;
|
||||
|
||||
typedef struct {
|
||||
const void* address;
|
||||
u64 size;
|
||||
s32 start_sample_offset;
|
||||
s32 end_sample_offset;
|
||||
bool is_looping;
|
||||
bool end_of_stream;
|
||||
bool sent_to_server;
|
||||
u8 _padding1[5];
|
||||
const void* context_addr;
|
||||
u64 context_sz;
|
||||
u64 _padding2;
|
||||
} AudioRendererWaveBuf;
|
||||
|
||||
typedef enum {
|
||||
AudioRendererVoicePlayState_Started,
|
||||
AudioRendererVoicePlayState_Stopped,
|
||||
AudioRendererVoicePlayState_Paused,
|
||||
} AudioRendererVoicePlayState;
|
||||
|
||||
typedef struct {
|
||||
u32 id;
|
||||
u32 node_id;
|
||||
bool is_new;
|
||||
bool is_used;
|
||||
AudioRendererVoicePlayState state : 8;
|
||||
PcmFormat sample_format : 8;
|
||||
u32 sample_rate;
|
||||
u32 priority;
|
||||
u32 sorting_order;
|
||||
u32 channel_count;
|
||||
float pitch;
|
||||
float volume;
|
||||
AudioRendererBiquadFilter biquads[2];
|
||||
u32 wavebuf_count;
|
||||
s16 wavebuf_head;
|
||||
u16 _padding1;
|
||||
u32 _padding2;
|
||||
const void* extra_params_ptr;
|
||||
u64 extra_params_sz;
|
||||
u32 dest_mix_id;
|
||||
u32 dest_splitter_id;
|
||||
AudioRendererWaveBuf wavebufs[4];
|
||||
u32 channel_ids[6];
|
||||
u8 _padding3[24];
|
||||
} AudioRendererVoiceInfoIn;
|
||||
|
||||
typedef struct {
|
||||
u64 played_sample_count;
|
||||
u32 num_wavebufs_consumed;
|
||||
u32 voice_drops_count;
|
||||
} AudioRendererVoiceInfoOut;
|
||||
|
||||
typedef struct {
|
||||
float volume;
|
||||
u32 sample_rate;
|
||||
u32 buffer_count;
|
||||
bool is_used;
|
||||
u8 _padding1[3];
|
||||
u32 mix_id;
|
||||
u32 _padding2;
|
||||
u32 node_id;
|
||||
u32 _padding3[2];
|
||||
float mix[24][24]; // [src_index][dest_index]
|
||||
u32 dest_mix_id;
|
||||
u32 dest_splitter_id;
|
||||
u32 _padding4;
|
||||
} AudioRendererMixInfoIn;
|
||||
|
||||
typedef struct {
|
||||
u8 coefficients[16];
|
||||
} AudioRendererDownMixParameters;
|
||||
|
||||
typedef enum {
|
||||
AudioRendererSinkType_Invalid,
|
||||
AudioRendererSinkType_Device,
|
||||
AudioRendererSinkType_CircularBuffer,
|
||||
} AudioRendererSinkType;
|
||||
|
||||
typedef struct {
|
||||
char name[255];
|
||||
u8 _padding1;
|
||||
u32 input_count;
|
||||
u8 inputs[6];
|
||||
u8 _padding2;
|
||||
bool downmix_params_enabled;
|
||||
AudioRendererDownMixParameters downmix_params;
|
||||
} AudioRendererDeviceSinkInfoIn;
|
||||
|
||||
typedef struct {
|
||||
void* buffer_ptr;
|
||||
u32 buffer_sz;
|
||||
u32 input_count;
|
||||
u32 sample_count;
|
||||
u32 last_read_offset;
|
||||
PcmFormat sample_format;
|
||||
u8 inputs[6];
|
||||
u8 _padding2[6];
|
||||
} AudioRendererCircularBufferSinkInfoIn;
|
||||
|
||||
typedef struct {
|
||||
AudioRendererSinkType type : 8;
|
||||
bool is_used;
|
||||
u8 _padding1[2];
|
||||
u32 node_id;
|
||||
u64 _padding2[3];
|
||||
union {
|
||||
AudioRendererDeviceSinkInfoIn device_sink;
|
||||
AudioRendererCircularBufferSinkInfoIn circular_buffer_sink;
|
||||
};
|
||||
} AudioRendererSinkInfoIn;
|
||||
|
||||
typedef struct {
|
||||
u32 last_written_offset;
|
||||
u32 unk1;
|
||||
u64 unk2;
|
||||
u64 _padding1[2];
|
||||
} AudioRendererSinkInfoOut;
|
||||
|
||||
typedef struct {
|
||||
u32 detail_target;
|
||||
u32 _padding1[3];
|
||||
} AudioRendererPerformanceBufferInfoIn;
|
||||
|
||||
typedef struct {
|
||||
u32 written_sz;
|
||||
u32 _padding1[3];
|
||||
} AudioRendererPerformanceBufferInfoOut;
|
||||
|
||||
static inline u32 audrenGetRevision(void)
|
||||
{
|
||||
extern u32 g_audrenRevision;
|
||||
return g_audrenRevision;
|
||||
}
|
||||
|
||||
AUDREN_CONSTEXPR int audrenGetMemPoolCount(const AudioRendererConfig* config)
|
||||
{
|
||||
return config->num_effects + 4 * config->num_voices;
|
||||
}
|
||||
|
||||
AUDREN_CONSTEXPR size_t audrenGetInputParamSize(const AudioRendererConfig* config)
|
||||
{
|
||||
size_t size = 0;
|
||||
size += sizeof(AudioRendererUpdateDataHeader);
|
||||
size += sizeof(AudioRendererBehaviorInfoIn);
|
||||
size += sizeof(AudioRendererMemPoolInfoIn) * audrenGetMemPoolCount(config);
|
||||
size += sizeof(AudioRendererChannelInfoIn) * config->num_voices;
|
||||
size += sizeof(AudioRendererVoiceInfoIn) * config->num_voices;
|
||||
// todo: effects, splitters
|
||||
size += sizeof(AudioRendererMixInfoIn) * config->num_mix_objs;
|
||||
size += sizeof(AudioRendererSinkInfoIn) * config->num_sinks;
|
||||
size += sizeof(AudioRendererPerformanceBufferInfoIn);
|
||||
return size;
|
||||
}
|
||||
|
||||
AUDREN_CONSTEXPR size_t audrenGetOutputParamSize(const AudioRendererConfig* config)
|
||||
{
|
||||
size_t size = 0;
|
||||
size += sizeof(AudioRendererUpdateDataHeader);
|
||||
size += sizeof(AudioRendererMemPoolInfoOut) * audrenGetMemPoolCount(config);
|
||||
size += sizeof(AudioRendererVoiceInfoOut) * config->num_voices;
|
||||
// todo: effects
|
||||
size += sizeof(AudioRendererSinkInfoOut) * config->num_sinks;
|
||||
size += sizeof(AudioRendererPerformanceBufferInfoOut);
|
||||
size += sizeof(AudioRendererBehaviorInfoOut);
|
||||
return size;
|
||||
}
|
||||
|
||||
Result audrenInitialize(const AudioRendererConfig* config);
|
||||
void audrenExit(void);
|
||||
void audrenWaitFrame(void);
|
||||
Result audrenGetState(u32* out_state);
|
||||
Result audrenRequestUpdateAudioRenderer(const void* in_param_buf, size_t in_param_buf_size, void* out_param_buf, size_t out_param_buf_size, void* perf_buf, size_t perf_buf_size);
|
||||
Result audrenStartAudioRenderer(void);
|
||||
Result audrenStopAudioRenderer(void);
|
||||
Result audrenSetAudioRendererRenderingTimeLimit(int percent);
|
414
nx/source/services/audren.c
Normal file
414
nx/source/services/audren.c
Normal file
@ -0,0 +1,414 @@
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "arm/atomics.h"
|
||||
#include "kernel/ipc.h"
|
||||
#include "kernel/tmem.h"
|
||||
#include "kernel/event.h"
|
||||
#include "services/sm.h"
|
||||
#include "services/applet.h"
|
||||
#include "services/audren.h"
|
||||
|
||||
u32 g_audrenRevision;
|
||||
|
||||
static Service g_audrenIAudioRenderer;
|
||||
static TransferMemory g_audrenWorkBuf;
|
||||
static Event g_audrenEvent;
|
||||
|
||||
typedef struct {
|
||||
s32 sample_rate;
|
||||
s32 sample_count;
|
||||
s32 mix_buffer_count;
|
||||
s32 submix_count;
|
||||
s32 voice_count;
|
||||
s32 sink_count;
|
||||
s32 effect_count;
|
||||
s32 unk1;
|
||||
u8 unk2;
|
||||
u8 _padding1[3];
|
||||
s32 splitter_count;
|
||||
s32 unk3;
|
||||
s32 unk4;
|
||||
u32 revision;
|
||||
} AudioRendererParameter;
|
||||
|
||||
static Result _audrenOpenAudioRenderer(Service* audren_mgr, const AudioRendererParameter* param, u64 aruid);
|
||||
static Result _audrenGetWorkBufferSize(Service* audren_mgr, const AudioRendererParameter* param, u64* out_size);
|
||||
static Result _audrenQuerySystemEvent(void);
|
||||
|
||||
Result audrenInitialize(const AudioRendererConfig* config)
|
||||
{
|
||||
Result rc;
|
||||
if (serviceIsActive(&g_audrenIAudioRenderer))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
||||
|
||||
// Validate configuration
|
||||
if (config->num_voices < 1 || config->num_voices > 1024)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
if (config->num_effects < 0 || config->num_effects > 256)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
if (config->num_sinks < 1 || config->num_sinks > 256)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
if (config->num_mix_objs < 1 || config->num_mix_objs > 256)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
if (config->num_mix_buffers < 1 || config->num_mix_buffers > 256)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||
|
||||
// Choose revision (i.e. if splitters are used then at least revision 2 must be used)
|
||||
// (TODO: abstract away differences between revisions according to provided parameters)
|
||||
g_audrenRevision = AUDREN_REVISION_3; // todo: ?!?
|
||||
|
||||
// Prepare parameter structure
|
||||
AudioRendererParameter param = {0};
|
||||
param.sample_rate = config->output_rate == AudioRendererOutputRate_32kHz ? 32000 : 48000;
|
||||
param.sample_count = config->output_rate == AudioRendererOutputRate_32kHz ? AUDREN_SAMPLES_PER_FRAME_32KHZ : AUDREN_SAMPLES_PER_FRAME_48KHZ;
|
||||
param.mix_buffer_count = config->num_mix_buffers;
|
||||
param.submix_count = config->num_mix_objs - 1;
|
||||
param.voice_count = config->num_voices;
|
||||
param.sink_count = config->num_sinks;
|
||||
param.effect_count = config->num_effects;
|
||||
param.revision = g_audrenRevision;
|
||||
|
||||
// Get aruid
|
||||
u64 aruid = 0;
|
||||
rc = appletGetAppletResourceUserId(&aruid);
|
||||
//if (R_FAILED(rc)) return rc; // apparently audren still inits fine with aruid = 0 so this isn't a fatal error condition
|
||||
|
||||
// Open IAudioRendererManager
|
||||
Service audrenMgrSrv;
|
||||
rc = smGetService(&audrenMgrSrv, "audren:u");
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
// Get required work buffer size
|
||||
size_t workBufSize = 0;
|
||||
rc = _audrenGetWorkBufferSize(&audrenMgrSrv, ¶m, &workBufSize);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
// Create transfermem work buffer object
|
||||
workBufSize = (workBufSize + 0xFFF) &~ 0xFFF; // 1.x fails hard and returns a non-page-aligned work buffer size
|
||||
rc = tmemCreate(&g_audrenWorkBuf, workBufSize, Perm_None);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
// Create the IAudioRenderer service
|
||||
rc = _audrenOpenAudioRenderer(&audrenMgrSrv, ¶m, aruid);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
// Finally, get the handle to the system event
|
||||
rc = _audrenQuerySystemEvent();
|
||||
if (R_FAILED(rc))
|
||||
serviceClose(&g_audrenIAudioRenderer);
|
||||
}
|
||||
if (R_FAILED(rc))
|
||||
tmemClose(&g_audrenWorkBuf);
|
||||
}
|
||||
}
|
||||
serviceClose(&audrenMgrSrv);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void audrenExit(void)
|
||||
{
|
||||
if (!serviceIsActive(&g_audrenIAudioRenderer))
|
||||
return;
|
||||
|
||||
eventClose(&g_audrenEvent);
|
||||
serviceClose(&g_audrenIAudioRenderer);
|
||||
tmemClose(&g_audrenWorkBuf);
|
||||
}
|
||||
|
||||
void audrenWaitFrame(void)
|
||||
{
|
||||
eventWait(&g_audrenEvent, U64_MAX);
|
||||
eventClear(&g_audrenEvent);
|
||||
}
|
||||
|
||||
Result _audrenOpenAudioRenderer(Service* audren_mgr, const AudioRendererParameter* param, u64 aruid)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
|
||||
AudioRendererParameter param;
|
||||
u64 work_buffer_size;
|
||||
u64 aruid;
|
||||
} *raw;
|
||||
|
||||
ipcSendPid(&c);
|
||||
ipcSendHandleCopy(&c, g_audrenWorkBuf.handle);
|
||||
ipcSendHandleCopy(&c, CUR_PROCESS_HANDLE);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->param = *param;
|
||||
raw->work_buffer_size = g_audrenWorkBuf.size;
|
||||
raw->aruid = aruid;
|
||||
|
||||
Result rc = serviceIpcDispatch(audren_mgr);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
serviceCreate(&g_audrenIAudioRenderer, r.Handles[0]);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result _audrenGetWorkBufferSize(Service* audren_mgr, const AudioRendererParameter* param, size_t* out_size)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
|
||||
AudioRendererParameter param;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
raw->param = *param;
|
||||
|
||||
Result rc = serviceIpcDispatch(audren_mgr);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u64 work_buf_size;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc) && out_size)
|
||||
*out_size = resp->work_buf_size;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result audrenGetState(u32* out_state)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 3;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_audrenIAudioRenderer);
|
||||
|
||||
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) && out_state)
|
||||
*out_state = resp->state;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result audrenRequestUpdateAudioRenderer(const void* in_param_buf, size_t in_param_buf_size, void* out_param_buf, size_t out_param_buf_size, void* perf_buf, size_t perf_buf_size)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
ipcAddSendBuffer(&c, in_param_buf, in_param_buf_size, BufferType_Normal);
|
||||
ipcAddRecvBuffer(&c, out_param_buf, out_param_buf_size, BufferType_Normal);
|
||||
ipcAddRecvBuffer(&c, perf_buf, perf_buf_size, BufferType_Normal);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 4;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_audrenIAudioRenderer);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result audrenStartAudioRenderer(void)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 5;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_audrenIAudioRenderer);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result audrenStopAudioRenderer(void)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 6;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_audrenIAudioRenderer);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result _audrenQuerySystemEvent(void)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 7;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_audrenIAudioRenderer);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
eventLoadRemote(&g_audrenEvent, r.Handles[0]);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result audrenSetAudioRendererRenderingTimeLimit(int percent)
|
||||
{
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
int percent;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 8;
|
||||
raw->percent = percent;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_audrenIAudioRenderer);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
Loading…
Reference in New Issue
Block a user