summaryrefslogtreecommitdiffstats
path: root/src/audio_core/in
diff options
context:
space:
mode:
authorKelebek1 <eeeedddccc@hotmail.co.uk>2022-07-17 00:48:45 +0200
committerKelebek1 <eeeedddccc@hotmail.co.uk>2022-07-22 02:11:32 +0200
commit458da8a94877677f086f06cdeecf959ec4283a33 (patch)
tree583166d77602ad90a0d552f37de8729ad80fd6c1 /src/audio_core/in
parentMerge pull request #8598 from Link4565/recv-dontwait (diff)
downloadyuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.gz
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.bz2
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.lz
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.xz
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.zst
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.zip
Diffstat (limited to '')
-rw-r--r--src/audio_core/in/audio_in.cpp100
-rw-r--r--src/audio_core/in/audio_in.h147
-rw-r--r--src/audio_core/in/audio_in_system.cpp213
-rw-r--r--src/audio_core/in/audio_in_system.h275
-rw-r--r--src/audio_core/info_updater.cpp511
-rw-r--r--src/audio_core/info_updater.h57
6 files changed, 735 insertions, 568 deletions
diff --git a/src/audio_core/in/audio_in.cpp b/src/audio_core/in/audio_in.cpp
new file mode 100644
index 000000000..c946895d6
--- /dev/null
+++ b/src/audio_core/in/audio_in.cpp
@@ -0,0 +1,100 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "audio_core/audio_in_manager.h"
+#include "audio_core/in/audio_in.h"
+#include "core/hle/kernel/k_event.h"
+
+namespace AudioCore::AudioIn {
+
+In::In(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
+ : manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
+ session_id_} {}
+
+void In::Free() {
+ std::scoped_lock l{parent_mutex};
+ manager.ReleaseSessionId(system.GetSessionId());
+}
+
+System& In::GetSystem() {
+ return system;
+}
+
+AudioIn::State In::GetState() {
+ std::scoped_lock l{parent_mutex};
+ return system.GetState();
+}
+
+Result In::StartSystem() {
+ std::scoped_lock l{parent_mutex};
+ return system.Start();
+}
+
+void In::StartSession() {
+ std::scoped_lock l{parent_mutex};
+ system.StartSession();
+}
+
+Result In::StopSystem() {
+ std::scoped_lock l{parent_mutex};
+ return system.Stop();
+}
+
+Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
+ std::scoped_lock l{parent_mutex};
+
+ if (system.AppendBuffer(buffer, tag)) {
+ return ResultSuccess;
+ }
+ return Service::Audio::ERR_BUFFER_COUNT_EXCEEDED;
+}
+
+void In::ReleaseAndRegisterBuffers() {
+ std::scoped_lock l{parent_mutex};
+ if (system.GetState() == State::Started) {
+ system.ReleaseBuffers();
+ system.RegisterBuffers();
+ }
+}
+
+bool In::FlushAudioInBuffers() {
+ std::scoped_lock l{parent_mutex};
+ return system.FlushAudioInBuffers();
+}
+
+u32 In::GetReleasedBuffers(std::span<u64> tags) {
+ std::scoped_lock l{parent_mutex};
+ return system.GetReleasedBuffers(tags);
+}
+
+Kernel::KReadableEvent& In::GetBufferEvent() {
+ std::scoped_lock l{parent_mutex};
+ return event->GetReadableEvent();
+}
+
+f32 In::GetVolume() {
+ std::scoped_lock l{parent_mutex};
+ return system.GetVolume();
+}
+
+void In::SetVolume(f32 volume) {
+ std::scoped_lock l{parent_mutex};
+ system.SetVolume(volume);
+}
+
+bool In::ContainsAudioBuffer(u64 tag) {
+ std::scoped_lock l{parent_mutex};
+ return system.ContainsAudioBuffer(tag);
+}
+
+u32 In::GetBufferCount() {
+ std::scoped_lock l{parent_mutex};
+ return system.GetBufferCount();
+}
+
+u64 In::GetPlayedSampleCount() {
+ std::scoped_lock l{parent_mutex};
+ return system.GetPlayedSampleCount();
+}
+
+} // namespace AudioCore::AudioIn
diff --git a/src/audio_core/in/audio_in.h b/src/audio_core/in/audio_in.h
new file mode 100644
index 000000000..6253891d5
--- /dev/null
+++ b/src/audio_core/in/audio_in.h
@@ -0,0 +1,147 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <mutex>
+
+#include "audio_core/in/audio_in_system.h"
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KEvent;
+class KReadableEvent;
+} // namespace Kernel
+
+namespace AudioCore::AudioIn {
+class Manager;
+
+/**
+ * Interface between the service and audio in system. Mainly responsible for forwarding service
+ * calls to the system.
+ */
+class In {
+public:
+ explicit In(Core::System& system, Manager& manager, Kernel::KEvent* event, size_t session_id);
+
+ /**
+ * Free this audio in from the audio in manager.
+ */
+ void Free();
+
+ /**
+ * Get this audio in's system.
+ */
+ System& GetSystem();
+
+ /**
+ * Get the current state.
+ *
+ * @return Started or Stopped.
+ */
+ AudioIn::State GetState();
+
+ /**
+ * Start the system
+ *
+ * @return Result code
+ */
+ Result StartSystem();
+
+ /**
+ * Start the system's device session.
+ */
+ void StartSession();
+
+ /**
+ * Stop the system.
+ *
+ * @return Result code
+ */
+ Result StopSystem();
+
+ /**
+ * Append a new buffer to the system, the buffer event will be signalled when it is filled.
+ *
+ * @param buffer - The new buffer to append.
+ * @param tag - Unique tag for this buffer.
+ * @return Result code.
+ */
+ Result AppendBuffer(const AudioInBuffer& buffer, u64 tag);
+
+ /**
+ * Release all completed buffers, and register any appended.
+ */
+ void ReleaseAndRegisterBuffers();
+
+ /**
+ * Flush all buffers.
+ */
+ bool FlushAudioInBuffers();
+
+ /**
+ * Get all of the currently released buffers.
+ *
+ * @param tags - Output container for the buffer tags which were released.
+ * @return The number of buffers released.
+ */
+ u32 GetReleasedBuffers(std::span<u64> tags);
+
+ /**
+ * Get the buffer event for this audio in, this event will be signalled when a buffer is filled.
+ *
+ * @return The buffer event.
+ */
+ Kernel::KReadableEvent& GetBufferEvent();
+
+ /**
+ * Get the current system volume.
+ *
+ * @return The current volume.
+ */
+ f32 GetVolume();
+
+ /**
+ * Set the system volume.
+ *
+ * @param volume - The volume to set.
+ */
+ void SetVolume(f32 volume);
+
+ /**
+ * Check if a buffer is in the system.
+ *
+ * @param tag - The tag to search for.
+ * @return True if the buffer is in the system, otherwise false.
+ */
+ bool ContainsAudioBuffer(u64 tag);
+
+ /**
+ * Get the maximum number of buffers.
+ *
+ * @return The maximum number of buffers.
+ */
+ u32 GetBufferCount();
+
+ /**
+ * Get the total played sample count for this audio in.
+ *
+ * @return The played sample count.
+ */
+ u64 GetPlayedSampleCount();
+
+private:
+ /// The AudioIn::Manager this audio in is registered with
+ Manager& manager;
+ /// Manager's mutex
+ std::recursive_mutex& parent_mutex;
+ /// Buffer event, signalled when buffers are ready to be released
+ Kernel::KEvent* event;
+ /// Main audio in system
+ System system;
+};
+
+} // namespace AudioCore::AudioIn
diff --git a/src/audio_core/in/audio_in_system.cpp b/src/audio_core/in/audio_in_system.cpp
new file mode 100644
index 000000000..ec5d37ed4
--- /dev/null
+++ b/src/audio_core/in/audio_in_system.cpp
@@ -0,0 +1,213 @@
+// 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/in/audio_in_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::AudioIn {
+
+System::System(Core::System& system_, Kernel::KEvent* event_, const 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();
+}
+
+void System::StartSession() {
+ session->Start();
+}
+
+size_t System::GetSessionId() const {
+ return session_id;
+}
+
+std::string_view System::GetDefaultDeviceName() {
+ return "BuiltInHeadset";
+}
+
+std::string_view System::GetDefaultUacDeviceName() {
+ return "Uac";
+}
+
+Result System::IsConfigValid(const std::string_view device_name,
+ const AudioInParameter& in_params) {
+ if ((device_name.size() > 0) &&
+ (device_name != GetDefaultDeviceName() && device_name != GetDefaultUacDeviceName())) {
+ 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;
+ }
+
+ return ResultSuccess;
+}
+
+Result System::Initialize(std::string& device_name, const AudioInParameter& in_params,
+ const u32 handle_, const 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(GetDefaultDeviceName());
+ } 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;
+ is_uac = name == "Uac";
+ return ResultSuccess;
+}
+
+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::In);
+ 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 AudioInBuffer& buffer, const 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::FlushAudioInBuffers() {
+ 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, "AudioIn 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();
+}
+
+bool System::IsUac() const {
+ return is_uac;
+}
+
+} // namespace AudioCore::AudioIn
diff --git a/src/audio_core/in/audio_in_system.h b/src/audio_core/in/audio_in_system.h
new file mode 100644
index 000000000..165e35d83
--- /dev/null
+++ b/src/audio_core/in/audio_in_system.h
@@ -0,0 +1,275 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <atomic>
+#include <memory>
+#include <span>
+#include <string>
+
+#include "audio_core/common/common.h"
+#include "audio_core/device/audio_buffers.h"
+#include "audio_core/device/device_session.h"
+#include "core/hle/service/audio/errors.h"
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KEvent;
+}
+
+namespace AudioCore::AudioIn {
+
+constexpr SessionTypes SessionType = SessionTypes::AudioIn;
+
+struct AudioInParameter {
+ /* 0x0 */ s32_le sample_rate;
+ /* 0x4 */ u16_le channel_count;
+ /* 0x6 */ u16_le reserved;
+};
+static_assert(sizeof(AudioInParameter) == 0x8, "AudioInParameter is an invalid size");
+
+struct AudioInParameterInternal {
+ /* 0x0 */ u32_le sample_rate;
+ /* 0x4 */ u32_le channel_count;
+ /* 0x8 */ u32_le sample_format;
+ /* 0xC */ u32_le state;
+};
+static_assert(sizeof(AudioInParameterInternal) == 0x10,
+ "AudioInParameterInternal is an invalid size");
+
+struct AudioInBuffer {
+ /* 0x00 */ AudioInBuffer* next;
+ /* 0x08 */ VAddr samples;
+ /* 0x10 */ u64 capacity;
+ /* 0x18 */ u64 size;
+ /* 0x20 */ u64 offset;
+};
+static_assert(sizeof(AudioInBuffer) == 0x28, "AudioInBuffer is an invalid size");
+
+enum class State {
+ Started,
+ Stopped,
+};
+
+/**
+ * Controls and drives audio input.
+ */
+class System {
+public:
+ explicit System(Core::System& system, Kernel::KEvent* event, size_t session_id);
+ ~System();
+
+ /**
+ * Get the default audio input device name.
+ *
+ * @return The default audio input device name.
+ */
+ std::string_view GetDefaultDeviceName();
+
+ /**
+ * Get the default USB audio input device name.
+ * This is preferred over non-USB as some games refuse to work with the BuiltInHeadset
+ * (e.g Let's Sing).
+ *
+ * @return The default USB audio input device name.
+ */
+ std::string_view GetDefaultUacDeviceName();
+
+ /**
+ * Is the given initialize config valid?
+ *
+ * @param device_name - The name of the requested input device.
+ * @param in_params - Input parameters, see AudioInParameter.
+ * @return Result code.
+ */
+ Result IsConfigValid(std::string_view device_name, const AudioInParameter& in_params);
+
+ /**
+ * Initialize this system.
+ *
+ * @param device_name - The name of the requested input device.
+ * @param in_params - Input parameters, see AudioInParameter.
+ * @param handle - Unused.
+ * @param applet_resource_user_id - Unused.
+ * @return Result code.
+ */
+ Result Initialize(std::string& device_name, const AudioInParameter& in_params, u32 handle,
+ u64 applet_resource_user_id);
+
+ /**
+ * Start this system.
+ *
+ * @return Result code.
+ */
+ Result Start();
+
+ /**
+ * Stop this system.
+ *
+ * @return Result code.
+ */
+ Result Stop();
+
+ /**
+ * Finalize this system.
+ */
+ void Finalize();
+
+ /**
+ * Start this system's device session.
+ */
+ void StartSession();
+
+ /**
+ * Get this system's id.
+ */
+ size_t GetSessionId() const;
+
+ /**
+ * Append a new buffer to the device.
+ *
+ * @param buffer - New buffer to append.
+ * @param tag - Unique tag of the buffer.
+ * @return True if the buffer was appended, otherwise false.
+ */
+ bool AppendBuffer(const AudioInBuffer& buffer, u64 tag);
+
+ /**
+ * Register all appended buffers.
+ */
+ void RegisterBuffers();
+
+ /**
+ * Release all registered buffers.
+ */
+ void ReleaseBuffers();
+
+ /**
+ * Get all released buffers.
+ *
+ * @param tags - Container to be filled with the released buffers' tags.
+ * @return The number of buffers released.
+ */
+ u32 GetReleasedBuffers(std::span<u64> tags);
+
+ /**
+ * Flush all appended and registered buffers.
+ *
+ * @return True if buffers were successfully flushed, otherwise false.
+ */
+ bool FlushAudioInBuffers();
+
+ /**
+ * Get this system's current channel count.
+ *
+ * @return The channel count.
+ */
+ u16 GetChannelCount() const;
+
+ /**
+ * Get this system's current sample rate.
+ *
+ * @return The sample rate.
+ */
+ u32 GetSampleRate() const;
+
+ /**
+ * Get this system's current sample format.
+ *
+ * @return The sample format.
+ */
+ SampleFormat GetSampleFormat() const;
+
+ /**
+ * Get this system's current state.
+ *
+ * @return The current state.
+ */
+ State GetState();
+
+ /**
+ * Get this system's name.
+ *
+ * @return The system's name.
+ */
+ std::string GetName() const;
+
+ /**
+ * Get this system's current volume.
+ *
+ * @return The system's current volume.
+ */
+ f32 GetVolume() const;
+
+ /**
+ * Set this system's current volume.
+ *
+ * @param The new volume.
+ */
+ void SetVolume(f32 volume);
+
+ /**
+ * Does the system contain this buffer?
+ *
+ * @param tag - Unique tag to search for.
+ * @return True if the buffer is in the system, otherwise false.
+ */
+ bool ContainsAudioBuffer(u64 tag);
+
+ /**
+ * Get the maximum number of usable buffers (default 32).
+ *
+ * @return The number of buffers.
+ */
+ u32 GetBufferCount();
+
+ /**
+ * Get the total number of samples played by this system.
+ *
+ * @return The number of samples.
+ */
+ u64 GetPlayedSampleCount() const;
+
+ /**
+ * Is this system using a USB device?
+ *
+ * @return True if using a USB device, otherwise false.
+ */
+ bool IsUac() const;
+
+private:
+ /// Core system
+ Core::System& system;
+ /// (Unused)
+ u32 handle{};
+ /// (Unused)
+ u64 applet_resource_user_id{};
+ /// Buffer event, signalled when a buffer is ready
+ Kernel::KEvent* buffer_event;
+ /// Session id of this system
+ size_t session_id{};
+ /// Device session for this system
+ std::unique_ptr<DeviceSession> session;
+ /// Audio buffers in use by this system
+ AudioBuffers<BufferCount> buffers{BufferCount};
+ /// Sample rate of this system
+ u32 sample_rate{};
+ /// Sample format of this system
+ SampleFormat sample_format{SampleFormat::PcmInt16};
+ /// Channel count of this system
+ u16 channel_count{};
+ /// State of this system
+ std::atomic<State> state{State::Stopped};
+ /// Name of this system
+ std::string name{};
+ /// Volume of this system
+ f32 volume{1.0f};
+ /// Is this system's device USB?
+ bool is_uac{false};
+};
+
+} // namespace AudioCore::AudioIn
diff --git a/src/audio_core/info_updater.cpp b/src/audio_core/info_updater.cpp
deleted file mode 100644
index 0065e6e53..000000000
--- a/src/audio_core/info_updater.cpp
+++ /dev/null
@@ -1,511 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "audio_core/behavior_info.h"
-#include "audio_core/effect_context.h"
-#include "audio_core/info_updater.h"
-#include "audio_core/memory_pool.h"
-#include "audio_core/mix_context.h"
-#include "audio_core/sink_context.h"
-#include "audio_core/splitter_context.h"
-#include "audio_core/voice_context.h"
-#include "common/logging/log.h"
-
-namespace AudioCore {
-
-InfoUpdater::InfoUpdater(const std::vector<u8>& in_params_, std::vector<u8>& out_params_,
- BehaviorInfo& behavior_info_)
- : in_params(in_params_), out_params(out_params_), behavior_info(behavior_info_) {
- ASSERT(
- AudioCommon::CanConsumeBuffer(in_params.size(), 0, sizeof(AudioCommon::UpdateDataHeader)));
- std::memcpy(&input_header, in_params.data(), sizeof(AudioCommon::UpdateDataHeader));
- output_header.total_size = sizeof(AudioCommon::UpdateDataHeader);
-}
-
-InfoUpdater::~InfoUpdater() = default;
-
-bool InfoUpdater::UpdateBehaviorInfo(BehaviorInfo& in_behavior_info) {
- if (input_header.size.behavior != sizeof(BehaviorInfo::InParams)) {
- LOG_ERROR(Audio, "Behavior info is an invalid size, expecting 0x{:X} but got 0x{:X}",
- sizeof(BehaviorInfo::InParams), input_header.size.behavior);
- return false;
- }
-
- if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset,
- sizeof(BehaviorInfo::InParams))) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- BehaviorInfo::InParams behavior_in{};
- std::memcpy(&behavior_in, in_params.data() + input_offset, sizeof(BehaviorInfo::InParams));
- input_offset += sizeof(BehaviorInfo::InParams);
-
- // Make sure it's an audio revision we can actually support
- if (!AudioCommon::IsValidRevision(behavior_in.revision)) {
- LOG_ERROR(Audio, "Invalid input revision, revision=0x{:08X}", behavior_in.revision);
- return false;
- }
-
- // Make sure that our behavior info revision matches the input
- if (in_behavior_info.GetUserRevision() != behavior_in.revision) {
- LOG_ERROR(Audio,
- "User revision differs from input revision, expecting 0x{:08X} but got 0x{:08X}",
- in_behavior_info.GetUserRevision(), behavior_in.revision);
- return false;
- }
-
- // Update behavior info flags
- in_behavior_info.ClearError();
- in_behavior_info.UpdateFlags(behavior_in.flags);
-
- return true;
-}
-
-bool InfoUpdater::UpdateMemoryPools(std::vector<ServerMemoryPoolInfo>& memory_pool_info) {
- const auto memory_pool_count = memory_pool_info.size();
- const auto total_memory_pool_in = sizeof(ServerMemoryPoolInfo::InParams) * memory_pool_count;
- const auto total_memory_pool_out = sizeof(ServerMemoryPoolInfo::OutParams) * memory_pool_count;
-
- if (input_header.size.memory_pool != total_memory_pool_in) {
- LOG_ERROR(Audio, "Memory pools are an invalid size, expecting 0x{:X} but got 0x{:X}",
- total_memory_pool_in, input_header.size.memory_pool);
- return false;
- }
-
- if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, total_memory_pool_in)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- std::vector<ServerMemoryPoolInfo::InParams> mempool_in(memory_pool_count);
- std::vector<ServerMemoryPoolInfo::OutParams> mempool_out(memory_pool_count);
-
- std::memcpy(mempool_in.data(), in_params.data() + input_offset, total_memory_pool_in);
- input_offset += total_memory_pool_in;
-
- // Update our memory pools
- for (std::size_t i = 0; i < memory_pool_count; i++) {
- if (!memory_pool_info[i].Update(mempool_in[i], mempool_out[i])) {
- LOG_ERROR(Audio, "Failed to update memory pool {}!", i);
- return false;
- }
- }
-
- if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset,
- sizeof(BehaviorInfo::InParams))) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- std::memcpy(out_params.data() + output_offset, mempool_out.data(), total_memory_pool_out);
- output_offset += total_memory_pool_out;
- output_header.size.memory_pool = static_cast<u32>(total_memory_pool_out);
- return true;
-}
-
-bool InfoUpdater::UpdateVoiceChannelResources(VoiceContext& voice_context) {
- const auto voice_count = voice_context.GetVoiceCount();
- const auto voice_size = voice_count * sizeof(VoiceChannelResource::InParams);
- std::vector<VoiceChannelResource::InParams> resources_in(voice_count);
-
- if (input_header.size.voice_channel_resource != voice_size) {
- LOG_ERROR(Audio, "VoiceChannelResource is an invalid size, expecting 0x{:X} but got 0x{:X}",
- voice_size, input_header.size.voice_channel_resource);
- return false;
- }
-
- if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, voice_size)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- std::memcpy(resources_in.data(), in_params.data() + input_offset, voice_size);
- input_offset += voice_size;
-
- // Update our channel resources
- for (std::size_t i = 0; i < voice_count; i++) {
- // Grab our channel resource
- auto& resource = voice_context.GetChannelResource(i);
- resource.Update(resources_in[i]);
- }
-
- return true;
-}
-
-bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
- [[maybe_unused]] std::vector<ServerMemoryPoolInfo>& memory_pool_info,
- [[maybe_unused]] VAddr audio_codec_dsp_addr) {
- const auto voice_count = voice_context.GetVoiceCount();
- std::vector<VoiceInfo::InParams> voice_in(voice_count);
- std::vector<VoiceInfo::OutParams> voice_out(voice_count);
-
- const auto voice_in_size = voice_count * sizeof(VoiceInfo::InParams);
- const auto voice_out_size = voice_count * sizeof(VoiceInfo::OutParams);
-
- if (input_header.size.voice != voice_in_size) {
- LOG_ERROR(Audio, "Voices are an invalid size, expecting 0x{:X} but got 0x{:X}",
- voice_in_size, input_header.size.voice);
- return false;
- }
-
- if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, voice_in_size)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- std::memcpy(voice_in.data(), in_params.data() + input_offset, voice_in_size);
- input_offset += voice_in_size;
-
- // Set all voices to not be in use
- for (std::size_t i = 0; i < voice_count; i++) {
- voice_context.GetInfo(i).GetInParams().in_use = false;
- }
-
- // Update our voices
- for (std::size_t i = 0; i < voice_count; i++) {
- auto& voice_in_params = voice_in[i];
- const auto channel_count = static_cast<std::size_t>(voice_in_params.channel_count);
- // Skip if it's not currently in use
- if (!voice_in_params.is_in_use) {
- continue;
- }
- // Voice states for each channel
- std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> voice_states{};
- ASSERT(static_cast<std::size_t>(voice_in_params.id) < voice_count);
-
- // Grab our current voice info
- auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(voice_in_params.id));
-
- ASSERT(channel_count <= AudioCommon::MAX_CHANNEL_COUNT);
-
- // Get all our channel voice states
- for (std::size_t channel = 0; channel < channel_count; channel++) {
- voice_states[channel] =
- &voice_context.GetState(voice_in_params.voice_channel_resource_ids[channel]);
- }
-
- if (voice_in_params.is_new) {
- // Default our values for our voice
- voice_info.Initialize();
-
- // Zero out our voice states
- for (std::size_t channel = 0; channel < channel_count; channel++) {
- std::memset(voice_states[channel], 0, sizeof(VoiceState));
- }
- }
-
- // Update our voice
- voice_info.UpdateParameters(voice_in_params, behavior_info);
- // TODO(ogniK): Handle mapping errors with behavior info based on in params response
-
- // Update our wave buffers
- voice_info.UpdateWaveBuffers(voice_in_params, voice_states, behavior_info);
- voice_info.WriteOutStatus(voice_out[i], voice_in_params, voice_states);
- }
-
- if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, voice_out_size)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
- std::memcpy(out_params.data() + output_offset, voice_out.data(), voice_out_size);
- output_offset += voice_out_size;
- output_header.size.voice = static_cast<u32>(voice_out_size);
- return true;
-}
-
-bool InfoUpdater::UpdateEffects(EffectContext& effect_context, bool is_active) {
- const auto effect_count = effect_context.GetCount();
- std::vector<EffectInfo::InParams> effect_in(effect_count);
- std::vector<EffectInfo::OutParams> effect_out(effect_count);
-
- const auto total_effect_in = effect_count * sizeof(EffectInfo::InParams);
- const auto total_effect_out = effect_count * sizeof(EffectInfo::OutParams);
-
- if (input_header.size.effect != total_effect_in) {
- LOG_ERROR(Audio, "Effects are an invalid size, expecting 0x{:X} but got 0x{:X}",
- total_effect_in, input_header.size.effect);
- return false;
- }
-
- if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, total_effect_in)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- std::memcpy(effect_in.data(), in_params.data() + input_offset, total_effect_in);
- input_offset += total_effect_in;
-
- // Update effects
- for (std::size_t i = 0; i < effect_count; i++) {
- auto* info = effect_context.GetInfo(i);
- if (effect_in[i].type != info->GetType()) {
- info = effect_context.RetargetEffect(i, effect_in[i].type);
- }
-
- info->Update(effect_in[i]);
-
- if ((!is_active && info->GetUsage() != UsageState::Initialized) ||
- info->GetUsage() == UsageState::Stopped) {
- effect_out[i].status = UsageStatus::Removed;
- } else {
- effect_out[i].status = UsageStatus::Used;
- }
- }
-
- if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_effect_out)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- std::memcpy(out_params.data() + output_offset, effect_out.data(), total_effect_out);
- output_offset += total_effect_out;
- output_header.size.effect = static_cast<u32>(total_effect_out);
-
- return true;
-}
-
-bool InfoUpdater::UpdateSplitterInfo(SplitterContext& splitter_context) {
- std::size_t start_offset = input_offset;
- std::size_t bytes_read{};
- // Update splitter context
- if (!splitter_context.Update(in_params, input_offset, bytes_read)) {
- LOG_ERROR(Audio, "Failed to update splitter context!");
- return false;
- }
-
- const auto consumed = input_offset - start_offset;
-
- if (input_header.size.splitter != consumed) {
- LOG_ERROR(Audio, "Splitters is an invalid size, expecting 0x{:X} but got 0x{:X}",
- bytes_read, input_header.size.splitter);
- return false;
- }
-
- return true;
-}
-
-Result InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
- SplitterContext& splitter_context, EffectContext& effect_context) {
- std::vector<MixInfo::InParams> mix_in_params;
-
- if (!behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
- // If we're not dirty, get ALL mix in parameters
- const auto context_mix_count = mix_context.GetCount();
- const auto total_mix_in = context_mix_count * sizeof(MixInfo::InParams);
- if (input_header.size.mixer != total_mix_in) {
- LOG_ERROR(Audio, "Mixer is an invalid size, expecting 0x{:X} but got 0x{:X}",
- total_mix_in, input_header.size.mixer);
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
-
- if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, total_mix_in)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
-
- mix_in_params.resize(context_mix_count);
- std::memcpy(mix_in_params.data(), in_params.data() + input_offset, total_mix_in);
-
- input_offset += total_mix_in;
- } else {
- // Only update the "dirty" mixes
- MixInfo::DirtyHeader dirty_header{};
- if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset,
- sizeof(MixInfo::DirtyHeader))) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
-
- std::memcpy(&dirty_header, in_params.data() + input_offset, sizeof(MixInfo::DirtyHeader));
- input_offset += sizeof(MixInfo::DirtyHeader);
-
- const auto total_mix_in =
- dirty_header.mixer_count * sizeof(MixInfo::InParams) + sizeof(MixInfo::DirtyHeader);
-
- if (input_header.size.mixer != total_mix_in) {
- LOG_ERROR(Audio, "Mixer is an invalid size, expecting 0x{:X} but got 0x{:X}",
- total_mix_in, input_header.size.mixer);
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
-
- if (dirty_header.mixer_count != 0) {
- mix_in_params.resize(dirty_header.mixer_count);
- std::memcpy(mix_in_params.data(), in_params.data() + input_offset,
- mix_in_params.size() * sizeof(MixInfo::InParams));
- input_offset += mix_in_params.size() * sizeof(MixInfo::InParams);
- }
- }
-
- // Get our total input count
- const auto mix_count = mix_in_params.size();
-
- if (!behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
- // Only verify our buffer count if we're not dirty
- std::size_t total_buffer_count{};
- for (std::size_t i = 0; i < mix_count; i++) {
- const auto& in = mix_in_params[i];
- total_buffer_count += in.buffer_count;
- if (static_cast<std::size_t>(in.dest_mix_id) > mix_count &&
- in.dest_mix_id != AudioCommon::NO_MIX && in.mix_id != AudioCommon::FINAL_MIX) {
- LOG_ERROR(
- Audio,
- "Invalid mix destination, mix_id={:X}, dest_mix_id={:X}, mix_buffer_count={:X}",
- in.mix_id, in.dest_mix_id, mix_buffer_count);
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
- }
-
- if (total_buffer_count > mix_buffer_count) {
- LOG_ERROR(Audio,
- "Too many mix buffers used! mix_buffer_count={:X}, requesting_buffers={:X}",
- mix_buffer_count, total_buffer_count);
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
- }
-
- if (mix_buffer_count == 0) {
- LOG_ERROR(Audio, "No mix buffers!");
- return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
- }
-
- bool should_sort = false;
- for (std::size_t i = 0; i < mix_count; i++) {
- const auto& mix_in = mix_in_params[i];
- std::size_t target_mix{};
- if (behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
- target_mix = mix_in.mix_id;
- } else {
- // Non dirty supported games just use i instead of the actual mix_id
- target_mix = i;
- }
- auto& mix_info = mix_context.GetInfo(target_mix);
- auto& mix_info_params = mix_info.GetInParams();
- if (mix_info_params.in_use != mix_in.in_use) {
- mix_info_params.in_use = mix_in.in_use;
- mix_info.ResetEffectProcessingOrder();
- should_sort = true;
- }
-
- if (mix_in.in_use) {
- should_sort |= mix_info.Update(mix_context.GetEdgeMatrix(), mix_in, behavior_info,
- splitter_context, effect_context);
- }
- }
-
- if (should_sort && behavior_info.IsSplitterSupported()) {
- // Sort our splitter data
- if (!mix_context.TsortInfo(splitter_context)) {
- return AudioCommon::Audren::ERR_SPLITTER_SORT_FAILED;
- }
- }
-
- // TODO(ogniK): Sort when splitter is suppoorted
-
- return ResultSuccess;
-}
-
-bool InfoUpdater::UpdateSinks(SinkContext& sink_context) {
- const auto sink_count = sink_context.GetCount();
- std::vector<SinkInfo::InParams> sink_in_params(sink_count);
- const auto total_sink_in = sink_count * sizeof(SinkInfo::InParams);
-
- if (input_header.size.sink != total_sink_in) {
- LOG_ERROR(Audio, "Sinks are an invalid size, expecting 0x{:X} but got 0x{:X}",
- total_sink_in, input_header.size.effect);
- return false;
- }
-
- if (!AudioCommon::CanConsumeBuffer(in_params.size(), input_offset, total_sink_in)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- std::memcpy(sink_in_params.data(), in_params.data() + input_offset, total_sink_in);
- input_offset += total_sink_in;
-
- // TODO(ogniK): Properly update sinks
- if (!sink_in_params.empty()) {
- sink_context.UpdateMainSink(sink_in_params[0]);
- }
-
- output_header.size.sink = static_cast<u32>(0x20 * sink_count);
- output_offset += 0x20 * sink_count;
- return true;
-}
-
-bool InfoUpdater::UpdatePerformanceBuffer() {
- output_header.size.performance = 0x10;
- output_offset += 0x10;
- return true;
-}
-
-bool InfoUpdater::UpdateErrorInfo([[maybe_unused]] BehaviorInfo& in_behavior_info) {
- const auto total_beahvior_info_out = sizeof(BehaviorInfo::OutParams);
-
- if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_beahvior_info_out)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
-
- BehaviorInfo::OutParams behavior_info_out{};
- behavior_info.CopyErrorInfo(behavior_info_out);
-
- std::memcpy(out_params.data() + output_offset, &behavior_info_out, total_beahvior_info_out);
- output_offset += total_beahvior_info_out;
- output_header.size.behavior = total_beahvior_info_out;
-
- return true;
-}
-
-struct RendererInfo {
- u64_le elasped_frame_count{};
- INSERT_PADDING_WORDS(2);
-};
-static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size");
-
-bool InfoUpdater::UpdateRendererInfo(std::size_t elapsed_frame_count) {
- const auto total_renderer_info_out = sizeof(RendererInfo);
- if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_renderer_info_out)) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
- RendererInfo out{};
- out.elasped_frame_count = elapsed_frame_count;
- std::memcpy(out_params.data() + output_offset, &out, total_renderer_info_out);
- output_offset += total_renderer_info_out;
- output_header.size.render_info = total_renderer_info_out;
-
- return true;
-}
-
-bool InfoUpdater::CheckConsumedSize() const {
- if (output_offset != out_params.size()) {
- LOG_ERROR(Audio, "Output is not consumed! Consumed {}, but requires {}. {} bytes remaining",
- output_offset, out_params.size(), out_params.size() - output_offset);
- return false;
- }
- /*if (input_offset != in_params.size()) {
- LOG_ERROR(Audio, "Input is not consumed!");
- return false;
- }*/
- return true;
-}
-
-bool InfoUpdater::WriteOutputHeader() {
- if (!AudioCommon::CanConsumeBuffer(out_params.size(), 0,
- sizeof(AudioCommon::UpdateDataHeader))) {
- LOG_ERROR(Audio, "Buffer is an invalid size!");
- return false;
- }
- output_header.revision = AudioCommon::CURRENT_PROCESS_REVISION;
- const auto& sz = output_header.size;
- output_header.total_size += sz.behavior + sz.memory_pool + sz.voice +
- sz.voice_channel_resource + sz.effect + sz.mixer + sz.sink +
- sz.performance + sz.splitter + sz.render_info;
-
- std::memcpy(out_params.data(), &output_header, sizeof(AudioCommon::UpdateDataHeader));
- return true;
-}
-
-} // namespace AudioCore
diff --git a/src/audio_core/info_updater.h b/src/audio_core/info_updater.h
deleted file mode 100644
index 17e66b036..000000000
--- a/src/audio_core/info_updater.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <vector>
-#include "audio_core/common.h"
-#include "common/common_types.h"
-
-namespace AudioCore {
-
-class BehaviorInfo;
-class ServerMemoryPoolInfo;
-class VoiceContext;
-class EffectContext;
-class MixContext;
-class SinkContext;
-class SplitterContext;
-
-class InfoUpdater {
-public:
- // TODO(ogniK): Pass process handle when we support it
- InfoUpdater(const std::vector<u8>& in_params_, std::vector<u8>& out_params_,
- BehaviorInfo& behavior_info_);
- ~InfoUpdater();
-
- bool UpdateBehaviorInfo(BehaviorInfo& in_behavior_info);
- bool UpdateMemoryPools(std::vector<ServerMemoryPoolInfo>& memory_pool_info);
- bool UpdateVoiceChannelResources(VoiceContext& voice_context);
- bool UpdateVoices(VoiceContext& voice_context,
- std::vector<ServerMemoryPoolInfo>& memory_pool_info,
- VAddr audio_codec_dsp_addr);
- bool UpdateEffects(EffectContext& effect_context, bool is_active);
- bool UpdateSplitterInfo(SplitterContext& splitter_context);
- Result UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
- SplitterContext& splitter_context, EffectContext& effect_context);
- bool UpdateSinks(SinkContext& sink_context);
- bool UpdatePerformanceBuffer();
- bool UpdateErrorInfo(BehaviorInfo& in_behavior_info);
- bool UpdateRendererInfo(std::size_t elapsed_frame_count);
- bool CheckConsumedSize() const;
-
- bool WriteOutputHeader();
-
-private:
- const std::vector<u8>& in_params;
- std::vector<u8>& out_params;
- BehaviorInfo& behavior_info;
-
- AudioCommon::UpdateDataHeader input_header{};
- AudioCommon::UpdateDataHeader output_header{};
-
- std::size_t input_offset{sizeof(AudioCommon::UpdateDataHeader)};
- std::size_t output_offset{sizeof(AudioCommon::UpdateDataHeader)};
-};
-
-} // namespace AudioCore