From fb1a158e8f1a7992f785e9708d63405f07862a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Sat, 18 Apr 2020 03:05:31 +0530 Subject: [PATCH] Optimize Audio by using Circular Buffers, Handle Device Disconnection and Fix Some Bugs This optimizes a lot of audio by using a circular buffer rather than queues. In addition to handling device disconnection using oboe callbacks and fix bugs in regards to audio saturation. --- app/src/main/cpp/skyline/audio.cpp | 65 +++---- app/src/main/cpp/skyline/audio.h | 16 +- app/src/main/cpp/skyline/audio/common.h | 158 ++++++++++++++++++ app/src/main/cpp/skyline/audio/track.cpp | 17 +- app/src/main/cpp/skyline/audio/track.h | 16 +- .../cpp/skyline/services/audio/IAudioOut.cpp | 13 +- .../audio/IAudioRenderer/IAudioRenderer.cpp | 66 ++++---- .../audio/IAudioRenderer/IAudioRenderer.h | 16 +- 8 files changed, 270 insertions(+), 97 deletions(-) diff --git a/app/src/main/cpp/skyline/audio.cpp b/app/src/main/cpp/skyline/audio.cpp index bb45ada5..30cd26c9 100644 --- a/app/src/main/cpp/skyline/audio.cpp +++ b/app/src/main/cpp/skyline/audio.cpp @@ -5,67 +5,68 @@ namespace skyline::audio { Audio::Audio(const DeviceState &state) : state(state), oboe::AudioStreamCallback() { - oboe::AudioStreamBuilder builder; - - builder.setChannelCount(constant::ChannelCount) - ->setSampleRate(constant::SampleRate) - ->setFormat(constant::PcmFormat) - ->setCallback(this) - ->openManagedStream(outputStream); + builder.setChannelCount(constant::ChannelCount); + builder.setSampleRate(constant::SampleRate); + builder.setFormat(constant::PcmFormat); + builder.setFramesPerCallback(constant::MixBufferSize); + builder.setUsage(oboe::Usage::Game); + builder.setCallback(this); + builder.openManagedStream(outputStream); outputStream->requestStart(); } - Audio::~Audio() { - outputStream->close(); - } - std::shared_ptr Audio::OpenTrack(const int channelCount, const int sampleRate, const std::function &releaseCallback) { - std::shared_ptr track = std::make_shared(channelCount, sampleRate, releaseCallback); + std::lock_guard trackGuard(trackMutex); + + auto track = std::make_shared(channelCount, sampleRate, releaseCallback); audioTracks.push_back(track); return track; } void Audio::CloseTrack(std::shared_ptr &track) { + std::lock_guard trackGuard(trackMutex); + audioTracks.erase(std::remove(audioTracks.begin(), audioTracks.end(), track), audioTracks.end()); track.reset(); } oboe::DataCallbackResult Audio::onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames) { i16 *destBuffer = static_cast(audioData); - uint setIndex = 0; - size_t sampleI16Size = static_cast(numFrames) * audioStream->getChannelCount(); + size_t streamSamples = static_cast(numFrames) * audioStream->getChannelCount(); + size_t writtenSamples = 0; + + std::unique_lock trackLock(trackMutex); for (auto &track : audioTracks) { if (track->playbackState == AudioOutState::Stopped) continue; - track->bufferLock.lock(); + std::lock_guard bufferGuard(track->bufferLock); - std::queue &srcBuffer = track->sampleQueue; - size_t amount = std::min(srcBuffer.size(), sampleI16Size); + auto trackSamples = track->samples.Read(destBuffer, streamSamples, [](i16 *source, i16 *destination) { + *destination = Saturate(static_cast(*destination) + static_cast(*source)); + }, writtenSamples); - for (size_t i = 0; i < amount; i++) { - if (setIndex == i) { - destBuffer[i] = srcBuffer.front(); - setIndex++; - } else { - destBuffer[i] += srcBuffer.front(); - } + writtenSamples = std::max(trackSamples, writtenSamples); - srcBuffer.pop(); - } - - track->sampleCounter += amount; + track->sampleCounter += trackSamples; track->CheckReleasedBuffers(); - - track->bufferLock.unlock(); } - if (sampleI16Size > setIndex) - memset(destBuffer, 0, (sampleI16Size - setIndex) * 2); + trackLock.unlock(); + + if (streamSamples > writtenSamples) + memset(destBuffer + writtenSamples, 0, (streamSamples - writtenSamples) * sizeof(i16)); return oboe::DataCallbackResult::Continue; } + + void Audio::onErrorAfterClose(oboe::AudioStream *audioStream, oboe::Result error) { + if (error == oboe::Result::ErrorDisconnected) { + builder.openManagedStream(outputStream); + outputStream->requestStart(); + } + } } diff --git a/app/src/main/cpp/skyline/audio.h b/app/src/main/cpp/skyline/audio.h index c3d35cab..23ba52b5 100644 --- a/app/src/main/cpp/skyline/audio.h +++ b/app/src/main/cpp/skyline/audio.h @@ -17,17 +17,14 @@ namespace skyline::audio { class Audio : public oboe::AudioStreamCallback { private: const DeviceState &state; //!< The state of the device + oboe::AudioStreamBuilder builder; //!< The audio stream builder, used to open oboe::ManagedStream outputStream; //!< The output oboe audio stream - std::vector> audioTracks; //!< Vector containing a pointer of every open audio track + std::vector> audioTracks; //!< A vector of shared_ptr to every open audio track + Mutex trackMutex; //!< This mutex is used to ensure that audioTracks isn't modified while it is being used 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 @@ -50,5 +47,12 @@ namespace skyline::audio { * @param numFrames The amount of frames the sample data needs to contain */ oboe::DataCallbackResult onAudioReady(oboe::AudioStream *audioStream, void *audioData, int32_t numFrames); + + /** + * @brief The callback oboe uses to notify the application about stream closure + * @param audioStream The audio stream we are being called by + * @param error The error due to which the stream is being closed + */ + void onErrorAfterClose(oboe::AudioStream *audioStream, oboe::Result error); }; } diff --git a/app/src/main/cpp/skyline/audio/common.h b/app/src/main/cpp/skyline/audio/common.h index c54a6f0d..bd64ddc2 100644 --- a/app/src/main/cpp/skyline/audio/common.h +++ b/app/src/main/cpp/skyline/audio/common.h @@ -5,12 +5,14 @@ #include #include +#include namespace skyline { namespace constant { constexpr auto SampleRate = 48000; //!< The common sampling rate to use for audio output constexpr auto ChannelCount = 2; //!< The common amount of channels to use for audio output constexpr auto PcmFormat = oboe::AudioFormat::I16; //!< The common PCM data format to use for audio output + constexpr size_t MixBufferSize = 960; //!< The size of the mix buffer by default }; namespace audio { @@ -44,5 +46,161 @@ namespace skyline { u64 finalSample; //!< The final sample this buffer will be played in bool released; //!< If the buffer has been released }; + + /** + * @brief This saturates the specified value according to the numeric limits of Out + * @tparam Out The return value type and the numeric limit clamp + * @tparam Intermediate The intermediate type that is converted to from In before clamping + * @tparam In The input value type + * @param value The value to saturate + * @return The saturated value + */ + template + inline Out Saturate(In value) { + return static_cast(std::clamp(static_cast(value), static_cast(std::numeric_limits::min()), static_cast(std::numeric_limits::max()))); + } + + /** + * @brief This class is used to abstract an array into a circular buffer + * @tparam Type The type of elements stored in the buffer + * @tparam Size The maximum size of the circular buffer + */ + template + class CircularBuffer { + private: + std::array array{}; //!< The internal array holding the circular buffer + Type *start{array.begin()}; //!< The start/oldest element of the internal array + Type *end{array.begin()}; //!< The end/newest element of the internal array + bool empty{true}; //!< This boolean is used to differentiate between the buffer being full or empty + Mutex mtx; //!< The mutex ensures that the buffer operations don't overlap + + public: + /** + * @brief This reads data from this buffer into the specified buffer + * @param address The address to write buffer data into + * @param maxSize The maximum amount of data to write in units of Type + * @param function If this is specified, then this is called rather than memcpy + * @return The amount of data written into the input buffer in units of Type + */ + inline size_t Read(Type *address, ssize_t maxSize, void function(Type *, Type *) = {}, ssize_t copyOffset = -1) { + std::lock_guard guard(mtx); + + if (empty) + return 0; + + ssize_t size{}, sizeBegin{}, sizeEnd{}; + + if (start < end) { + sizeEnd = std::min(end - start, maxSize); + + size = sizeEnd; + } else { + sizeEnd = std::min(array.end() - start, maxSize); + sizeBegin = std::min(end - array.begin(), maxSize - sizeEnd); + + size = sizeBegin + sizeEnd; + } + + if (function && copyOffset) { + auto sourceEnd = start + ((copyOffset != -1) ? copyOffset : sizeEnd); + + for (auto source = start, destination = address; source < sourceEnd; source++, destination++) + function(source, destination); + + if (copyOffset != -1) { + std::memcpy(address + copyOffset, start + copyOffset, (sizeEnd - copyOffset) * sizeof(Type)); + copyOffset -= sizeEnd; + } + } else { + std::memcpy(address, start, sizeEnd * sizeof(Type)); + } + + address += sizeEnd; + + if (sizeBegin) { + if (function && copyOffset) { + auto sourceEnd = array.begin() + ((copyOffset != -1) ? copyOffset : sizeBegin); + + for (auto source = array.begin(), destination = address; source < sourceEnd; source++, destination++) + function(source, destination); + + if (copyOffset != -1) + std::memcpy(array.begin() + copyOffset, address + copyOffset, (sizeBegin - copyOffset) * sizeof(Type)); + } else { + std::memcpy(address, array.begin(), sizeBegin * sizeof(Type)); + } + + start = array.begin() + sizeBegin; + } else { + start += sizeEnd; + } + + if (start == end) + empty = true; + + return static_cast(size); + } + + /** + * @brief This appends data from the specified buffer into this buffer + * @param address The address of the buffer + * @param size The size of the buffer in units of Type + */ + inline void Append(Type *address, ssize_t size) { + std::lock_guard guard(mtx); + + while (size) { + if (start <= end && end != array.end()) { + auto sizeEnd = std::min(array.end() - end, size); + std::memcpy(end, address, sizeEnd * sizeof(Type)); + + address += sizeEnd; + size -= sizeEnd; + + end += sizeEnd; + } else { + auto sizePreStart = (end == array.end()) ? std::min(start - array.begin(), size) : std::min(start - end, size); + auto sizePostStart = std::min(array.end() - start, size - sizePreStart); + + if (sizePreStart) + std::memcpy((end == array.end()) ? array.begin() : end, address, sizePreStart * sizeof(Type)); + + if (end == array.end()) + end = array.begin() + sizePreStart; + else + end += sizePreStart; + + address += sizePreStart; + size -= sizePreStart; + + if (sizePostStart) + std::memcpy(end, address, sizePostStart * sizeof(Type)); + + if (start == array.end()) + start = array.begin() + sizePostStart; + else + start += sizePostStart; + + if (end == array.end()) + end = array.begin() + sizePostStart; + else + end += sizePostStart; + + address += sizePostStart; + size -= sizePostStart; + } + + empty = false; + } + } + + /** + * @brief This appends data from a vector to the buffer + * @param sampleData A reference to a vector containing the data to be appended + */ + inline void Append(const std::vector &data) { + Append(const_cast(data.data()), data.size()); + } + }; } } diff --git a/app/src/main/cpp/skyline/audio/track.cpp b/app/src/main/cpp/skyline/audio/track.cpp index b8ada88e..6a9f0d4f 100644 --- a/app/src/main/cpp/skyline/audio/track.cpp +++ b/app/src/main/cpp/skyline/audio/track.cpp @@ -43,24 +43,21 @@ namespace skyline::audio { return bufferIds; } - void AudioTrack::AppendBuffer(const std::vector &sampleData, u64 tag) { + void AudioTrack::AppendBuffer(u64 tag, const i16* address, u64 size) { BufferIdentifier identifier; identifier.released = false; identifier.tag = tag; - if (identifierQueue.empty()) - identifier.finalSample = sampleData.size(); + if (identifiers.empty()) + identifier.finalSample = size; else - identifier.finalSample = sampleData.size() + identifierQueue.front().finalSample; + identifier.finalSample = size + identifiers.front().finalSample; - bufferLock.lock(); + std::lock_guard guard(bufferLock); - identifierQueue.push_front(identifier); - for (const auto &sample : sampleData) - sampleQueue.push(sample); - - bufferLock.unlock(); + identifiers.push_front(identifier); + samples.Append(const_cast(address), size); } void AudioTrack::CheckReleasedBuffers() { diff --git a/app/src/main/cpp/skyline/audio/track.h b/app/src/main/cpp/skyline/audio/track.h index 341b1cd9..a2f3c2be 100644 --- a/app/src/main/cpp/skyline/audio/track.h +++ b/app/src/main/cpp/skyline/audio/track.h @@ -22,7 +22,7 @@ namespace skyline::audio { const u32 sampleRate; //!< The sample rate of the track public: - std::queue sampleQueue; //!< Queue of all appended buffer data + CircularBuffer samples; //!< A vector of all appended audio samples Mutex bufferLock; //!< This mutex ensures that appending to buffers doesn't overlap AudioOutState playbackState{AudioOutState::Stopped}; //!< The current state of playback @@ -63,10 +63,20 @@ namespace skyline::audio { /** * @brief Appends audio samples to the output buffer - * @param sampleData Reference to a vector containing I16 format pcm data * @param tag The tag of the buffer + * @param address The address of the audio buffer + * @param size The size of the audio buffer in i16 units */ - void AppendBuffer(const std::vector &sampleData, u64 tag); + void AppendBuffer(u64 tag, const i16* address, u64 size); + + /** + * @brief Appends audio samples to the output buffer + * @param tag The tag of the buffer + * @param sampleData A reference to a vector containing I16 format PCM data + */ + void AppendBuffer(u64 tag, const std::vector &sampleData = {}) { + AppendBuffer(tag, sampleData.data(), sampleData.size()); + } /** * @brief Checks if any buffers have been released and calls the appropriate callback for them diff --git a/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp b/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp index e1788c19..9c5ed1e9 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp +++ b/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp @@ -47,10 +47,15 @@ namespace skyline::service::audio { state.logger->Debug("IAudioOut: Appending buffer with address: 0x{:X}, size: 0x{:X}", data.sampleBufferPtr, data.sampleSize); - tmpSampleBuffer.resize(data.sampleSize / sizeof(i16)); - state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize); - resampler.ResampleBuffer(tmpSampleBuffer, static_cast(sampleRate) / constant::SampleRate, channelCount); - track->AppendBuffer(tmpSampleBuffer, tag); + if(sampleRate != constant::SampleRate) { + tmpSampleBuffer.resize(data.sampleSize / sizeof(i16)); + state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize); + resampler.ResampleBuffer(tmpSampleBuffer, static_cast(sampleRate) / constant::SampleRate, channelCount); + + track->AppendBuffer(tag, tmpSampleBuffer); + } else { + track->AppendBuffer(tag, state.process->GetPointer(data.sampleBufferPtr), data.sampleSize); + } } void IAudioOut::RegisterBufferEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { diff --git a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp index e9359cc0..42e35679 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp +++ b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp @@ -5,8 +5,8 @@ #include "IAudioRenderer.h" namespace skyline::service::audio::IAudioRenderer { - IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams ¶ms) - : releaseEvent(std::make_shared(state)), rendererParams(params), memoryPoolCount(params.effectCount + params.voiceCount * 4), samplesPerBuffer(state.settings->GetInt("audren_buffer_size")), BaseService(state, manager, Service::audio_IAudioRenderer, "audio:IAudioRenderer", { + IAudioRenderer::IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParameters ¶meters) + : releaseEvent(std::make_shared(state)), parameters(parameters), BaseService(state, manager, Service::audio_IAudioRenderer, "audio:IAudioRenderer", { {0x0, SFUNC(IAudioRenderer::GetSampleRate)}, {0x1, SFUNC(IAudioRenderer::GetSampleCount)}, {0x2, SFUNC(IAudioRenderer::GetMixBufferCount)}, @@ -16,17 +16,17 @@ namespace skyline::service::audio::IAudioRenderer { {0x6, SFUNC(IAudioRenderer::Stop)}, {0x7, SFUNC(IAudioRenderer::QuerySystemEvent)}, }) { - track = state.audio->OpenTrack(constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); }); + track = state.audio->OpenTrack(constant::ChannelCount, parameters.sampleRate, [this]() { releaseEvent->Signal(); }); track->Start(); - memoryPools.resize(memoryPoolCount); - effects.resize(rendererParams.effectCount); - voices.resize(rendererParams.voiceCount, Voice(state)); + memoryPools.resize(parameters.effectCount + parameters.voiceCount * 4); + effects.resize(parameters.effectCount); + voices.resize(parameters.voiceCount, Voice(state)); // Fill track with empty samples that we will triple buffer - track->AppendBuffer(std::vector(), 0); - track->AppendBuffer(std::vector(), 1); - track->AppendBuffer(std::vector(), 2); + track->AppendBuffer(0); + track->AppendBuffer(1); + track->AppendBuffer(2); } IAudioRenderer::~IAudioRenderer() { @@ -34,15 +34,15 @@ namespace skyline::service::audio::IAudioRenderer { } void IAudioRenderer::GetSampleRate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(rendererParams.sampleRate); + response.Push(parameters.sampleRate); } void IAudioRenderer::GetSampleCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(rendererParams.sampleCount); + response.Push(parameters.sampleCount); } void IAudioRenderer::GetMixBufferCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(rendererParams.subMixCount); + response.Push(parameters.subMixCount); } void IAudioRenderer::GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { @@ -57,6 +57,7 @@ namespace skyline::service::audio::IAudioRenderer { inputAddress += sizeof(UpdateDataHeader); inputAddress += inputHeader.behaviorSize; // Unused + auto memoryPoolCount = memoryPools.size(); std::vector memoryPoolsIn(memoryPoolCount); state.process->ReadMemory(memoryPoolsIn.data(), inputAddress, memoryPoolCount * sizeof(MemoryPoolIn)); inputAddress += inputHeader.memoryPoolSize; @@ -65,15 +66,15 @@ namespace skyline::service::audio::IAudioRenderer { memoryPools[i].ProcessInput(memoryPoolsIn[i]); inputAddress += inputHeader.voiceResourceSize; - std::vector voicesIn(rendererParams.voiceCount); - state.process->ReadMemory(voicesIn.data(), inputAddress, rendererParams.voiceCount * sizeof(VoiceIn)); + std::vector voicesIn(parameters.voiceCount); + state.process->ReadMemory(voicesIn.data(), inputAddress, parameters.voiceCount * sizeof(VoiceIn)); inputAddress += inputHeader.voiceSize; for (auto i = 0; i < voicesIn.size(); i++) voices[i].ProcessInput(voicesIn[i]); - std::vector effectsIn(rendererParams.effectCount); - state.process->ReadMemory(effectsIn.data(), inputAddress, rendererParams.effectCount * sizeof(EffectIn)); + std::vector effectsIn(parameters.effectCount); + state.process->ReadMemory(effectsIn.data(), inputAddress, parameters.effectCount * sizeof(EffectIn)); for (auto i = 0; i < effectsIn.size(); i++) effects[i].ProcessInput(effectsIn[i]); @@ -83,10 +84,10 @@ namespace skyline::service::audio::IAudioRenderer { UpdateDataHeader outputHeader{ .revision = constant::RevMagic, .behaviorSize = 0xb0, - .memoryPoolSize = (rendererParams.effectCount + rendererParams.voiceCount * 4) * static_cast(sizeof(MemoryPoolOut)), - .voiceSize = rendererParams.voiceCount * static_cast(sizeof(VoiceOut)), - .effectSize = rendererParams.effectCount * static_cast(sizeof(EffectOut)), - .sinkSize = rendererParams.sinkCount * 0x20, + .memoryPoolSize = (parameters.effectCount + parameters.voiceCount * 4) * static_cast(sizeof(MemoryPoolOut)), + .voiceSize = parameters.voiceCount * static_cast(sizeof(VoiceOut)), + .effectSize = parameters.effectCount * static_cast(sizeof(EffectOut)), + .sinkSize = parameters.sinkCount * 0x20, .performanceManagerSize = 0x10, .elapsedFrameCountInfoSize = 0x0 }; @@ -129,38 +130,37 @@ namespace skyline::service::audio::IAudioRenderer { for (auto &tag : released) { MixFinalBuffer(); - track->AppendBuffer(sampleBuffer, tag); + track->AppendBuffer(tag, sampleBuffer.data(), sampleBuffer.size()); } } void IAudioRenderer::MixFinalBuffer() { - int setIndex = 0; - sampleBuffer.resize(static_cast(samplesPerBuffer * constant::ChannelCount)); + u32 writtenSamples = 0; for (auto &voice : voices) { if (!voice.Playable()) continue; - int bufferOffset = 0; - int pendingSamples = samplesPerBuffer; + u32 bufferOffset{}; + u32 pendingSamples = constant::MixBufferSize; while (pendingSamples > 0) { - int voiceBufferSize = 0; - int voiceBufferOffset = 0; - std::vector &voiceSamples = voice.GetBufferData(pendingSamples, voiceBufferOffset, voiceBufferSize); + u32 voiceBufferOffset{}; + u32 voiceBufferSize{}; + auto &voiceSamples = voice.GetBufferData(pendingSamples, voiceBufferOffset, voiceBufferSize); if (voiceBufferSize == 0) break; pendingSamples -= voiceBufferSize / constant::ChannelCount; - for (int i = voiceBufferOffset; i < voiceBufferOffset + voiceBufferSize; i++) { - if (setIndex == bufferOffset) { - sampleBuffer[bufferOffset] = static_cast(std::clamp(static_cast(static_cast(voiceSamples[i]) * voice.volume), static_cast(std::numeric_limits::min()), static_cast(std::numeric_limits::max()))); + for (auto index = voiceBufferOffset; index < voiceBufferOffset + voiceBufferSize; index++) { + if (writtenSamples == bufferOffset) { + sampleBuffer[bufferOffset] = skyline::audio::Saturate(voiceSamples[index] * voice.volume); - setIndex++; + writtenSamples++; } else { - sampleBuffer[bufferOffset] += static_cast(std::clamp(static_cast(sampleBuffer[voiceSamples[i]]) + static_cast(static_cast(voiceSamples[i]) * voice.volume), static_cast(std::numeric_limits::min()), static_cast(std::numeric_limits::max()))); + sampleBuffer[bufferOffset] = skyline::audio::Saturate(sampleBuffer[bufferOffset] + (voiceSamples[index] * voice.volume)); } bufferOffset++; diff --git a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.h b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.h index 1999f1b8..d3f8efa7 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.h +++ b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.h @@ -21,7 +21,7 @@ namespace skyline { /** * @brief The parameters used to configure an IAudioRenderer */ - struct AudioRendererParams { + struct AudioRendererParameters { u32 sampleRate; //!< The sample rate to use for the renderer u32 sampleCount; //!< The buffer sample count u32 mixBufferCount; //!< The amount of mix buffers to use @@ -36,7 +36,7 @@ namespace skyline { u32 _unk0_; u32 revision; //!< The revision of audren to use }; - static_assert(sizeof(AudioRendererParams) == 0x34); + static_assert(sizeof(AudioRendererParameters) == 0x34); /** * @brief Header containing information about the software side audren implementation @@ -63,21 +63,19 @@ namespace skyline { */ class IAudioRenderer : public BaseService { private: - AudioRendererParams rendererParams; //!< The parameters to use for the renderer + AudioRendererParameters parameters; //!< The parameters to use for the renderer RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used std::shared_ptr track; //!< The audio track associated with the audio renderer std::shared_ptr releaseEvent; //!< The KEvent that is signalled when a buffer has been released std::vector memoryPools; //!< An vector of all memory pools that the guest may need std::vector effects; //!< An vector of all effects that the guest may need std::vector voices; //!< An vector of all voices that the guest may need - std::vector sampleBuffer; //!< The final output data that is appended to the stream - + std::array sampleBuffer; //!< The final output data that is appended to the stream 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 + * @return The amount of samples present in the buffer */ void MixFinalBuffer(); @@ -88,9 +86,9 @@ namespace skyline { public: /** - * @param params The parameters to use for rendering + * @param parameters The parameters to use for rendering */ - IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams ¶ms); + IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParameters ¶meters); /** * @brief Closes the audio track