summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/service/am/service/application_functions.cpp6
-rw-r--r--src/core/hle/service/audio/audin_u.cpp393
-rw-r--r--src/core/hle/service/audio/audin_u.h38
-rw-r--r--src/core/hle/service/audio/audio.cpp28
-rw-r--r--src/core/hle/service/audio/audio_controller.cpp31
-rw-r--r--src/core/hle/service/audio/audio_controller.h1
-rw-r--r--src/core/hle/service/audio/audio_device.cpp163
-rw-r--r--src/core/hle/service/audio/audio_device.h58
-rw-r--r--src/core/hle/service/audio/audio_in.cpp146
-rw-r--r--src/core/hle/service/audio/audio_in.h53
-rw-r--r--src/core/hle/service/audio/audio_in_manager.cpp125
-rw-r--r--src/core/hle/service/audio/audio_in_manager.h57
-rw-r--r--src/core/hle/service/audio/audio_out.cpp146
-rw-r--r--src/core/hle/service/audio/audio_out.h58
-rw-r--r--src/core/hle/service/audio/audio_out_manager.cpp101
-rw-r--r--src/core/hle/service/audio/audio_out_manager.h44
-rw-r--r--src/core/hle/service/audio/audio_renderer.cpp139
-rw-r--r--src/core/hle/service/audio/audio_renderer.h54
-rw-r--r--src/core/hle/service/audio/audio_renderer_manager.cpp104
-rw-r--r--src/core/hle/service/audio/audio_renderer_manager.h37
-rw-r--r--src/core/hle/service/audio/audout_u.cpp323
-rw-r--r--src/core/hle/service/audio/audout_u.h37
-rw-r--r--src/core/hle/service/audio/audren_u.cpp552
-rw-r--r--src/core/hle/service/audio/audren_u.h35
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager.cpp (renamed from src/core/hle/service/audio/audrec_u.cpp)7
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager.h (renamed from src/core/hle/service/audio/audrec_a.h)6
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp (renamed from src/core/hle/service/audio/audrec_a.cpp)7
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager_for_applet.h (renamed from src/core/hle/service/audio/audrec_u.h)7
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder.cpp145
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder.h63
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder_manager.cpp156
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder_manager.h53
-rw-r--r--src/core/hle/service/audio/hwopus.cpp502
-rw-r--r--src/core/hle/service/audio/hwopus.h36
-rw-r--r--src/core/hle/service/cmif_serialization.h2
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.h2
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp33
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h23
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp161
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h50
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.cpp47
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.h7
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp589
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.h72
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_types.h (renamed from src/core/hle/service/filesystem/fsp/fsp_util.h)12
-rw-r--r--src/core/hle/service/olsc/daemon_controller.cpp40
-rw-r--r--src/core/hle/service/olsc/daemon_controller.h20
-rw-r--r--src/core/hle/service/olsc/native_handle_holder.cpp28
-rw-r--r--src/core/hle/service/olsc/native_handle_holder.h22
-rw-r--r--src/core/hle/service/olsc/olsc.cpp223
-rw-r--r--src/core/hle/service/olsc/olsc_service_for_application.cpp63
-rw-r--r--src/core/hle/service/olsc/olsc_service_for_application.h23
-rw-r--r--src/core/hle/service/olsc/olsc_service_for_system_service.cpp117
-rw-r--r--src/core/hle/service/olsc/olsc_service_for_system_service.h27
-rw-r--r--src/core/hle/service/olsc/remote_storage_controller.cpp54
-rw-r--r--src/core/hle/service/olsc/remote_storage_controller.h19
-rw-r--r--src/core/hle/service/olsc/transfer_task_list_controller.cpp55
-rw-r--r--src/core/hle/service/olsc/transfer_task_list_controller.h20
-rw-r--r--src/core/hle/service/pctl/parental_control_service.cpp434
-rw-r--r--src/core/hle/service/pctl/parental_control_service.h86
-rw-r--r--src/core/hle/service/pctl/parental_control_service_factory.cpp40
-rw-r--r--src/core/hle/service/pctl/parental_control_service_factory.h31
-rw-r--r--src/core/hle/service/pctl/pctl.cpp27
-rw-r--r--src/core/hle/service/pctl/pctl.h9
-rw-r--r--src/core/hle/service/pctl/pctl_module.cpp550
-rw-r--r--src/core/hle/service/pctl/pctl_module.h47
-rw-r--r--src/core/hle/service/pctl/pctl_results.h15
-rw-r--r--src/core/hle/service/pctl/pctl_types.h43
-rw-r--r--src/core/hle/service/services.cpp2
69 files changed, 3425 insertions, 3279 deletions
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
index cb53b07e0..bfccb6b09 100644
--- a/src/core/hle/service/am/service/application_functions.cpp
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -123,13 +123,13 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
FileSys::SaveDataAttribute attribute{};
- attribute.title_id = m_applet->program_id;
+ attribute.program_id = m_applet->program_id;
attribute.user_id = user_id.AsU128();
- attribute.type = FileSys::SaveDataType::SaveData;
+ attribute.type = FileSys::SaveDataType::Account;
FileSys::VirtualDir save_data{};
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
- &save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
+ &save_data, FileSys::SaveDataSpaceId::User, attribute));
*out_size = 0;
R_SUCCEED();
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
deleted file mode 100644
index de2aa6906..000000000
--- a/src/core/hle/service/audio/audin_u.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "audio_core/in/audio_in_system.h"
-#include "audio_core/renderer/audio_device.h"
-#include "common/common_funcs.h"
-#include "common/logging/log.h"
-#include "common/scratch_buffer.h"
-#include "common/string_util.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/audio/audin_u.h"
-#include "core/hle/service/ipc_helpers.h"
-
-namespace Service::Audio {
-using namespace AudioCore::AudioIn;
-
-class IAudioIn final : public ServiceFramework<IAudioIn> {
-public:
- explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
- const std::string& device_name, const AudioInParameter& in_params,
- Kernel::KProcess* handle, u64 applet_resource_user_id)
- : ServiceFramework{system_, "IAudioIn"},
- service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")},
- process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IAudioIn::GetAudioInState, "GetAudioInState"},
- {1, &IAudioIn::Start, "Start"},
- {2, &IAudioIn::Stop, "Stop"},
- {3, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBuffer"},
- {4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"},
- {5, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffer"},
- {6, &IAudioIn::ContainsAudioInBuffer, "ContainsAudioInBuffer"},
- {7, &IAudioIn::AppendAudioInBuffer, "AppendUacInBuffer"},
- {8, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBufferAuto"},
- {9, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffersAuto"},
- {10, &IAudioIn::AppendAudioInBuffer, "AppendUacInBufferAuto"},
- {11, &IAudioIn::GetAudioInBufferCount, "GetAudioInBufferCount"},
- {12, &IAudioIn::SetDeviceGain, "SetDeviceGain"},
- {13, &IAudioIn::GetDeviceGain, "GetDeviceGain"},
- {14, &IAudioIn::FlushAudioInBuffers, "FlushAudioInBuffers"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-
- process->Open();
-
- if (impl->GetSystem()
- .Initialize(device_name, in_params, handle, applet_resource_user_id)
- .IsError()) {
- LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
- }
- }
-
- ~IAudioIn() override {
- impl->Free();
- service_context.CloseEvent(event);
- process->Close();
- }
-
- [[nodiscard]] std::shared_ptr<In> GetImpl() {
- return impl;
- }
-
-private:
- void GetAudioInState(HLERequestContext& ctx) {
- const auto state = static_cast<u32>(impl->GetState());
-
- LOG_DEBUG(Service_Audio, "called. State={}", state);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(state);
- }
-
- void Start(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto result = impl->StartSystem();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void Stop(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto result = impl->StopSystem();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void AppendAudioInBuffer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- u64 tag = rp.PopRaw<u64>();
-
- const auto in_buffer_size{ctx.GetReadBufferSize()};
- if (in_buffer_size < sizeof(AudioInBuffer)) {
- LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
- }
-
- const auto& in_buffer = ctx.ReadBuffer();
- AudioInBuffer buffer{};
- std::memcpy(&buffer, in_buffer.data(), sizeof(AudioInBuffer));
-
- [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
- LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag);
-
- auto result = impl->AppendBuffer(buffer, tag);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void RegisterBufferEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto& buffer_event = impl->GetBufferEvent();
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(buffer_event);
- }
-
- void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
- const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
- released_buffer.resize_destructive(write_buffer_size);
- released_buffer[0] = 0;
-
- const auto count = impl->GetReleasedBuffers(released_buffer);
-
- LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
- impl->GetSystem().GetSessionId(), count);
-
- ctx.WriteBuffer(released_buffer);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(count);
- }
-
- void ContainsAudioInBuffer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const u64 tag{rp.Pop<u64>()};
- const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
-
- LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_queued);
- }
-
- void GetAudioInBufferCount(HLERequestContext& ctx) {
- const auto buffer_count = impl->GetBufferCount();
-
- LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_count);
- }
-
- void SetDeviceGain(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto volume{rp.Pop<f32>()};
- LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
-
- impl->SetVolume(volume);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetDeviceGain(HLERequestContext& ctx) {
- auto volume{impl->GetVolume()};
-
- LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(volume);
- }
-
- void FlushAudioInBuffers(HLERequestContext& ctx) {
- bool flushed{impl->FlushAudioInBuffers()};
-
- LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(flushed);
- }
-
- KernelHelpers::ServiceContext service_context;
- Kernel::KEvent* event;
- Kernel::KProcess* process;
- std::shared_ptr<AudioCore::AudioIn::In> impl;
- Common::ScratchBuffer<u64> released_buffer;
-};
-
-AudInU::AudInU(Core::System& system_)
- : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"},
- impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &AudInU::ListAudioIns, "ListAudioIns"},
- {1, &AudInU::OpenAudioIn, "OpenAudioIn"},
- {2, &AudInU::ListAudioIns, "ListAudioInsAuto"},
- {3, &AudInU::OpenAudioIn, "OpenAudioInAuto"},
- {4, &AudInU::ListAudioInsAutoFiltered, "ListAudioInsAutoFiltered"},
- {5, &AudInU::OpenAudioInProtocolSpecified, "OpenAudioInProtocolSpecified"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudInU::~AudInU() = default;
-
-void AudInU::ListAudioIns(HLERequestContext& ctx) {
- using namespace AudioCore::Renderer;
-
- LOG_DEBUG(Service_Audio, "called");
-
- const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
- std::vector<AudioDevice::AudioDeviceName> device_names{};
-
- u32 out_count{0};
- if (write_count > 0) {
- out_count = impl->GetDeviceNames(device_names, write_count, false);
- ctx.WriteBuffer(device_names);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(out_count);
-}
-
-void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) {
- using namespace AudioCore::Renderer;
-
- LOG_DEBUG(Service_Audio, "called");
-
- const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
- std::vector<AudioDevice::AudioDeviceName> device_names{};
-
- u32 out_count{0};
- if (write_count > 0) {
- out_count = impl->GetDeviceNames(device_names, write_count, true);
- ctx.WriteBuffer(device_names);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(out_count);
-}
-
-void AudInU::OpenAudioIn(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto in_params{rp.PopRaw<AudioInParameter>()};
- auto applet_resource_user_id{rp.PopRaw<u64>()};
- const auto device_name_data{ctx.ReadBuffer()};
- auto device_name = Common::StringFromBuffer(device_name_data);
- auto handle{ctx.GetCopyHandle(0)};
-
- auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
- if (process.IsNull()) {
- LOG_ERROR(Service_Audio, "Failed to get process handle");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- std::scoped_lock l{impl->mutex};
- auto link{impl->LinkToManager()};
- if (link.IsError()) {
- LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(link);
- return;
- }
-
- size_t new_session_id{};
- auto result{impl->AcquireSessionId(new_session_id)};
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
- impl->num_free_sessions);
-
- auto audio_in =
- std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
- process.GetPointerUnsafe(), applet_resource_user_id);
- impl->sessions[new_session_id] = audio_in->GetImpl();
- impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
-
- auto& out_system = impl->sessions[new_session_id]->GetSystem();
- AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
- .channel_count = out_system.GetChannelCount(),
- .sample_format =
- static_cast<u32>(out_system.GetSampleFormat()),
- .state = static_cast<u32>(out_system.GetState())};
-
- IPC::ResponseBuilder rb{ctx, 6, 0, 1};
-
- std::string out_name{out_system.GetName()};
- ctx.WriteBuffer(out_name);
-
- rb.Push(ResultSuccess);
- rb.PushRaw<AudioInParameterInternal>(out_params);
- rb.PushIpcInterface<IAudioIn>(audio_in);
-}
-
-void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto protocol_specified{rp.PopRaw<u64>()};
- auto in_params{rp.PopRaw<AudioInParameter>()};
- auto applet_resource_user_id{rp.PopRaw<u64>()};
- const auto device_name_data{ctx.ReadBuffer()};
- auto device_name = Common::StringFromBuffer(device_name_data);
- auto handle{ctx.GetCopyHandle(0)};
-
- auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
- if (process.IsNull()) {
- LOG_ERROR(Service_Audio, "Failed to get process handle");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- std::scoped_lock l{impl->mutex};
- auto link{impl->LinkToManager()};
- if (link.IsError()) {
- LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(link);
- return;
- }
-
- size_t new_session_id{};
- auto result{impl->AcquireSessionId(new_session_id)};
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
- impl->num_free_sessions);
-
- auto audio_in =
- std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
- process.GetPointerUnsafe(), applet_resource_user_id);
- impl->sessions[new_session_id] = audio_in->GetImpl();
- impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
-
- auto& out_system = impl->sessions[new_session_id]->GetSystem();
- AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
- .channel_count = out_system.GetChannelCount(),
- .sample_format =
- static_cast<u32>(out_system.GetSampleFormat()),
- .state = static_cast<u32>(out_system.GetState())};
-
- IPC::ResponseBuilder rb{ctx, 6, 0, 1};
-
- std::string out_name{out_system.GetName()};
- if (protocol_specified == 0) {
- if (out_system.IsUac()) {
- out_name = "UacIn";
- } else {
- out_name = "DeviceIn";
- }
- }
-
- ctx.WriteBuffer(out_name);
-
- rb.Push(ResultSuccess);
- rb.PushRaw<AudioInParameterInternal>(out_params);
- rb.PushIpcInterface<IAudioIn>(audio_in);
-}
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
deleted file mode 100644
index 51e770ff9..000000000
--- a/src/core/hle/service/audio/audin_u.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "audio_core/audio_in_manager.h"
-#include "audio_core/in/audio_in.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace AudioCore::AudioOut {
-class Manager;
-class In;
-} // namespace AudioCore::AudioOut
-
-namespace Service::Audio {
-
-class AudInU final : public ServiceFramework<AudInU> {
-public:
- explicit AudInU(Core::System& system_);
- ~AudInU() override;
-
-private:
- void ListAudioIns(HLERequestContext& ctx);
- void ListAudioInsAutoFiltered(HLERequestContext& ctx);
- void OpenInOutImpl(HLERequestContext& ctx);
- void OpenAudioIn(HLERequestContext& ctx);
- void OpenAudioInProtocolSpecified(HLERequestContext& ctx);
-
- KernelHelpers::ServiceContext service_context;
- std::unique_ptr<AudioCore::AudioIn::Manager> impl;
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 44af030eb..331176bf7 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -2,14 +2,14 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
-#include "core/hle/service/audio/audin_u.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/audio/audio_controller.h"
-#include "core/hle/service/audio/audout_u.h"
-#include "core/hle/service/audio/audrec_a.h"
-#include "core/hle/service/audio/audrec_u.h"
-#include "core/hle/service/audio/audren_u.h"
-#include "core/hle/service/audio/hwopus.h"
+#include "core/hle/service/audio/audio_in_manager.h"
+#include "core/hle/service/audio/audio_out_manager.h"
+#include "core/hle/service/audio/audio_renderer_manager.h"
+#include "core/hle/service/audio/final_output_recorder_manager.h"
+#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
+#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
@@ -19,12 +19,16 @@ void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
- server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system));
- server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system));
- server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system));
- server_manager->RegisterNamedService("audrec:u", std::make_shared<AudRecU>(system));
- server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system));
- server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system));
+ server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system));
+ server_manager->RegisterNamedService("audout:u", std::make_shared<IAudioOutManager>(system));
+ server_manager->RegisterNamedService(
+ "audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system));
+ server_manager->RegisterNamedService("audrec:u",
+ std::make_shared<IFinalOutputRecorderManager>(system));
+ server_manager->RegisterNamedService("audren:u",
+ std::make_shared<IAudioRendererManager>(system));
+ server_manager->RegisterNamedService("hwopus",
+ std::make_shared<IHardwareOpusDecoderManager>(system));
ServerManager::RunServer(std::move(server_manager));
}
diff --git a/src/core/hle/service/audio/audio_controller.cpp b/src/core/hle/service/audio/audio_controller.cpp
index a6da66d0f..c9804cf9c 100644
--- a/src/core/hle/service/audio/audio_controller.cpp
+++ b/src/core/hle/service/audio/audio_controller.cpp
@@ -16,27 +16,27 @@ IAudioController::IAudioController(Core::System& system_)
static const FunctionInfo functions[] = {
{0, nullptr, "GetTargetVolume"},
{1, nullptr, "SetTargetVolume"},
- {2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
- {3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
+ {2, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
+ {3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
{4, nullptr, "IsTargetMute"},
{5, nullptr, "SetTargetMute"},
{6, nullptr, "IsTargetConnected"},
{7, nullptr, "SetDefaultTarget"},
{8, nullptr, "GetDefaultTarget"},
- {9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
- {10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
+ {9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
+ {10, D<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
{11, nullptr, "SetForceMutePolicy"},
- {12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
- {13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
- {14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
+ {12, D<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
+ {13, D<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
+ {14, D<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
{15, nullptr, "SetOutputTarget"},
{16, nullptr, "SetInputTargetForceEnabled"},
- {17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
- {18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
+ {17, D<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
+ {18, D<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
- {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
+ {22, D<&IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent>, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
{23, nullptr, "SetSystemOutputMasterVolume"},
{24, nullptr, "GetSystemOutputMasterVolume"},
{25, nullptr, "GetAudioVolumeDataForPlayReport"},
@@ -44,11 +44,11 @@ IAudioController::IAudioController(Core::System& system_)
{27, nullptr, "SetVolumeMappingTableForDev"},
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
- {30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
- {31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
+ {30, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
+ {31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
{32, nullptr, "GetActiveOutputTarget"},
{33, nullptr, "GetTargetDeviceInfo"},
- {34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
+ {34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
{35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{37, nullptr, "SetHearingProtectionSafeguardEnabled"},
@@ -150,6 +150,11 @@ Result IAudioController::GetHeadphoneOutputLevelMode(
R_SUCCEED();
}
+Result IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent() {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+ R_SUCCEED();
+}
+
Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
diff --git a/src/core/hle/service/audio/audio_controller.h b/src/core/hle/service/audio/audio_controller.h
index 9e8514373..d37c4843e 100644
--- a/src/core/hle/service/audio/audio_controller.h
+++ b/src/core/hle/service/audio/audio_controller.h
@@ -45,6 +45,7 @@ private:
Set::AudioOutputMode output_mode);
Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
+ Result NotifyHeadphoneVolumeWarningDisplayedEvent();
Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event);
diff --git a/src/core/hle/service/audio/audio_device.cpp b/src/core/hle/service/audio/audio_device.cpp
new file mode 100644
index 000000000..438f3cccd
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.cpp
@@ -0,0 +1,163 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "audio_core/audio_core.h"
+#include "common/string_util.h"
+#include "core/hle/service/audio/audio_device.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+using namespace AudioCore::Renderer;
+
+IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
+ u32 device_num)
+ : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
+ impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
+ event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"},
+ {1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"},
+ {2, D<&IAudioDevice::GetAudioDeviceOutputVolume>, "GetAudioDeviceOutputVolume"},
+ {3, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioDeviceName"},
+ {4, D<&IAudioDevice::QueryAudioDeviceSystemEvent>, "QueryAudioDeviceSystemEvent"},
+ {5, D<&IAudioDevice::GetActiveChannelCount>, "GetActiveChannelCount"},
+ {6, D<&IAudioDevice::ListAudioDeviceNameAuto>, "ListAudioDeviceNameAuto"},
+ {7, D<&IAudioDevice::SetAudioDeviceOutputVolumeAuto>, "SetAudioDeviceOutputVolumeAuto"},
+ {8, D<&IAudioDevice::GetAudioDeviceOutputVolumeAuto>, "GetAudioDeviceOutputVolumeAuto"},
+ {10, D<&IAudioDevice::GetActiveAudioDeviceNameAuto>, "GetActiveAudioDeviceNameAuto"},
+ {11, D<&IAudioDevice::QueryAudioDeviceInputEvent>, "QueryAudioDeviceInputEvent"},
+ {12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
+ {13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
+ {14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
+ };
+ RegisterHandlers(functions);
+
+ event->Signal();
+}
+
+IAudioDevice::~IAudioDevice() {
+ service_context.CloseEvent(event);
+}
+
+Result IAudioDevice::ListAudioDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
+ R_RETURN(this->ListAudioDeviceNameAuto(out_names, out_count));
+}
+
+Result IAudioDevice::SetAudioDeviceOutputVolume(
+ InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume) {
+ R_RETURN(this->SetAudioDeviceOutputVolumeAuto(name, volume));
+}
+
+Result IAudioDevice::GetAudioDeviceOutputVolume(
+ Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name) {
+ R_RETURN(this->GetAudioDeviceOutputVolumeAuto(out_volume, name));
+}
+
+Result IAudioDevice::GetActiveAudioDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name) {
+ R_RETURN(this->GetActiveAudioDeviceNameAuto(out_name));
+}
+
+Result IAudioDevice::ListAudioDeviceNameAuto(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
+ Out<s32> out_count) {
+ *out_count = impl->ListAudioDeviceName(out_names);
+
+ std::string out{};
+ for (s32 i = 0; i < *out_count; i++) {
+ std::string a{};
+ u32 j = 0;
+ while (out_names[i].name[j] != '\0') {
+ a += out_names[i].name[j];
+ j++;
+ }
+ out += "\n\t" + a;
+ }
+
+ LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
+ R_SUCCEED();
+}
+
+Result IAudioDevice::SetAudioDeviceOutputVolumeAuto(
+ InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume) {
+ R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
+
+ const std::string device_name = Common::StringFromBuffer(name[0].name);
+ LOG_DEBUG(Service_Audio, "called. name={}, volume={}", device_name, volume);
+
+ if (device_name == "AudioTvOutput") {
+ impl->SetDeviceVolumes(volume);
+ }
+
+ R_SUCCEED();
+}
+
+Result IAudioDevice::GetAudioDeviceOutputVolumeAuto(
+ Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name) {
+ R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
+
+ const std::string device_name = Common::StringFromBuffer(name[0].name);
+ LOG_DEBUG(Service_Audio, "called. Name={}", device_name);
+
+ *out_volume = 1.0f;
+ if (device_name == "AudioTvOutput") {
+ *out_volume = impl->GetDeviceVolume(device_name);
+ }
+
+ R_SUCCEED();
+}
+
+Result IAudioDevice::GetActiveAudioDeviceNameAuto(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name) {
+ R_UNLESS(!out_name.empty(), Audio::ResultInsufficientBuffer);
+ out_name[0] = AudioDevice::AudioDeviceName("AudioTvOutput");
+ LOG_DEBUG(Service_Audio, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IAudioDevice::QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "(STUBBED) called");
+ event->Signal();
+ *out_event = &event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IAudioDevice::QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "(STUBBED) called");
+ *out_event = &event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IAudioDevice::QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_event = &event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IAudioDevice::GetActiveChannelCount(Out<u32> out_active_channel_count) {
+ *out_active_channel_count = system.AudioCore().GetOutputSink().GetSystemChannels();
+ LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", *out_active_channel_count);
+ R_SUCCEED();
+}
+
+Result IAudioDevice::ListAudioOutputDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
+ *out_count = impl->ListAudioOutputDeviceName(out_names);
+
+ std::string out{};
+ for (s32 i = 0; i < *out_count; i++) {
+ std::string a{};
+ u32 j = 0;
+ while (out_names[i].name[j] != '\0') {
+ a += out_names[i].name[j];
+ j++;
+ }
+ out += "\n\t" + a;
+ }
+
+ LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_device.h b/src/core/hle/service/audio/audio_device.h
new file mode 100644
index 000000000..752157272
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.h
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/renderer/audio_device.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::Audio {
+
+using AudioCore::Renderer::AudioDevice;
+
+class IAudioDevice final : public ServiceFramework<IAudioDevice> {
+
+public:
+ explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
+ u32 device_num);
+ ~IAudioDevice() override;
+
+private:
+ Result ListAudioDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
+ Out<s32> out_count);
+ Result SetAudioDeviceOutputVolume(
+ InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume);
+ Result GetAudioDeviceOutputVolume(
+ Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name);
+ Result GetActiveAudioDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name);
+ Result ListAudioDeviceNameAuto(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
+ Out<s32> out_count);
+ Result SetAudioDeviceOutputVolumeAuto(
+ InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume);
+ Result GetAudioDeviceOutputVolumeAuto(
+ Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name);
+ Result GetActiveAudioDeviceNameAuto(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name);
+ Result QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetActiveChannelCount(Out<u32> out_active_channel_count);
+ Result ListAudioOutputDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
+ Out<s32> out_count);
+
+ KernelHelpers::ServiceContext service_context;
+ std::unique_ptr<AudioCore::Renderer::AudioDevice> impl;
+ Kernel::KEvent* event;
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in.cpp b/src/core/hle/service/audio/audio_in.cpp
new file mode 100644
index 000000000..416803acc
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in.cpp
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/audio/audio_in.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/ipc_helpers.h"
+
+namespace Service::Audio {
+using namespace AudioCore::AudioIn;
+
+IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
+ const std::string& device_name, const AudioInParameter& in_params,
+ Kernel::KProcess* handle, u64 applet_resource_user_id)
+ : ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
+ event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_,
+ manager, event,
+ session_id)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioIn::GetAudioInState>, "GetAudioInState"},
+ {1, D<&IAudioIn::Start>, "Start"},
+ {2, D<&IAudioIn::Stop>, "Stop"},
+ {3, D<&IAudioIn::AppendAudioInBuffer>, "AppendAudioInBuffer"},
+ {4, D<&IAudioIn::RegisterBufferEvent>, "RegisterBufferEvent"},
+ {5, D<&IAudioIn::GetReleasedAudioInBuffers>, "GetReleasedAudioInBuffers"},
+ {6, D<&IAudioIn::ContainsAudioInBuffer>, "ContainsAudioInBuffer"},
+ {7, D<&IAudioIn::AppendAudioInBuffer>, "AppendUacInBuffer"},
+ {8, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendAudioInBufferAuto"},
+ {9, D<&IAudioIn::GetReleasedAudioInBuffersAuto>, "GetReleasedAudioInBuffersAuto"},
+ {10, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendUacInBufferAuto"},
+ {11, D<&IAudioIn::GetAudioInBufferCount>, "GetAudioInBufferCount"},
+ {12, D<&IAudioIn::SetDeviceGain>, "SetDeviceGain"},
+ {13, D<&IAudioIn::GetDeviceGain>, "GetDeviceGain"},
+ {14, D<&IAudioIn::FlushAudioInBuffers>, "FlushAudioInBuffers"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+
+ process->Open();
+
+ if (impl->GetSystem()
+ .Initialize(device_name, in_params, handle, applet_resource_user_id)
+ .IsError()) {
+ LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
+ }
+}
+
+IAudioIn::~IAudioIn() {
+ impl->Free();
+ service_context.CloseEvent(event);
+ process->Close();
+}
+
+Result IAudioIn::GetAudioInState(Out<u32> out_state) {
+ *out_state = static_cast<u32>(impl->GetState());
+ LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
+ R_SUCCEED();
+}
+
+Result IAudioIn::Start() {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->StartSystem());
+}
+
+Result IAudioIn::Stop() {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->StopSystem());
+}
+
+Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
+ u64 buffer_client_ptr) {
+ R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
+}
+
+Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
+ u64 buffer_client_ptr) {
+ if (buffer.empty()) {
+ LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
+ R_THROW(Audio::ResultInsufficientBuffer);
+ }
+
+ [[maybe_unused]] const auto session_id{impl->GetSystem().GetSessionId()};
+ LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", session_id,
+ buffer_client_ptr);
+
+ R_RETURN(impl->AppendBuffer(buffer[0], buffer_client_ptr));
+}
+
+Result IAudioIn::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_event = &impl->GetBufferEvent();
+ R_SUCCEED();
+}
+
+Result IAudioIn::GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
+ Out<u32> out_count) {
+ R_RETURN(this->GetReleasedAudioInBuffersAuto(out_audio_buffer, out_count));
+}
+
+Result IAudioIn::GetReleasedAudioInBuffersAuto(
+ OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
+
+ if (!out_audio_buffer.empty()) {
+ out_audio_buffer[0] = 0;
+ }
+ *out_count = impl->GetReleasedBuffers(out_audio_buffer);
+
+ LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
+ impl->GetSystem().GetSessionId(), *out_count);
+ R_SUCCEED();
+}
+
+Result IAudioIn::ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
+ *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
+
+ LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
+ *out_contains_buffer);
+ R_SUCCEED();
+}
+
+Result IAudioIn::GetAudioInBufferCount(Out<u32> out_buffer_count) {
+ *out_buffer_count = impl->GetBufferCount();
+ LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
+ R_SUCCEED();
+}
+
+Result IAudioIn::SetDeviceGain(f32 device_gain) {
+ impl->SetVolume(device_gain);
+ LOG_DEBUG(Service_Audio, "called. Gain {}", device_gain);
+ R_SUCCEED();
+}
+
+Result IAudioIn::GetDeviceGain(Out<f32> out_device_gain) {
+ *out_device_gain = impl->GetVolume();
+ LOG_DEBUG(Service_Audio, "called. Gain {}", *out_device_gain);
+ R_SUCCEED();
+}
+
+Result IAudioIn::FlushAudioInBuffers(Out<bool> out_flushed) {
+ *out_flushed = impl->FlushAudioInBuffers();
+ LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in.h b/src/core/hle/service/audio/audio_in.h
new file mode 100644
index 000000000..3fe1e1e87
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in.h
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/in/audio_in.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class IAudioIn final : public ServiceFramework<IAudioIn> {
+public:
+ explicit IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager,
+ size_t session_id, const std::string& device_name,
+ const AudioCore::AudioIn::AudioInParameter& in_params,
+ Kernel::KProcess* handle, u64 applet_resource_user_id);
+ ~IAudioIn() override;
+
+ std::shared_ptr<AudioCore::AudioIn::In> GetImpl() {
+ return impl;
+ }
+
+ Result GetAudioInState(Out<u32> out_state);
+ Result Start();
+ Result Stop();
+ Result AppendAudioInBuffer(
+ InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
+ u64 buffer_client_ptr);
+ Result AppendAudioInBufferAuto(
+ InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
+ u64 buffer_client_ptr);
+ Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
+ Out<u32> out_count);
+ Result GetReleasedAudioInBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
+ Out<u32> out_count);
+ Result ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
+ Result GetAudioInBufferCount(Out<u32> out_buffer_count);
+ Result SetDeviceGain(f32 device_gain);
+ Result GetDeviceGain(Out<f32> out_device_gain);
+ Result FlushAudioInBuffers(Out<bool> out_flushed);
+
+private:
+ Kernel::KProcess* process;
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* event;
+ std::shared_ptr<AudioCore::AudioIn::In> impl;
+ Common::ScratchBuffer<u64> released_buffer;
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in_manager.cpp b/src/core/hle/service/audio/audio_in_manager.cpp
new file mode 100644
index 000000000..2675a5773
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in_manager.cpp
@@ -0,0 +1,125 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/string_util.h"
+#include "core/hle/service/audio/audio_in.h"
+#include "core/hle/service/audio/audio_in_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+using namespace AudioCore::AudioIn;
+
+IAudioInManager::IAudioInManager(Core::System& system_)
+ : ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
+ system_)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioInManager::ListAudioIns>, "ListAudioIns"},
+ {1, D<&IAudioInManager::OpenAudioIn>, "OpenAudioIn"},
+ {2, D<&IAudioInManager::ListAudioIns>, "ListAudioInsAuto"},
+ {3, D<&IAudioInManager::OpenAudioIn>, "OpenAudioInAuto"},
+ {4, D<&IAudioInManager::ListAudioInsAutoFiltered>, "ListAudioInsAutoFiltered"},
+ {5, D<&IAudioInManager::OpenAudioInProtocolSpecified>, "OpenAudioInProtocolSpecified"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAudioInManager::~IAudioInManager() = default;
+
+Result IAudioInManager::ListAudioIns(
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, Out<u32> out_count) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
+}
+
+Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
+ AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
+ name, {}, parameter, process_handle, aruid));
+}
+
+Result IAudioInManager::ListAudioInsAuto(
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
+}
+
+Result IAudioInManager::OpenAudioInAuto(
+ Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
+ name, {}, parameter, process_handle, aruid));
+}
+
+Result IAudioInManager::ListAudioInsAutoFiltered(
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_count = impl->GetDeviceNames(out_audio_ins, true);
+ R_SUCCEED();
+}
+
+Result IAudioInManager::OpenAudioInProtocolSpecified(
+ Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
+ AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ if (!process_handle) {
+ LOG_ERROR(Service_Audio, "Failed to get process handle");
+ R_THROW(ResultUnknown);
+ }
+ if (name.empty() || out_name.empty()) {
+ LOG_ERROR(Service_Audio, "Invalid buffers");
+ R_THROW(ResultUnknown);
+ }
+
+ std::scoped_lock l{impl->mutex};
+
+ size_t new_session_id{};
+
+ R_TRY(impl->LinkToManager());
+ R_TRY(impl->AcquireSessionId(new_session_id));
+
+ LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
+ impl->num_free_sessions);
+
+ const auto device_name = Common::StringFromBuffer(name[0].name);
+ *out_audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name,
+ parameter, process_handle.Get(), aruid.pid);
+ impl->sessions[new_session_id] = (*out_audio_in)->GetImpl();
+ impl->applet_resource_user_ids[new_session_id] = aruid.pid;
+
+ auto& out_system = impl->sessions[new_session_id]->GetSystem();
+ *out_parameter_internal =
+ AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
+ .channel_count = out_system.GetChannelCount(),
+ .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
+ .state = static_cast<u32>(out_system.GetState())};
+
+ out_name[0] = AudioDeviceName(out_system.GetName());
+
+ if (protocol == Protocol{}) {
+ if (out_system.IsUac()) {
+ out_name[0] = AudioDeviceName("UacIn");
+ } else {
+ out_name[0] = AudioDeviceName("DeviceIn");
+ }
+ }
+
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in_manager.h b/src/core/hle/service/audio/audio_in_manager.h
new file mode 100644
index 000000000..2a983bc60
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in_manager.h
@@ -0,0 +1,57 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/audio_in_manager.h"
+#include "audio_core/in/audio_in_system.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
+using Protocol = std::array<u32, 2>;
+
+class IAudioIn;
+
+class IAudioInManager final : public ServiceFramework<IAudioInManager> {
+public:
+ explicit IAudioInManager(Core::System& system_);
+ ~IAudioInManager() override;
+
+private:
+ Result ListAudioIns(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins,
+ Out<u32> out_count);
+ Result OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
+ AudioCore::AudioIn::AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid);
+
+ Result ListAudioInsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins,
+ Out<u32> out_count);
+ Result OpenAudioInAuto(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
+ AudioCore::AudioIn::AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid);
+
+ Result ListAudioInsAutoFiltered(
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count);
+ Result OpenAudioInProtocolSpecified(
+ Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
+ AudioCore::AudioIn::AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
+
+ std::unique_ptr<AudioCore::AudioIn::Manager> impl;
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out.cpp b/src/core/hle/service/audio/audio_out.cpp
new file mode 100644
index 000000000..53009d5d7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out.cpp
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "audio_core/out/audio_out.h"
+#include "audio_core/out/audio_out_system.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/service/audio/audio_out.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+using namespace AudioCore::AudioOut;
+
+IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
+ const std::string& device_name, const AudioOutParameter& in_params,
+ Kernel::KProcess* handle, u64 applet_resource_user_id)
+ : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
+ event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
+ impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
+
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioOut::GetAudioOutState>, "GetAudioOutState"},
+ {1, D<&IAudioOut::Start>, "Start"},
+ {2, D<&IAudioOut::Stop>, "Stop"},
+ {3, D<&IAudioOut::AppendAudioOutBuffer>, "AppendAudioOutBuffer"},
+ {4, D<&IAudioOut::RegisterBufferEvent>, "RegisterBufferEvent"},
+ {5, D<&IAudioOut::GetReleasedAudioOutBuffers>, "GetReleasedAudioOutBuffers"},
+ {6, D<&IAudioOut::ContainsAudioOutBuffer>, "ContainsAudioOutBuffer"},
+ {7, D<&IAudioOut::AppendAudioOutBufferAuto>, "AppendAudioOutBufferAuto"},
+ {8, D<&IAudioOut::GetReleasedAudioOutBuffersAuto>, "GetReleasedAudioOutBuffersAuto"},
+ {9, D<&IAudioOut::GetAudioOutBufferCount>, "GetAudioOutBufferCount"},
+ {10, D<&IAudioOut::GetAudioOutPlayedSampleCount>, "GetAudioOutPlayedSampleCount"},
+ {11, D<&IAudioOut::FlushAudioOutBuffers>, "FlushAudioOutBuffers"},
+ {12, D<&IAudioOut::SetAudioOutVolume>, "SetAudioOutVolume"},
+ {13, D<&IAudioOut::GetAudioOutVolume>, "GetAudioOutVolume"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+
+ process->Open();
+}
+
+IAudioOut::~IAudioOut() {
+ impl->Free();
+ service_context.CloseEvent(event);
+ process->Close();
+}
+
+Result IAudioOut::GetAudioOutState(Out<u32> out_state) {
+ *out_state = static_cast<u32>(impl->GetState());
+ LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
+ R_SUCCEED();
+}
+
+Result IAudioOut::Start() {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->StartSystem());
+}
+
+Result IAudioOut::Stop() {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->StopSystem());
+}
+
+Result IAudioOut::AppendAudioOutBuffer(
+ InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
+ R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
+}
+
+Result IAudioOut::AppendAudioOutBufferAuto(
+ InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
+ if (audio_out_buffer.empty()) {
+ LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
+ R_THROW(Audio::ResultInsufficientBuffer);
+ }
+
+ LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
+ impl->GetSystem().GetSessionId(), buffer_client_ptr);
+ R_RETURN(impl->AppendBuffer(audio_out_buffer[0], buffer_client_ptr));
+}
+
+Result IAudioOut::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_event = &impl->GetBufferEvent();
+ R_SUCCEED();
+}
+
+Result IAudioOut::GetReleasedAudioOutBuffers(
+ OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, Out<u32> out_count) {
+ R_RETURN(this->GetReleasedAudioOutBuffersAuto(out_audio_buffer, out_count));
+}
+
+Result IAudioOut::GetReleasedAudioOutBuffersAuto(
+ OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
+
+ if (!out_audio_buffer.empty()) {
+ out_audio_buffer[0] = 0;
+ }
+ *out_count = impl->GetReleasedBuffers(out_audio_buffer);
+
+ LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
+ impl->GetSystem().GetSessionId(), *out_count);
+ R_SUCCEED();
+}
+
+Result IAudioOut::ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
+ *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
+
+ LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
+ *out_contains_buffer);
+ R_SUCCEED();
+}
+
+Result IAudioOut::GetAudioOutBufferCount(Out<u32> out_buffer_count) {
+ *out_buffer_count = impl->GetBufferCount();
+ LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
+ R_SUCCEED();
+}
+
+Result IAudioOut::GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count) {
+ *out_played_sample_count = impl->GetPlayedSampleCount();
+ LOG_DEBUG(Service_Audio, "called. Played samples={}", *out_played_sample_count);
+ R_SUCCEED();
+}
+
+Result IAudioOut::FlushAudioOutBuffers(Out<bool> out_flushed) {
+ *out_flushed = impl->FlushAudioOutBuffers();
+ LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
+ R_SUCCEED();
+}
+
+Result IAudioOut::SetAudioOutVolume(f32 volume) {
+ LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
+ impl->SetVolume(volume);
+ R_SUCCEED();
+}
+
+Result IAudioOut::GetAudioOutVolume(Out<f32> out_volume) {
+ *out_volume = impl->GetVolume();
+ LOG_DEBUG(Service_Audio, "called. Volume={}", *out_volume);
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out.h b/src/core/hle/service/audio/audio_out.h
new file mode 100644
index 000000000..779b213e7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out.h
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/audio_out_manager.h"
+#include "audio_core/out/audio_out_system.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::Audio {
+
+class IAudioOut : public ServiceFramework<IAudioOut> {
+public:
+ explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
+ size_t session_id, const std::string& device_name,
+ const AudioCore::AudioOut::AudioOutParameter& in_params,
+ Kernel::KProcess* handle, u64 applet_resource_user_id);
+ ~IAudioOut() override;
+
+ std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
+ return impl;
+ }
+
+ Result GetAudioOutState(Out<u32> out_state);
+ Result Start();
+ Result Stop();
+ Result AppendAudioOutBuffer(
+ InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer,
+ u64 buffer_client_ptr);
+ Result AppendAudioOutBufferAuto(
+ InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer,
+ u64 buffer_client_ptr);
+ Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetReleasedAudioOutBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
+ Out<u32> out_count);
+ Result GetReleasedAudioOutBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
+ Out<u32> out_count);
+ Result ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
+ Result GetAudioOutBufferCount(Out<u32> out_buffer_count);
+ Result GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count);
+ Result FlushAudioOutBuffers(Out<bool> out_flushed);
+ Result SetAudioOutVolume(f32 volume);
+ Result GetAudioOutVolume(Out<f32> out_volume);
+
+private:
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* event;
+ Kernel::KProcess* process;
+ std::shared_ptr<AudioCore::AudioOut::Out> impl;
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out_manager.cpp b/src/core/hle/service/audio/audio_out_manager.cpp
new file mode 100644
index 000000000..153445097
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out_manager.cpp
@@ -0,0 +1,101 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/string_util.h"
+#include "core/hle/service/audio/audio_out.h"
+#include "core/hle/service/audio/audio_out_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/memory.h"
+
+namespace Service::Audio {
+using namespace AudioCore::AudioOut;
+
+IAudioOutManager::IAudioOutManager(Core::System& system_)
+ : ServiceFramework{system_, "audout:u"}, impl{std::make_unique<Manager>(system_)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"},
+ {1, D<&IAudioOutManager::OpenAudioOut>, "OpenAudioOut"},
+ {2, D<&IAudioOutManager::ListAudioOutsAuto>, "ListAudioOutsAuto"},
+ {3, D<&IAudioOutManager::OpenAudioOutAuto>, "OpenAudioOutAuto"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAudioOutManager::~IAudioOutManager() = default;
+
+Result IAudioOutManager::ListAudioOuts(
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, Out<u32> out_count) {
+ R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
+}
+
+Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioOut>> out_audio_out,
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
+ AudioOutParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid) {
+ R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
+ parameter, process_handle, aruid));
+}
+
+Result IAudioOutManager::ListAudioOutsAuto(
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, Out<u32> out_count) {
+ if (!out_audio_outs.empty()) {
+ out_audio_outs[0] = AudioDeviceName("DeviceOut");
+ *out_count = 1;
+ LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
+ } else {
+ *out_count = 0;
+ LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
+ }
+
+ R_SUCCEED();
+}
+
+Result IAudioOutManager::OpenAudioOutAuto(
+ Out<AudioOutParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioOut>> out_audio_out,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
+ if (!process_handle) {
+ LOG_ERROR(Service_Audio, "Failed to get process handle");
+ R_THROW(ResultUnknown);
+ }
+ if (name.empty() || out_name.empty()) {
+ LOG_ERROR(Service_Audio, "Invalid buffers");
+ R_THROW(ResultUnknown);
+ }
+
+ size_t new_session_id{};
+ R_TRY(impl->LinkToManager());
+ R_TRY(impl->AcquireSessionId(new_session_id));
+
+ const auto device_name = Common::StringFromBuffer(name[0].name);
+ LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
+ impl->num_free_sessions);
+
+ auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name,
+ parameter, process_handle.Get(), aruid.pid);
+ R_TRY(audio_out->GetImpl()->GetSystem().Initialize(device_name, parameter, process_handle.Get(),
+ aruid.pid));
+
+ *out_audio_out = audio_out;
+ impl->sessions[new_session_id] = audio_out->GetImpl();
+ impl->applet_resource_user_ids[new_session_id] = aruid.pid;
+
+ auto& out_system = impl->sessions[new_session_id]->GetSystem();
+ *out_parameter_internal =
+ AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
+ .channel_count = out_system.GetChannelCount(),
+ .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
+ .state = static_cast<u32>(out_system.GetState())};
+
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out_manager.h b/src/core/hle/service/audio/audio_out_manager.h
new file mode 100644
index 000000000..eaa27bc79
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out_manager.h
@@ -0,0 +1,44 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/audio_out_manager.h"
+#include "audio_core/out/audio_out.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
+class IAudioOut;
+
+class IAudioOutManager final : public ServiceFramework<IAudioOutManager> {
+public:
+ explicit IAudioOutManager(Core::System& system_);
+ ~IAudioOutManager() override;
+
+private:
+ Result ListAudioOuts(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs,
+ Out<u32> out_count);
+ Result OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioOut>> out_audio_out,
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
+ AudioCore::AudioOut::AudioOutParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid);
+ Result ListAudioOutsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs,
+ Out<u32> out_count);
+ Result OpenAudioOutAuto(
+ Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioOut>> out_audio_out,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
+ AudioCore::AudioOut::AudioOutParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
+
+ std::unique_ptr<AudioCore::AudioOut::Manager> impl;
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.cpp b/src/core/hle/service/audio/audio_renderer.cpp
new file mode 100644
index 000000000..fc4aad233
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.cpp
@@ -0,0 +1,139 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/audio/audio_renderer.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+using namespace AudioCore::Renderer;
+
+IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_,
+ AudioCore::AudioRendererParameterInternal& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
+ Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
+ s32 session_id)
+ : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
+ rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
+ impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{
+ process_handle_} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
+ {1, D<&IAudioRenderer::GetSampleCount>, "GetSampleCount"},
+ {2, D<&IAudioRenderer::GetMixBufferCount>, "GetMixBufferCount"},
+ {3, D<&IAudioRenderer::GetState>, "GetState"},
+ {4, D<&IAudioRenderer::RequestUpdate>, "RequestUpdate"},
+ {5, D<&IAudioRenderer::Start>, "Start"},
+ {6, D<&IAudioRenderer::Stop>, "Stop"},
+ {7, D<&IAudioRenderer::QuerySystemEvent>, "QuerySystemEvent"},
+ {8, D<&IAudioRenderer::SetRenderingTimeLimit>, "SetRenderingTimeLimit"},
+ {9, D<&IAudioRenderer::GetRenderingTimeLimit>, "GetRenderingTimeLimit"},
+ {10, D<&IAudioRenderer::RequestUpdateAuto>, "RequestUpdateAuto"},
+ {11, nullptr, "ExecuteAudioRendererRendering"},
+ {12, D<&IAudioRenderer::SetVoiceDropParameter>, "SetVoiceDropParameter"},
+ {13, D<&IAudioRenderer::GetVoiceDropParameter>, "GetVoiceDropParameter"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+
+ process_handle->Open();
+ impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle,
+ applet_resource_user_id, session_id);
+}
+
+IAudioRenderer::~IAudioRenderer() {
+ impl->Finalize();
+ service_context.CloseEvent(rendered_event);
+ process_handle->Close();
+}
+
+Result IAudioRenderer::GetSampleRate(Out<u32> out_sample_rate) {
+ *out_sample_rate = impl->GetSystem().GetSampleRate();
+ LOG_DEBUG(Service_Audio, "called. Sample rate {}", *out_sample_rate);
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetSampleCount(Out<u32> out_sample_count) {
+ *out_sample_count = impl->GetSystem().GetSampleCount();
+ LOG_DEBUG(Service_Audio, "called. Sample count {}", *out_sample_count);
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetState(Out<u32> out_state) {
+ *out_state = !impl->GetSystem().IsActive();
+ LOG_DEBUG(Service_Audio, "called, state {}", *out_state);
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetMixBufferCount(Out<u32> out_mix_buffer_count) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_mix_buffer_count = impl->GetSystem().GetMixBufferCount();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
+ OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
+ InBuffer<BufferAttr_HipcMapAlias> input) {
+ R_RETURN(this->RequestUpdateAuto(out_buffer, out_performance_buffer, input));
+}
+
+Result IAudioRenderer::RequestUpdateAuto(
+ OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
+ OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
+ InBuffer<BufferAttr_HipcAutoSelect> input) {
+ LOG_TRACE(Service_Audio, "called");
+
+ const auto result = impl->RequestUpdate(input, out_performance_buffer, out_buffer);
+ if (result.IsFailure()) {
+ LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.GetDescription());
+ }
+
+ R_RETURN(result);
+}
+
+Result IAudioRenderer::Start() {
+ LOG_DEBUG(Service_Audio, "called");
+ impl->Start();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::Stop() {
+ LOG_DEBUG(Service_Audio, "called");
+ impl->Stop();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_UNLESS(impl->GetSystem().GetExecutionMode() != AudioCore::ExecutionMode::Manual,
+ Audio::ResultNotSupported);
+ *out_event = &rendered_event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::SetRenderingTimeLimit(u32 rendering_time_limit) {
+ LOG_DEBUG(Service_Audio, "called");
+ impl->GetSystem().SetRenderingTimeLimit(rendering_time_limit);
+ ;
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetRenderingTimeLimit(Out<u32> out_rendering_time_limit) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_rendering_time_limit = impl->GetSystem().GetRenderingTimeLimit();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::SetVoiceDropParameter(f32 voice_drop_parameter) {
+ LOG_DEBUG(Service_Audio, "called");
+ impl->GetSystem().SetVoiceDropParameter(voice_drop_parameter);
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetVoiceDropParameter(Out<f32> out_voice_drop_parameter) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_voice_drop_parameter = impl->GetSystem().GetVoiceDropParameter();
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.h b/src/core/hle/service/audio/audio_renderer.h
new file mode 100644
index 000000000..f25c50ce8
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.h
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/renderer/audio_renderer.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::Audio {
+
+class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
+public:
+ explicit IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
+ AudioCore::AudioRendererParameterInternal& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
+ Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
+ s32 session_id);
+ ~IAudioRenderer() override;
+
+private:
+ Result GetSampleRate(Out<u32> out_sample_rate);
+ Result GetSampleCount(Out<u32> out_sample_count);
+ Result GetState(Out<u32> out_state);
+ Result GetMixBufferCount(Out<u32> out_mix_buffer_count);
+ Result RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
+ OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
+ InBuffer<BufferAttr_HipcMapAlias> input);
+ Result RequestUpdateAuto(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
+ OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
+ InBuffer<BufferAttr_HipcAutoSelect> input);
+ Result Start();
+ Result Stop();
+ Result QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result SetRenderingTimeLimit(u32 rendering_time_limit);
+ Result GetRenderingTimeLimit(Out<u32> out_rendering_time_limit);
+ Result SetVoiceDropParameter(f32 voice_drop_parameter);
+ Result GetVoiceDropParameter(Out<f32> out_voice_drop_parameter);
+
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* rendered_event;
+ AudioCore::Renderer::Manager& manager;
+ std::unique_ptr<AudioCore::Renderer::Renderer> impl;
+ Kernel::KProcess* process_handle;
+ Common::ScratchBuffer<u8> output_buffer;
+ Common::ScratchBuffer<u8> performance_buffer;
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.cpp b/src/core/hle/service/audio/audio_renderer_manager.cpp
new file mode 100644
index 000000000..6a1345c07
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.cpp
@@ -0,0 +1,104 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "audio_core/audio_render_manager.h"
+#include "audio_core/common/feature_support.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/service/audio/audio_device.h"
+#include "core/hle/service/audio/audio_renderer.h"
+#include "core/hle/service/audio/audio_renderer_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+
+using namespace AudioCore::Renderer;
+
+IAudioRendererManager::IAudioRendererManager(Core::System& system_)
+ : ServiceFramework{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"},
+ {1, D<&IAudioRendererManager::GetWorkBufferSize>, "GetWorkBufferSize"},
+ {2, D<&IAudioRendererManager::GetAudioDeviceService>, "GetAudioDeviceService"},
+ {3, nullptr, "OpenAudioRendererForManualExecution"},
+ {4, D<&IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo>, "GetAudioDeviceServiceWithRevisionInfo"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAudioRendererManager::~IAudioRendererManager() = default;
+
+Result IAudioRendererManager::OpenAudioRenderer(
+ Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
+ AudioCore::AudioRendererParameterInternal parameter,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
+ LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
+ R_THROW(Audio::ResultOutOfSessions);
+ }
+
+ const auto session_id{impl->GetSessionId()};
+ if (session_id == -1) {
+ LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
+ R_THROW(Audio::ResultOutOfSessions);
+ }
+
+ LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
+ impl->GetSessionCount());
+
+ *out_audio_renderer =
+ std::make_shared<IAudioRenderer>(system, *impl, parameter, tmem_handle.Get(), tmem_size,
+ process_handle.Get(), aruid.pid, session_id);
+ R_SUCCEED();
+}
+
+Result IAudioRendererManager::GetWorkBufferSize(Out<u64> out_size,
+ AudioCore::AudioRendererParameterInternal params) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ R_TRY(impl->GetWorkBufferSize(params, *out_size))
+
+ std::string output_info{};
+ output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
+ output_info +=
+ fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
+ output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
+ static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
+ output_info += fmt::format(
+ "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
+ "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
+ "Context {:04X}",
+ params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
+ params.splitter_destinations, params.voices, params.perf_frames,
+ params.external_context_size);
+
+ LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
+ output_info, *out_size);
+ R_SUCCEED();
+}
+
+Result IAudioRendererManager::GetAudioDeviceService(
+ Out<SharedPointer<IAudioDevice>> out_audio_device, ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called, aruid={:#x}", aruid.pid);
+ *out_audio_device = std::make_shared<IAudioDevice>(
+ system, aruid.pid, Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
+ R_SUCCEED();
+}
+
+Result IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo(
+ Out<SharedPointer<IAudioDevice>> out_audio_device, u32 revision,
+ ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called, revision={} aruid={:#x}", AudioCore::GetRevisionNum(revision),
+ aruid.pid);
+ *out_audio_device =
+ std::make_shared<IAudioDevice>(system, aruid.pid, revision, num_audio_devices++);
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.h b/src/core/hle/service/audio/audio_renderer_manager.h
new file mode 100644
index 000000000..69eee664c
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.h
@@ -0,0 +1,37 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/audio_render_manager.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class IAudioDevice;
+class IAudioRenderer;
+
+class IAudioRendererManager final : public ServiceFramework<IAudioRendererManager> {
+public:
+ explicit IAudioRendererManager(Core::System& system_);
+ ~IAudioRendererManager() override;
+
+private:
+ Result OpenAudioRenderer(Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
+ AudioCore::AudioRendererParameterInternal parameter,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid);
+ Result GetWorkBufferSize(Out<u64> out_size,
+ AudioCore::AudioRendererParameterInternal parameter);
+ Result GetAudioDeviceService(Out<SharedPointer<IAudioDevice>> out_audio_device,
+ ClientAppletResourceUserId aruid);
+ Result GetAudioDeviceServiceWithRevisionInfo(Out<SharedPointer<IAudioDevice>> out_audio_device,
+ u32 revision, ClientAppletResourceUserId aruid);
+
+ std::unique_ptr<AudioCore::Renderer::Manager> impl;
+ u32 num_audio_devices{0};
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
deleted file mode 100644
index 8cc7b69f4..000000000
--- a/src/core/hle/service/audio/audout_u.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <array>
-#include <cstring>
-#include <vector>
-
-#include "audio_core/out/audio_out_system.h"
-#include "audio_core/renderer/audio_device.h"
-#include "common/common_funcs.h"
-#include "common/logging/log.h"
-#include "common/scratch_buffer.h"
-#include "common/string_util.h"
-#include "common/swap.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/audio/audout_u.h"
-#include "core/hle/service/audio/errors.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/memory.h"
-
-namespace Service::Audio {
-using namespace AudioCore::AudioOut;
-
-class IAudioOut final : public ServiceFramework<IAudioOut> {
-public:
- explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
- size_t session_id, const std::string& device_name,
- const AudioOutParameter& in_params, Kernel::KProcess* handle,
- u64 applet_resource_user_id)
- : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
- event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
- impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
-
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
- {1, &IAudioOut::Start, "Start"},
- {2, &IAudioOut::Stop, "Stop"},
- {3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"},
- {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
- {5, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffers"},
- {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
- {7, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBufferAuto"},
- {8, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffersAuto"},
- {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
- {10, &IAudioOut::GetAudioOutPlayedSampleCount, "GetAudioOutPlayedSampleCount"},
- {11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"},
- {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"},
- {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"},
- };
- // clang-format on
- RegisterHandlers(functions);
-
- process->Open();
- }
-
- ~IAudioOut() override {
- impl->Free();
- service_context.CloseEvent(event);
- process->Close();
- }
-
- [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
- return impl;
- }
-
-private:
- void GetAudioOutState(HLERequestContext& ctx) {
- const auto state = static_cast<u32>(impl->GetState());
-
- LOG_DEBUG(Service_Audio, "called. State={}", state);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(state);
- }
-
- void Start(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto result = impl->StartSystem();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void Stop(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto result = impl->StopSystem();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void AppendAudioOutBuffer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- u64 tag = rp.PopRaw<u64>();
-
- const auto in_buffer_size{ctx.GetReadBufferSize()};
- if (in_buffer_size < sizeof(AudioOutBuffer)) {
- LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
- }
-
- const auto& in_buffer = ctx.ReadBuffer();
- AudioOutBuffer buffer{};
- std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer));
-
- LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
- impl->GetSystem().GetSessionId(), tag);
-
- auto result = impl->AppendBuffer(buffer, tag);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void RegisterBufferEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto& buffer_event = impl->GetBufferEvent();
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(buffer_event);
- }
-
- void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
- const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
- released_buffer.resize_destructive(write_buffer_size);
- released_buffer[0] = 0;
-
- const auto count = impl->GetReleasedBuffers(released_buffer);
-
- ctx.WriteBuffer(released_buffer);
-
- LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
- impl->GetSystem().GetSessionId(), count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(count);
- }
-
- void ContainsAudioOutBuffer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const u64 tag{rp.Pop<u64>()};
- const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
-
- LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_queued);
- }
-
- void GetAudioOutBufferCount(HLERequestContext& ctx) {
- const auto buffer_count = impl->GetBufferCount();
-
- LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_count);
- }
-
- void GetAudioOutPlayedSampleCount(HLERequestContext& ctx) {
- const auto samples_played = impl->GetPlayedSampleCount();
-
- LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(samples_played);
- }
-
- void FlushAudioOutBuffers(HLERequestContext& ctx) {
- bool flushed{impl->FlushAudioOutBuffers()};
-
- LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(flushed);
- }
-
- void SetAudioOutVolume(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto volume = rp.Pop<f32>();
-
- LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
-
- impl->SetVolume(volume);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetAudioOutVolume(HLERequestContext& ctx) {
- const auto volume = impl->GetVolume();
-
- LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(volume);
- }
-
- KernelHelpers::ServiceContext service_context;
- Kernel::KEvent* event;
- Kernel::KProcess* process;
- std::shared_ptr<AudioCore::AudioOut::Out> impl;
- Common::ScratchBuffer<u64> released_buffer;
-};
-
-AudOutU::AudOutU(Core::System& system_)
- : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"},
- impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &AudOutU::ListAudioOuts, "ListAudioOuts"},
- {1, &AudOutU::OpenAudioOut, "OpenAudioOut"},
- {2, &AudOutU::ListAudioOuts, "ListAudioOutsAuto"},
- {3, &AudOutU::OpenAudioOut, "OpenAudioOutAuto"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudOutU::~AudOutU() = default;
-
-void AudOutU::ListAudioOuts(HLERequestContext& ctx) {
- using namespace AudioCore::Renderer;
-
- std::scoped_lock l{impl->mutex};
-
- const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
- std::vector<AudioDevice::AudioDeviceName> device_names{};
- if (write_count > 0) {
- device_names.emplace_back("DeviceOut");
- LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
- } else {
- LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
- }
-
- ctx.WriteBuffer(device_names);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(static_cast<u32>(device_names.size()));
-}
-
-void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto in_params{rp.PopRaw<AudioOutParameter>()};
- auto applet_resource_user_id{rp.PopRaw<u64>()};
- const auto device_name_data{ctx.ReadBuffer()};
- auto device_name = Common::StringFromBuffer(device_name_data);
- auto handle{ctx.GetCopyHandle(0)};
-
- auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
- if (process.IsNull()) {
- LOG_ERROR(Service_Audio, "Failed to get process handle");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- auto link{impl->LinkToManager()};
- if (link.IsError()) {
- LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(link);
- return;
- }
-
- size_t new_session_id{};
- auto result{impl->AcquireSessionId(new_session_id)};
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
- impl->num_free_sessions);
-
- auto audio_out =
- std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params,
- process.GetPointerUnsafe(), applet_resource_user_id);
- result = audio_out->GetImpl()->GetSystem().Initialize(
- device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id);
- if (result.IsError()) {
- LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- impl->sessions[new_session_id] = audio_out->GetImpl();
- impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
-
- auto& out_system = impl->sessions[new_session_id]->GetSystem();
- AudioOutParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
- .channel_count = out_system.GetChannelCount(),
- .sample_format =
- static_cast<u32>(out_system.GetSampleFormat()),
- .state = static_cast<u32>(out_system.GetState())};
-
- IPC::ResponseBuilder rb{ctx, 6, 0, 1};
-
- ctx.WriteBuffer(out_system.GetName());
-
- rb.Push(ResultSuccess);
- rb.PushRaw<AudioOutParameterInternal>(out_params);
- rb.PushIpcInterface<IAudioOut>(audio_out);
-}
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
deleted file mode 100644
index 8f288c6e0..000000000
--- a/src/core/hle/service/audio/audout_u.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "audio_core/audio_out_manager.h"
-#include "audio_core/out/audio_out.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace AudioCore::AudioOut {
-class Manager;
-class Out;
-} // namespace AudioCore::AudioOut
-
-namespace Service::Audio {
-
-class IAudioOut;
-
-class AudOutU final : public ServiceFramework<AudOutU> {
-public:
- explicit AudOutU(Core::System& system_);
- ~AudOutU() override;
-
-private:
- void ListAudioOuts(HLERequestContext& ctx);
- void OpenAudioOut(HLERequestContext& ctx);
-
- KernelHelpers::ServiceContext service_context;
- std::unique_ptr<AudioCore::AudioOut::Manager> impl;
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
deleted file mode 100644
index 10108abc0..000000000
--- a/src/core/hle/service/audio/audren_u.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <array>
-#include <memory>
-
-#include "audio_core/audio_core.h"
-#include "audio_core/common/audio_renderer_parameter.h"
-#include "audio_core/common/feature_support.h"
-#include "audio_core/renderer/audio_device.h"
-#include "audio_core/renderer/audio_renderer.h"
-#include "audio_core/renderer/voice/voice_info.h"
-#include "common/alignment.h"
-#include "common/bit_util.h"
-#include "common/common_funcs.h"
-#include "common/logging/log.h"
-#include "common/polyfill_ranges.h"
-#include "common/scratch_buffer.h"
-#include "common/string_util.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/kernel/k_transfer_memory.h"
-#include "core/hle/service/audio/audren_u.h"
-#include "core/hle/service/audio/errors.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/memory.h"
-
-using namespace AudioCore::Renderer;
-
-namespace Service::Audio {
-
-class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
-public:
- explicit IAudioRenderer(Core::System& system_, Manager& manager_,
- AudioCore::AudioRendererParameterInternal& params,
- Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
- u32 process_handle, Kernel::KProcess& process_,
- u64 applet_resource_user_id, s32 session_id)
- : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
- rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
- impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
- {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
- {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
- {3, &IAudioRenderer::GetState, "GetState"},
- {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
- {5, &IAudioRenderer::Start, "Start"},
- {6, &IAudioRenderer::Stop, "Stop"},
- {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
- {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
- {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
- {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"},
- {11, nullptr, "ExecuteAudioRendererRendering"},
- {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"},
- {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"},
- };
- // clang-format on
- RegisterHandlers(functions);
-
- process.Open();
- impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
- applet_resource_user_id, session_id);
- }
-
- ~IAudioRenderer() override {
- impl->Finalize();
- service_context.CloseEvent(rendered_event);
- process.Close();
- }
-
-private:
- void GetSampleRate(HLERequestContext& ctx) {
- const auto sample_rate{impl->GetSystem().GetSampleRate()};
-
- LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(sample_rate);
- }
-
- void GetSampleCount(HLERequestContext& ctx) {
- const auto sample_count{impl->GetSystem().GetSampleCount()};
-
- LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(sample_count);
- }
-
- void GetState(HLERequestContext& ctx) {
- const u32 state{!impl->GetSystem().IsActive()};
-
- LOG_DEBUG(Service_Audio, "called, state {}", state);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(state);
- }
-
- void GetMixBufferCount(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- const auto buffer_count{impl->GetSystem().GetMixBufferCount()};
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_count);
- }
-
- void RequestUpdate(HLERequestContext& ctx) {
- LOG_TRACE(Service_Audio, "called");
-
- const auto input{ctx.ReadBuffer(0)};
-
- // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
- // checking size 0. Performance size is 0 for most games.
-
- auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
- if (is_buffer_b) {
- const auto buffersB{ctx.BufferDescriptorB()};
- output_buffer.resize_destructive(buffersB[0].Size());
- performance_buffer.resize_destructive(buffersB[1].Size());
- } else {
- const auto buffersC{ctx.BufferDescriptorC()};
- output_buffer.resize_destructive(buffersC[0].Size());
- performance_buffer.resize_destructive(buffersC[1].Size());
- }
-
- auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
-
- if (result.IsSuccess()) {
- if (is_buffer_b) {
- ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
- ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
- } else {
- ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
- ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
- }
- } else {
- LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!",
- result.GetDescription());
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void Start(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- impl->Start();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void Stop(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- impl->Stop();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void QuerySystemEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Audio::ResultNotSupported);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(rendered_event->GetReadableEvent());
- }
-
- void SetRenderingTimeLimit(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- IPC::RequestParser rp{ctx};
- auto limit = rp.PopRaw<u32>();
-
- auto& system_ = impl->GetSystem();
- system_.SetRenderingTimeLimit(limit);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetRenderingTimeLimit(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto& system_ = impl->GetSystem();
- auto time = system_.GetRenderingTimeLimit();
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(time);
- }
-
- void ExecuteAudioRendererRendering(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
- }
-
- void SetVoiceDropParameter(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- IPC::RequestParser rp{ctx};
- auto voice_drop_param{rp.Pop<f32>()};
-
- auto& system_ = impl->GetSystem();
- system_.SetVoiceDropParameter(voice_drop_param);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetVoiceDropParameter(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto& system_ = impl->GetSystem();
- auto voice_drop_param{system_.GetVoiceDropParameter()};
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(voice_drop_param);
- }
-
- KernelHelpers::ServiceContext service_context;
- Kernel::KEvent* rendered_event;
- Manager& manager;
- std::unique_ptr<Renderer> impl;
- Kernel::KProcess& process;
- Common::ScratchBuffer<u8> output_buffer;
- Common::ScratchBuffer<u8> performance_buffer;
-};
-
-class IAudioDevice final : public ServiceFramework<IAudioDevice> {
-
-public:
- explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
- u32 device_num)
- : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
- impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
- event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
- static const FunctionInfo functions[] = {
- {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
- {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
- {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
- {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
- {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
- {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
- {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
- {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
- {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
- {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
- {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
- {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
- {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"},
- {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"},
- };
- RegisterHandlers(functions);
-
- event->Signal();
- }
-
- ~IAudioDevice() override {
- service_context.CloseEvent(event);
- }
-
-private:
- void ListAudioDeviceName(HLERequestContext& ctx) {
- const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
-
- std::vector<AudioDevice::AudioDeviceName> out_names{};
-
- const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
-
- std::string out{};
- for (u32 i = 0; i < out_count; i++) {
- std::string a{};
- u32 j = 0;
- while (out_names[i].name[j] != '\0') {
- a += out_names[i].name[j];
- j++;
- }
- out += "\n\t" + a;
- }
-
- LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
-
- IPC::ResponseBuilder rb{ctx, 3};
-
- ctx.WriteBuffer(out_names);
-
- rb.Push(ResultSuccess);
- rb.Push(out_count);
- }
-
- void SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const f32 volume = rp.Pop<f32>();
-
- const auto device_name_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(device_name_buffer);
-
- LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume);
-
- if (name == "AudioTvOutput") {
- impl->SetDeviceVolumes(volume);
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
- const auto device_name_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(device_name_buffer);
-
- LOG_DEBUG(Service_Audio, "called. Name={}", name);
-
- f32 volume{1.0f};
- if (name == "AudioTvOutput") {
- volume = impl->GetDeviceVolume(name);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(volume);
- }
-
- void GetActiveAudioDeviceName(HLERequestContext& ctx) {
- const auto write_size = ctx.GetWriteBufferSize();
- std::string out_name{"AudioTvOutput"};
-
- LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);
-
- out_name.resize(write_size);
-
- ctx.WriteBuffer(out_name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "(STUBBED) called");
-
- event->Signal();
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(event->GetReadableEvent());
- }
-
- void GetActiveChannelCount(HLERequestContext& ctx) {
- const auto& sink{system.AudioCore().GetOutputSink()};
- u32 channel_count{sink.GetSystemChannels()};
-
- LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);
-
- IPC::ResponseBuilder rb{ctx, 3};
-
- rb.Push(ResultSuccess);
- rb.Push<u32>(channel_count);
- }
-
- void QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(event->GetReadableEvent());
- }
-
- void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(event->GetReadableEvent());
- }
-
- void ListAudioOutputDeviceName(HLERequestContext& ctx) {
- const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
-
- std::vector<AudioDevice::AudioDeviceName> out_names{};
-
- const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
-
- std::string out{};
- for (u32 i = 0; i < out_count; i++) {
- std::string a{};
- u32 j = 0;
- while (out_names[i].name[j] != '\0') {
- a += out_names[i].name[j];
- j++;
- }
- out += "\n\t" + a;
- }
-
- LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
-
- IPC::ResponseBuilder rb{ctx, 3};
-
- ctx.WriteBuffer(out_names);
-
- rb.Push(ResultSuccess);
- rb.Push(out_count);
- }
-
- KernelHelpers::ServiceContext service_context;
- std::unique_ptr<AudioDevice> impl;
- Kernel::KEvent* event;
-};
-
-AudRenU::AudRenU(Core::System& system_)
- : ServiceFramework{system_, "audren:u"},
- service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
- {1, &AudRenU::GetWorkBufferSize, "GetWorkBufferSize"},
- {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
- {3, nullptr, "OpenAudioRendererForManualExecution"},
- {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudRenU::~AudRenU() = default;
-
-void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- AudioCore::AudioRendererParameterInternal params;
- rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
- rp.Skip(1, false);
- auto transfer_memory_size = rp.Pop<u64>();
- auto applet_resource_user_id = rp.Pop<u64>();
- auto transfer_memory_handle = ctx.GetCopyHandle(0);
- auto process_handle = ctx.GetCopyHandle(1);
-
- if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
- LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Audio::ResultOutOfSessions);
- return;
- }
-
- auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- const auto session_id{impl->GetSessionId()};
- if (session_id == -1) {
- LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Audio::ResultOutOfSessions);
- return;
- }
-
- LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
- impl->GetSessionCount());
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(),
- transfer_memory_size, process_handle, *process,
- applet_resource_user_id, session_id);
-}
-
-void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) {
- AudioCore::AudioRendererParameterInternal params;
-
- IPC::RequestParser rp{ctx};
- rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
-
- u64 size{0};
- auto result = impl->GetWorkBufferSize(params, size);
-
- std::string output_info{};
- output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
- output_info +=
- fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
- output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
- static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
- output_info += fmt::format(
- "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
- "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
- "Context {:04X}",
- params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
- params.splitter_destinations, params.voices, params.perf_frames,
- params.external_context_size);
-
- LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
- output_info, size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push<u64>(size);
-}
-
-void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto applet_resource_user_id = rp.Pop<u64>();
-
- LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id,
- ::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
-}
-
-void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) {
- LOG_ERROR(Service_Audio, "called. Implement me!");
-}
-
-void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) {
- struct Parameters {
- u32 revision;
- u64 applet_resource_user_id;
- };
-
- IPC::RequestParser rp{ctx};
-
- const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>();
-
- LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}",
- AudioCore::GetRevisionNum(revision), applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision,
- num_audio_devices++);
-}
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
deleted file mode 100644
index 3d7993a16..000000000
--- a/src/core/hle/service/audio/audren_u.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "audio_core/audio_render_manager.h"
-#include "common/scratch_buffer.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-class IAudioRenderer;
-
-class AudRenU final : public ServiceFramework<AudRenU> {
-public:
- explicit AudRenU(Core::System& system_);
- ~AudRenU() override;
-
-private:
- void OpenAudioRenderer(HLERequestContext& ctx);
- void GetWorkBufferSize(HLERequestContext& ctx);
- void GetAudioDeviceService(HLERequestContext& ctx);
- void OpenAudioRendererForManualExecution(HLERequestContext& ctx);
- void GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx);
-
- KernelHelpers::ServiceContext service_context;
- std::unique_ptr<AudioCore::Renderer::Manager> impl;
- u32 num_audio_devices{0};
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/final_output_recorder_manager.cpp
index bc55cec17..f70a0e62d 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/final_output_recorder_manager.cpp
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hle/service/audio/audrec_u.h"
+#include "core/hle/service/audio/final_output_recorder_manager.h"
namespace Service::Audio {
@@ -30,13 +30,14 @@ public:
}
};
-AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} {
+IFinalOutputRecorderManager::IFinalOutputRecorderManager(Core::System& system_)
+ : ServiceFramework{system_, "audrec:u"} {
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFinalOutputRecorder"},
};
RegisterHandlers(functions);
}
-AudRecU::~AudRecU() = default;
+IFinalOutputRecorderManager::~IFinalOutputRecorderManager() = default;
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/final_output_recorder_manager.h
index 9edf89f6c..0663b894e 100644
--- a/src/core/hle/service/audio/audrec_a.h
+++ b/src/core/hle/service/audio/final_output_recorder_manager.h
@@ -11,10 +11,10 @@ class System;
namespace Service::Audio {
-class AudRecA final : public ServiceFramework<AudRecA> {
+class IFinalOutputRecorderManager final : public ServiceFramework<IFinalOutputRecorderManager> {
public:
- explicit AudRecA(Core::System& system_);
- ~AudRecA() override;
+ explicit IFinalOutputRecorderManager(Core::System& system_);
+ ~IFinalOutputRecorderManager() override;
};
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
index fa82e9ac7..7e2e42bbe 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
@@ -1,11 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hle/service/audio/audrec_a.h"
+#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
namespace Service::Audio {
-AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} {
+IFinalOutputRecorderManagerForApplet::IFinalOutputRecorderManagerForApplet(Core::System& system_)
+ : ServiceFramework{system_, "audrec:a"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestSuspend"},
@@ -16,6 +17,6 @@ AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"}
RegisterHandlers(functions);
}
-AudRecA::~AudRecA() = default;
+IFinalOutputRecorderManagerForApplet::~IFinalOutputRecorderManagerForApplet() = default;
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
index 8b4817884..27940f7e0 100644
--- a/src/core/hle/service/audio/audrec_u.h
+++ b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
@@ -11,10 +11,11 @@ class System;
namespace Service::Audio {
-class AudRecU final : public ServiceFramework<AudRecU> {
+class IFinalOutputRecorderManagerForApplet final
+ : public ServiceFramework<IFinalOutputRecorderManagerForApplet> {
public:
- explicit AudRecU(Core::System& system_);
- ~AudRecU() override;
+ explicit IFinalOutputRecorderManagerForApplet(Core::System& system_);
+ ~IFinalOutputRecorderManagerForApplet() override;
};
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder.cpp b/src/core/hle/service/audio/hardware_opus_decoder.cpp
new file mode 100644
index 000000000..03d3374c1
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder.cpp
@@ -0,0 +1,145 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/audio/hardware_opus_decoder.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+
+using namespace AudioCore::OpusDecoder;
+
+IHardwareOpusDecoder::IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
+ : ServiceFramework{system_, "IHardwareOpusDecoder"},
+ impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IHardwareOpusDecoder::DecodeInterleavedOld>, "DecodeInterleavedOld"},
+ {1, D<&IHardwareOpusDecoder::SetContext>, "SetContext"},
+ {2, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld>, "DecodeInterleavedForMultiStreamOld"},
+ {3, D<&IHardwareOpusDecoder::SetContextForMultiStream>, "SetContextForMultiStream"},
+ {4, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfOld>, "DecodeInterleavedWithPerfOld"},
+ {5, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld>, "DecodeInterleavedForMultiStreamWithPerfOld"},
+ {6, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld>, "DecodeInterleavedWithPerfAndResetOld"},
+ {7, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld>, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
+ {8, D<&IHardwareOpusDecoder::DecodeInterleaved>, "DecodeInterleaved"},
+ {9, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStream>, "DecodeInterleavedForMultiStream"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IHardwareOpusDecoder::~IHardwareOpusDecoder() = default;
+
+Result IHardwareOpusDecoder::Initialize(const OpusParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory,
+ u64 transfer_memory_size) {
+ return impl->Initialize(params, transfer_memory, transfer_memory_size);
+}
+
+Result IHardwareOpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory,
+ u64 transfer_memory_size) {
+ return impl->Initialize(params, transfer_memory, transfer_memory_size);
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data) {
+ R_TRY(impl->DecodeInterleaved(out_data_size, nullptr, out_sample_count, opus_data, out_pcm_data,
+ false));
+ LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
+ *out_sample_count);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->SetContext(decoder_context));
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld(
+ OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, Out<u32> out_data_size,
+ Out<u32> out_sample_count, InBuffer<BufferAttr_HipcMapAlias> opus_data) {
+ R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, nullptr, out_sample_count, opus_data,
+ out_pcm_data, false));
+ LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
+ *out_sample_count);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::SetContextForMultiStream(
+ InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->SetContext(decoder_context));
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedWithPerfOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data) {
+ R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
+ out_pcm_data, false));
+ LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
+ *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data) {
+ R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
+ opus_data, out_pcm_data, false));
+ LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
+ *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
+ R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
+ out_pcm_data, reset));
+ LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
+ *out_data_size, *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
+ R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
+ opus_data, out_pcm_data, reset));
+ LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
+ *out_data_size, *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleaved(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
+ bool reset) {
+ R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
+ out_pcm_data, reset));
+ LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
+ *out_data_size, *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedForMultiStream(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
+ bool reset) {
+ R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
+ opus_data, out_pcm_data, reset));
+ LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
+ *out_data_size, *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder.h b/src/core/hle/service/audio/hardware_opus_decoder.h
new file mode 100644
index 000000000..511bf46bd
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder.h
@@ -0,0 +1,63 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/opus/decoder.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
+public:
+ explicit IHardwareOpusDecoder(Core::System& system_,
+ AudioCore::OpusDecoder::HardwareOpus& hardware_opus);
+ ~IHardwareOpusDecoder() override;
+
+ Result Initialize(const AudioCore::OpusDecoder::OpusParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
+ Result Initialize(const AudioCore::OpusDecoder::OpusMultiStreamParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
+
+private:
+ Result DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data);
+ Result SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
+ Result DecodeInterleavedForMultiStreamOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data);
+ Result SetContextForMultiStream(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
+ Result DecodeInterleavedWithPerfOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data);
+ Result DecodeInterleavedForMultiStreamWithPerfOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data);
+ Result DecodeInterleavedWithPerfAndResetOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
+ Result DecodeInterleavedForMultiStreamWithPerfAndResetOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
+ Result DecodeInterleaved(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
+ bool reset);
+ Result DecodeInterleavedForMultiStream(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
+ bool reset);
+
+ std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
+ Common::ScratchBuffer<u8> output_data;
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp b/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
new file mode 100644
index 000000000..9de72e30f
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
@@ -0,0 +1,156 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/audio/hardware_opus_decoder.h"
+#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+
+using namespace AudioCore::OpusDecoder;
+
+IHardwareOpusDecoderManager::IHardwareOpusDecoderManager(Core::System& system_)
+ : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoder>, "OpenHardwareOpusDecoder"},
+ {1, D<&IHardwareOpusDecoderManager::GetWorkBufferSize>, "GetWorkBufferSize"},
+ {2, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream>, "OpenOpusDecoderForMultiStream"},
+ {3, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream>, "GetWorkBufferSizeForMultiStream"},
+ {4, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx>, "OpenHardwareOpusDecoderEx"},
+ {5, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeEx>, "GetWorkBufferSizeEx"},
+ {6, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx>, "OpenHardwareOpusDecoderForMultiStreamEx"},
+ {7, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx>, "GetWorkBufferSizeForMultiStreamEx"},
+ {8, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeExEx>, "GetWorkBufferSizeExEx"},
+ {9, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx>, "GetWorkBufferSizeForMultiStreamExEx"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+}
+
+IHardwareOpusDecoderManager::~IHardwareOpusDecoderManager() = default;
+
+Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoder(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParameters params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
+ LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
+ params.sample_rate, params.channel_count, tmem_size);
+
+ auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
+ OpusParametersEx ex{
+ .sample_rate = params.sample_rate,
+ .channel_count = params.channel_count,
+ .use_large_frame_size = false,
+ };
+ R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
+
+ *out_decoder = decoder;
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSize(Out<u32> out_size, OpusParameters params) {
+ R_TRY(impl.GetWorkBufferSize(params, *out_size));
+ LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size {:#x}",
+ params.sample_rate, params.channel_count, *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
+ LOG_DEBUG(Service_Audio,
+ "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
+ "transfer_memory_size {:#x}",
+ params->sample_rate, params->channel_count, params->total_stream_count,
+ params->stereo_stream_count, tmem_size);
+
+ auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
+
+ OpusMultiStreamParametersEx ex{
+ .sample_rate = params->sample_rate,
+ .channel_count = params->channel_count,
+ .total_stream_count = params->total_stream_count,
+ .stereo_stream_count = params->stereo_stream_count,
+ .use_large_frame_size = false,
+ .mappings{},
+ };
+ std::memcpy(ex.mappings.data(), params->mappings.data(), sizeof(params->mappings));
+ R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
+
+ *out_decoder = decoder;
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params) {
+ R_TRY(impl.GetWorkBufferSizeForMultiStream(*params, *out_size));
+ LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParametersEx params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
+ LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
+ params.sample_rate, params.channel_count, tmem_size);
+
+ auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
+ R_TRY(decoder->Initialize(params, tmem_handle.Get(), tmem_size));
+
+ *out_decoder = decoder;
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(Out<u32> out_size,
+ OpusParametersEx params) {
+ R_TRY(impl.GetWorkBufferSizeEx(params, *out_size));
+ LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
+ LOG_DEBUG(Service_Audio,
+ "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
+ "use_large_frame_size {}"
+ "transfer_memory_size {:#x}",
+ params->sample_rate, params->channel_count, params->total_stream_count,
+ params->stereo_stream_count, params->use_large_frame_size, tmem_size);
+
+ auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
+
+ R_TRY(decoder->Initialize(*params, tmem_handle.Get(), tmem_size));
+
+ *out_decoder = decoder;
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
+ R_TRY(impl.GetWorkBufferSizeForMultiStreamEx(*params, *out_size));
+ LOG_DEBUG(Service_Audio,
+ "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
+ "use_large_frame_size {} -- returned size {:#x}",
+ params->sample_rate, params->channel_count, params->total_stream_count,
+ params->stereo_stream_count, params->use_large_frame_size, *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeExEx(Out<u32> out_size,
+ OpusParametersEx params) {
+ R_TRY(impl.GetWorkBufferSizeExEx(params, *out_size));
+ LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
+ R_TRY(impl.GetWorkBufferSizeForMultiStreamExEx(*params, *out_size));
+ LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
+ R_SUCCEED();
+}
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder_manager.h b/src/core/hle/service/audio/hardware_opus_decoder_manager.h
new file mode 100644
index 000000000..4f869c517
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder_manager.h
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/opus/decoder_manager.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class IHardwareOpusDecoder;
+
+using AudioCore::OpusDecoder::OpusMultiStreamParameters;
+using AudioCore::OpusDecoder::OpusMultiStreamParametersEx;
+using AudioCore::OpusDecoder::OpusParameters;
+using AudioCore::OpusDecoder::OpusParametersEx;
+
+class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
+public:
+ explicit IHardwareOpusDecoderManager(Core::System& system_);
+ ~IHardwareOpusDecoderManager() override;
+
+private:
+ Result OpenHardwareOpusDecoder(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ OpusParameters params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle);
+ Result GetWorkBufferSize(Out<u32> out_size, OpusParameters params);
+ Result OpenHardwareOpusDecoderForMultiStream(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle);
+ Result GetWorkBufferSizeForMultiStream(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params);
+ Result OpenHardwareOpusDecoderEx(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ OpusParametersEx params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle);
+ Result GetWorkBufferSizeEx(Out<u32> out_size, OpusParametersEx params);
+ Result OpenHardwareOpusDecoderForMultiStreamEx(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle);
+ Result GetWorkBufferSizeForMultiStreamEx(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
+ Result GetWorkBufferSizeExEx(Out<u32> out_size, OpusParametersEx params);
+ Result GetWorkBufferSizeForMultiStreamExEx(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
+
+ Core::System& system;
+ AudioCore::OpusDecoder::OpusDecoderManager impl;
+};
+
+} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
deleted file mode 100644
index 91f33aabd..000000000
--- a/src/core/hle/service/audio/hwopus.cpp
+++ /dev/null
@@ -1,502 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <memory>
-#include <vector>
-
-#include "audio_core/opus/decoder.h"
-#include "audio_core/opus/parameters.h"
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "common/scratch_buffer.h"
-#include "core/core.h"
-#include "core/hle/service/audio/hwopus.h"
-#include "core/hle/service/ipc_helpers.h"
-
-namespace Service::Audio {
-using namespace AudioCore::OpusDecoder;
-
-class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
-public:
- explicit IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
- : ServiceFramework{system_, "IHardwareOpusDecoder"},
- impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IHardwareOpusDecoder::DecodeInterleavedOld, "DecodeInterleavedOld"},
- {1, &IHardwareOpusDecoder::SetContext, "SetContext"},
- {2, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld, "DecodeInterleavedForMultiStreamOld"},
- {3, &IHardwareOpusDecoder::SetContextForMultiStream, "SetContextForMultiStream"},
- {4, &IHardwareOpusDecoder::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
- {5, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld, "DecodeInterleavedForMultiStreamWithPerfOld"},
- {6, &IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld, "DecodeInterleavedWithPerfAndResetOld"},
- {7, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
- {8, &IHardwareOpusDecoder::DecodeInterleaved, "DecodeInterleaved"},
- {9, &IHardwareOpusDecoder::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
- Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
- u64 transfer_memory_size) {
- return impl->Initialize(params, transfer_memory, transfer_memory_size);
- }
-
- Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
- u64 transfer_memory_size) {
- return impl->Initialize(params, transfer_memory, transfer_memory_size);
- }
-
-private:
- void DecodeInterleavedOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- auto result =
- impl->DecodeInterleaved(&size, nullptr, &sample_count, input_data, output_data, false);
-
- LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- }
-
- void SetContext(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- LOG_DEBUG(Service_Audio, "called");
-
- auto input_data{ctx.ReadBuffer(0)};
- auto result = impl->SetContext(input_data);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void DecodeInterleavedForMultiStreamOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- auto result = impl->DecodeInterleavedForMultiStream(&size, nullptr, &sample_count,
- input_data, output_data, false);
-
- LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- }
-
- void SetContextForMultiStream(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- LOG_DEBUG(Service_Audio, "called");
-
- auto input_data{ctx.ReadBuffer(0)};
- auto result = impl->SetContext(input_data);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void DecodeInterleavedWithPerfOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
- output_data, false);
-
- LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
- sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleavedForMultiStreamWithPerfOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
- input_data, output_data, false);
-
- LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
- sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleavedWithPerfAndResetOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto reset{rp.Pop<bool>()};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
- output_data, reset);
-
- LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
- reset, size, sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleavedForMultiStreamWithPerfAndResetOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto reset{rp.Pop<bool>()};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
- input_data, output_data, reset);
-
- LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
- reset, size, sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleaved(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto reset{rp.Pop<bool>()};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
- output_data, reset);
-
- LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
- reset, size, sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleavedForMultiStream(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto reset{rp.Pop<bool>()};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
- input_data, output_data, reset);
-
- LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
- reset, size, sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
- Common::ScratchBuffer<u8> output_data;
-};
-
-void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto params = rp.PopRaw<OpusParameters>();
- auto transfer_memory_size{rp.Pop<u32>()};
- auto transfer_memory_handle{ctx.GetCopyHandle(0)};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
- params.sample_rate, params.channel_count, transfer_memory_size);
-
- auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
-
- OpusParametersEx ex{
- .sample_rate = params.sample_rate,
- .channel_count = params.channel_count,
- .use_large_frame_size = false,
- };
- auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result);
- rb.PushIpcInterface(decoder);
-}
-
-void HwOpus::GetWorkBufferSize(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<OpusParameters>();
-
- u64 size{};
- auto result = impl.GetWorkBufferSize(params, size);
-
- LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size 0x{:X}",
- params.sample_rate, params.channel_count, size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParameters params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
-
- auto transfer_memory_size{rp.Pop<u32>()};
- auto transfer_memory_handle{ctx.GetCopyHandle(0)};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- LOG_DEBUG(Service_Audio,
- "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
- "transfer_memory_size 0x{:X}",
- params.sample_rate, params.channel_count, params.total_stream_count,
- params.stereo_stream_count, transfer_memory_size);
-
- auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
-
- OpusMultiStreamParametersEx ex{
- .sample_rate = params.sample_rate,
- .channel_count = params.channel_count,
- .total_stream_count = params.total_stream_count,
- .stereo_stream_count = params.stereo_stream_count,
- .use_large_frame_size = false,
- .mappings{},
- };
- std::memcpy(ex.mappings.data(), params.mappings.data(), sizeof(params.mappings));
- auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result);
- rb.PushIpcInterface(decoder);
-}
-
-void HwOpus::GetWorkBufferSizeForMultiStream(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParameters params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeForMultiStream(params, size);
-
- LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto params = rp.PopRaw<OpusParametersEx>();
- auto transfer_memory_size{rp.Pop<u32>()};
- auto transfer_memory_handle{ctx.GetCopyHandle(0)};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
- params.sample_rate, params.channel_count, transfer_memory_size);
-
- auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
-
- auto result =
- decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result);
- rb.PushIpcInterface(decoder);
-}
-
-void HwOpus::GetWorkBufferSizeEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<OpusParametersEx>();
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeEx(params, size);
-
- LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParametersEx params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
-
- auto transfer_memory_size{rp.Pop<u32>()};
- auto transfer_memory_handle{ctx.GetCopyHandle(0)};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- LOG_DEBUG(Service_Audio,
- "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
- "use_large_frame_size {}"
- "transfer_memory_size 0x{:X}",
- params.sample_rate, params.channel_count, params.total_stream_count,
- params.stereo_stream_count, params.use_large_frame_size, transfer_memory_size);
-
- auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
-
- auto result =
- decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result);
- rb.PushIpcInterface(decoder);
-}
-
-void HwOpus::GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParametersEx params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeForMultiStreamEx(params, size);
-
- LOG_DEBUG(Service_Audio,
- "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
- "use_large_frame_size {} -- returned size 0x{:X}",
- params.sample_rate, params.channel_count, params.total_stream_count,
- params.stereo_stream_count, params.use_large_frame_size, size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::GetWorkBufferSizeExEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<OpusParametersEx>();
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeExEx(params, size);
-
- LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParametersEx params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeForMultiStreamExEx(params, size);
-
- LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-HwOpus::HwOpus(Core::System& system_)
- : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
- static const FunctionInfo functions[] = {
- {0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
- {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
- {2, &HwOpus::OpenHardwareOpusDecoderForMultiStream, "OpenOpusDecoderForMultiStream"},
- {3, &HwOpus::GetWorkBufferSizeForMultiStream, "GetWorkBufferSizeForMultiStream"},
- {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
- {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
- {6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx,
- "OpenHardwareOpusDecoderForMultiStreamEx"},
- {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
- {8, &HwOpus::GetWorkBufferSizeExEx, "GetWorkBufferSizeExEx"},
- {9, &HwOpus::GetWorkBufferSizeForMultiStreamExEx, "GetWorkBufferSizeForMultiStreamExEx"},
- };
- RegisterHandlers(functions);
-}
-
-HwOpus::~HwOpus() = default;
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
deleted file mode 100644
index d3960065e..000000000
--- a/src/core/hle/service/audio/hwopus.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "audio_core/opus/decoder_manager.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-
-class HwOpus final : public ServiceFramework<HwOpus> {
-public:
- explicit HwOpus(Core::System& system_);
- ~HwOpus() override;
-
-private:
- void OpenHardwareOpusDecoder(HLERequestContext& ctx);
- void GetWorkBufferSize(HLERequestContext& ctx);
- void OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx);
- void GetWorkBufferSizeForMultiStream(HLERequestContext& ctx);
- void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
- void GetWorkBufferSizeEx(HLERequestContext& ctx);
- void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx);
- void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
- void GetWorkBufferSizeExEx(HLERequestContext& ctx);
- void GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx);
-
- Core::System& system;
- AudioCore::OpusDecoder::OpusDecoderManager impl;
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
index f24682c34..5a5f610f3 100644
--- a/src/core/hle/service/cmif_serialization.h
+++ b/src/core/hle/service/cmif_serialization.h
@@ -415,7 +415,7 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
auto& buffer = temp[OutBufferIndex];
const size_t size = buffer.size();
- if (ctx.CanWriteBuffer(OutBufferIndex)) {
+ if (size > 0 && ctx.CanWriteBuffer(OutBufferIndex)) {
if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
ctx.WriteBuffer(buffer.data(), size, OutBufferIndex);
} else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) {
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
index 113369203..dd069f36f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
@@ -9,7 +9,7 @@
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/filesystem/filesystem.h"
-#include "core/hle/service/filesystem/fsp/fsp_util.h"
+#include "core/hle/service/filesystem/fsp/fsp_types.h"
#include "core/hle/service/service.h"
namespace FileSys::Sf {
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
new file mode 100644
index 000000000..626328234
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
@@ -0,0 +1,33 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
+#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
+
+namespace Service::FileSystem {
+
+IMultiCommitManager::IMultiCommitManager(Core::System& system_)
+ : ServiceFramework{system_, "IMultiCommitManager"} {
+ static const FunctionInfo functions[] = {
+ {1, D<&IMultiCommitManager::Add>, "Add"},
+ {2, D<&IMultiCommitManager::Commit>, "Commit"},
+ };
+ RegisterHandlers(functions);
+}
+
+IMultiCommitManager::~IMultiCommitManager() = default;
+
+Result IMultiCommitManager::Add(std::shared_ptr<IFileSystem> filesystem) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ R_SUCCEED();
+}
+
+Result IMultiCommitManager::Commit() {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ R_SUCCEED();
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
new file mode 100644
index 000000000..8ebf7c7d9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
+public:
+ explicit IMultiCommitManager(Core::System& system_);
+ ~IMultiCommitManager() override;
+
+private:
+ Result Add(std::shared_ptr<IFileSystem> filesystem);
+ Result Commit();
+
+ FileSys::VirtualFile backend;
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
new file mode 100644
index 000000000..ff823586b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
@@ -0,0 +1,161 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/hex_util.h"
+#include "core/file_sys/savedata_factory.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
+#include "core/hle/service/filesystem/save_data_controller.h"
+
+namespace Service::FileSystem {
+
+ISaveDataInfoReader::ISaveDataInfoReader(Core::System& system_,
+ std::shared_ptr<SaveDataController> save_data_controller_,
+ FileSys::SaveDataSpaceId space)
+ : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
+ save_data_controller_} {
+ static const FunctionInfo functions[] = {
+ {0, D<&ISaveDataInfoReader::ReadSaveDataInfo>, "ReadSaveDataInfo"},
+ };
+ RegisterHandlers(functions);
+
+ FindAllSaves(space);
+}
+
+ISaveDataInfoReader::~ISaveDataInfoReader() = default;
+
+static u64 stoull_be(std::string_view str) {
+ if (str.size() != 16) {
+ return 0;
+ }
+
+ const auto bytes = Common::HexStringToArray<0x8>(str);
+ u64 out{};
+ std::memcpy(&out, bytes.data(), sizeof(u64));
+
+ return Common::swap64(out);
+}
+
+Result ISaveDataInfoReader::ReadSaveDataInfo(
+ Out<u64> out_count, OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries) {
+ LOG_DEBUG(Service_FS, "called");
+
+ // Calculate how many entries we can fit in the output buffer
+ const u64 count_entries = out_entries.size();
+
+ // Cap at total number of entries.
+ const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
+
+ // Determine data start and end
+ const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
+ const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
+ const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
+
+ next_entry_index += actual_entries;
+
+ // Write the data to memory
+ std::memcpy(out_entries.data(), begin, range_size);
+ *out_count = actual_entries;
+
+ R_SUCCEED();
+}
+
+void ISaveDataInfoReader::FindAllSaves(FileSys::SaveDataSpaceId space) {
+ FileSys::VirtualDir save_root{};
+ const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
+
+ if (result != ResultSuccess || save_root == nullptr) {
+ LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
+ return;
+ }
+
+ for (const auto& type : save_root->GetSubdirectories()) {
+ if (type->GetName() == "save") {
+ FindNormalSaves(space, type);
+ } else if (space == FileSys::SaveDataSpaceId::Temporary) {
+ FindTemporaryStorageSaves(space, type);
+ }
+ }
+}
+
+void ISaveDataInfoReader::FindNormalSaves(FileSys::SaveDataSpaceId space,
+ const FileSys::VirtualDir& type) {
+ for (const auto& save_id : type->GetSubdirectories()) {
+ for (const auto& user_id : save_id->GetSubdirectories()) {
+ // Skip non user id subdirectories
+ if (user_id->GetName().size() != 0x20) {
+ continue;
+ }
+
+ const auto save_id_numeric = stoull_be(save_id->GetName());
+ auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ if (save_id_numeric != 0) {
+ // System Save Data
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::System,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ 0,
+ user_id->GetSize(),
+ {},
+ {},
+ });
+
+ continue;
+ }
+
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ const auto device = std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
+ [](u8 val) { return val == 0; });
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ device ? FileSys::SaveDataType::Device : FileSys::SaveDataType::Account,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ {},
+ });
+ }
+ }
+ }
+}
+
+void ISaveDataInfoReader::FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space,
+ const FileSys::VirtualDir& type) {
+ for (const auto& user_id : type->GetSubdirectories()) {
+ // Skip non user id subdirectories
+ if (user_id->GetName().size() != 0x20) {
+ continue;
+ }
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ if (!title_id->GetFiles().empty() || !title_id->GetSubdirectories().empty()) {
+ auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::Temporary,
+ {},
+ user_id_numeric,
+ stoull_be(type->GetName()),
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ {},
+ });
+ }
+ }
+ }
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
new file mode 100644
index 000000000..e45ad852b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
@@ -0,0 +1,50 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class SaveDataController;
+
+class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
+public:
+ explicit ISaveDataInfoReader(Core::System& system_,
+ std::shared_ptr<SaveDataController> save_data_controller_,
+ FileSys::SaveDataSpaceId space);
+ ~ISaveDataInfoReader() override;
+
+ struct SaveDataInfo {
+ u64_le save_id_unknown;
+ FileSys::SaveDataSpaceId space;
+ FileSys::SaveDataType type;
+ INSERT_PADDING_BYTES(0x6);
+ std::array<u8, 0x10> user_id;
+ u64_le save_id;
+ u64_le title_id;
+ u64_le save_image_size;
+ u16_le index;
+ FileSys::SaveDataRank rank;
+ INSERT_PADDING_BYTES(0x25);
+ };
+ static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
+
+ Result ReadSaveDataInfo(Out<u64> out_count,
+ OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries);
+
+private:
+ void FindAllSaves(FileSys::SaveDataSpaceId space);
+ void FindNormalSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
+ void FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
+
+ std::shared_ptr<SaveDataController> save_data_controller;
+ std::vector<SaveDataInfo> info;
+ u64 next_entry_index = 0;
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
index 98223c1f9..213f19808 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
@@ -2,61 +2,44 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/file_sys/errors.h"
+#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
-#include "core/hle/service/ipc_helpers.h"
namespace Service::FileSystem {
IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
: ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
- {0, &IStorage::Read, "Read"},
+ {0, D<&IStorage::Read>, "Read"},
{1, nullptr, "Write"},
{2, nullptr, "Flush"},
{3, nullptr, "SetSize"},
- {4, &IStorage::GetSize, "GetSize"},
+ {4, D<&IStorage::GetSize>, "GetSize"},
{5, nullptr, "OperateRange"},
};
RegisterHandlers(functions);
}
-void IStorage::Read(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const s64 offset = rp.Pop<s64>();
- const s64 length = rp.Pop<s64>();
-
+Result IStorage::Read(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
+ s64 offset, s64 length) {
LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
- // Error checking
- if (length < 0) {
- LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultInvalidSize);
- return;
- }
- if (offset < 0) {
- LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultInvalidOffset);
- return;
- }
+ R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
+ R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset);
// Read the data from the Storage backend
- std::vector<u8> output = backend->ReadBytes(length, offset);
- // Write the data to memory
- ctx.WriteBuffer(output);
+ backend->Read(out_bytes.data(), length, offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void IStorage::GetSize(HLERequestContext& ctx) {
- const u64 size = backend->GetSize();
- LOG_DEBUG(Service_FS, "called, size={}", size);
+Result IStorage::GetSize(Out<u64> out_size) {
+ *out_size = backend->GetSize();
+
+ LOG_DEBUG(Service_FS, "called, size={}", *out_size);
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(size);
+ R_SUCCEED();
}
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
index cb5bebcc9..74d879386 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
@@ -4,6 +4,7 @@
#pragma once
#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/cmif_types.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/service.h"
@@ -16,8 +17,10 @@ public:
private:
FileSys::VirtualFile backend;
- void Read(HLERequestContext& ctx);
- void GetSize(HLERequestContext& ctx);
+ Result Read(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
+ s64 offset, s64 length);
+ Result GetSize(Out<u64> out_size);
};
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index 2d49f30c8..fc67a4713 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -27,8 +27,11 @@
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"
+#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
+#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
+#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
#include "core/hle/service/filesystem/fsp/fsp_srv.h"
#include "core/hle/service/filesystem/romfs_controller.h"
@@ -39,182 +42,6 @@
#include "core/reporter.h"
namespace Service::FileSystem {
-enum class FileSystemProxyType : u8 {
- Code = 0,
- Rom = 1,
- Logo = 2,
- Control = 3,
- Manual = 4,
- Meta = 5,
- Data = 6,
- Package = 7,
- RegisteredUpdate = 8,
-};
-
-class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
-public:
- explicit ISaveDataInfoReader(Core::System& system_,
- std::shared_ptr<SaveDataController> save_data_controller_,
- FileSys::SaveDataSpaceId space)
- : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
- save_data_controller_} {
- static const FunctionInfo functions[] = {
- {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
- };
- RegisterHandlers(functions);
-
- FindAllSaves(space);
- }
-
- void ReadSaveDataInfo(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- // Calculate how many entries we can fit in the output buffer
- const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
-
- // Cap at total number of entries.
- const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
-
- // Determine data start and end
- const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
- const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
- const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
-
- next_entry_index += actual_entries;
-
- // Write the data to memory
- ctx.WriteBuffer(begin, range_size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(actual_entries);
- }
-
-private:
- static u64 stoull_be(std::string_view str) {
- if (str.size() != 16)
- return 0;
-
- const auto bytes = Common::HexStringToArray<0x8>(str);
- u64 out{};
- std::memcpy(&out, bytes.data(), sizeof(u64));
-
- return Common::swap64(out);
- }
-
- void FindAllSaves(FileSys::SaveDataSpaceId space) {
- FileSys::VirtualDir save_root{};
- const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
-
- if (result != ResultSuccess || save_root == nullptr) {
- LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
- return;
- }
-
- for (const auto& type : save_root->GetSubdirectories()) {
- if (type->GetName() == "save") {
- for (const auto& save_id : type->GetSubdirectories()) {
- for (const auto& user_id : save_id->GetSubdirectories()) {
- // Skip non user id subdirectories
- if (user_id->GetName().size() != 0x20) {
- continue;
- }
-
- const auto save_id_numeric = stoull_be(save_id->GetName());
- auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
- std::reverse(user_id_numeric.begin(), user_id_numeric.end());
-
- if (save_id_numeric != 0) {
- // System Save Data
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- FileSys::SaveDataType::SystemSaveData,
- {},
- user_id_numeric,
- save_id_numeric,
- 0,
- user_id->GetSize(),
- {},
- {},
- });
-
- continue;
- }
-
- for (const auto& title_id : user_id->GetSubdirectories()) {
- const auto device =
- std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
- [](u8 val) { return val == 0; });
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- device ? FileSys::SaveDataType::DeviceSaveData
- : FileSys::SaveDataType::SaveData,
- {},
- user_id_numeric,
- save_id_numeric,
- stoull_be(title_id->GetName()),
- title_id->GetSize(),
- {},
- {},
- });
- }
- }
- }
- } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
- // Temporary Storage
- for (const auto& user_id : type->GetSubdirectories()) {
- // Skip non user id subdirectories
- if (user_id->GetName().size() != 0x20) {
- continue;
- }
- for (const auto& title_id : user_id->GetSubdirectories()) {
- if (!title_id->GetFiles().empty() ||
- !title_id->GetSubdirectories().empty()) {
- auto user_id_numeric =
- Common::HexStringToArray<0x10>(user_id->GetName());
- std::reverse(user_id_numeric.begin(), user_id_numeric.end());
-
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- FileSys::SaveDataType::TemporaryStorage,
- {},
- user_id_numeric,
- stoull_be(type->GetName()),
- stoull_be(title_id->GetName()),
- title_id->GetSize(),
- {},
- {},
- });
- }
- }
- }
- }
- }
- }
-
- struct SaveDataInfo {
- u64_le save_id_unknown;
- FileSys::SaveDataSpaceId space;
- FileSys::SaveDataType type;
- INSERT_PADDING_BYTES(0x6);
- std::array<u8, 0x10> user_id;
- u64_le save_id;
- u64_le title_id;
- u64_le save_image_size;
- u16_le index;
- FileSys::SaveDataRank rank;
- INSERT_PADDING_BYTES(0x25);
- };
- static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
-
- ProcessId process_id = 0;
- std::shared_ptr<SaveDataController> save_data_controller;
- std::vector<SaveDataInfo> info;
- u64 next_entry_index = 0;
-};
FSP_SRV::FSP_SRV(Core::System& system_)
: ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
@@ -222,20 +49,20 @@ FSP_SRV::FSP_SRV(Core::System& system_)
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFileSystem"},
- {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"},
+ {1, D<&FSP_SRV::SetCurrentProcess>, "SetCurrentProcess"},
{2, nullptr, "OpenDataFileSystemByCurrentProcess"},
- {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"},
+ {7, D<&FSP_SRV::OpenFileSystemWithPatch>, "OpenFileSystemWithPatch"},
{8, nullptr, "OpenFileSystemWithId"},
{9, nullptr, "OpenDataFileSystemByApplicationId"},
{11, nullptr, "OpenBisFileSystem"},
{12, nullptr, "OpenBisStorage"},
{13, nullptr, "InvalidateBisCache"},
{17, nullptr, "OpenHostFileSystem"},
- {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"},
+ {18, D<&FSP_SRV::OpenSdCardFileSystem>, "OpenSdCardFileSystem"},
{19, nullptr, "FormatSdCardFileSystem"},
{21, nullptr, "DeleteSaveDataFileSystem"},
- {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"},
- {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"},
+ {22, D<&FSP_SRV::CreateSaveDataFileSystem>, "CreateSaveDataFileSystem"},
+ {23, D<&FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId>, "CreateSaveDataFileSystemBySystemSaveDataId"},
{24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
{25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
{26, nullptr, "FormatSdCardDryRun"},
@@ -245,26 +72,26 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{31, nullptr, "OpenGameCardFileSystem"},
{32, nullptr, "ExtendSaveDataFileSystem"},
{33, nullptr, "DeleteCacheStorage"},
- {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"},
+ {34, D<&FSP_SRV::GetCacheStorageSize>, "GetCacheStorageSize"},
{35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
{36, nullptr, "OpenHostFileSystemWithOption"},
- {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"},
- {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"},
- {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"},
+ {51, D<&FSP_SRV::OpenSaveDataFileSystem>, "OpenSaveDataFileSystem"},
+ {52, D<&FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId>, "OpenSaveDataFileSystemBySystemSaveDataId"},
+ {53, D<&FSP_SRV::OpenReadOnlySaveDataFileSystem>, "OpenReadOnlySaveDataFileSystem"},
{57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
{58, nullptr, "ReadSaveDataFileSystemExtraData"},
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
{60, nullptr, "OpenSaveDataInfoReader"},
- {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
- {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"},
+ {61, D<&FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId>, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
+ {62, D<&FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage>, "OpenSaveDataInfoReaderOnlyCacheStorage"},
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
{65, nullptr, "UpdateSaveDataMacForDebug"},
{66, nullptr, "WriteSaveDataFileSystemExtraData2"},
{67, nullptr, "FindSaveDataWithFilter"},
{68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
{69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
- {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
- {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
+ {70, D<&FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute>, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
+ {71, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute>, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
{80, nullptr, "OpenSaveDataMetaFile"},
{81, nullptr, "OpenSaveDataTransferManager"},
{82, nullptr, "OpenSaveDataTransferManagerVersion2"},
@@ -279,12 +106,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{110, nullptr, "OpenContentStorageFileSystem"},
{120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
{130, nullptr, "OpenCustomStorageFileSystem"},
- {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
+ {200, D<&FSP_SRV::OpenDataStorageByCurrentProcess>, "OpenDataStorageByCurrentProcess"},
{201, nullptr, "OpenDataStorageByProgramId"},
- {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
- {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
+ {202, D<&FSP_SRV::OpenDataStorageByDataId>, "OpenDataStorageByDataId"},
+ {203, D<&FSP_SRV::OpenPatchDataStorageByCurrentProcess>, "OpenPatchDataStorageByCurrentProcess"},
{204, nullptr, "OpenDataFileSystemByProgramIndex"},
- {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"},
+ {205, D<&FSP_SRV::OpenDataStorageWithProgramIndex>, "OpenDataStorageWithProgramIndex"},
{206, nullptr, "OpenDataStorageByPath"},
{400, nullptr, "OpenDeviceOperator"},
{500, nullptr, "OpenSdCardDetectionEventNotifier"},
@@ -324,25 +151,25 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{1000, nullptr, "SetBisRootForHost"},
{1001, nullptr, "SetSaveDataSize"},
{1002, nullptr, "SetSaveDataRootPath"},
- {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"},
- {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
- {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
- {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
+ {1003, D<&FSP_SRV::DisableAutoSaveDataCreation>, "DisableAutoSaveDataCreation"},
+ {1004, D<&FSP_SRV::SetGlobalAccessLogMode>, "SetGlobalAccessLogMode"},
+ {1005, D<&FSP_SRV::GetGlobalAccessLogMode>, "GetGlobalAccessLogMode"},
+ {1006, D<&FSP_SRV::OutputAccessLogToSdCard>, "OutputAccessLogToSdCard"},
{1007, nullptr, "RegisterUpdatePartition"},
{1008, nullptr, "OpenRegisteredUpdatePartition"},
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1010, nullptr, "SetDataStorageRedirectTarget"},
- {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"},
+ {1011, D<&FSP_SRV::GetProgramIndexForAccessLog>, "GetProgramIndexForAccessLog"},
{1012, nullptr, "GetFsStackUsage"},
{1013, nullptr, "UnsetSaveDataRootPath"},
{1014, nullptr, "OutputMultiProgramTagAccessLog"},
- {1016, &FSP_SRV::FlushAccessLogOnSdCard, "FlushAccessLogOnSdCard"},
+ {1016, D<&FSP_SRV::FlushAccessLogOnSdCard>, "FlushAccessLogOnSdCard"},
{1017, nullptr, "OutputApplicationInfoAccessLog"},
{1018, nullptr, "SetDebugOption"},
{1019, nullptr, "UnsetDebugOption"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
- {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
+ {1200, D<&FSP_SRV::OpenMultiCommitManager>, "OpenMultiCommitManager"},
{1300, nullptr, "OpenBisWiper"},
};
// clang-format on
@@ -355,234 +182,177 @@ FSP_SRV::FSP_SRV(Core::System& system_)
FSP_SRV::~FSP_SRV() = default;
-void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
- current_process_id = ctx.GetPID();
+Result FSP_SRV::SetCurrentProcess(ClientProcessId pid) {
+ current_process_id = *pid;
LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
- const auto res =
- fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(res);
+ R_RETURN(
+ fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id));
}
-void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- struct InputParameters {
- FileSystemProxyType type;
- u64 program_id;
- };
- static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size");
-
- const auto params = rp.PopRaw<InputParameters>();
- LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type,
- params.program_id);
+Result FSP_SRV::OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
+ FileSystemProxyType type, u64 open_program_id) {
+ LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", type,
+ open_program_id);
// FIXME: many issues with this
- ASSERT(params.type == FileSystemProxyType::Manual);
+ ASSERT(type == FileSystemProxyType::Manual);
const auto manual_romfs = romfs_controller->OpenPatchedRomFS(
- params.program_id, FileSys::ContentRecordType::HtmlDocument);
+ open_program_id, FileSys::ContentRecordType::HtmlDocument);
ASSERT(manual_romfs != nullptr);
const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs);
ASSERT(extracted_romfs != nullptr);
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFileSystem>(system, extracted_romfs,
- SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
+ *out_interface = std::make_shared<IFileSystem>(
+ system, extracted_romfs, SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
+
+ R_SUCCEED();
}
-void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
+Result FSP_SRV::OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface) {
LOG_DEBUG(Service_FS, "called");
FileSys::VirtualDir sdmc_dir{};
fsc.OpenSDMC(&sdmc_dir);
- auto filesystem = std::make_shared<IFileSystem>(
+ *out_interface = std::make_shared<IFileSystem>(
system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
+ R_SUCCEED();
}
-void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
- [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
- u128 uid = rp.PopRaw<u128>();
-
+Result FSP_SRV::CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
+ FileSys::SaveDataAttribute save_struct, u128 uid) {
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
uid[1], uid[0]);
FileSys::VirtualDir save_data_dir{};
- save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser,
- save_struct);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::User,
+ save_struct));
}
-void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
- [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
-
+Result FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(
+ FileSys::SaveDataCreationInfo save_create_struct, FileSys::SaveDataAttribute save_struct) {
LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
FileSys::VirtualDir save_data_dir{};
- save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem,
- save_struct);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::System,
+ save_struct));
}
-void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- struct Parameters {
- FileSys::SaveDataSpaceId space_id;
- FileSys::SaveDataAttribute attribute;
- };
-
- const auto parameters = rp.PopRaw<Parameters>();
-
+Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute) {
LOG_INFO(Service_FS, "called.");
FileSys::VirtualDir dir{};
- auto result =
- save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 0};
- rb.Push(FileSys::ResultTargetNotFound);
- return;
- }
+ R_TRY(save_data_controller->OpenSaveData(&dir, space_id, attribute));
FileSys::StorageId id{};
- switch (parameters.space_id) {
- case FileSys::SaveDataSpaceId::NandUser:
+ switch (space_id) {
+ case FileSys::SaveDataSpaceId::User:
id = FileSys::StorageId::NandUser;
break;
- case FileSys::SaveDataSpaceId::SdCardSystem:
- case FileSys::SaveDataSpaceId::SdCardUser:
+ case FileSys::SaveDataSpaceId::SdSystem:
+ case FileSys::SaveDataSpaceId::SdUser:
id = FileSys::StorageId::SdCard;
break;
- case FileSys::SaveDataSpaceId::NandSystem:
+ case FileSys::SaveDataSpaceId::System:
id = FileSys::StorageId::NandSystem;
break;
- case FileSys::SaveDataSpaceId::TemporaryStorage:
+ case FileSys::SaveDataSpaceId::Temporary:
case FileSys::SaveDataSpaceId::ProperSystem:
case FileSys::SaveDataSpaceId::SafeMode:
ASSERT(false);
}
- auto filesystem =
+ *out_interface =
std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
+ R_SUCCEED();
}
-void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) {
+Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute) {
LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
- OpenSaveDataFileSystem(ctx);
+ R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
}
-void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) {
+Result FSP_SRV::OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute) {
LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
- OpenSaveDataFileSystem(ctx);
+ R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
}
-void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
+Result FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(
+ OutInterface<ISaveDataInfoReader> out_interface, FileSys::SaveDataSpaceId space) {
LOG_INFO(Service_FS, "called, space={}", space);
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISaveDataInfoReader>(
- std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space));
+ *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space);
+
+ R_SUCCEED();
}
-void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
+Result FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(
+ OutInterface<ISaveDataInfoReader> out_interface) {
LOG_WARNING(Service_FS, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller,
- FileSys::SaveDataSpaceId::TemporaryStorage);
+ *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller,
+ FileSys::SaveDataSpaceId::Temporary);
+
+ R_SUCCEED();
}
-void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
+Result FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute() {
LOG_WARNING(Service_FS, "(STUBBED) called.");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- struct Parameters {
- FileSys::SaveDataSpaceId space_id;
- FileSys::SaveDataAttribute attribute;
- };
-
- const auto parameters = rp.PopRaw<Parameters>();
+Result FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
+ FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
+ InBuffer<BufferAttr_HipcMapAlias> mask_buffer, OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
// Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
- constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
+ // In an earlier version of the code, this was returned as an out argument, but this is not
+ // correct
+ [[maybe_unused]] constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
LOG_WARNING(Service_FS,
- "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
+ "(STUBBED) called, flags={}, space_id={}, attribute.program_id={:016X}\n"
"attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
"attribute.type={}, attribute.rank={}, attribute.index={}",
- flags, parameters.space_id, parameters.attribute.title_id,
- parameters.attribute.user_id[1], parameters.attribute.user_id[0],
- parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank,
- parameters.attribute.index);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(flags);
+ flags, space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
+ attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
+
+ R_SUCCEED();
}
-void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
+Result FSP_SRV::OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface) {
LOG_DEBUG(Service_FS, "called");
if (!romfs) {
auto current_romfs = romfs_controller->OpenRomFSCurrentProcess();
if (!current_romfs) {
// TODO (bunnei): Find the right error code to use here
- LOG_CRITICAL(Service_FS, "no file system interface available!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
+ LOG_CRITICAL(Service_FS, "No file system interface available!");
+ R_RETURN(ResultUnknown);
}
romfs = current_romfs;
}
- auto storage = std::make_shared<IStorage>(system, romfs);
+ *out_interface = std::make_shared<IStorage>(system, romfs);
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
+ R_SUCCEED();
}
-void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto storage_id = rp.PopRaw<FileSys::StorageId>();
- const auto unknown = rp.PopRaw<u32>();
- const auto title_id = rp.PopRaw<u64>();
-
+Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
+ FileSys::StorageId storage_id, u32 unknown, u64 title_id) {
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
storage_id, unknown, title_id);
@@ -592,19 +362,15 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
if (archive != nullptr) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
- return;
+ *out_interface = std::make_shared<IStorage>(system, archive);
+ R_SUCCEED();
}
// TODO(DarkLordZach): Find the right error code to use here
LOG_ERROR(Service_FS,
- "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
+ "Could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
storage_id);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
+ R_RETURN(ResultUnknown);
}
const FileSys::PatchManager pm{title_id, fsc, content_provider};
@@ -614,28 +380,20 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
auto storage = std::make_shared<IStorage>(
system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
+ *out_interface = std::move(storage);
+ R_SUCCEED();
}
-void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto storage_id = rp.PopRaw<FileSys::StorageId>();
- const auto title_id = rp.PopRaw<u64>();
+Result FSP_SRV::OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
+ FileSys::StorageId storage_id, u64 title_id) {
+ LOG_WARNING(Service_FS, "(STUBBED) called with storage_id={:02X}, title_id={:016X}", storage_id,
+ title_id);
- LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultTargetNotFound);
+ R_RETURN(FileSys::ResultTargetNotFound);
}
-void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto program_index = rp.PopRaw<u8>();
-
+Result FSP_SRV::OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface,
+ u8 program_index) {
LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex(
@@ -643,123 +401,80 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
if (!patched_romfs) {
// TODO: Find the right error code to use here
- LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
+ LOG_ERROR(Service_FS, "Could not open storage with program_index={}", program_index);
+ R_RETURN(ResultUnknown);
}
- auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs));
+ *out_interface = std::make_shared<IStorage>(system, std::move(patched_romfs));
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
+ R_SUCCEED();
}
-void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) {
+Result FSP_SRV::DisableAutoSaveDataCreation() {
LOG_DEBUG(Service_FS, "called");
save_data_controller->SetAutoCreate(false);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- access_log_mode = rp.PopEnum<AccessLogMode>();
+Result FSP_SRV::SetGlobalAccessLogMode(AccessLogMode access_log_mode_) {
+ LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode_);
- LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode);
+ access_log_mode = access_log_mode_;
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) {
+Result FSP_SRV::GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode) {
LOG_DEBUG(Service_FS, "called");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(access_log_mode);
-}
+ *out_access_log_mode = access_log_mode;
-void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) {
- const auto raw = ctx.ReadBufferCopy();
- auto log = Common::StringFromFixedZeroTerminatedBuffer(
- reinterpret_cast<const char*>(raw.data()), raw.size());
+ R_SUCCEED();
+}
+Result FSP_SRV::OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer) {
LOG_DEBUG(Service_FS, "called");
+ auto log = Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(log_message_buffer.data()), log_message_buffer.size());
reporter.SaveFSAccessLog(log);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
+Result FSP_SRV::GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
+ Out<u32> out_access_log_program_index) {
+ LOG_DEBUG(Service_FS, "(STUBBED) called");
+
+ *out_access_log_version = AccessLogVersion::Latest;
+ *out_access_log_program_index = access_log_program_index;
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.PushEnum(AccessLogVersion::Latest);
- rb.Push(access_log_program_index);
+ R_SUCCEED();
}
-void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) {
+Result FSP_SRV::FlushAccessLogOnSdCard() {
LOG_DEBUG(Service_FS, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto index{rp.Pop<s32>()};
-
+Result FSP_SRV::GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size) {
LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(ResultSuccess);
- rb.Push(s64{0});
- rb.Push(s64{0});
-}
-
-class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
-public:
- explicit IMultiCommitManager(Core::System& system_)
- : ServiceFramework{system_, "IMultiCommitManager"} {
- static const FunctionInfo functions[] = {
- {1, &IMultiCommitManager::Add, "Add"},
- {2, &IMultiCommitManager::Commit, "Commit"},
- };
- RegisterHandlers(functions);
- }
+ *out_data_size = 0;
+ *out_journal_size = 0;
-private:
- FileSys::VirtualFile backend;
-
- void Add(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void Commit(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-};
+ R_SUCCEED();
+}
-void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) {
+Result FSP_SRV::OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface) {
LOG_DEBUG(Service_FS, "called");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system));
+ *out_interface = std::make_shared<IMultiCommitManager>(system);
+
+ R_SUCCEED();
}
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h
index 59406e6f9..ee67f6bc1 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h
@@ -4,6 +4,9 @@
#pragma once
#include <memory>
+#include "core/file_sys/fs_save_data_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/filesystem/fsp/fsp_types.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -20,6 +23,11 @@ namespace Service::FileSystem {
class RomFsController;
class SaveDataController;
+class IFileSystem;
+class ISaveDataInfoReader;
+class IStorage;
+class IMultiCommitManager;
+
enum class AccessLogVersion : u32 {
V7_0_0 = 2,
@@ -38,30 +46,46 @@ public:
~FSP_SRV() override;
private:
- void SetCurrentProcess(HLERequestContext& ctx);
- void OpenFileSystemWithPatch(HLERequestContext& ctx);
- void OpenSdCardFileSystem(HLERequestContext& ctx);
- void CreateSaveDataFileSystem(HLERequestContext& ctx);
- void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx);
- void OpenSaveDataFileSystem(HLERequestContext& ctx);
- void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx);
- void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx);
- void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx);
- void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx);
- void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx);
- void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx);
- void OpenDataStorageByCurrentProcess(HLERequestContext& ctx);
- void OpenDataStorageByDataId(HLERequestContext& ctx);
- void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx);
- void OpenDataStorageWithProgramIndex(HLERequestContext& ctx);
- void DisableAutoSaveDataCreation(HLERequestContext& ctx);
- void SetGlobalAccessLogMode(HLERequestContext& ctx);
- void GetGlobalAccessLogMode(HLERequestContext& ctx);
- void OutputAccessLogToSdCard(HLERequestContext& ctx);
- void FlushAccessLogOnSdCard(HLERequestContext& ctx);
- void GetProgramIndexForAccessLog(HLERequestContext& ctx);
- void OpenMultiCommitManager(HLERequestContext& ctx);
- void GetCacheStorageSize(HLERequestContext& ctx);
+ Result SetCurrentProcess(ClientProcessId pid);
+ Result OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
+ FileSystemProxyType type, u64 open_program_id);
+ Result OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface);
+ Result CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
+ FileSys::SaveDataAttribute save_struct, u128 uid);
+ Result CreateSaveDataFileSystemBySystemSaveDataId(
+ FileSys::SaveDataCreationInfo save_create_struct, FileSys::SaveDataAttribute save_struct);
+ Result OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute);
+ Result OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute);
+ Result OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute);
+ Result OpenSaveDataInfoReaderBySaveDataSpaceId(OutInterface<ISaveDataInfoReader> out_interface,
+ FileSys::SaveDataSpaceId space);
+ Result OpenSaveDataInfoReaderOnlyCacheStorage(OutInterface<ISaveDataInfoReader> out_interface);
+ Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute();
+ Result ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
+ FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
+ InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
+ OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
+ Result OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface);
+ Result OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
+ FileSys::StorageId storage_id, u32 unknown, u64 title_id);
+ Result OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
+ FileSys::StorageId storage_id, u64 title_id);
+ Result OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface, u8 program_index);
+ Result DisableAutoSaveDataCreation();
+ Result SetGlobalAccessLogMode(AccessLogMode access_log_mode_);
+ Result GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode);
+ Result OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer);
+ Result FlushAccessLogOnSdCard();
+ Result GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
+ Out<u32> out_access_log_program_index);
+ Result OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface);
+ Result GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size);
FileSystemController& fsc;
const FileSys::ContentProvider& content_provider;
diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_types.h
index 253f866db..294da6a2d 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_util.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_types.h
@@ -7,6 +7,18 @@
namespace Service::FileSystem {
+enum class FileSystemProxyType : u8 {
+ Code = 0,
+ Rom = 1,
+ Logo = 2,
+ Control = 3,
+ Manual = 4,
+ Meta = 5,
+ Data = 6,
+ Package = 7,
+ RegisteredUpdate = 8,
+};
+
struct SizeGetter {
std::function<u64()> get_free_size;
std::function<u64()> get_total_size;
diff --git a/src/core/hle/service/olsc/daemon_controller.cpp b/src/core/hle/service/olsc/daemon_controller.cpp
new file mode 100644
index 000000000..7823780a8
--- /dev/null
+++ b/src/core/hle/service/olsc/daemon_controller.cpp
@@ -0,0 +1,40 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/daemon_controller.h"
+
+namespace Service::OLSC {
+
+IDaemonController::IDaemonController(Core::System& system_)
+ : ServiceFramework{system_, "IDaemonController"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IDaemonController::GetAutoTransferEnabledForAccountAndApplication>, "GetAutoTransferEnabledForAccountAndApplication"},
+ {1, nullptr, "SetAutoTransferEnabledForAccountAndApplication"},
+ {2, nullptr, "GetGlobalUploadEnabledForAccount"},
+ {3, nullptr, "SetGlobalUploadEnabledForAccount"},
+ {4, nullptr, "TouchAccount"},
+ {5, nullptr, "GetGlobalDownloadEnabledForAccount"},
+ {6, nullptr, "SetGlobalDownloadEnabledForAccount"},
+ {10, nullptr, "GetForbiddenSaveDataIndication"},
+ {11, nullptr, "GetStopperObject"},
+ {12, nullptr, "GetState"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IDaemonController::~IDaemonController() = default;
+
+Result IDaemonController::GetAutoTransferEnabledForAccountAndApplication(Out<bool> out_is_enabled,
+ Common::UUID user_id,
+ u64 application_id) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called, user_id={} application_id={:016X}",
+ user_id.FormattedString(), application_id);
+ *out_is_enabled = false;
+ R_SUCCEED();
+}
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/daemon_controller.h b/src/core/hle/service/olsc/daemon_controller.h
new file mode 100644
index 000000000..dfad7f52a
--- /dev/null
+++ b/src/core/hle/service/olsc/daemon_controller.h
@@ -0,0 +1,20 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/uuid.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class IDaemonController final : public ServiceFramework<IDaemonController> {
+public:
+ explicit IDaemonController(Core::System& system_);
+ ~IDaemonController() override;
+
+private:
+ Result GetAutoTransferEnabledForAccountAndApplication(Out<bool> out_is_enabled,
+ Common::UUID user_id, u64 application_id);
+};
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/native_handle_holder.cpp b/src/core/hle/service/olsc/native_handle_holder.cpp
new file mode 100644
index 000000000..3cb5d7b11
--- /dev/null
+++ b/src/core/hle/service/olsc/native_handle_holder.cpp
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/native_handle_holder.h"
+
+namespace Service::OLSC {
+
+INativeHandleHolder::INativeHandleHolder(Core::System& system_)
+ : ServiceFramework{system_, "INativeHandleHolder"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&INativeHandleHolder::GetNativeHandle>, "GetNativeHandle"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+INativeHandleHolder::~INativeHandleHolder() = default;
+
+Result INativeHandleHolder::GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ *out_event = nullptr;
+ R_SUCCEED();
+}
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/native_handle_holder.h b/src/core/hle/service/olsc/native_handle_holder.h
new file mode 100644
index 000000000..a44754c20
--- /dev/null
+++ b/src/core/hle/service/olsc/native_handle_holder.h
@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::OLSC {
+
+class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
+public:
+ explicit INativeHandleHolder(Core::System& system_);
+ ~INativeHandleHolder() override;
+
+private:
+ Result GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
+};
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index 889f27c31..18e5ad43f 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -1,226 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/olsc/olsc.h"
+#include "core/hle/service/olsc/olsc_service_for_application.h"
+#include "core/hle/service/olsc/olsc_service_for_system_service.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::OLSC {
-class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
-public:
- explicit IOlscServiceForApplication(Core::System& system_)
- : ServiceFramework{system_, "olsc:u"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IOlscServiceForApplication::Initialize, "Initialize"},
- {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
- {13, &IOlscServiceForApplication::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
- {14, &IOlscServiceForApplication::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
- {15, nullptr, "SetCustomData"},
- {16, nullptr, "DeleteSaveDataBackupSetting"},
- {18, nullptr, "GetSaveDataBackupInfoCache"},
- {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
- {22, nullptr, "DeleteSaveDataBackupAsync"},
- {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
- {26, nullptr, "DownloadSaveDataBackupAsync"},
- {27, nullptr, "UploadSaveDataBackupAsync"},
- {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
- {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
- {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
- {9015, nullptr, "SetCustomDataForDebug"},
- {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
- {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
- {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
- {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
- {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
- {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void Initialize(HLERequestContext& ctx) {
- LOG_WARNING(Service_OLSC, "(STUBBED) called");
-
- initialized = true;
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetSaveDataBackupSetting(HLERequestContext& ctx) {
- LOG_WARNING(Service_OLSC, "(STUBBED) called");
-
- // backup_setting is set to 0 since real value is unknown
- constexpr u64 backup_setting = 0;
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(backup_setting);
- }
-
- void SetSaveDataBackupSettingEnabled(HLERequestContext& ctx) {
- LOG_WARNING(Service_OLSC, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- bool initialized{};
-};
-
-class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
-public:
- explicit INativeHandleHolder(Core::System& system_)
- : ServiceFramework{system_, "INativeHandleHolder"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "GetNativeHandle"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
-public:
- explicit ITransferTaskListController(Core::System& system_)
- : ServiceFramework{system_, "ITransferTaskListController"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown0"},
- {1, nullptr, "Unknown1"},
- {2, nullptr, "Unknown2"},
- {3, nullptr, "Unknown3"},
- {4, nullptr, "Unknown4"},
- {5, &ITransferTaskListController::GetNativeHandleHolder , "GetNativeHandleHolder"},
- {6, nullptr, "Unknown6"},
- {7, nullptr, "Unknown7"},
- {8, nullptr, "GetRemoteStorageController"},
- {9, &ITransferTaskListController::GetNativeHandleHolder, "GetNativeHandleHolder2"},
- {10, nullptr, "Unknown10"},
- {11, nullptr, "Unknown11"},
- {12, nullptr, "Unknown12"},
- {13, nullptr, "Unknown13"},
- {14, nullptr, "Unknown14"},
- {15, nullptr, "Unknown15"},
- {16, nullptr, "Unknown16"},
- {17, nullptr, "Unknown17"},
- {18, nullptr, "Unknown18"},
- {19, nullptr, "Unknown19"},
- {20, nullptr, "Unknown20"},
- {21, nullptr, "Unknown21"},
- {22, nullptr, "Unknown22"},
- {23, nullptr, "Unknown23"},
- {24, nullptr, "Unknown24"},
- {25, nullptr, "Unknown25"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void GetNativeHandleHolder(HLERequestContext& ctx) {
- LOG_INFO(Service_OLSC, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<INativeHandleHolder>(system);
- }
-};
-
-class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
-public:
- explicit IOlscServiceForSystemService(Core::System& system_)
- : ServiceFramework{system_, "olsc:s"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IOlscServiceForSystemService::OpenTransferTaskListController, "OpenTransferTaskListController"},
- {1, nullptr, "OpenRemoteStorageController"},
- {2, nullptr, "OpenDaemonController"},
- {10, nullptr, "Unknown10"},
- {11, nullptr, "Unknown11"},
- {12, nullptr, "Unknown12"},
- {13, nullptr, "Unknown13"},
- {100, nullptr, "ListLastTransferTaskErrorInfo"},
- {101, nullptr, "GetLastErrorInfoCount"},
- {102, nullptr, "RemoveLastErrorInfoOld"},
- {103, nullptr, "GetLastErrorInfo"},
- {104, nullptr, "GetLastErrorEventHolder"},
- {105, nullptr, "GetLastTransferTaskErrorInfo"},
- {200, nullptr, "GetDataTransferPolicyInfo"},
- {201, nullptr, "RemoveDataTransferPolicyInfo"},
- {202, nullptr, "UpdateDataTransferPolicyOld"},
- {203, nullptr, "UpdateDataTransferPolicy"},
- {204, nullptr, "CleanupDataTransferPolicyInfo"},
- {205, nullptr, "RequestDataTransferPolicy"},
- {300, nullptr, "GetAutoTransferSeriesInfo"},
- {301, nullptr, "UpdateAutoTransferSeriesInfo"},
- {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
- {900, nullptr, "CleanupTransferTask"},
- {902, nullptr, "CleanupSeriesInfoType0"},
- {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
- {904, nullptr, "CleanupApplicationAutoTransferSetting"},
- {905, nullptr, "CleanupErrorHistory"},
- {906, nullptr, "SetLastError"},
- {907, nullptr, "AddSaveDataArchiveInfoType0"},
- {908, nullptr, "RemoveSeriesInfoType0"},
- {909, nullptr, "GetSeriesInfoType0"},
- {910, nullptr, "RemoveLastErrorInfo"},
- {911, nullptr, "CleanupSeriesInfoType1"},
- {912, nullptr, "RemoveSeriesInfoType1"},
- {913, nullptr, "GetSeriesInfoType1"},
- {1000, nullptr, "UpdateIssueOld"},
- {1010, nullptr, "Unknown1010"},
- {1011, nullptr, "ListIssueInfoOld"},
- {1012, nullptr, "GetIssueOld"},
- {1013, nullptr, "GetIssue2Old"},
- {1014, nullptr, "GetIssue3Old"},
- {1020, nullptr, "RepairIssueOld"},
- {1021, nullptr, "RepairIssueWithUserIdOld"},
- {1022, nullptr, "RepairIssue2Old"},
- {1023, nullptr, "RepairIssue3Old"},
- {1024, nullptr, "Unknown1024"},
- {1100, nullptr, "UpdateIssue"},
- {1110, nullptr, "Unknown1110"},
- {1111, nullptr, "ListIssueInfo"},
- {1112, nullptr, "GetIssue"},
- {1113, nullptr, "GetIssue2"},
- {1114, nullptr, "GetIssue3"},
- {1120, nullptr, "RepairIssue"},
- {1121, nullptr, "RepairIssueWithUserId"},
- {1122, nullptr, "RepairIssue2"},
- {1123, nullptr, "RepairIssue3"},
- {1124, nullptr, "Unknown1124"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void OpenTransferTaskListController(HLERequestContext& ctx) {
- LOG_INFO(Service_OLSC, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<ITransferTaskListController>(system);
- }
-};
-
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
- server_manager->RegisterNamedService("olsc:u",
- std::make_shared<IOlscServiceForApplication>(system));
- server_manager->RegisterNamedService("olsc:s",
- std::make_shared<IOlscServiceForSystemService>(system));
+ const auto OlscFactoryForApplication = [&] {
+ return std::make_shared<IOlscServiceForApplication>(system);
+ };
+
+ const auto OlscFactoryForSystemService = [&] {
+ return std::make_shared<IOlscServiceForSystemService>(system);
+ };
+
+ server_manager->RegisterNamedService("olsc:u", OlscFactoryForApplication);
+ server_manager->RegisterNamedService("olsc:s", OlscFactoryForSystemService);
ServerManager::RunServer(std::move(server_manager));
}
diff --git a/src/core/hle/service/olsc/olsc_service_for_application.cpp b/src/core/hle/service/olsc/olsc_service_for_application.cpp
new file mode 100644
index 000000000..01360f5ef
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_application.cpp
@@ -0,0 +1,63 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/olsc_service_for_application.h"
+
+namespace Service::OLSC {
+
+IOlscServiceForApplication::IOlscServiceForApplication(Core::System& system_)
+ : ServiceFramework{system_, "olsc:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IOlscServiceForApplication::Initialize>, "Initialize"},
+ {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
+ {13, D<&IOlscServiceForApplication::GetSaveDataBackupSetting>, "GetSaveDataBackupSetting"},
+ {14, D<&IOlscServiceForApplication::SetSaveDataBackupSettingEnabled>, "SetSaveDataBackupSettingEnabled"},
+ {15, nullptr, "SetCustomData"},
+ {16, nullptr, "DeleteSaveDataBackupSetting"},
+ {18, nullptr, "GetSaveDataBackupInfoCache"},
+ {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
+ {22, nullptr, "DeleteSaveDataBackupAsync"},
+ {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
+ {26, nullptr, "DownloadSaveDataBackupAsync"},
+ {27, nullptr, "UploadSaveDataBackupAsync"},
+ {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
+ {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
+ {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
+ {9015, nullptr, "SetCustomDataForDebug"},
+ {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
+ {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
+ {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
+ {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
+ {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
+ {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IOlscServiceForApplication::~IOlscServiceForApplication() = default;
+
+Result IOlscServiceForApplication::Initialize(ClientProcessId process_id) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ initialized = true;
+ R_SUCCEED();
+}
+
+Result IOlscServiceForApplication::GetSaveDataBackupSetting(Out<u8> out_save_data_backup_setting) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ // backup_setting is set to 0 since real value is unknown
+ *out_save_data_backup_setting = 0;
+ R_SUCCEED();
+}
+
+Result IOlscServiceForApplication::SetSaveDataBackupSettingEnabled(bool enabled,
+ NS::Uid account_id) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called, enabled={}, account_id={}", enabled,
+ account_id.uuid.FormattedString());
+ R_SUCCEED();
+}
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_application.h b/src/core/hle/service/olsc/olsc_service_for_application.h
new file mode 100644
index 000000000..3f9ac7536
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_application.h
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/ns/ns_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
+public:
+ explicit IOlscServiceForApplication(Core::System& system_);
+ ~IOlscServiceForApplication() override;
+
+private:
+ Result Initialize(ClientProcessId process_id);
+ Result GetSaveDataBackupSetting(Out<u8> out_save_data_backup_setting);
+ Result SetSaveDataBackupSettingEnabled(bool enabled, NS::Uid account_id);
+
+ bool initialized{};
+};
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_system_service.cpp b/src/core/hle/service/olsc/olsc_service_for_system_service.cpp
new file mode 100644
index 000000000..f027933c9
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_system_service.cpp
@@ -0,0 +1,117 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/daemon_controller.h"
+#include "core/hle/service/olsc/olsc_service_for_system_service.h"
+#include "core/hle/service/olsc/remote_storage_controller.h"
+#include "core/hle/service/olsc/transfer_task_list_controller.h"
+
+namespace Service::OLSC {
+
+IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_)
+ : ServiceFramework{system_, "olsc:s"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IOlscServiceForSystemService::OpenTransferTaskListController>, "OpenTransferTaskListController"},
+ {1, D<&IOlscServiceForSystemService::OpenRemoteStorageController>, "OpenRemoteStorageController"},
+ {2, D<&IOlscServiceForSystemService::OpenDaemonController>, "OpenDaemonController"},
+ {10, nullptr, "Unknown10"},
+ {11, nullptr, "Unknown11"},
+ {12, nullptr, "Unknown12"},
+ {13, nullptr, "Unknown13"},
+ {100, nullptr, "ListLastTransferTaskErrorInfo"},
+ {101, nullptr, "GetLastErrorInfoCount"},
+ {102, nullptr, "RemoveLastErrorInfoOld"},
+ {103, nullptr, "GetLastErrorInfo"},
+ {104, nullptr, "GetLastErrorEventHolder"},
+ {105, nullptr, "GetLastTransferTaskErrorInfo"},
+ {200, D<&IOlscServiceForSystemService::GetDataTransferPolicyInfo>, "GetDataTransferPolicyInfo"},
+ {201, nullptr, "RemoveDataTransferPolicyInfo"},
+ {202, nullptr, "UpdateDataTransferPolicyOld"},
+ {203, nullptr, "UpdateDataTransferPolicy"},
+ {204, nullptr, "CleanupDataTransferPolicyInfo"},
+ {205, nullptr, "RequestDataTransferPolicy"},
+ {300, nullptr, "GetAutoTransferSeriesInfo"},
+ {301, nullptr, "UpdateAutoTransferSeriesInfo"},
+ {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
+ {900, nullptr, "CleanupTransferTask"},
+ {902, nullptr, "CleanupSeriesInfoType0"},
+ {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
+ {904, nullptr, "CleanupApplicationAutoTransferSetting"},
+ {905, nullptr, "CleanupErrorHistory"},
+ {906, nullptr, "SetLastError"},
+ {907, nullptr, "AddSaveDataArchiveInfoType0"},
+ {908, nullptr, "RemoveSeriesInfoType0"},
+ {909, nullptr, "GetSeriesInfoType0"},
+ {910, nullptr, "RemoveLastErrorInfo"},
+ {911, nullptr, "CleanupSeriesInfoType1"},
+ {912, nullptr, "RemoveSeriesInfoType1"},
+ {913, nullptr, "GetSeriesInfoType1"},
+ {1000, nullptr, "UpdateIssueOld"},
+ {1010, nullptr, "Unknown1010"},
+ {1011, nullptr, "ListIssueInfoOld"},
+ {1012, nullptr, "GetIssueOld"},
+ {1013, nullptr, "GetIssue2Old"},
+ {1014, nullptr, "GetIssue3Old"},
+ {1020, nullptr, "RepairIssueOld"},
+ {1021, nullptr, "RepairIssueWithUserIdOld"},
+ {1022, nullptr, "RepairIssue2Old"},
+ {1023, nullptr, "RepairIssue3Old"},
+ {1024, nullptr, "Unknown1024"},
+ {1100, nullptr, "UpdateIssue"},
+ {1110, nullptr, "Unknown1110"},
+ {1111, nullptr, "ListIssueInfo"},
+ {1112, nullptr, "GetIssue"},
+ {1113, nullptr, "GetIssue2"},
+ {1114, nullptr, "GetIssue3"},
+ {1120, nullptr, "RepairIssue"},
+ {1121, nullptr, "RepairIssueWithUserId"},
+ {1122, nullptr, "RepairIssue2"},
+ {1123, nullptr, "RepairIssue3"},
+ {1124, nullptr, "Unknown1124"},
+ {10000, D<&IOlscServiceForSystemService::CloneService>, "CloneService"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IOlscServiceForSystemService::~IOlscServiceForSystemService() = default;
+
+Result IOlscServiceForSystemService::OpenTransferTaskListController(
+ Out<SharedPointer<ITransferTaskListController>> out_interface) {
+ LOG_INFO(Service_OLSC, "called");
+ *out_interface = std::make_shared<ITransferTaskListController>(system);
+ R_SUCCEED();
+}
+
+Result IOlscServiceForSystemService::OpenRemoteStorageController(
+ Out<SharedPointer<IRemoteStorageController>> out_interface) {
+ LOG_INFO(Service_OLSC, "called");
+ *out_interface = std::make_shared<IRemoteStorageController>(system);
+ R_SUCCEED();
+}
+
+Result IOlscServiceForSystemService::OpenDaemonController(
+ Out<SharedPointer<IDaemonController>> out_interface) {
+ LOG_INFO(Service_OLSC, "called");
+ *out_interface = std::make_shared<IDaemonController>(system);
+ R_SUCCEED();
+}
+
+Result IOlscServiceForSystemService::GetDataTransferPolicyInfo(Out<u16> out_policy_info,
+ u64 application_id) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ *out_policy_info = 0;
+ R_SUCCEED();
+}
+
+Result IOlscServiceForSystemService::CloneService(
+ Out<SharedPointer<IOlscServiceForSystemService>> out_interface) {
+ LOG_INFO(Service_OLSC, "called");
+ *out_interface = std::static_pointer_cast<IOlscServiceForSystemService>(shared_from_this());
+ R_SUCCEED();
+}
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_system_service.h b/src/core/hle/service/olsc/olsc_service_for_system_service.h
new file mode 100644
index 000000000..13026272a
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_system_service.h
@@ -0,0 +1,27 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class IDaemonController;
+class IRemoteStorageController;
+class ITransferTaskListController;
+
+class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
+public:
+ explicit IOlscServiceForSystemService(Core::System& system_);
+ ~IOlscServiceForSystemService() override;
+
+private:
+ Result OpenTransferTaskListController(
+ Out<SharedPointer<ITransferTaskListController>> out_interface);
+ Result OpenRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
+ Result OpenDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
+ Result GetDataTransferPolicyInfo(Out<u16> out_policy_info, u64 application_id);
+ Result CloneService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
+};
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/remote_storage_controller.cpp b/src/core/hle/service/olsc/remote_storage_controller.cpp
new file mode 100644
index 000000000..81d9c96ab
--- /dev/null
+++ b/src/core/hle/service/olsc/remote_storage_controller.cpp
@@ -0,0 +1,54 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/remote_storage_controller.h"
+
+namespace Service::OLSC {
+
+IRemoteStorageController::IRemoteStorageController(Core::System& system_)
+ : ServiceFramework{system_, "IRemoteStorageController"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetSaveDataArchiveInfoBySaveDataId"},
+ {1, nullptr, "GetSaveDataArchiveInfoByApplicationId"},
+ {3, nullptr, "GetSaveDataArchiveCount"},
+ {6, nullptr, "CleanupSaveDataArchives"},
+ {7, nullptr, "CreateSaveDataArchiveCacheUpdationTask"},
+ {8, nullptr, "CreateSaveDataArchiveCacheUpdationForSpecifiedApplicationTask"},
+ {9, nullptr, "Delete"},
+ {10, nullptr, "GetSeriesInfo"},
+ {11, nullptr, "CreateDeleteDataTask"},
+ {12, nullptr, "DeleteSeriesInfo"},
+ {13, nullptr, "CreateRegisterNotificationTokenTask"},
+ {14, nullptr, "UpdateSeriesInfo"},
+ {15, nullptr, "RegisterUploadSaveDataTransferTaskForAutonomyRegistration"},
+ {16, nullptr, "CreateCleanupToDeleteSaveDataArchiveInfoTask"},
+ {17, nullptr, "ListDataInfo"},
+ {18, nullptr, "GetDataInfo"},
+ {19, nullptr, "Unknown19"},
+ {20, nullptr, "CreateSaveDataArchiveInfoCacheForSaveDataBackupUpdationTask"},
+ {21, nullptr, "ListSecondarySaves"},
+ {22, D<&IRemoteStorageController::GetSecondarySave>, "GetSecondarySave"},
+ {23, nullptr, "TouchSecondarySave"},
+ {24, nullptr, "GetSecondarySaveDataInfo"},
+ {25, nullptr, "RegisterDownloadSaveDataTransferTaskForAutonomyRegistration"},
+ {900, nullptr, "Unknown900"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IRemoteStorageController::~IRemoteStorageController() = default;
+
+Result IRemoteStorageController::GetSecondarySave(Out<bool> out_has_secondary_save,
+ Out<std::array<u64, 3>> out_unknown,
+ u64 application_id) {
+ LOG_ERROR(Service_OLSC, "(STUBBED) called, application_id={:016X}", application_id);
+ *out_has_secondary_save = false;
+ *out_unknown = {};
+ R_SUCCEED();
+}
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/remote_storage_controller.h b/src/core/hle/service/olsc/remote_storage_controller.h
new file mode 100644
index 000000000..e7a0b5244
--- /dev/null
+++ b/src/core/hle/service/olsc/remote_storage_controller.h
@@ -0,0 +1,19 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class IRemoteStorageController final : public ServiceFramework<IRemoteStorageController> {
+public:
+ explicit IRemoteStorageController(Core::System& system_);
+ ~IRemoteStorageController() override;
+
+private:
+ Result GetSecondarySave(Out<bool> out_has_secondary_save, Out<std::array<u64, 3>> out_unknown,
+ u64 application_id);
+};
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/transfer_task_list_controller.cpp b/src/core/hle/service/olsc/transfer_task_list_controller.cpp
new file mode 100644
index 000000000..8ea9a0f1e
--- /dev/null
+++ b/src/core/hle/service/olsc/transfer_task_list_controller.cpp
@@ -0,0 +1,55 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/native_handle_holder.h"
+#include "core/hle/service/olsc/transfer_task_list_controller.h"
+
+namespace Service::OLSC {
+
+ITransferTaskListController::ITransferTaskListController(Core::System& system_)
+ : ServiceFramework{system_, "ITransferTaskListController"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown0"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "GetRemoteStorageController"},
+ {9, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder2"},
+ {10, nullptr, "Unknown10"},
+ {11, nullptr, "Unknown11"},
+ {12, nullptr, "Unknown12"},
+ {13, nullptr, "Unknown13"},
+ {14, nullptr, "Unknown14"},
+ {15, nullptr, "Unknown15"},
+ {16, nullptr, "Unknown16"},
+ {17, nullptr, "Unknown17"},
+ {18, nullptr, "Unknown18"},
+ {19, nullptr, "Unknown19"},
+ {20, nullptr, "Unknown20"},
+ {21, nullptr, "Unknown21"},
+ {22, nullptr, "Unknown22"},
+ {23, nullptr, "Unknown23"},
+ {24, nullptr, "Unknown24"},
+ {25, nullptr, "Unknown25"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ITransferTaskListController::~ITransferTaskListController() = default;
+
+Result ITransferTaskListController::GetNativeHandleHolder(
+ Out<SharedPointer<INativeHandleHolder>> out_holder) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ *out_holder = std::make_shared<INativeHandleHolder>(system);
+ R_SUCCEED();
+}
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/transfer_task_list_controller.h b/src/core/hle/service/olsc/transfer_task_list_controller.h
new file mode 100644
index 000000000..f10a71375
--- /dev/null
+++ b/src/core/hle/service/olsc/transfer_task_list_controller.h
@@ -0,0 +1,20 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class INativeHandleHolder;
+
+class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
+public:
+ explicit ITransferTaskListController(Core::System& system_);
+ ~ITransferTaskListController() override;
+
+private:
+ Result GetNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
+};
+
+} // namespace Service::OLSC
diff --git a/src/core/hle/service/pctl/parental_control_service.cpp b/src/core/hle/service/pctl/parental_control_service.cpp
new file mode 100644
index 000000000..f57f2f157
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service.cpp
@@ -0,0 +1,434 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/pctl/parental_control_service.h"
+#include "core/hle/service/pctl/pctl_results.h"
+
+namespace Service::PCTL {
+
+IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
+ : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
+ service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
+ unlinked_event{service_context}, request_suspension_event{service_context} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, D<&IParentalControlService::Initialize>, "Initialize"},
+ {1001, D<&IParentalControlService::CheckFreeCommunicationPermission>, "CheckFreeCommunicationPermission"},
+ {1002, D<&IParentalControlService::ConfirmLaunchApplicationPermission>, "ConfirmLaunchApplicationPermission"},
+ {1003, D<&IParentalControlService::ConfirmResumeApplicationPermission>, "ConfirmResumeApplicationPermission"},
+ {1004, D<&IParentalControlService::ConfirmSnsPostPermission>, "ConfirmSnsPostPermission"},
+ {1005, nullptr, "ConfirmSystemSettingsPermission"},
+ {1006, D<&IParentalControlService::IsRestrictionTemporaryUnlocked>, "IsRestrictionTemporaryUnlocked"},
+ {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
+ {1008, nullptr, "EnterRestrictedSystemSettings"},
+ {1009, nullptr, "LeaveRestrictedSystemSettings"},
+ {1010, D<&IParentalControlService::IsRestrictedSystemSettingsEntered>, "IsRestrictedSystemSettingsEntered"},
+ {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
+ {1012, nullptr, "GetRestrictedFeatures"},
+ {1013, D<&IParentalControlService::ConfirmStereoVisionPermission>, "ConfirmStereoVisionPermission"},
+ {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
+ {1015, nullptr, "ConfirmPlayableApplicationVideo"},
+ {1016, nullptr, "ConfirmShowNewsPermission"},
+ {1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"},
+ {1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"},
+ {1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"},
+ {1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"},
+ {1033, nullptr, "SetSafetyLevel"},
+ {1034, nullptr, "GetSafetyLevelSettings"},
+ {1035, D<&IParentalControlService::GetCurrentSettings>, "GetCurrentSettings"},
+ {1036, nullptr, "SetCustomSafetyLevelSettings"},
+ {1037, nullptr, "GetDefaultRatingOrganization"},
+ {1038, nullptr, "SetDefaultRatingOrganization"},
+ {1039, D<&IParentalControlService::GetFreeCommunicationApplicationListCount>, "GetFreeCommunicationApplicationListCount"},
+ {1042, nullptr, "AddToFreeCommunicationApplicationList"},
+ {1043, nullptr, "DeleteSettings"},
+ {1044, nullptr, "GetFreeCommunicationApplicationList"},
+ {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
+ {1046, nullptr, "DisableFeaturesForReset"},
+ {1047, nullptr, "NotifyApplicationDownloadStarted"},
+ {1048, nullptr, "NotifyNetworkProfileCreated"},
+ {1049, nullptr, "ResetFreeCommunicationApplicationList"},
+ {1061, D<&IParentalControlService::ConfirmStereoVisionRestrictionConfigurable>, "ConfirmStereoVisionRestrictionConfigurable"},
+ {1062, D<&IParentalControlService::GetStereoVisionRestriction>, "GetStereoVisionRestriction"},
+ {1063, D<&IParentalControlService::SetStereoVisionRestriction>, "SetStereoVisionRestriction"},
+ {1064, D<&IParentalControlService::ResetConfirmedStereoVisionPermission>, "ResetConfirmedStereoVisionPermission"},
+ {1065, D<&IParentalControlService::IsStereoVisionPermitted>, "IsStereoVisionPermitted"},
+ {1201, nullptr, "UnlockRestrictionTemporarily"},
+ {1202, nullptr, "UnlockSystemSettingsRestriction"},
+ {1203, nullptr, "SetPinCode"},
+ {1204, nullptr, "GenerateInquiryCode"},
+ {1205, nullptr, "CheckMasterKey"},
+ {1206, D<&IParentalControlService::GetPinCodeLength>, "GetPinCodeLength"},
+ {1207, nullptr, "GetPinCodeChangedEvent"},
+ {1208, nullptr, "GetPinCode"},
+ {1403, D<&IParentalControlService::IsPairingActive>, "IsPairingActive"},
+ {1406, nullptr, "GetSettingsLastUpdated"},
+ {1411, nullptr, "GetPairingAccountInfo"},
+ {1421, nullptr, "GetAccountNickname"},
+ {1424, nullptr, "GetAccountState"},
+ {1425, nullptr, "RequestPostEvents"},
+ {1426, nullptr, "GetPostEventInterval"},
+ {1427, nullptr, "SetPostEventInterval"},
+ {1432, D<&IParentalControlService::GetSynchronizationEvent>, "GetSynchronizationEvent"},
+ {1451, D<&IParentalControlService::StartPlayTimer>, "StartPlayTimer"},
+ {1452, D<&IParentalControlService::StopPlayTimer>, "StopPlayTimer"},
+ {1453, D<&IParentalControlService::IsPlayTimerEnabled>, "IsPlayTimerEnabled"},
+ {1454, nullptr, "GetPlayTimerRemainingTime"},
+ {1455, D<&IParentalControlService::IsRestrictedByPlayTimer>, "IsRestrictedByPlayTimer"},
+ {1456, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"},
+ {1457, D<&IParentalControlService::GetPlayTimerEventToRequestSuspension>, "GetPlayTimerEventToRequestSuspension"},
+ {1458, D<&IParentalControlService::IsPlayTimerAlarmDisabled>, "IsPlayTimerAlarmDisabled"},
+ {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
+ {1472, nullptr, "CancelNetworkRequest"},
+ {1473, D<&IParentalControlService::GetUnlinkedEvent>, "GetUnlinkedEvent"},
+ {1474, nullptr, "ClearUnlinkedEvent"},
+ {1601, nullptr, "DisableAllFeatures"},
+ {1602, nullptr, "PostEnableAllFeatures"},
+ {1603, nullptr, "IsAllFeaturesDisabled"},
+ {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
+ {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
+ {1903, nullptr, "GetExemptApplicationListCountForDebug"},
+ {1904, nullptr, "GetExemptApplicationListForDebug"},
+ {1905, nullptr, "UpdateExemptApplicationListForDebug"},
+ {1906, nullptr, "AddToExemptApplicationListForDebug"},
+ {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
+ {1908, nullptr, "ClearExemptApplicationListForDebug"},
+ {1941, nullptr, "DeletePairing"},
+ {1951, nullptr, "SetPlayTimerSettingsForDebug"},
+ {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
+ {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
+ {2001, nullptr, "RequestPairingAsync"},
+ {2002, nullptr, "FinishRequestPairing"},
+ {2003, nullptr, "AuthorizePairingAsync"},
+ {2004, nullptr, "FinishAuthorizePairing"},
+ {2005, nullptr, "RetrievePairingInfoAsync"},
+ {2006, nullptr, "FinishRetrievePairingInfo"},
+ {2007, nullptr, "UnlinkPairingAsync"},
+ {2008, nullptr, "FinishUnlinkPairing"},
+ {2009, nullptr, "GetAccountMiiImageAsync"},
+ {2010, nullptr, "FinishGetAccountMiiImage"},
+ {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
+ {2012, nullptr, "FinishGetAccountMiiImageContentType"},
+ {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
+ {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
+ {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
+ {2016, nullptr, "RequestUpdateExemptionListAsync"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+}
+
+IParentalControlService::~IParentalControlService() = default;
+
+bool IParentalControlService::CheckFreeCommunicationPermissionImpl() const {
+ if (states.temporary_unlocked) {
+ return true;
+ }
+ if ((states.application_info.parental_control_flag & 1) == 0) {
+ return true;
+ }
+ if (pin_code[0] == '\0') {
+ return true;
+ }
+ if (!settings.is_free_communication_default_on) {
+ return true;
+ }
+ // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
+ // but as we don't have multiproceses support yet, we can just assume our application is
+ // valid for the time being
+ return true;
+}
+
+bool IParentalControlService::ConfirmStereoVisionPermissionImpl() const {
+ if (states.temporary_unlocked) {
+ return true;
+ }
+ if (pin_code[0] == '\0') {
+ return true;
+ }
+ if (!settings.is_stero_vision_restricted) {
+ return false;
+ }
+ return true;
+}
+
+void IParentalControlService::SetStereoVisionRestrictionImpl(bool is_restricted) {
+ if (settings.disabled) {
+ return;
+ }
+
+ if (pin_code[0] == '\0') {
+ return;
+ }
+ settings.is_stero_vision_restricted = is_restricted;
+}
+
+Result IParentalControlService::Initialize() {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (False(capability & (Capability::Application | Capability::System))) {
+ LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ // TODO(ogniK): Recovery flag initialization for pctl:r
+
+ const auto program_id = system.GetApplicationProcessProgramID();
+ if (program_id != 0) {
+ const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
+ system.GetContentProvider()};
+ const auto control = pm.GetControlMetadata();
+ if (control.first) {
+ states.tid_from_event = 0;
+ states.launch_time_valid = false;
+ states.is_suspended = false;
+ states.free_communication = false;
+ states.stereo_vision = false;
+ states.application_info = ApplicationInfo{
+ .application_id = program_id,
+ .age_rating = control.first->GetRatingAge(),
+ .parental_control_flag = control.first->GetParentalControlFlag(),
+ .capability = capability,
+ };
+
+ if (False(capability & (Capability::System | Capability::Recovery))) {
+ // TODO(ogniK): Signal application launch event
+ }
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result IParentalControlService::CheckFreeCommunicationPermission() {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (!CheckFreeCommunicationPermissionImpl()) {
+ R_THROW(PCTL::ResultNoFreeCommunication);
+ } else {
+ states.free_communication = true;
+ R_SUCCEED();
+ }
+}
+
+Result IParentalControlService::ConfirmLaunchApplicationPermission(
+ InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
+ application_id);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ConfirmResumeApplicationPermission(
+ InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
+ application_id);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ConfirmSnsPostPermission() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ R_THROW(PCTL::ResultNoFreeCommunication);
+}
+
+Result IParentalControlService::IsRestrictionTemporaryUnlocked(
+ Out<bool> out_is_temporary_unlocked) {
+ *out_is_temporary_unlocked = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
+ *out_is_temporary_unlocked);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsRestrictedSystemSettingsEntered(
+ Out<bool> out_is_restricted_system_settings_entered) {
+ *out_is_restricted_system_settings_entered = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
+ *out_is_restricted_system_settings_entered);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ConfirmStereoVisionPermission() {
+ LOG_DEBUG(Service_PCTL, "called");
+ states.stereo_vision = true;
+ R_SUCCEED();
+}
+
+Result IParentalControlService::EndFreeCommunication() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsFreeCommunicationAvailable() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+
+ if (!CheckFreeCommunicationPermissionImpl()) {
+ R_THROW(PCTL::ResultNoFreeCommunication);
+ } else {
+ R_SUCCEED();
+ }
+}
+
+Result IParentalControlService::IsRestrictionEnabled(Out<bool> out_restriction_enabled) {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (False(capability & (Capability::Status | Capability::Recovery))) {
+ LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
+ *out_restriction_enabled = false;
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ *out_restriction_enabled = pin_code[0] != '\0';
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetSafetyLevel(Out<u32> out_safety_level) {
+ *out_safety_level = 0;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", *out_safety_level);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetCurrentSettings(Out<RestrictionSettings> out_settings) {
+ LOG_INFO(Service_PCTL, "called");
+ *out_settings = restriction_settings;
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetFreeCommunicationApplicationListCount(Out<s32> out_count) {
+ *out_count = 4;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", *out_count);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ConfirmStereoVisionRestrictionConfigurable() {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ if (pin_code[0] == '\0') {
+ R_THROW(PCTL::ResultNoRestrictionEnabled);
+ }
+
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsStereoVisionPermitted(Out<bool> out_is_permitted) {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (!ConfirmStereoVisionPermissionImpl()) {
+ *out_is_permitted = false;
+ R_THROW(PCTL::ResultStereoVisionRestricted);
+ } else {
+ *out_is_permitted = true;
+ R_SUCCEED();
+ }
+}
+
+Result IParentalControlService::GetPinCodeLength(Out<s32> out_length) {
+ *out_length = 0;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, length={}", *out_length);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsPairingActive(Out<bool> out_is_pairing_active) {
+ *out_is_pairing_active = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", *out_is_pairing_active);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetSynchronizationEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_PCTL, "called");
+ *out_event = synchronization_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IParentalControlService::StartPlayTimer() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IParentalControlService::StopPlayTimer() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled) {
+ *out_is_play_timer_enabled = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, enabled={}", *out_is_play_timer_enabled);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer) {
+ *out_is_restricted_by_play_timer = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, restricted={}", *out_is_restricted_by_play_timer);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetPlayTimerSettings(
+ Out<PlayTimerSettings> out_play_timer_settings) {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ *out_play_timer_settings = {};
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetPlayTimerEventToRequestSuspension(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_PCTL, "called");
+ *out_event = request_suspension_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled) {
+ *out_play_timer_alarm_disabled = false;
+ LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
+ *out_play_timer_alarm_disabled);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_PCTL, "called");
+ *out_event = unlinked_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetStereoVisionRestriction(
+ Out<bool> out_stereo_vision_restriction) {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ *out_stereo_vision_restriction = false;
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ *out_stereo_vision_restriction = settings.is_stero_vision_restricted;
+ R_SUCCEED();
+}
+
+Result IParentalControlService::SetStereoVisionRestriction(bool stereo_vision_restriction) {
+ LOG_DEBUG(Service_PCTL, "called, can_use={}", stereo_vision_restriction);
+
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ SetStereoVisionRestrictionImpl(stereo_vision_restriction);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ResetConfirmedStereoVisionPermission() {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ states.stereo_vision = false;
+
+ R_SUCCEED();
+}
+
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service.h b/src/core/hle/service/pctl/parental_control_service.h
new file mode 100644
index 000000000..03dbaa2e5
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service.h
@@ -0,0 +1,86 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/os/event.h"
+#include "core/hle/service/pctl/pctl_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PCTL {
+
+class IParentalControlService final : public ServiceFramework<IParentalControlService> {
+public:
+ explicit IParentalControlService(Core::System& system_, Capability capability_);
+ ~IParentalControlService() override;
+
+private:
+ bool CheckFreeCommunicationPermissionImpl() const;
+ bool ConfirmStereoVisionPermissionImpl() const;
+ void SetStereoVisionRestrictionImpl(bool is_restricted);
+
+ Result Initialize();
+ Result CheckFreeCommunicationPermission();
+ Result ConfirmLaunchApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
+ u64 nacp_flag, u64 application_id);
+ Result ConfirmResumeApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
+ u64 nacp_flag, u64 application_id);
+ Result ConfirmSnsPostPermission();
+ Result IsRestrictionTemporaryUnlocked(Out<bool> out_is_temporary_unlocked);
+ Result IsRestrictedSystemSettingsEntered(Out<bool> out_is_restricted_system_settings_entered);
+ Result ConfirmStereoVisionPermission();
+ Result EndFreeCommunication();
+ Result IsFreeCommunicationAvailable();
+ Result IsRestrictionEnabled(Out<bool> out_restriction_enabled);
+ Result GetSafetyLevel(Out<u32> out_safety_level);
+ Result GetCurrentSettings(Out<RestrictionSettings> out_settings);
+ Result GetFreeCommunicationApplicationListCount(Out<s32> out_count);
+ Result ConfirmStereoVisionRestrictionConfigurable();
+ Result IsStereoVisionPermitted(Out<bool> out_is_permitted);
+ Result GetPinCodeLength(Out<s32> out_length);
+ Result IsPairingActive(Out<bool> out_is_pairing_active);
+ Result GetSynchronizationEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result StartPlayTimer();
+ Result StopPlayTimer();
+ Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
+ Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
+ Result GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings);
+ Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
+ Result GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetStereoVisionRestriction(Out<bool> out_stereo_vision_restriction);
+ Result SetStereoVisionRestriction(bool stereo_vision_restriction);
+ Result ResetConfirmedStereoVisionPermission();
+
+ struct States {
+ u64 current_tid{};
+ ApplicationInfo application_info{};
+ u64 tid_from_event{};
+ bool launch_time_valid{};
+ bool is_suspended{};
+ bool temporary_unlocked{};
+ bool free_communication{};
+ bool stereo_vision{};
+ };
+
+ struct ParentalControlSettings {
+ bool is_stero_vision_restricted{};
+ bool is_free_communication_default_on{};
+ bool disabled{};
+ };
+
+ States states{};
+ ParentalControlSettings settings{};
+ RestrictionSettings restriction_settings{};
+ std::array<char, 8> pin_code{};
+ Capability capability{};
+
+ KernelHelpers::ServiceContext service_context;
+ Event synchronization_event;
+ Event unlinked_event;
+ Event request_suspension_event;
+};
+
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service_factory.cpp b/src/core/hle/service/pctl/parental_control_service_factory.cpp
new file mode 100644
index 000000000..7d8f361e9
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service_factory.cpp
@@ -0,0 +1,40 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/pctl/parental_control_service.h"
+#include "core/hle/service/pctl/parental_control_service_factory.h"
+
+namespace Service::PCTL {
+
+IParentalControlServiceFactory::IParentalControlServiceFactory(Core::System& system_,
+ const char* name_,
+ Capability capability_)
+ : ServiceFramework{system_, name_}, capability{capability_} {
+ static const FunctionInfo functions[] = {
+ {0, D<&IParentalControlServiceFactory::CreateService>, "CreateService"},
+ {1, D<&IParentalControlServiceFactory::CreateServiceWithoutInitialize>,
+ "CreateServiceWithoutInitialize"},
+ };
+ RegisterHandlers(functions);
+}
+
+IParentalControlServiceFactory::~IParentalControlServiceFactory() = default;
+
+Result IParentalControlServiceFactory::CreateService(
+ Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
+ LOG_DEBUG(Service_PCTL, "called");
+ // TODO(ogniK): Get application id from process
+ *out_service = std::make_shared<IParentalControlService>(system, capability);
+ R_SUCCEED();
+}
+
+Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
+ Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
+ LOG_DEBUG(Service_PCTL, "called");
+ // TODO(ogniK): Get application id from process
+ *out_service = std::make_shared<IParentalControlService>(system, capability);
+ R_SUCCEED();
+}
+
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service_factory.h b/src/core/hle/service/pctl/parental_control_service_factory.h
new file mode 100644
index 000000000..362988add
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service_factory.h
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/pctl/pctl_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PCTL {
+
+class IParentalControlService;
+
+class IParentalControlServiceFactory : public ServiceFramework<IParentalControlServiceFactory> {
+public:
+ explicit IParentalControlServiceFactory(Core::System& system_, const char* name_,
+ Capability capability_);
+ ~IParentalControlServiceFactory() override;
+
+ Result CreateService(Out<SharedPointer<IParentalControlService>> out_service,
+ ClientProcessId process_id);
+ Result CreateServiceWithoutInitialize(Out<SharedPointer<IParentalControlService>> out_service,
+ ClientProcessId process_id);
+
+private:
+ Capability capability{};
+};
+
+void LoopProcess(Core::System& system);
+
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index 3f47bf094..d92dbe216 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -1,19 +1,28 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/hle/service/pctl/parental_control_service_factory.h"
#include "core/hle/service/pctl/pctl.h"
+#include "core/hle/service/server_manager.h"
namespace Service::PCTL {
-PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
- Capability capability_)
- : Interface{system_, std::move(module_), name, capability_} {
- static const FunctionInfo functions[] = {
- {0, &PCTL::CreateService, "CreateService"},
- {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
- };
- RegisterHandlers(functions);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("pctl",
+ std::make_shared<IParentalControlServiceFactory>(
+ system, "pctl",
+ Capability::Application | Capability::SnsPost |
+ Capability::Status | Capability::StereoVision));
+ // TODO(ogniK): Implement remaining capabilities
+ server_manager->RegisterNamedService("pctl:a", std::make_shared<IParentalControlServiceFactory>(
+ system, "pctl:a", Capability::None));
+ server_manager->RegisterNamedService("pctl:r", std::make_shared<IParentalControlServiceFactory>(
+ system, "pctl:r", Capability::None));
+ server_manager->RegisterNamedService("pctl:s", std::make_shared<IParentalControlServiceFactory>(
+ system, "pctl:s", Capability::None));
+ ServerManager::RunServer(std::move(server_manager));
}
-PCTL::~PCTL() = default;
} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 87f93161e..5f9d03d4d 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -3,19 +3,12 @@
#pragma once
-#include "core/hle/service/pctl/pctl_module.h"
-
namespace Core {
class System;
}
namespace Service::PCTL {
-class PCTL final : public Module::Interface {
-public:
- explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
- Capability capability_);
- ~PCTL() override;
-};
+void LoopProcess(Core::System& system);
} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp
deleted file mode 100644
index 6a7fd72bc..000000000
--- a/src/core/hle/service/pctl/pctl_module.cpp
+++ /dev/null
@@ -1,550 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/file_sys/control_metadata.h"
-#include "core/file_sys/patch_manager.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/pctl/pctl.h"
-#include "core/hle/service/pctl/pctl_module.h"
-#include "core/hle/service/server_manager.h"
-
-namespace Service::PCTL {
-
-namespace Error {
-
-constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
-constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
-constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
-constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
-
-} // namespace Error
-
-class IParentalControlService final : public ServiceFramework<IParentalControlService> {
-public:
- explicit IParentalControlService(Core::System& system_, Capability capability_)
- : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
- service_context{system_, "IParentalControlService"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {1, &IParentalControlService::Initialize, "Initialize"},
- {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
- {1002, nullptr, "ConfirmLaunchApplicationPermission"},
- {1003, nullptr, "ConfirmResumeApplicationPermission"},
- {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
- {1005, nullptr, "ConfirmSystemSettingsPermission"},
- {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
- {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
- {1008, nullptr, "EnterRestrictedSystemSettings"},
- {1009, nullptr, "LeaveRestrictedSystemSettings"},
- {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
- {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
- {1012, nullptr, "GetRestrictedFeatures"},
- {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
- {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
- {1015, nullptr, "ConfirmPlayableApplicationVideo"},
- {1016, nullptr, "ConfirmShowNewsPermission"},
- {1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
- {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
- {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
- {1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
- {1033, nullptr, "SetSafetyLevel"},
- {1034, nullptr, "GetSafetyLevelSettings"},
- {1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
- {1036, nullptr, "SetCustomSafetyLevelSettings"},
- {1037, nullptr, "GetDefaultRatingOrganization"},
- {1038, nullptr, "SetDefaultRatingOrganization"},
- {1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
- {1042, nullptr, "AddToFreeCommunicationApplicationList"},
- {1043, nullptr, "DeleteSettings"},
- {1044, nullptr, "GetFreeCommunicationApplicationList"},
- {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
- {1046, nullptr, "DisableFeaturesForReset"},
- {1047, nullptr, "NotifyApplicationDownloadStarted"},
- {1048, nullptr, "NotifyNetworkProfileCreated"},
- {1049, nullptr, "ResetFreeCommunicationApplicationList"},
- {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
- {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
- {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
- {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"},
- {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"},
- {1201, nullptr, "UnlockRestrictionTemporarily"},
- {1202, nullptr, "UnlockSystemSettingsRestriction"},
- {1203, nullptr, "SetPinCode"},
- {1204, nullptr, "GenerateInquiryCode"},
- {1205, nullptr, "CheckMasterKey"},
- {1206, nullptr, "GetPinCodeLength"},
- {1207, nullptr, "GetPinCodeChangedEvent"},
- {1208, nullptr, "GetPinCode"},
- {1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
- {1406, nullptr, "GetSettingsLastUpdated"},
- {1411, nullptr, "GetPairingAccountInfo"},
- {1421, nullptr, "GetAccountNickname"},
- {1424, nullptr, "GetAccountState"},
- {1425, nullptr, "RequestPostEvents"},
- {1426, nullptr, "GetPostEventInterval"},
- {1427, nullptr, "SetPostEventInterval"},
- {1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
- {1451, nullptr, "StartPlayTimer"},
- {1452, nullptr, "StopPlayTimer"},
- {1453, nullptr, "IsPlayTimerEnabled"},
- {1454, nullptr, "GetPlayTimerRemainingTime"},
- {1455, nullptr, "IsRestrictedByPlayTimer"},
- {1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
- {1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
- {1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
- {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
- {1472, nullptr, "CancelNetworkRequest"},
- {1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
- {1474, nullptr, "ClearUnlinkedEvent"},
- {1601, nullptr, "DisableAllFeatures"},
- {1602, nullptr, "PostEnableAllFeatures"},
- {1603, nullptr, "IsAllFeaturesDisabled"},
- {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
- {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
- {1903, nullptr, "GetExemptApplicationListCountForDebug"},
- {1904, nullptr, "GetExemptApplicationListForDebug"},
- {1905, nullptr, "UpdateExemptApplicationListForDebug"},
- {1906, nullptr, "AddToExemptApplicationListForDebug"},
- {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
- {1908, nullptr, "ClearExemptApplicationListForDebug"},
- {1941, nullptr, "DeletePairing"},
- {1951, nullptr, "SetPlayTimerSettingsForDebug"},
- {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
- {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
- {2001, nullptr, "RequestPairingAsync"},
- {2002, nullptr, "FinishRequestPairing"},
- {2003, nullptr, "AuthorizePairingAsync"},
- {2004, nullptr, "FinishAuthorizePairing"},
- {2005, nullptr, "RetrievePairingInfoAsync"},
- {2006, nullptr, "FinishRetrievePairingInfo"},
- {2007, nullptr, "UnlinkPairingAsync"},
- {2008, nullptr, "FinishUnlinkPairing"},
- {2009, nullptr, "GetAccountMiiImageAsync"},
- {2010, nullptr, "FinishGetAccountMiiImage"},
- {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
- {2012, nullptr, "FinishGetAccountMiiImageContentType"},
- {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
- {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
- {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
- {2016, nullptr, "RequestUpdateExemptionListAsync"},
- };
- // clang-format on
- RegisterHandlers(functions);
-
- synchronization_event =
- service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
- unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
- request_suspension_event =
- service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
- }
-
- ~IParentalControlService() {
- service_context.CloseEvent(synchronization_event);
- service_context.CloseEvent(unlinked_event);
- service_context.CloseEvent(request_suspension_event);
- };
-
-private:
- bool CheckFreeCommunicationPermissionImpl() const {
- if (states.temporary_unlocked) {
- return true;
- }
- if ((states.application_info.parental_control_flag & 1) == 0) {
- return true;
- }
- if (pin_code[0] == '\0') {
- return true;
- }
- if (!settings.is_free_communication_default_on) {
- return true;
- }
- // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
- // but as we don't have multiproceses support yet, we can just assume our application is
- // valid for the time being
- return true;
- }
-
- bool ConfirmStereoVisionPermissionImpl() const {
- if (states.temporary_unlocked) {
- return true;
- }
- if (pin_code[0] == '\0') {
- return true;
- }
- if (!settings.is_stero_vision_restricted) {
- return false;
- }
- return true;
- }
-
- void SetStereoVisionRestrictionImpl(bool is_restricted) {
- if (settings.disabled) {
- return;
- }
-
- if (pin_code[0] == '\0') {
- return;
- }
- settings.is_stero_vision_restricted = is_restricted;
- }
-
- void Initialize(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
- IPC::ResponseBuilder rb{ctx, 2};
-
- if (False(capability & (Capability::Application | Capability::System))) {
- LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
- return;
- }
-
- // TODO(ogniK): Recovery flag initialization for pctl:r
-
- const auto tid = system.GetApplicationProcessProgramID();
- if (tid != 0) {
- const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
- system.GetContentProvider()};
- const auto control = pm.GetControlMetadata();
- if (control.first) {
- states.tid_from_event = 0;
- states.launch_time_valid = false;
- states.is_suspended = false;
- states.free_communication = false;
- states.stereo_vision = false;
- states.application_info = ApplicationInfo{
- .tid = tid,
- .age_rating = control.first->GetRatingAge(),
- .parental_control_flag = control.first->GetParentalControlFlag(),
- .capability = capability,
- };
-
- if (False(capability & (Capability::System | Capability::Recovery))) {
- // TODO(ogniK): Signal application launch event
- }
- }
- }
-
- rb.Push(ResultSuccess);
- }
-
- void CheckFreeCommunicationPermission(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- if (!CheckFreeCommunicationPermissionImpl()) {
- rb.Push(Error::ResultNoFreeCommunication);
- } else {
- rb.Push(ResultSuccess);
- }
-
- states.free_communication = true;
- }
-
- void ConfirmSnsPostPermission(HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Error::ResultNoFreeCommunication);
- }
-
- void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
- const bool is_temporary_unlocked = false;
-
- LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
- is_temporary_unlocked);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u8>(is_temporary_unlocked);
- }
-
- void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
- states.stereo_vision = true;
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void EndFreeCommunication(HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void IsFreeCommunicationAvailable(HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- if (!CheckFreeCommunicationPermissionImpl()) {
- rb.Push(Error::ResultNoFreeCommunication);
- } else {
- rb.Push(ResultSuccess);
- }
- }
-
- void IsRestrictionEnabled(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- if (False(capability & (Capability::Status | Capability::Recovery))) {
- LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
- rb.Push(Error::ResultNoCapability);
- rb.Push(false);
- return;
- }
-
- rb.Push(pin_code[0] != '\0');
- }
-
- void GetSafetyLevel(HLERequestContext& ctx) {
- const u32 safety_level = 0;
-
- LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(safety_level);
- }
-
- void GetCurrentSettings(HLERequestContext& ctx) {
- LOG_INFO(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushRaw(restriction_settings);
- }
-
- void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
- const u32 count = 4;
-
- LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(count);
- }
-
- void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2};
-
- if (False(capability & Capability::StereoVision)) {
- LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
- rb.Push(Error::ResultNoCapability);
- return;
- }
-
- if (pin_code[0] == '\0') {
- rb.Push(Error::ResultNoRestrictionEnabled);
- return;
- }
-
- rb.Push(ResultSuccess);
- }
-
- void IsStereoVisionPermitted(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- if (!ConfirmStereoVisionPermissionImpl()) {
- rb.Push(Error::ResultStereoVisionRestricted);
- rb.Push(false);
- } else {
- rb.Push(ResultSuccess);
- rb.Push(true);
- }
- }
-
- void IsPairingActive(HLERequestContext& ctx) {
- const bool is_pairing_active = false;
-
- LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u8>(is_pairing_active);
- }
-
- void GetSynchronizationEvent(HLERequestContext& ctx) {
- LOG_INFO(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(synchronization_event->GetReadableEvent());
- }
-
- void GetPlayTimerSettings(HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
-
- const PlayTimerSettings timer_settings{};
-
- IPC::ResponseBuilder rb{ctx, 15};
- rb.Push(ResultSuccess);
- rb.PushRaw(timer_settings);
- }
-
- void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
- LOG_INFO(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
- }
-
- void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
- const bool is_play_timer_alarm_disabled = false;
-
- LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
- is_play_timer_alarm_disabled);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u8>(is_play_timer_alarm_disabled);
- }
-
- void GetUnlinkedEvent(HLERequestContext& ctx) {
- LOG_INFO(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(unlinked_event->GetReadableEvent());
- }
-
- void SetStereoVisionRestriction(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto can_use = rp.Pop<bool>();
- LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
-
- IPC::ResponseBuilder rb{ctx, 2};
- if (False(capability & Capability::StereoVision)) {
- LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
- rb.Push(Error::ResultNoCapability);
- return;
- }
-
- SetStereoVisionRestrictionImpl(can_use);
- rb.Push(ResultSuccess);
- }
-
- void GetStereoVisionRestriction(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- if (False(capability & Capability::StereoVision)) {
- LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
- rb.Push(Error::ResultNoCapability);
- rb.Push(false);
- return;
- }
-
- rb.Push(ResultSuccess);
- rb.Push(settings.is_stero_vision_restricted);
- }
-
- void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- states.stereo_vision = false;
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- struct ApplicationInfo {
- u64 tid{};
- std::array<u8, 32> age_rating{};
- u32 parental_control_flag{};
- Capability capability{};
- };
-
- struct States {
- u64 current_tid{};
- ApplicationInfo application_info{};
- u64 tid_from_event{};
- bool launch_time_valid{};
- bool is_suspended{};
- bool temporary_unlocked{};
- bool free_communication{};
- bool stereo_vision{};
- };
-
- struct ParentalControlSettings {
- bool is_stero_vision_restricted{};
- bool is_free_communication_default_on{};
- bool disabled{};
- };
-
- // This is nn::pctl::RestrictionSettings
- struct RestrictionSettings {
- u8 rating_age;
- bool sns_post_restriction;
- bool free_communication_restriction;
- };
- static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
-
- // This is nn::pctl::PlayTimerSettings
- struct PlayTimerSettings {
- std::array<u32, 13> settings;
- };
- static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
-
- States states{};
- ParentalControlSettings settings{};
- RestrictionSettings restriction_settings{};
- std::array<char, 8> pin_code{};
- Capability capability{};
-
- Kernel::KEvent* synchronization_event;
- Kernel::KEvent* unlinked_event;
- Kernel::KEvent* request_suspension_event;
- KernelHelpers::ServiceContext service_context;
-};
-
-void Module::Interface::CreateService(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- // TODO(ogniK): Get TID from process
-
- rb.PushIpcInterface<IParentalControlService>(system, capability);
-}
-
-void Module::Interface::CreateServiceWithoutInitialize(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IParentalControlService>(system, capability);
-}
-
-Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
- const char* name_, Capability capability_)
- : ServiceFramework{system_, name_}, module{std::move(module_)}, capability{capability_} {}
-
-Module::Interface::~Interface() = default;
-
-void LoopProcess(Core::System& system) {
- auto server_manager = std::make_unique<ServerManager>(system);
-
- auto module = std::make_shared<Module>();
- server_manager->RegisterNamedService(
- "pctl", std::make_shared<PCTL>(system, module, "pctl",
- Capability::Application | Capability::SnsPost |
- Capability::Status | Capability::StereoVision));
- // TODO(ogniK): Implement remaining capabilities
- server_manager->RegisterNamedService(
- "pctl:a", std::make_shared<PCTL>(system, module, "pctl:a", Capability::None));
- server_manager->RegisterNamedService(
- "pctl:r", std::make_shared<PCTL>(system, module, "pctl:r", Capability::None));
- server_manager->RegisterNamedService(
- "pctl:s", std::make_shared<PCTL>(system, module, "pctl:s", Capability::None));
- ServerManager::RunServer(std::move(server_manager));
-}
-
-} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_module.h b/src/core/hle/service/pctl/pctl_module.h
deleted file mode 100644
index dff0d3f08..000000000
--- a/src/core/hle/service/pctl/pctl_module.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "common/common_funcs.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::PCTL {
-
-enum class Capability : u32 {
- None = 0,
- Application = 1 << 0,
- SnsPost = 1 << 1,
- Recovery = 1 << 6,
- Status = 1 << 8,
- StereoVision = 1 << 9,
- System = 1 << 15,
-};
-DECLARE_ENUM_FLAG_OPERATORS(Capability);
-
-class Module final {
-public:
- class Interface : public ServiceFramework<Interface> {
- public:
- explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
- const char* name_, Capability capability_);
- ~Interface() override;
-
- void CreateService(HLERequestContext& ctx);
- void CreateServiceWithoutInitialize(HLERequestContext& ctx);
-
- protected:
- std::shared_ptr<Module> module;
-
- private:
- Capability capability{};
- };
-};
-
-void LoopProcess(Core::System& system);
-
-} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_results.h b/src/core/hle/service/pctl/pctl_results.h
new file mode 100644
index 000000000..1fc54727b
--- /dev/null
+++ b/src/core/hle/service/pctl/pctl_results.h
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::PCTL {
+
+constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
+constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
+constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
+constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
+
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_types.h b/src/core/hle/service/pctl/pctl_types.h
new file mode 100644
index 000000000..daaecdf48
--- /dev/null
+++ b/src/core/hle/service/pctl/pctl_types.h
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/common_funcs.h"
+
+namespace Service::PCTL {
+
+enum class Capability : u32 {
+ None = 0,
+ Application = 1 << 0,
+ SnsPost = 1 << 1,
+ Recovery = 1 << 6,
+ Status = 1 << 8,
+ StereoVision = 1 << 9,
+ System = 1 << 15,
+};
+DECLARE_ENUM_FLAG_OPERATORS(Capability);
+
+struct ApplicationInfo {
+ u64 application_id{};
+ std::array<u8, 32> age_rating{};
+ u32 parental_control_flag{};
+ Capability capability{};
+};
+static_assert(sizeof(ApplicationInfo) == 0x30, "ApplicationInfo has incorrect size.");
+
+// This is nn::pctl::RestrictionSettings
+struct RestrictionSettings {
+ u8 rating_age;
+ bool sns_post_restriction;
+ bool free_communication_restriction;
+};
+static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
+
+// This is nn::pctl::PlayTimerSettings
+struct PlayTimerSettings {
+ std::array<u32, 13> settings;
+};
+static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
+
+} // namespace Service::PCTL
diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp
index d6c6eff50..1aa85ea54 100644
--- a/src/core/hle/service/services.cpp
+++ b/src/core/hle/service/services.cpp
@@ -46,7 +46,7 @@
#include "core/hle/service/olsc/olsc.h"
#include "core/hle/service/omm/omm.h"
#include "core/hle/service/pcie/pcie.h"
-#include "core/hle/service/pctl/pctl_module.h"
+#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/pcv/pcv.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/prepo/prepo.h"