Compare commits

...

1 Commits

Author SHA1 Message Date
bunnei
f0fcb300de audio_renderer: Process audio data on another thread. 2020-01-22 19:57:04 -05:00
3 changed files with 66 additions and 9 deletions

View File

@@ -8,6 +8,7 @@
#include "audio_core/codec.h" #include "audio_core/codec.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/writable_event.h" #include "core/hle/kernel/writable_event.h"
#include "core/memory.h" #include "core/memory.h"
@@ -17,6 +18,18 @@ namespace AudioCore {
constexpr u32 STREAM_SAMPLE_RATE{48000}; constexpr u32 STREAM_SAMPLE_RATE{48000};
constexpr u32 STREAM_NUM_CHANNELS{2}; constexpr u32 STREAM_NUM_CHANNELS{2};
static void RunThread(AudioRenderer::SynchState& synch_state) {
MicroProfileOnThreadCreate("AudioRendererThread");
while (synch_state.is_running) {
auto next{synch_state.input_queue.PopWait()};
if (next.empty()) {
continue;
}
synch_state.output_queue.Push(synch_state.renderer.UpdateAudioRenderer(std::move(next)));
}
}
class AudioRenderer::VoiceState { class AudioRenderer::VoiceState {
public: public:
bool IsPlaying() const { bool IsPlaying() const {
@@ -72,12 +85,14 @@ private:
EffectOutStatus out_status{}; EffectOutStatus out_status{};
EffectInStatus info{}; EffectInStatus info{};
}; };
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Memory::Memory& memory_, AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Memory::Memory& memory_,
AudioRendererParameter params, AudioRendererParameter params,
std::shared_ptr<Kernel::WritableEvent> buffer_event, std::shared_ptr<Kernel::WritableEvent> buffer_event,
std::size_t instance_number) std::size_t instance_number)
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
effects(params.effect_count), memory{memory_} { effects(params.effect_count), memory{memory_},
synch_state{*this}, thread{RunThread, std::ref(synch_state)} {
audio_out = std::make_unique<AudioCore::AudioOut>(); audio_out = std::make_unique<AudioCore::AudioOut>();
stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
@@ -90,7 +105,12 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Memory::Memo
QueueMixedBuffer(2); QueueMixedBuffer(2);
} }
AudioRenderer::~AudioRenderer() = default; AudioRenderer::~AudioRenderer() {
// Terminate thread
synch_state.is_running = false;
QueueUpdateAudioRenderer({}); // Queue empty data to force thread to wakeup
thread.join();
}
u32 AudioRenderer::GetSampleRate() const { u32 AudioRenderer::GetSampleRate() const {
return worker_params.sample_rate; return worker_params.sample_rate;
@@ -113,7 +133,15 @@ static constexpr u32 VersionFromRevision(u32_le rev) {
return ((rev >> 24) & 0xff) - 0x30; return ((rev >> 24) & 0xff) - 0x30;
} }
std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) { void AudioRenderer::QueueUpdateAudioRenderer(std::vector<u8>&& input_params) {
synch_state.input_queue.Push(std::move(input_params));
}
std::vector<u8> AudioRenderer::GetUpdateAudioRendererResult() {
return synch_state.output_queue.PopWait();
}
std::vector<u8> AudioRenderer::UpdateAudioRenderer(std::vector<u8>&& input_params) {
// Copy UpdateDataHeader struct // Copy UpdateDataHeader struct
UpdateDataHeader config{}; UpdateDataHeader config{};
std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader)); std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader));

View File

@@ -6,12 +6,14 @@
#include <array> #include <array>
#include <memory> #include <memory>
#include <thread>
#include <vector> #include <vector>
#include "audio_core/stream.h" #include "audio_core/stream.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/swap.h" #include "common/swap.h"
#include "common/threadsafe_queue.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
namespace Core::Timing { namespace Core::Timing {
@@ -226,14 +228,29 @@ public:
std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
~AudioRenderer(); ~AudioRenderer();
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params); void QueueUpdateAudioRenderer(std::vector<u8>&& input_params);
void QueueMixedBuffer(Buffer::Tag tag); std::vector<u8> GetUpdateAudioRendererResult();
void ReleaseAndQueueBuffers(); std::vector<u8> UpdateAudioRenderer(std::vector<u8>&& input_params);
u32 GetSampleRate() const; u32 GetSampleRate() const;
u32 GetSampleCount() const; u32 GetSampleCount() const;
u32 GetMixBufferCount() const; u32 GetMixBufferCount() const;
Stream::State GetStreamState() const; Stream::State GetStreamState() const;
/// Struct used to synchronize the AudioRenderer thread
struct SynchState final {
SynchState(AudioRenderer& renderer) : renderer{renderer} {}
std::atomic_bool is_running{true};
Common::SPSCQueue<std::vector<u8>> input_queue;
Common::SPSCQueue<std::vector<u8>> output_queue;
AudioRenderer& renderer;
};
private:
void QueueMixedBuffer(Buffer::Tag tag);
void ReleaseAndQueueBuffers();
private: private:
class EffectState; class EffectState;
class VoiceState; class VoiceState;
@@ -245,6 +262,10 @@ private:
std::unique_ptr<AudioOut> audio_out; std::unique_ptr<AudioOut> audio_out;
StreamPtr stream; StreamPtr stream;
Memory::Memory& memory; Memory::Memory& memory;
// Used for thread management
SynchState synch_state;
std::thread thread;
}; };
} // namespace AudioCore } // namespace AudioCore

View File

@@ -92,9 +92,17 @@ private:
} }
void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called"); LOG_DEBUG(Service_Audio, "called");
renderer->QueueUpdateAudioRenderer(ctx.ReadBuffer());
ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); ctx.SleepClientThread("IAudioRenderer::RequestUpdateImpl", UINT64_MAX,
[=](std::shared_ptr<Kernel::Thread> thread,
Kernel::HLERequestContext& ctx,
Kernel::ThreadWakeupReason reason) {
ctx.WriteBuffer(renderer->GetUpdateAudioRendererResult());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
},
system_event.writable);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }