summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/audio_renderer.cpp178
-rw-r--r--src/audio_core/audio_renderer.h6
-rw-r--r--src/core/hle/service/audio/audren_u.cpp10
3 files changed, 115 insertions, 79 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 80ffddb10..0757cd804 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -12,6 +12,7 @@
#include "audio_core/voice_context.h"
#include "common/logging/log.h"
#include "common/settings.h"
+#include "core/core_timing.h"
#include "core/memory.h"
namespace {
@@ -68,7 +69,9 @@ namespace {
} // namespace
namespace AudioCore {
-AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
+constexpr s32 NUM_BUFFERS = 2;
+
+AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_,
AudioCommon::AudioRendererParameter params,
Stream::ReleaseCallback&& release_callback,
std::size_t instance_number)
@@ -77,7 +80,8 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
sink_context(params.sink_count), splitter_context(),
voices(params.voice_count), memory{memory_},
command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context,
- memory) {
+ memory),
+ core_timing{core_timing_} {
behavior_info.SetUserRevision(params.revision);
splitter_context.Initialize(behavior_info, params.splitter_count,
params.num_splitter_send_channels);
@@ -86,16 +90,27 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
stream = audio_out->OpenStream(
core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
- audio_out->StartStream(stream);
-
- QueueMixedBuffer(0);
- QueueMixedBuffer(1);
- QueueMixedBuffer(2);
- QueueMixedBuffer(3);
+ process_event = Core::Timing::CreateEvent(
+ fmt::format("AudioRenderer-Instance{}-Process", instance_number),
+ [this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); });
+ for (s32 i = 0; i < NUM_BUFFERS; ++i) {
+ QueueMixedBuffer(i);
+ }
}
AudioRenderer::~AudioRenderer() = default;
+ResultCode AudioRenderer::Start() {
+ audio_out->StartStream(stream);
+ ReleaseAndQueueBuffers();
+ return ResultSuccess;
+}
+
+ResultCode AudioRenderer::Stop() {
+ audio_out->StopStream(stream);
+ return ResultSuccess;
+}
+
u32 AudioRenderer::GetSampleRate() const {
return worker_params.sample_rate;
}
@@ -114,89 +129,88 @@ Stream::State AudioRenderer::GetStreamState() const {
ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params) {
+ {
+ std::scoped_lock lock{mutex};
+ InfoUpdater info_updater{input_params, output_params, behavior_info};
- InfoUpdater info_updater{input_params, output_params, behavior_info};
-
- if (!info_updater.UpdateBehaviorInfo(behavior_info)) {
- LOG_ERROR(Audio, "Failed to update behavior info input parameters");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
-
- if (!info_updater.UpdateMemoryPools(memory_pool_info)) {
- LOG_ERROR(Audio, "Failed to update memory pool parameters");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
-
- if (!info_updater.UpdateVoiceChannelResources(voice_context)) {
- LOG_ERROR(Audio, "Failed to update voice channel resource parameters");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
+ if (!info_updater.UpdateBehaviorInfo(behavior_info)) {
+ LOG_ERROR(Audio, "Failed to update behavior info input parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
- if (!info_updater.UpdateVoices(voice_context, memory_pool_info, 0)) {
- LOG_ERROR(Audio, "Failed to update voice parameters");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
+ if (!info_updater.UpdateMemoryPools(memory_pool_info)) {
+ LOG_ERROR(Audio, "Failed to update memory pool parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
- // TODO(ogniK): Deal with stopped audio renderer but updates still taking place
- if (!info_updater.UpdateEffects(effect_context, true)) {
- LOG_ERROR(Audio, "Failed to update effect parameters");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
+ if (!info_updater.UpdateVoiceChannelResources(voice_context)) {
+ LOG_ERROR(Audio, "Failed to update voice channel resource parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
- if (behavior_info.IsSplitterSupported()) {
- if (!info_updater.UpdateSplitterInfo(splitter_context)) {
- LOG_ERROR(Audio, "Failed to update splitter parameters");
+ if (!info_updater.UpdateVoices(voice_context, memory_pool_info, 0)) {
+ LOG_ERROR(Audio, "Failed to update voice parameters");
return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- }
- const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
- splitter_context, effect_context);
+ // TODO(ogniK): Deal with stopped audio renderer but updates still taking place
+ if (!info_updater.UpdateEffects(effect_context, true)) {
+ LOG_ERROR(Audio, "Failed to update effect parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
- if (mix_result.IsError()) {
- LOG_ERROR(Audio, "Failed to update mix parameters");
- return mix_result;
- }
+ if (behavior_info.IsSplitterSupported()) {
+ if (!info_updater.UpdateSplitterInfo(splitter_context)) {
+ LOG_ERROR(Audio, "Failed to update splitter parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+ }
- // TODO(ogniK): Sinks
- if (!info_updater.UpdateSinks(sink_context)) {
- LOG_ERROR(Audio, "Failed to update sink parameters");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
+ const auto mix_result = info_updater.UpdateMixes(
+ mix_context, worker_params.mix_buffer_count, splitter_context, effect_context);
- // TODO(ogniK): Performance buffer
- if (!info_updater.UpdatePerformanceBuffer()) {
- LOG_ERROR(Audio, "Failed to update performance buffer parameters");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
+ if (mix_result.IsError()) {
+ LOG_ERROR(Audio, "Failed to update mix parameters");
+ return mix_result;
+ }
- if (!info_updater.UpdateErrorInfo(behavior_info)) {
- LOG_ERROR(Audio, "Failed to update error info");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
+ // TODO(ogniK): Sinks
+ if (!info_updater.UpdateSinks(sink_context)) {
+ LOG_ERROR(Audio, "Failed to update sink parameters");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
- if (behavior_info.IsElapsedFrameCountSupported()) {
- if (!info_updater.UpdateRendererInfo(elapsed_frame_count)) {
- LOG_ERROR(Audio, "Failed to update renderer info");
+ // TODO(ogniK): Performance buffer
+ if (!info_updater.UpdatePerformanceBuffer()) {
+ LOG_ERROR(Audio, "Failed to update performance buffer parameters");
return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
}
- }
- // TODO(ogniK): Statistics
- if (!info_updater.WriteOutputHeader()) {
- LOG_ERROR(Audio, "Failed to write output header");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
+ if (!info_updater.UpdateErrorInfo(behavior_info)) {
+ LOG_ERROR(Audio, "Failed to update error info");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
- // TODO(ogniK): Check when all sections are implemented
+ if (behavior_info.IsElapsedFrameCountSupported()) {
+ if (!info_updater.UpdateRendererInfo(elapsed_frame_count)) {
+ LOG_ERROR(Audio, "Failed to update renderer info");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+ }
+ // TODO(ogniK): Statistics
- if (!info_updater.CheckConsumedSize()) {
- LOG_ERROR(Audio, "Audio buffers were not consumed!");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
+ if (!info_updater.WriteOutputHeader()) {
+ LOG_ERROR(Audio, "Failed to write output header");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
- ReleaseAndQueueBuffers();
+ // TODO(ogniK): Check when all sections are implemented
+ if (!info_updater.CheckConsumedSize()) {
+ LOG_ERROR(Audio, "Audio buffers were not consumed!");
+ return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
+ }
+ }
return ResultSuccess;
}
@@ -315,10 +329,24 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
}
void AudioRenderer::ReleaseAndQueueBuffers() {
- const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)};
- for (const auto& tag : released_buffers) {
- QueueMixedBuffer(tag);
+ if (!stream->IsPlaying()) {
+ return;
+ }
+
+ {
+ std::scoped_lock lock{mutex};
+ const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)};
+ for (const auto& tag : released_buffers) {
+ QueueMixedBuffer(tag);
+ }
}
+
+ const f32 sample_rate = static_cast<f32>(GetSampleRate());
+ const f32 sample_count = static_cast<f32>(GetSampleCount());
+ const f32 consume_rate = sample_rate / (sample_count * (sample_count / 240));
+ const s32 ms = (1000 / static_cast<s32>(consume_rate)) - 1;
+ const std::chrono::milliseconds next_event_time(std::max(ms / NUM_BUFFERS, 1));
+ core_timing.ScheduleEvent(next_event_time, process_event, {});
}
} // namespace AudioCore
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 18567f618..88fdd13dd 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -6,6 +6,7 @@
#include <array>
#include <memory>
+#include <mutex>
#include <vector>
#include "audio_core/behavior_info.h"
@@ -45,6 +46,8 @@ public:
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params);
+ [[nodiscard]] ResultCode Start();
+ [[nodiscard]] ResultCode Stop();
void QueueMixedBuffer(Buffer::Tag tag);
void ReleaseAndQueueBuffers();
[[nodiscard]] u32 GetSampleRate() const;
@@ -68,6 +71,9 @@ private:
Core::Memory::Memory& memory;
CommandGenerator command_generator;
std::size_t elapsed_frame_count{};
+ Core::Timing::CoreTiming& core_timing;
+ std::shared_ptr<Core::Timing::EventType> process_event;
+ std::mutex mutex;
};
} // namespace AudioCore
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 800feba6e..feb5150e1 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -110,17 +110,19 @@ private:
void Start(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
+ const auto result = renderer->Start();
- rb.Push(ResultSuccess);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
}
void Stop(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
+ const auto result = renderer->Stop();
- rb.Push(ResultSuccess);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
}
void QuerySystemEvent(Kernel::HLERequestContext& ctx) {