summaryrefslogtreecommitdiffstats
path: root/src/audio_core/out/audio_out_system.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio_core/out/audio_out_system.cpp')
-rw-r--r--src/audio_core/out/audio_out_system.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/audio_core/out/audio_out_system.cpp b/src/audio_core/out/audio_out_system.cpp
new file mode 100644
index 000000000..35afddf06
--- /dev/null
+++ b/src/audio_core/out/audio_out_system.cpp
@@ -0,0 +1,207 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <mutex>
+
+#include "audio_core/audio_event.h"
+#include "audio_core/audio_manager.h"
+#include "audio_core/out/audio_out_system.h"
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/kernel/k_event.h"
+
+namespace AudioCore::AudioOut {
+
+System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_)
+ : system{system_}, buffer_event{event_},
+ session_id{session_id_}, session{std::make_unique<DeviceSession>(system_)} {}
+
+System::~System() {
+ Finalize();
+}
+
+void System::Finalize() {
+ Stop();
+ session->Finalize();
+ buffer_event->GetWritableEvent().Signal();
+}
+
+std::string_view System::GetDefaultOutputDeviceName() {
+ return "DeviceOut";
+}
+
+Result System::IsConfigValid(std::string_view device_name, const AudioOutParameter& in_params) {
+ if ((device_name.size() > 0) && (device_name != GetDefaultOutputDeviceName())) {
+ return Service::Audio::ERR_INVALID_DEVICE_NAME;
+ }
+
+ if (in_params.sample_rate != TargetSampleRate && in_params.sample_rate > 0) {
+ return Service::Audio::ERR_INVALID_SAMPLE_RATE;
+ }
+
+ if (in_params.channel_count == 0 || in_params.channel_count == 2 ||
+ in_params.channel_count == 6) {
+ return ResultSuccess;
+ }
+
+ return Service::Audio::ERR_INVALID_CHANNEL_COUNT;
+}
+
+Result System::Initialize(std::string& device_name, const AudioOutParameter& in_params, u32 handle_,
+ u64& applet_resource_user_id_) {
+ auto result = IsConfigValid(device_name, in_params);
+ if (result.IsError()) {
+ return result;
+ }
+
+ handle = handle_;
+ applet_resource_user_id = applet_resource_user_id_;
+ if (device_name.empty() || device_name[0] == '\0') {
+ name = std::string(GetDefaultOutputDeviceName());
+ } else {
+ name = std::move(device_name);
+ }
+
+ sample_rate = TargetSampleRate;
+ sample_format = SampleFormat::PcmInt16;
+ channel_count = in_params.channel_count <= 2 ? 2 : 6;
+ volume = 1.0f;
+ return ResultSuccess;
+}
+
+void System::StartSession() {
+ session->Start();
+}
+
+size_t System::GetSessionId() const {
+ return session_id;
+}
+
+Result System::Start() {
+ if (state != State::Stopped) {
+ return Service::Audio::ERR_OPERATION_FAILED;
+ }
+
+ session->Initialize(name, sample_format, channel_count, session_id, handle,
+ applet_resource_user_id, Sink::StreamType::Out);
+ session->SetVolume(volume);
+ session->Start();
+ state = State::Started;
+
+ std::vector<AudioBuffer> buffers_to_flush{};
+ buffers.RegisterBuffers(buffers_to_flush);
+ session->AppendBuffers(buffers_to_flush);
+
+ return ResultSuccess;
+}
+
+Result System::Stop() {
+ if (state == State::Started) {
+ session->Stop();
+ session->SetVolume(0.0f);
+ state = State::Stopped;
+ }
+
+ return ResultSuccess;
+}
+
+bool System::AppendBuffer(const AudioOutBuffer& buffer, u64 tag) {
+ if (buffers.GetTotalBufferCount() == BufferCount) {
+ return false;
+ }
+
+ AudioBuffer new_buffer{
+ .played_timestamp = 0, .samples = buffer.samples, .tag = tag, .size = buffer.size};
+
+ buffers.AppendBuffer(new_buffer);
+ RegisterBuffers();
+
+ return true;
+}
+
+void System::RegisterBuffers() {
+ if (state == State::Started) {
+ std::vector<AudioBuffer> registered_buffers{};
+ buffers.RegisterBuffers(registered_buffers);
+ session->AppendBuffers(registered_buffers);
+ }
+}
+
+void System::ReleaseBuffers() {
+ bool signal{buffers.ReleaseBuffers(system.CoreTiming(), *session)};
+ if (signal) {
+ // Signal if any buffer was released, or if none are registered, we need more.
+ buffer_event->GetWritableEvent().Signal();
+ }
+}
+
+u32 System::GetReleasedBuffers(std::span<u64> tags) {
+ return buffers.GetReleasedBuffers(tags);
+}
+
+bool System::FlushAudioOutBuffers() {
+ if (state != State::Started) {
+ return false;
+ }
+
+ u32 buffers_released{};
+ buffers.FlushBuffers(buffers_released);
+
+ if (buffers_released > 0) {
+ buffer_event->GetWritableEvent().Signal();
+ }
+ return true;
+}
+
+u16 System::GetChannelCount() const {
+ return channel_count;
+}
+
+u32 System::GetSampleRate() const {
+ return sample_rate;
+}
+
+SampleFormat System::GetSampleFormat() const {
+ return sample_format;
+}
+
+State System::GetState() {
+ switch (state) {
+ case State::Started:
+ case State::Stopped:
+ return state;
+ default:
+ LOG_ERROR(Service_Audio, "AudioOut invalid state!");
+ state = State::Stopped;
+ break;
+ }
+ return state;
+}
+
+std::string System::GetName() const {
+ return name;
+}
+
+f32 System::GetVolume() const {
+ return volume;
+}
+
+void System::SetVolume(const f32 volume_) {
+ volume = volume_;
+ session->SetVolume(volume_);
+}
+
+bool System::ContainsAudioBuffer(const u64 tag) {
+ return buffers.ContainsBuffer(tag);
+}
+
+u32 System::GetBufferCount() {
+ return buffers.GetAppendedRegisteredCount();
+}
+
+u64 System::GetPlayedSampleCount() const {
+ return session->GetPlayedSampleCount();
+}
+
+} // namespace AudioCore::AudioOut