Refactor audio backend and services

Use the new service naming convention.
Move both audout and audren into one directory.
Close the audio stream upon emulator exit.
This commit is contained in:
Billy Laws 2020-02-17 19:11:59 +00:00 committed by ◱ PixelyIon
parent 2e0ac9bdd5
commit 52d47120a8
21 changed files with 174 additions and 160 deletions

View File

@ -52,11 +52,12 @@ add_library(skyline SHARED
${source_DIR}/skyline/services/serviceman.cpp
${source_DIR}/skyline/services/sm/IUserInterface.cpp
${source_DIR}/skyline/services/fatalsrv/IService.cpp
${source_DIR}/skyline/services/audout/audout.cpp
${source_DIR}/skyline/services/audren/IAudioRendererManager.cpp
${source_DIR}/skyline/services/audren/IAudioRenderer.cpp
${source_DIR}/skyline/services/audren/voice.cpp
${source_DIR}/skyline/services/audren/memoryPool.cpp
${source_DIR}/skyline/services/audio/IAudioOutManager.cpp
${source_DIR}/skyline/services/audio/IAudioOut.cpp
${source_DIR}/skyline/services/audio/IAudioRendererManager.cpp
${source_DIR}/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp
${source_DIR}/skyline/services/audio/IAudioRenderer/voice.cpp
${source_DIR}/skyline/services/audio/IAudioRenderer/memoryPool.cpp
${source_DIR}/skyline/services/settings/ISystemSettingsServer.cpp
${source_DIR}/skyline/services/apm/apm.cpp
${source_DIR}/skyline/services/am/applet.cpp

View File

@ -13,7 +13,11 @@ namespace skyline::audio {
outputStream->requestStart();
}
std::shared_ptr<AudioTrack> Audio::OpenTrack(int channelCount, int sampleRate, const std::function<void()> &releaseCallback) {
Audio::~Audio() {
outputStream->close();
}
std::shared_ptr<AudioTrack> Audio::OpenTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback) {
std::shared_ptr<AudioTrack> track = std::make_shared<AudioTrack>(channelCount, sampleRate, releaseCallback);
audioTracks.push_back(track);
@ -27,7 +31,7 @@ namespace skyline::audio {
oboe::DataCallbackResult Audio::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) {
i16 *destBuffer = static_cast<i16 *>(audioData);
int setIndex = 0;
uint setIndex = 0;
size_t sampleI16Size = static_cast<size_t>(numFrames) * audioStream->getChannelCount();
for (auto &track : audioTracks) {

View File

@ -20,6 +20,11 @@ namespace skyline::audio {
public:
Audio(const DeviceState &state);
/**
* @brief The destructor for the audio class
*/
~Audio();
/**
* @brief Opens a new track that can be used to play sound
* @param channelCount The amount channels that are present in the track
@ -27,7 +32,7 @@ namespace skyline::audio {
* @param releaseCallback The callback to call when a buffer has been released
* @return A shared pointer to a new AudioTrack object
*/
std::shared_ptr<AudioTrack> OpenTrack(int channelCount, int sampleRate, const std::function<void()> &releaseCallback);
std::shared_ptr<AudioTrack> OpenTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback);
/**
* @brief Closes a track and frees its data

View File

@ -1,7 +1,7 @@
#include "track.h"
namespace skyline::audio {
AudioTrack::AudioTrack(int channelCount, int sampleRate, const std::function<void()> &releaseCallback) : channelCount(channelCount), sampleRate(sampleRate), releaseCallback(releaseCallback) {
AudioTrack::AudioTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback) : channelCount(channelCount), sampleRate(sampleRate), releaseCallback(releaseCallback) {
if (sampleRate != constant::SampleRate)
throw exception("Unsupported audio sample rate: {}", sampleRate);

View File

@ -15,8 +15,8 @@ namespace skyline::audio {
const std::function<void()> releaseCallback; //!< Callback called when a buffer has been played
std::deque<BufferIdentifier> identifierQueue; //!< Queue of all appended buffer identifiers
int channelCount; //!< The amount channels present in the track
int sampleRate; //!< The sample rate of the track
const int channelCount; //!< The amount channels present in the track
const int sampleRate; //!< The sample rate of the track
public:
std::queue<i16> sampleQueue; //!< Queue of all appended buffer data
@ -30,7 +30,7 @@ namespace skyline::audio {
* @param sampleRate The sample rate to use for the track
* @param releaseCallback A callback to call when a buffer has been played
*/
AudioTrack(int channelCount, int sampleRate, const std::function<void()> &releaseCallback);
AudioTrack(const int channelCount, const int sampleRate, const std::function<void()> &releaseCallback);
/**
* @brief Starts audio playback using data from appended buffers.

View File

@ -1,36 +1,8 @@
#include "audout.h"
#include <kernel/types/KProcess.h>
#include "IAudioOut.h"
namespace skyline::service::audout {
audoutU::audoutU(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::audout_u, "audout:u", {
{0x0, SFUNC(audoutU::ListAudioOuts)},
{0x1, SFUNC(audoutU::OpenAudioOut)}
}) {}
void audoutU::ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
state.process->WriteMemory(reinterpret_cast<void *>(const_cast<char *>(constant::DefaultAudioOutName.data())),
request.outputBuf.at(0).address, constant::DefaultAudioOutName.size());
}
void audoutU::OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
u32 sampleRate = request.Pop<u32>();
request.Pop<u16>(); // Channel count is stored in the upper half of a u32
u16 channelCount = request.Pop<u16>();
state.logger->Debug("audoutU: Opening an IAudioOut with sample rate: {}, channel count: {}", sampleRate, channelCount);
sampleRate = sampleRate ? sampleRate : audio::constant::SampleRate;
channelCount = channelCount ? channelCount : static_cast<u16>(audio::constant::ChannelCount);
manager.RegisterService(std::make_shared<IAudioOut>(state, manager, channelCount, sampleRate), session, response);
response.Push<u32>(sampleRate);
response.Push<u16>(channelCount);
response.Push<u16>(0);
response.Push(static_cast<u32>(audio::PcmFormat::Int16));
response.Push(static_cast<u32>(audio::AudioOutState::Stopped));
}
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, int channelCount, int sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, Service::audout_IAudioOut, "audout:IAudioOut", {
namespace skyline::service::audio {
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, const int channelCount, const int sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, Service::audio_IAudioOut, "audio:IAudioOut", {
{0x0, SFUNC(IAudioOut::GetAudioOutState)},
{0x1, SFUNC(IAudioOut::StartAudioOut)},
{0x2, SFUNC(IAudioOut::StopAudioOut)},
@ -39,7 +11,7 @@ namespace skyline::service::audout {
{0x5, SFUNC(IAudioOut::GetReleasedAudioOutBuffer)},
{0x6, SFUNC(IAudioOut::ContainsAudioOutBuffer)}
}) {
track = state.audio->OpenTrack(channelCount, audio::constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
track = state.audio->OpenTrack(channelCount, skyline::audio::constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
}
IAudioOut::~IAudioOut() {
@ -74,7 +46,7 @@ namespace skyline::service::audout {
tmpSampleBuffer.resize(data.sampleSize / sizeof(i16));
state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize);
resampler.ResampleBuffer(tmpSampleBuffer, static_cast<double>(sampleRate) / audio::constant::SampleRate, channelCount);
resampler.ResampleBuffer(tmpSampleBuffer, static_cast<double>(sampleRate) / skyline::audio::constant::SampleRate, channelCount);
track->AppendBuffer(tmpSampleBuffer, tag);
}

View File

@ -1,53 +1,31 @@
#pragma once
#include <audio/resampler.h>
#include <audio.h>
#include <kernel/types/KEvent.h>
#include <services/base_service.h>
#include <services/serviceman.h>
#include <kernel/types/KEvent.h>
namespace skyline::service::audout {
namespace constant {
constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name
};
#include <audio/resampler.h>
#include <audio.h>
namespace skyline::service::audio {
/**
* @brief audout:u or IAudioOutManager is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u)
*/
class audoutU : public BaseService {
public:
audoutU(const DeviceState &state, ServiceManager &manager);
/**
* @brief Returns a list of all available audio outputs (https://switchbrew.org/wiki/Audio_services#ListAudioOuts)
*/
void ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Creates a new audoutU::IAudioOut object and returns a handle to it (https://switchbrew.org/wiki/Audio_services#OpenAudioOut)
*/
void OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
/**
* @brief IAudioOut is a service opened when OpenAudioOut is called by audout (https://switchbrew.org/wiki/Audio_services#IAudioOut)
* @brief IAudioOut is a service opened when OpenAudioOut is called by IAudioOutManager (https://switchbrew.org/wiki/Audio_services#IAudioOut)
*/
class IAudioOut : public BaseService {
private:
audio::Resampler resampler; //!< The audio resampler object used to resample audio
std::shared_ptr<audio::AudioTrack> track; //!< The audio track associated with the audio out
skyline::audio::Resampler resampler; //!< The audio resampler object used to resample audio
std::shared_ptr<skyline::audio::AudioTrack> track; //!< The audio track associated with the audio out
std::shared_ptr<type::KEvent> releaseEvent; //!< The KEvent that is signalled when a buffer has been released
std::vector<i16> tmpSampleBuffer; //!< A temporary buffer used to store sample data in AppendAudioOutBuffer
int sampleRate; //!< The sample rate of the audio out
int channelCount; //!< The amount of channels in the data sent to the audio out
const int sampleRate; //!< The sample rate of the audio out
const int channelCount; //!< The amount of channels in the data sent to the audio out
public:
/**
* @param channelCount The channel count of the audio data the audio out will be fed
* @param sampleRate The sample rate of the audio data the audio out will be fed
*/
IAudioOut(const DeviceState &state, ServiceManager &manager, int channelCount, int sampleRate);
IAudioOut(const DeviceState &state, ServiceManager &manager, const int channelCount, const int sampleRate);
/**
* @brief Closes the audio track

View File

@ -0,0 +1,33 @@
#include <kernel/types/KProcess.h>
#include "IAudioOutManager.h"
#include "IAudioOut.h"
namespace skyline::service::audio {
IAudioOutManager::IAudioOutManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::audio_IAudioOutManager, "audio:IAudioOutManager", {
{0x0, SFUNC(IAudioOutManager::ListAudioOuts)},
{0x1, SFUNC(IAudioOutManager::OpenAudioOut)}
}) {}
void IAudioOutManager::ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
state.process->WriteMemory(reinterpret_cast<void *>(const_cast<char *>(constant::DefaultAudioOutName.data())),
request.outputBuf.at(0).address, constant::DefaultAudioOutName.size());
}
void IAudioOutManager::OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
u32 sampleRate = request.Pop<u32>();
request.Pop<u16>(); // Channel count is stored in the upper half of a u32
u16 channelCount = request.Pop<u16>();
state.logger->Debug("audoutU: Opening an IAudioOut with sample rate: {}, channel count: {}", sampleRate, channelCount);
sampleRate = sampleRate ? sampleRate : skyline::audio::constant::SampleRate;
channelCount = channelCount ? channelCount : static_cast<u16>(skyline::audio::constant::ChannelCount);
manager.RegisterService(std::make_shared<IAudioOut>(state, manager, channelCount, sampleRate), session, response);
response.Push<u32>(sampleRate);
response.Push<u16>(channelCount);
response.Push<u16>(0);
response.Push(static_cast<u32>(skyline::audio::PcmFormat::Int16));
response.Push(static_cast<u32>(skyline::audio::AudioOutState::Stopped));
}
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <kernel/types/KEvent.h>
#include <services/base_service.h>
#include <services/serviceman.h>
namespace skyline::service::audio {
namespace constant {
constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name
};
/**
* @brief IAudioOutManager or audout:u is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u)
*/
class IAudioOutManager : public BaseService {
public:
IAudioOutManager(const DeviceState &state, ServiceManager &manager);
/**
* @brief Returns a list of all available audio outputs (https://switchbrew.org/wiki/Audio_services#ListAudioOuts)
*/
void ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Creates a new audoutU::IAudioOut object and returns a handle to it (https://switchbrew.org/wiki/Audio_services#OpenAudioOut)
*/
void OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
}

View File

@ -1,8 +1,9 @@
#include "IAudioRenderer.h"
#include <kernel/types/KProcess.h>
#include "IAudioRenderer.h"
namespace skyline::service::audren {
IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams &params) : releaseEvent(std::make_shared<type::KEvent>(state)), rendererParams(params), BaseService(state, manager, Service::IAudioRenderer, "IAudioRenderer", {
namespace skyline::service::audio::IAudioRenderer {
IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams &params)
: releaseEvent(std::make_shared<type::KEvent>(state)), rendererParams(params), memoryPoolCount(params.effectCount + params.voiceCount * 4), samplesPerBuffer(state.settings->GetInt("audren_buffer_size")), BaseService(state, manager, Service::audio_IAudioRenderer, "audio:IAudioRenderer", {
{0x0, SFUNC(IAudioRenderer::GetSampleRate)},
{0x1, SFUNC(IAudioRenderer::GetSampleCount)},
{0x2, SFUNC(IAudioRenderer::GetMixBufferCount)},
@ -12,11 +13,9 @@ namespace skyline::service::audren {
{0x6, SFUNC(IAudioRenderer::Stop)},
{0x7, SFUNC(IAudioRenderer::QuerySystemEvent)},
}) {
track = state.audio->OpenTrack(audio::constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); });
track = state.audio->OpenTrack(skyline::audio::constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); });
track->Start();
samplesPerBuffer = state.settings->GetInt("audren_buffer_size");
memoryPoolCount = rendererParams.effectCount + rendererParams.voiceCount * 4;
memoryPools.resize(memoryPoolCount);
effects.resize(rendererParams.effectCount);
voices.resize(rendererParams.voiceCount, Voice(state));
@ -78,7 +77,7 @@ namespace skyline::service::audren {
UpdateAudio();
UpdateDataHeader outputHeader {
UpdateDataHeader outputHeader{
.revision = constant::RevMagic,
.behaviorSize = 0xb0,
.memoryPoolSize = (rendererParams.effectCount + rendererParams.voiceCount * 4) * static_cast<u32>(sizeof(MemoryPoolOut)),
@ -133,7 +132,7 @@ namespace skyline::service::audren {
void IAudioRenderer::MixFinalBuffer() {
int setIndex = 0;
sampleBuffer.resize(samplesPerBuffer * audio::constant::ChannelCount);
sampleBuffer.resize(samplesPerBuffer * skyline::audio::constant::ChannelCount);
for (auto &voice : voices) {
if (!voice.Playable())
@ -150,7 +149,7 @@ namespace skyline::service::audren {
if (voiceBufferSize == 0)
break;
pendingSamples -= voiceBufferSize / audio::constant::ChannelCount;
pendingSamples -= voiceBufferSize / skyline::audio::constant::ChannelCount;
for (int i = voiceBufferOffset; i < voiceBufferOffset + voiceBufferSize; i++) {
if (setIndex == bufferOffset) {
@ -171,11 +170,11 @@ namespace skyline::service::audren {
}
void IAudioRenderer::Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
playbackState = audio::AudioOutState::Started;
playbackState = skyline::audio::AudioOutState::Started;
}
void IAudioRenderer::Stop(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
playbackState = audio::AudioOutState::Stopped;
playbackState = skyline::audio::AudioOutState::Stopped;
}
void IAudioRenderer::QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {

View File

@ -1,15 +1,15 @@
#pragma once
#include <audio.h>
#include <kernel/types/KEvent.h>
#include <services/base_service.h>
#include <services/serviceman.h>
#include <kernel/types/KEvent.h>
#include <audio.h>
#include "memoryPool.h"
#include "effect.h"
#include "voice.h"
#include "revisionInfo.h"
namespace skyline::service::audren {
namespace skyline::service::audio::IAudioRenderer {
namespace constant {
constexpr int BufferAlignment = 0x40; //!< The alignment for all audren buffers
}
@ -58,18 +58,18 @@ namespace skyline::service::audren {
*/
class IAudioRenderer : public BaseService {
private:
std::shared_ptr<audio::AudioTrack> track; //!< The audio track associated with the audio renderer
AudioRendererParams rendererParams; //!< The parameters to use for the renderer
RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used
std::shared_ptr<skyline::audio::AudioTrack> track; //!< The audio track associated with the audio renderer
std::shared_ptr<type::KEvent> releaseEvent; //!< The KEvent that is signalled when a buffer has been released
std::vector<MemoryPool> memoryPools; //!< An vector of all memory pools that the guest may need
std::vector<Effect> effects; //!< An vector of all effects that the guest may need
std::vector<Voice> voices; //!< An vector of all voices that the guest may need
std::vector<i16> sampleBuffer; //!< The final output data that is appended to the stream
RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used
audio::AudioOutState playbackState{audio::AudioOutState::Stopped}; //!< The current state of playback
size_t memoryPoolCount{}; //!< The amount of memory pools the guest may need
int samplesPerBuffer{}; //!< The amount of samples each appended buffer should contain
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The current state of playback
const size_t memoryPoolCount; //!< The amount of memory pools the guest may need
const int samplesPerBuffer; //!< The amount of samples each appended buffer should contain
/**
* @brief Obtains new sample data from voices and mixes it together into the sample buffer

View File

@ -2,7 +2,7 @@
#include <common.h>
namespace skyline::service::audren {
namespace skyline::service::audio::IAudioRenderer {
/**
* @brief This enumerates various states an effect can be in
*/

View File

@ -1,7 +1,6 @@
#include <common.h>
#include "memoryPool.h"
namespace skyline::service::audren {
namespace skyline::service::audio::IAudioRenderer {
void MemoryPool::ProcessInput(const MemoryPoolIn &input) {
if (input.state == MemoryPoolState::RequestAttach)
output.state = MemoryPoolState::Attached;

View File

@ -2,7 +2,7 @@
#include <common.h>
namespace skyline::service::audren {
namespace skyline::service::audio::IAudioRenderer {
/**
* @brief This enumerates various states a memory pool can be in
*/

View File

@ -2,7 +2,7 @@
#include <common.h>
namespace skyline::service::audren {
namespace skyline::service::audio::IAudioRenderer {
namespace constant {
constexpr u32 SupportedRevision = 7; //!< The audren revision our implementation supports
constexpr u32 Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); //!< The HOS 1.0 revision magic

View File

@ -1,8 +1,7 @@
#include <common.h>
#include "voice.h"
#include <kernel/types/KProcess.h>
#include "voice.h"
namespace skyline::service::audren {
namespace skyline::service::audio::IAudioRenderer {
Voice::Voice(const DeviceState &state) : state(state) {}
void Voice::ProcessInput(const VoiceIn &input) {
@ -23,7 +22,7 @@ namespace skyline::service::audren {
return;
if (input.firstUpdate) {
if (input.pcmFormat != audio::PcmFormat::Int16)
if (input.pcmFormat != skyline::audio::PcmFormat::Int16)
throw exception("Unsupported voice PCM format: {}", input.pcmFormat);
pcmFormat = input.pcmFormat;
@ -48,7 +47,7 @@ namespace skyline::service::audren {
return;
switch (pcmFormat) {
case audio::PcmFormat::Int16:
case skyline::audio::PcmFormat::Int16:
sampleBuffer.resize(currentBuffer.size / sizeof(i16));
state.process->ReadMemory(sampleBuffer.data(), currentBuffer.position, currentBuffer.size);
break;
@ -56,15 +55,15 @@ namespace skyline::service::audren {
throw exception("Unsupported voice PCM format: {}", pcmFormat);
}
if (sampleRate != audio::constant::SampleRate)
sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast<double>(sampleRate) / audio::constant::SampleRate, channelCount);
if (sampleRate != skyline::audio::constant::SampleRate)
sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast<double>(sampleRate) / skyline::audio::constant::SampleRate, channelCount);
if (channelCount == 1 && audio::constant::ChannelCount != channelCount) {
if (channelCount == 1 && skyline::audio::constant::ChannelCount != channelCount) {
size_t originalSize = sampleBuffer.size();
sampleBuffer.resize((originalSize / channelCount) * audio::constant::ChannelCount);
sampleBuffer.resize((originalSize / channelCount) * skyline::audio::constant::ChannelCount);
for (size_t monoIndex = originalSize - 1, targetIndex = sampleBuffer.size(); monoIndex > 0; monoIndex--)
for (uint i = 0; i < audio::constant::ChannelCount; i++)
for (uint i = 0; i < skyline::audio::constant::ChannelCount; i++)
sampleBuffer[--targetIndex] = sampleBuffer[monoIndex];
}
}
@ -72,7 +71,7 @@ namespace skyline::service::audren {
std::vector<i16> &Voice::GetBufferData(int maxSamples, int &outOffset, int &outSize) {
WaveBuffer &currentBuffer = waveBuffers.at(bufferIndex);
if (!acquired || playbackState != audio::AudioOutState::Started) {
if (!acquired || playbackState != skyline::audio::AudioOutState::Started) {
outSize = 0;
return sampleBuffer;
}
@ -83,16 +82,16 @@ namespace skyline::service::audren {
}
outOffset = sampleOffset;
outSize = std::min(maxSamples * audio::constant::ChannelCount, static_cast<int>(sampleBuffer.size() - sampleOffset));
outSize = std::min(maxSamples * skyline::audio::constant::ChannelCount, static_cast<int>(sampleBuffer.size() - sampleOffset));
output.playedSamplesCount += outSize / audio::constant::ChannelCount;
output.playedSamplesCount += outSize / skyline::audio::constant::ChannelCount;
sampleOffset += outSize;
if (sampleOffset == sampleBuffer.size()) {
sampleOffset = 0;
if (currentBuffer.lastBuffer)
playbackState = audio::AudioOutState::Paused;
playbackState = skyline::audio::AudioOutState::Paused;
if (!currentBuffer.looping)
SetWaveBufferIndex(bufferIndex + 1);

View File

@ -1,11 +1,11 @@
#pragma once
#include <common.h>
#include <array>
#include <audio.h>
#include <audio/resampler.h>
#include <audio.h>
#include <common.h>
namespace skyline::service::audren {
namespace skyline::service::audio::IAudioRenderer {
/**
* @brief This stores data for configuring a biquadratic filter
*/
@ -46,8 +46,8 @@ namespace skyline::service::audren {
u32 nodeId; //!< The node ID of the voice
u8 firstUpdate; //!< Whether this voice is new
u8 acquired; //!< Whether the sample is in use
audio::AudioOutState playbackState; //!< The playback state
audio::PcmFormat pcmFormat; //!< The sample format
skyline::audio::AudioOutState playbackState; //!< The playback state
skyline::audio::PcmFormat pcmFormat; //!< The sample format
u32 sampleRate; //!< The sample rate
u32 priority; //!< The priority for this voice
u32 _unk0_;
@ -87,7 +87,7 @@ namespace skyline::service::audren {
const DeviceState &state; //!< The emulator state object
std::array<WaveBuffer, 4> waveBuffers; //!< An array containing the state of all four wave buffers
std::vector<i16> sampleBuffer; //!< A buffer containing processed sample data
audio::Resampler resampler; //!< The resampler object used for changing the sample rate of a stream
skyline::audio::Resampler resampler; //!< The resampler object used for changing the sample rate of a stream
bool acquired{false}; //!< If the voice is in use
bool bufferReload{true}; //!< If the buffer needs to be updated
@ -95,8 +95,8 @@ namespace skyline::service::audren {
int sampleOffset{}; //!< The offset in the sample data of the current wave buffer
int sampleRate{}; //!< The sample rate of the sample data
int channelCount{}; //!< The amount of channels in the sample data
audio::AudioOutState playbackState{audio::AudioOutState::Stopped}; //!< The playback state of the voice
audio::PcmFormat pcmFormat{audio::PcmFormat::Invalid}; //!< The PCM format used for guest audio data
skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The playback state of the voice
skyline::audio::PcmFormat pcmFormat{skyline::audio::PcmFormat::Invalid}; //!< The PCM format used for guest audio data
/**
* @brief Updates the sample buffer with data from the current wave buffer and processes it
@ -132,7 +132,7 @@ namespace skyline::service::audren {
* @return Whether the voice is currently playable
*/
inline bool Playable() {
return acquired && playbackState == audio::AudioOutState::Started && waveBuffers[bufferIndex].size != 0;
return acquired && playbackState == skyline::audio::AudioOutState::Started && waveBuffers[bufferIndex].size != 0;
}
};
}

View File

@ -1,52 +1,49 @@
#include "IAudioRenderer.h"
#include "IAudioRendererManager.h"
#include <kernel/types/KProcess.h>
#include "IAudioRenderer/IAudioRenderer.h"
#include "IAudioRendererManager.h"
namespace skyline::service::audren {
IAudioRendererManager::IAudioRendererManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::IAudioRendererManager, "IAudioRendererManager", {
namespace skyline::service::audio {
IAudioRendererManager::IAudioRendererManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::audio_IAudioRendererManager, "audio:IAudioRendererManager", {
{0x0, SFUNC(IAudioRendererManager::OpenAudioRenderer)},
{0x1, SFUNC(IAudioRendererManager::GetAudioRendererWorkBufferSize)}
}) {}
void IAudioRendererManager::OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
AudioRendererParams params = request.Pop<AudioRendererParams>();
IAudioRenderer::AudioRendererParams params = request.Pop<IAudioRenderer::AudioRendererParams>();
state.logger->Debug("IAudioRendererManager: Opening a rev {} IAudioRenderer with sample rate: {}, voice count: {}, effect count: {}",
ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
manager.RegisterService(std::make_shared<IAudioRenderer>(state, manager, params), session, response);
IAudioRenderer::ExtractVersionFromRevision(params.revision), params.sampleRate, params.voiceCount, params.effectCount);
manager.RegisterService(std::make_shared<IAudioRenderer::IAudioRenderer>(state, manager, params), session, response);
}
void IAudioRendererManager::GetAudioRendererWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
AudioRendererParams params = request.Pop<AudioRendererParams>();
IAudioRenderer::AudioRendererParams params = request.Pop<IAudioRenderer::AudioRendererParams>();
RevisionInfo revisionInfo;
IAudioRenderer::RevisionInfo revisionInfo{};
revisionInfo.SetUserRevision(params.revision);
u32 totalMixCount = params.subMixCount + 1;
i64 size = utils::AlignUp(params.mixBufferCount * 4, constant::BufferAlignment) +
i64 size = utils::AlignUp(params.mixBufferCount * 4, IAudioRenderer::constant::BufferAlignment) +
params.subMixCount * 0x400 +
totalMixCount * 0x940 +
params.voiceCount * 0x3F0 +
utils::AlignUp(totalMixCount * 8, 16) +
utils::AlignUp(params.voiceCount * 8, 16) +
utils::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), constant::BufferAlignment) +
utils::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), IAudioRenderer::constant::BufferAlignment) +
(params.sinkCount + params.subMixCount) * 0x2C0 +
(params.effectCount + params.voiceCount * 4) * 0x30 +
0x50;
if (revisionInfo.SplitterSupported()) {
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, constant::BufferAlignment);
i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, IAudioRenderer::constant::BufferAlignment);
if (nodeStateWorkSize < 0)
nodeStateWorkSize |= 7;
nodeStateWorkSize = 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (nodeStateWorkSize / 8);
i32 edgeMatrixWorkSize = utils::AlignUp(totalMixCount * totalMixCount, constant::BufferAlignment);
i32 edgeMatrixWorkSize = utils::AlignUp(totalMixCount * totalMixCount, IAudioRenderer::constant::BufferAlignment);
if (edgeMatrixWorkSize < 0)
edgeMatrixWorkSize |= 7;

View File

@ -1,25 +1,23 @@
#pragma once
#include <audio.h>
#include <services/base_service.h>
#include <services/serviceman.h>
#include <kernel/types/KEvent.h>
namespace skyline::service::audren {
namespace skyline::service::audio {
/**
* @brief audren:u or IAudioRendererManager is used to manage audio renderer outputs (https://switchbrew.org/wiki/Audio_services#audren:u)
* @brief IAudioRendererManager or audren:u is used to manage audio renderer outputs (https://switchbrew.org/wiki/Audio_services#audren:u)
*/
class IAudioRendererManager : public BaseService {
public:
IAudioRendererManager(const DeviceState &state, ServiceManager &manager);
/**
* @brief Creates a new audrenU::IAudioRenderer object and returns a handle to it
* @brief Creates a new IAudioRenderer object and returns a handle to it
*/
void OpenAudioRenderer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
/**
* @brief Calculates the size of the buffer the guest needs to allocate for audren
* @brief Calculates the size of the buffer the guest needs to allocate for IAudioRendererManager
*/
void GetAudioRendererWorkBufferSize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};

View File

@ -38,10 +38,10 @@ namespace skyline::service {
am_ILibraryAppletCreator,
am_IDebugFunctions,
am_IAppletCommonFunctions,
audout_u,
audout_IAudioOut,
IAudioRendererManager,
IAudioRenderer,
audio_IAudioOutManager,
audio_IAudioOut,
audio_IAudioRendererManager,
audio_IAudioRenderer,
hid_IHidServer,
hid_IAppletResource,
timesrv_IStaticService,
@ -66,8 +66,8 @@ namespace skyline::service {
{"apm", Service::apm},
{"appletOE", Service::am_appletOE},
{"appletAE", Service::am_appletAE},
{"audout:u", Service::audout_u},
{"audren:u", Service::IAudioRendererManager},
{"audout:u", Service::audio_IAudioOutManager},
{"audren:u", Service::audio_IAudioRendererManager},
{"hid", Service::hid_IHidServer},
{"time:s", Service::timesrv_IStaticService},
{"time:a", Service::timesrv_IStaticService},

View File

@ -1,11 +1,11 @@
#include <kernel/types/KProcess.h>
#include <services/audren/IAudioRendererManager.h>
#include "sm/IUserInterface.h"
#include "settings/ISystemSettingsServer.h"
#include "apm/apm.h"
#include "am/applet.h"
#include "am/appletController.h"
#include "audout/audout.h"
#include "audio/IAudioOutManager.h"
#include "audio/IAudioRendererManager.h"
#include "fatalsrv/IService.h"
#include "hid/IHidServer.h"
#include "timesrv/IStaticService.h"
@ -41,11 +41,11 @@ namespace skyline::service {
case Service::am_appletAE:
serviceObj = std::make_shared<am::appletAE>(state, *this);
break;
case Service::audout_u:
serviceObj = std::make_shared<audout::audoutU>(state, *this);
case Service::audio_IAudioOutManager:
serviceObj = std::make_shared<audio::IAudioOutManager>(state, *this);
break;
case Service::IAudioRendererManager:
serviceObj = std::make_shared<audren::IAudioRendererManager>(state, *this);
case Service::audio_IAudioRendererManager:
serviceObj = std::make_shared<audio::IAudioRendererManager>(state, *this);
break;
case Service::hid_IHidServer:
serviceObj = std::make_shared<hid::IHidServer>(state, *this);