Compare commits

...

33 Commits

Author SHA1 Message Date
2051b3d2d6 Android 262 2024-02-22 19:38:20 +00:00
921d800d66 Merge yuzu-emu#13117 2024-02-22 19:38:20 +00:00
6ab071dfb1 Merge yuzu-emu#13116 2024-02-22 19:38:20 +00:00
49f77aae14 Merge yuzu-emu#13115 2024-02-22 19:38:20 +00:00
08f4877288 Merge yuzu-emu#13100 2024-02-22 19:38:20 +00:00
3ebc0de12f Merge yuzu-emu#13096 2024-02-22 19:38:20 +00:00
7f9ad00b63 Merge yuzu-emu#13073 2024-02-22 19:38:19 +00:00
257b0ac59a Merge yuzu-emu#12749 2024-02-22 19:38:19 +00:00
e646ef45ac Merge yuzu-emu#12461 2024-02-22 19:38:19 +00:00
d12d9dad40 Merge pull request #12982 from FearlessTobi/fs-rewrite-part0
fs: Add FileSystemAccessor and use cmif serialization
2024-02-22 12:34:47 -05:00
2b3f1d3fc5 Merge pull request #13000 from liamwhite/skip-null-memory
device_memory_manager: skip unregistered interfaces on invalidate
2024-02-22 11:34:23 -06:00
984396a21a Merge pull request #13001 from liamwhite/scaled-availability
vulkan_device: don't use fixed cap for memory limits
2024-02-22 11:31:17 -06:00
4f95ee5209 Merge pull request #13075 from liamwhite/mali-having-a-bad-time
shader_recompiler: throw on missing geometry streams in geometry shaders
2024-02-22 11:30:26 -06:00
8bbc209950 Merge pull request #13105 from t895/connection-fix
android: Misc controller fixes
2024-02-21 10:43:46 -05:00
9e1a67b950 fs: add missing mutex header for member (#13106) 2024-02-21 16:43:05 +01:00
de5422b1fd android: Connect controllers with supported styles
If you tried to connect a controller that was previously configured with an unsupported style for your game, when you try to connect that controller, it will immediately disconnect. This ensures that the controller that is being connected will be changed to the first supported style index before being connected.
2024-02-21 08:37:55 -05:00
45f450fca5 android: Add additional check for hasMapping
Controls can have no mapping if they are either "[empty]" or and empty string. This was causing an issue if you reset mapping on all controllers and then tried to play a game. The check to determine whether auto mapping was required would fail and leave you will no mapped controllers. This feels a bit like user error but it smooths things out if you forget so I see it as necessary.
2024-02-21 08:17:30 -05:00
9a3fd76b25 android: Enable all controller styles on emulation shutdown 2024-02-21 08:13:54 -05:00
60fc6df407 Merge pull request #13099 from t895/default-fix
android: Fix extra stick setting default values
2024-02-21 07:02:58 -05:00
de2d496e71 android: Fix extra stick setting default values
The default value was accidentally hardcoded for all extra stick settings
2024-02-20 22:13:59 -05:00
7b5bdd076d Merge pull request #13095 from liamwhite/ns-oops
ns: fix alignment of uid type
2024-02-20 21:19:35 -05:00
e0c17a2113 Merge pull request #10529 from liamwhite/critical-spacing
caches: make critical reclamation less eager and possible in more cases
2024-02-20 23:19:27 -03:00
b107435a3f ns: fix alignment of uid type 2024-02-20 18:43:44 -05:00
ef50277124 Address review comments pt. 2 2024-02-19 19:22:51 +01:00
ba70dc4c13 Address review comments 2024-02-19 19:20:46 +01:00
934e420e36 fs: Refactor to use cmif serialization 2024-02-19 19:20:46 +01:00
d5e4617ab5 fs: Add FileSystemAccessor classes 2024-02-19 19:20:40 +01:00
f46dc31683 shader_recompiler: throw on missing geometry streams in geometry shaders 2024-02-19 00:34:00 -05:00
56810541f0 vulkan_device: don't use fixed cap for memory limits 2024-02-18 18:59:13 -05:00
461eaca7e8 device_memory_manager: skip unregistered interfaces on invalidate 2024-02-12 20:02:59 -05:00
368bf2211f texture_cache: tweak iteration tracking change 2024-02-11 13:41:13 -05:00
de8a623932 texture_cache: avoid overestimation of ASTC texture sizes 2024-02-11 13:41:13 -05:00
865a0186b6 caches: make critical reclamation less eager and possible in more cases 2024-02-11 13:41:13 -05:00
197 changed files with 17479 additions and 5295 deletions

View File

@ -1,3 +1,19 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`2831f5dc6`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13073](https://github.com/yuzu-emu/yuzu//pull/13073) | [`b5a17b501`](https://github.com/yuzu-emu/yuzu//pull/13073/files) | fsp: Migrate remaining interfaces to cmif serialization | [FearlessTobi](https://github.com/FearlessTobi/) | Yes |
| [13096](https://github.com/yuzu-emu/yuzu//pull/13096) | [`0a8759057`](https://github.com/yuzu-emu/yuzu//pull/13096/files) | texture_cache: use two-pass collection for costly load resources | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13100](https://github.com/yuzu-emu/yuzu//pull/13100) | [`c04567fad`](https://github.com/yuzu-emu/yuzu//pull/13100/files) | audio: move to new ipc | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13115](https://github.com/yuzu-emu/yuzu//pull/13115) | [`89c2fd3d2`](https://github.com/yuzu-emu/yuzu//pull/13115/files) | olsc, pctl: move to new ipc | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13116](https://github.com/yuzu-emu/yuzu//pull/13116) | [`54ed837ad`](https://github.com/yuzu-emu/yuzu//pull/13116/files) | android: Flip AB/XY for 8Bitdo controllers | [t895](https://github.com/t895/) | Yes |
| [13117](https://github.com/yuzu-emu/yuzu//pull/13117) | [`e85466c1a`](https://github.com/yuzu-emu/yuzu//pull/13117/files) | psc: stub overlay notification channel | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.
-----
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -314,3 +314,10 @@ endif()
if (NOT TARGET SimpleIni::SimpleIni)
add_subdirectory(simpleini)
endif()
# sse2neon
if (ARCHITECTURE_arm64 AND NOT TARGET sse2neon)
add_library(sse2neon INTERFACE)
target_include_directories(sse2neon INTERFACE sse2neon)
endif()

9282
externals/sse2neon/sse2neon.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -121,6 +121,7 @@ else()
-Wno-attributes
-Wno-invalid-offsetof
-Wno-unused-parameter
-Wno-missing-field-initializers
)
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
@ -164,6 +165,7 @@ else()
if (MINGW)
add_definitions(-DMINGW_HAS_SECURE_API)
add_compile_options("-msse4.1")
if (MINGW_STATIC_BUILD)
add_definitions(-DQT_STATICPLUGIN)

View File

@ -64,17 +64,17 @@ data class PlayerInput(
fun hasMapping(): Boolean {
var hasMapping = false
buttons.forEach {
if (it != "[empty]") {
if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}
analogs.forEach {
if (it != "[empty]") {
if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}
motions.forEach {
if (it != "[empty]") {
if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}

View File

@ -780,7 +780,7 @@ class SettingsFragmentPresenter(
playerIndex: Int,
paramName: String,
stick: NativeAnalog,
defaultValue: Int
defaultValue: Float
): AbstractIntSetting =
object : AbstractIntSetting {
val params get() = NativeInput.getStickParam(playerIndex, stick)
@ -788,7 +788,7 @@ class SettingsFragmentPresenter(
override val key = ""
override fun getInt(needsGlobal: Boolean): Int =
(params.get(paramName, 0.15f) * 100).toInt()
(params.get(paramName, defaultValue) * 100).toInt()
override fun setInt(value: Int) {
val tempParams = params
@ -796,12 +796,12 @@ class SettingsFragmentPresenter(
NativeInput.setStickParam(playerIndex, stick, tempParams)
}
override val defaultValue = defaultValue
override val defaultValue = (defaultValue * 100).toInt()
override fun getValueAsString(needsGlobal: Boolean): String =
getInt(needsGlobal).toString()
override fun reset() = setInt(defaultValue)
override fun reset() = setInt(this.defaultValue)
}
private fun getExtraStickSettings(
@ -811,11 +811,11 @@ class SettingsFragmentPresenter(
val stickIsController =
NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
val modifierRangeSetting =
getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50)
getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f)
val stickRangeSetting =
getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95)
getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f)
val stickDeadzoneSetting =
getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15)
getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f)
val out = mutableListOf<SettingsItem>().apply {
if (stickIsController) {

View File

@ -292,6 +292,9 @@ void EmulationSession::ShutdownEmulation() {
// Unload user input.
m_system.HIDCore().UnloadInputDevices();
// Enable all controllers
m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
// Shutdown the main emulated process
if (m_load_result == Core::SystemResultStatus::Success) {
m_system.DetachDebugger();
@ -665,7 +668,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1,
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1,
user_id->AsU128(), 0);
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
@ -833,8 +836,8 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
FileSys::OpenMode::Read);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
program_id, user_id->AsU128(), 0);
{}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
user_id->AsU128(), 0);
return Common::Android::ToJString(env, user_save_data_path);
}

View File

@ -102,8 +102,50 @@ void ApplyControllerConfig(size_t player_index,
}
}
std::vector<s32> GetSupportedStyles(int player_index) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
const auto npad_style_set = hid_core.GetSupportedStyleTag();
std::vector<s32> supported_indexes;
if (npad_style_set.fullkey == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey));
}
if (npad_style_set.joycon_dual == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual));
}
if (npad_style_set.joycon_left == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft));
}
if (npad_style_set.joycon_right == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight));
}
if (player_index == 0 && npad_style_set.handheld == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld));
}
if (npad_style_set.gamecube == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube));
}
return supported_indexes;
}
void ConnectController(size_t player_index, bool connected) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) {
auto supported_styles = GetSupportedStyles(player_index);
auto controller_style = controller->GetNpadStyleIndex(true);
auto style = std::find(supported_styles.begin(), supported_styles.end(),
static_cast<int>(controller_style));
if (style == supported_styles.end() && !supported_styles.empty()) {
controller->SetNpadStyleIndex(
static_cast<Core::HID::NpadStyleIndex>(supported_styles[0]));
}
});
if (player_index == 0) {
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
@ -522,36 +564,10 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv
jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
JNIEnv* env, jobject j_obj, jint j_player_index) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
const auto npad_style_set = hid_core.GetSupportedStyleTag();
std::vector<s32> supported_indexes;
if (npad_style_set.fullkey == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey));
}
if (npad_style_set.joycon_dual == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual));
}
if (npad_style_set.joycon_left == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft));
}
if (npad_style_set.joycon_right == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight));
}
if (j_player_index == 0 && npad_style_set.handheld == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld));
}
if (npad_style_set.gamecube == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube));
}
jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size());
env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(),
supported_indexes.data());
auto supported_styles = GetSupportedStyles(j_player_index);
jintArray j_supported_indexes = env->NewIntArray(supported_styles.size());
env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(),
supported_styles.data());
return j_supported_indexes;
}

View File

@ -73,16 +73,15 @@ void Manager::BufferReleaseAndRegister() {
}
}
u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names,
[[maybe_unused]] const u32 max_count,
u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
[[maybe_unused]] const bool filter) {
std::scoped_lock l{mutex};
LinkToManager();
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
if (input_devices.size() > 1) {
names.emplace_back("Uac");
if (!input_devices.empty() && !names.empty()) {
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
return 1;
}
return 0;

View File

@ -60,13 +60,11 @@ public:
* Get a list of audio in device names.
*
* @param names - Output container to write names to.
* @param max_count - Maximum number of device names to write. Unused
* @param filter - Should the list be filtered? Unused.
*
* @return Number of names written.
*/
u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count,
bool filter);
u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
/// Core system
Core::System& system;

View File

@ -146,11 +146,11 @@ public:
break;
}
tags[released++] = tag;
if (released >= tags.size()) {
break;
}
tags[released++] = tag;
}
return released;

View File

@ -28,8 +28,8 @@ OpusDecoder::~OpusDecoder() {
}
}
Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size) {
Result OpusDecoder::Initialize(const OpusParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size;
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
@ -59,7 +59,7 @@ Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory
R_SUCCEED();
}
Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params,
Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size;

View File

@ -22,10 +22,10 @@ public:
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
~OpusDecoder();
Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size);
Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size);
Result Initialize(const OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
std::span<const u8> input_data, std::span<u8> output_data, bool reset);
Result SetContext([[maybe_unused]] std::span<const u8> context);

View File

@ -38,7 +38,7 @@ OpusDecoderManager::OpusDecoderManager(Core::System& system_)
}
}
Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) {
OpusParametersEx ex{
.sample_rate = params.sample_rate,
.channel_count = params.channel_count,
@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_si
R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) {
R_RETURN(GetWorkBufferSizeExEx(params, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) {
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64&
R_SUCCEED();
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params,
u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params,
u32& out_size) {
OpusMultiStreamParametersEx ex{
.sample_rate = params.sample_rate,
.channel_count = params.channel_count,
@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParame
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params,
u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
const OpusMultiStreamParametersEx& params, u32& out_size) {
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params,
u64& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
const OpusMultiStreamParametersEx& params, u32& out_size) {
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,

View File

@ -22,17 +22,19 @@ public:
return hardware_opus;
}
Result GetWorkBufferSize(OpusParameters& params, u64& out_size);
Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size);
Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size);
Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size);
Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size);
Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size);
Result GetWorkBufferSize(const OpusParameters& params, u32& out_size);
Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size);
Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size);
Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size);
Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params,
u32& out_size);
Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params,
u32& out_size);
private:
Core::System& system;
HardwareOpus hardware_opus;
std::array<u64, MaxChannels> required_workbuffer_sizes{};
std::array<u32, MaxChannels> required_workbuffer_sizes{};
};
} // namespace AudioCore::OpusDecoder

View File

@ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_)
opus_decoder.SetSharedMemory(shared_memory);
}
u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
if (!opus_decoder.IsRunning()) {
return 0;
}
@ -55,10 +55,10 @@ u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
return 0;
}
return shared_memory.dsp_return_data[0];
return static_cast<u32>(shared_memory.dsp_return_data[0]);
}
u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = total_stream_count;
shared_memory.host_send_data[1] = stereo_stream_count;
@ -70,7 +70,7 @@ u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
return 0;
}
return shared_memory.dsp_return_data[0];
return static_cast<u32>(shared_memory.dsp_return_data[0]);
}
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
@ -94,8 +94,9 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count,
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 total_stream_count,
u32 stereo_stream_count, void* mappings,
void* buffer, u64 buffer_size) {
u32 stereo_stream_count,
const void* mappings, void* buffer,
u64 buffer_size) {
std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = (u64)buffer;
shared_memory.host_send_data[1] = buffer_size;

View File

@ -16,14 +16,14 @@ class HardwareOpus {
public:
HardwareOpus(Core::System& system);
u64 GetWorkBufferSize(u32 channel);
u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
u32 GetWorkBufferSize(u32 channel);
u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
u64 buffer_size);
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 totaL_stream_count, u32 stereo_stream_count,
void* mappings, void* buffer, u64 buffer_size);
const void* mappings, void* buffer, u64 buffer_size);
Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,

View File

@ -20,7 +20,7 @@ struct OpusParametersEx {
/* 0x00 */ u32 sample_rate;
/* 0x04 */ u32 channel_count;
/* 0x08 */ bool use_large_frame_size;
/* 0x09 */ INSERT_PADDING_BYTES(7);
/* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7);
}; // size = 0x10
static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
@ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx {
/* 0x08 */ u32 total_stream_count;
/* 0x0C */ u32 stereo_stream_count;
/* 0x10 */ bool use_large_frame_size;
/* 0x11 */ INSERT_PADDING_BYTES(7);
/* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7);
/* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
}; // size = 0x118
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,

View File

@ -36,8 +36,7 @@ AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id
: output_sink{system.AudioCore().GetOutputSink()},
applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
const size_t max_count) const {
u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const {
std::span<const AudioDeviceName> names{};
if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
@ -46,19 +45,18 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
names = device_names;
}
const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))};
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))};
for (u32 i = 0; i < out_count; i++) {
out_buffer.push_back(names[i]);
out_buffer[i] = names[i];
}
return out_count;
}
u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer,
const size_t max_count) const {
const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const {
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))};
for (u32 i = 0; i < out_count; i++) {
out_buffer.push_back(output_device_names[i]);
out_buffer[i] = output_device_names[i];
}
return out_count;
}

View File

@ -36,20 +36,18 @@ public:
* Get a list of the available output devices.
*
* @param out_buffer - Output buffer to write the available device names.
* @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written.
*/
u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const;
/**
* Get a list of the available output devices.
* Different to above somehow...
*
* @param out_buffer - Output buffer to write the available device names.
* @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written.
*/
u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const;
/**
* Set the volume of all streams in the backend sink.

View File

@ -17,9 +17,8 @@ Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* ren
Result Renderer::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory,
const u64 transfer_memory_size, const u32 process_handle,
Kernel::KProcess& process, const u64 applet_resource_user_id,
const s32 session_id) {
const u64 transfer_memory_size, Kernel::KProcess* process_handle,
const u64 applet_resource_user_id, const s32 session_id) {
if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio,
@ -30,7 +29,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
}
initialized = true;
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
applet_resource_user_id, session_id);
return ResultSuccess;

View File

@ -38,14 +38,14 @@ public:
* @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. Unused.
* @param process_handle - Process handle, also used for memory.
* @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer.
* @return Result code.
*/
Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
Kernel::KProcess* process_handle, u64 applet_resource_user_id,
s32 session_id);
/**

View File

@ -18,7 +18,7 @@
namespace AudioCore::Renderer {
InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
const u32 process_handle_, BehaviorInfo& behaviour_)
Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_)
: input{input_.data() + sizeof(UpdateDataHeader)},
input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>(

View File

@ -8,6 +8,10 @@
#include "common/common_types.h"
#include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer {
class BehaviorInfo;
class VoiceContext;
@ -39,8 +43,8 @@ class InfoUpdater {
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
public:
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle,
BehaviorInfo& behaviour);
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output,
Kernel::KProcess* process_handle, BehaviorInfo& behaviour);
/**
* Update the voice channel resources.
@ -197,7 +201,7 @@ private:
/// Expected output size, see CheckConsumedSize
u64 expected_output_size;
/// Unused
u32 process_handle;
Kernel::KProcess* process_handle;
/// Behaviour
BehaviorInfo& behaviour;
};

View File

@ -8,11 +8,11 @@
namespace AudioCore::Renderer {
PoolMapper::PoolMapper(u32 process_handle_, bool force_map_)
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_)
: process_handle{process_handle_}, force_map{force_map_} {}
PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_,
bool force_map_)
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_,
u32 pool_count_, bool force_map_)
: process_handle{process_handle_}, pool_infos{pool_infos_.data()},
pool_count{pool_count_}, force_map{force_map_} {}
@ -106,15 +106,17 @@ bool PoolMapper::IsForceMapEnabled() const {
return force_map;
}
u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
switch (pool->GetLocation()) {
case MemoryPoolInfo::Location::CPU:
return process_handle;
case MemoryPoolInfo::Location::DSP:
return Kernel::Svc::CurrentProcess;
// return Kernel::Svc::CurrentProcess;
return nullptr;
}
LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
return Kernel::Svc::CurrentProcess;
// return Kernel::Svc::CurrentProcess;
return nullptr;
}
bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr,
@ -147,14 +149,14 @@ bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const
}
bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
[[maybe_unused]] u32 handle{0};
[[maybe_unused]] Kernel::KProcess* handle{};
switch (pool.GetLocation()) {
case MemoryPoolInfo::Location::CPU:
handle = process_handle;
break;
case MemoryPoolInfo::Location::DSP:
handle = Kernel::Svc::CurrentProcess;
// handle = Kernel::Svc::CurrentProcess;
break;
}
// nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);

View File

@ -10,6 +10,10 @@
#include "common/common_types.h"
#include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer {
class AddressInfo;
@ -18,9 +22,9 @@ class AddressInfo;
*/
class PoolMapper {
public:
explicit PoolMapper(u32 process_handle, bool force_map);
explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count,
bool force_map);
explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map);
explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos,
u32 pool_count, bool force_map);
/**
* Clear the usage state for all given pools.
@ -98,7 +102,7 @@ public:
* @return CurrentProcessHandle if location == DSP,
* the PoolMapper's process_handle if location == CPU
*/
u32 GetProcessHandle(const MemoryPoolInfo* pool) const;
Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const;
/**
* Map the given region with the given handle. This is a no-op.
@ -167,7 +171,7 @@ public:
private:
/// Process handle for this mapper, used when location == CPU
u32 process_handle;
Kernel::KProcess* process_handle{};
/// List of memory pools assigned to this mapper
MemoryPoolInfo* pool_infos{};
/// The number of pools

View File

@ -102,8 +102,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_)
Result System::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle_, Kernel::KProcess& process_,
u64 applet_resource_user_id_, s32 session_id_) {
Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
s32 session_id_) {
if (!CheckValidRevision(params.revision)) {
return Service::Audio::ResultInvalidRevision;
}
@ -119,7 +119,6 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
behavior.SetUserLibRevision(params.revision);
process_handle = process_handle_;
process = &process_;
applet_resource_user_id = applet_resource_user_id_;
session_id = session_id_;
@ -132,7 +131,8 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
render_device = params.rendering_device;
execution_mode = params.execution_mode;
process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size);
process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
transfer_memory_size);
// Note: We're not actually using the transfer memory because it's a pain to code for.
// Allocate the memory normally instead and hope the game doesn't try to read anything back
@ -616,7 +616,7 @@ void System::SendCommandToDsp() {
static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
(static_cast<f32>(render_time_limit_percent) / 100.0f))};
audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
applet_resource_user_id, process,
applet_resource_user_id, process_handle,
reset_command_buffers);
reset_command_buffers = false;
command_buffer_size = command_size;

View File

@ -74,14 +74,14 @@ public:
* @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. Unused.
* @param process_handle - Process handle, also used for memory.
* @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer.
* @return Result code.
*/
Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
Kernel::KProcess* process_handle, u64 applet_resource_user_id,
s32 session_id);
/**
@ -278,9 +278,7 @@ private:
/// Does what locks do
std::mutex lock{};
/// Process this audio render is operating within, used for memory reads/writes.
Kernel::KProcess* process{};
/// Handle for the process for this system, unused
u32 process_handle{};
Kernel::KProcess* process_handle{};
/// Applet resource id for this system, unused
u64 applet_resource_user_id{};
/// Controls performance input and output

View File

@ -384,6 +384,12 @@ struct Values {
AstcRecompression::Bc3,
"astc_recompression",
Category::RendererAdvanced};
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
VramUsageMode::Conservative,
VramUsageMode::Conservative,
VramUsageMode::Aggressive,
"vram_usage_mode",
Category::RendererAdvanced};
SwitchableSetting<bool> async_presentation{linkage,
#ifdef ANDROID
true,

View File

@ -122,6 +122,8 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL, Vulkan, Null);
ENUM(ShaderBackend, Glsl, Glasm, SpirV);

View File

@ -38,6 +38,10 @@ std::string StringFromBuffer(std::span<const u8> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
std::string StringFromBuffer(std::span<const char> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
// Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string& str) {
const std::size_t s = str.find_first_not_of(" \t\r\n");

View File

@ -19,6 +19,7 @@ namespace Common {
[[nodiscard]] std::string ToUpper(std::string str);
[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
[[nodiscard]] std::string StringFromBuffer(std::span<const char> data);
[[nodiscard]] std::string StripSpaces(const std::string& s);
[[nodiscard]] std::string StripQuotes(const std::string& s);

View File

@ -58,9 +58,14 @@ add_library(core STATIC
file_sys/fs_operate_range.h
file_sys/fs_path.h
file_sys/fs_path_utility.h
file_sys/fs_save_data_types.h
file_sys/fs_string_util.h
file_sys/fsa/fs_i_directory.h
file_sys/fsa/fs_i_file.h
file_sys/fsa/fs_i_filesystem.h
file_sys/fsmitm_romfsbuild.cpp
file_sys/fsmitm_romfsbuild.h
file_sys/fssrv/fssrv_sf_path.h
file_sys/fssystem/fs_i_storage.h
file_sys/fssystem/fs_types.h
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@ -489,23 +494,33 @@ add_library(core STATIC
hle/service/apm/apm_controller.h
hle/service/apm/apm_interface.cpp
hle/service/apm/apm_interface.h
hle/service/audio/audin_u.cpp
hle/service/audio/audin_u.h
hle/service/audio/audio.cpp
hle/service/audio/audio.h
hle/service/audio/audio_controller.cpp
hle/service/audio/audio_controller.h
hle/service/audio/audout_u.cpp
hle/service/audio/audout_u.h
hle/service/audio/audrec_a.cpp
hle/service/audio/audrec_a.h
hle/service/audio/audrec_u.cpp
hle/service/audio/audrec_u.h
hle/service/audio/audren_u.cpp
hle/service/audio/audren_u.h
hle/service/audio/audio_device.cpp
hle/service/audio/audio_device.h
hle/service/audio/audio_in_manager.cpp
hle/service/audio/audio_in_manager.h
hle/service/audio/audio_in.cpp
hle/service/audio/audio_in.h
hle/service/audio/audio_out_manager.cpp
hle/service/audio/audio_out_manager.h
hle/service/audio/audio_out.cpp
hle/service/audio/audio_out.h
hle/service/audio/audio_renderer_manager.cpp
hle/service/audio/audio_renderer_manager.h
hle/service/audio/audio_renderer.cpp
hle/service/audio/audio_renderer.h
hle/service/audio/audio.cpp
hle/service/audio/audio.h
hle/service/audio/errors.h
hle/service/audio/hwopus.cpp
hle/service/audio/hwopus.h
hle/service/audio/final_output_recorder_manager_for_applet.cpp
hle/service/audio/final_output_recorder_manager_for_applet.h
hle/service/audio/final_output_recorder_manager.cpp
hle/service/audio/final_output_recorder_manager.h
hle/service/audio/hardware_opus_decoder_manager.cpp
hle/service/audio/hardware_opus_decoder_manager.h
hle/service/audio/hardware_opus_decoder.cpp
hle/service/audio/hardware_opus_decoder.h
hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h
hle/service/bcat/bcat.cpp
@ -595,6 +610,10 @@ add_library(core STATIC
hle/service/filesystem/fsp/fs_i_file.h
hle/service/filesystem/fsp/fs_i_filesystem.cpp
hle/service/filesystem/fsp/fs_i_filesystem.h
hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
hle/service/filesystem/fsp/fs_i_storage.cpp
hle/service/filesystem/fsp/fs_i_storage.h
hle/service/filesystem/fsp/fsp_ldr.cpp
@ -603,7 +622,7 @@ add_library(core STATIC
hle/service/filesystem/fsp/fsp_pr.h
hle/service/filesystem/fsp/fsp_srv.cpp
hle/service/filesystem/fsp/fsp_srv.h
hle/service/filesystem/fsp/fsp_util.h
hle/service/filesystem/fsp/fsp_types.h
hle/service/filesystem/romfs_controller.cpp
hle/service/filesystem/romfs_controller.h
hle/service/filesystem/save_data_controller.cpp
@ -860,8 +879,20 @@ add_library(core STATIC
hle/service/nvnflinger/ui/graphic_buffer.cpp
hle/service/nvnflinger/ui/graphic_buffer.h
hle/service/nvnflinger/window.h
hle/service/olsc/daemon_controller.cpp
hle/service/olsc/daemon_controller.h
hle/service/olsc/native_handle_holder.cpp
hle/service/olsc/native_handle_holder.h
hle/service/olsc/olsc_service_for_application.cpp
hle/service/olsc/olsc_service_for_application.h
hle/service/olsc/olsc_service_for_system_service.cpp
hle/service/olsc/olsc_service_for_system_service.h
hle/service/olsc/olsc.cpp
hle/service/olsc/olsc.h
hle/service/olsc/remote_storage_controller.cpp
hle/service/olsc/remote_storage_controller.h
hle/service/olsc/transfer_task_list_controller.cpp
hle/service/olsc/transfer_task_list_controller.h
hle/service/omm/omm.cpp
hle/service/omm/omm.h
hle/service/omm/operation_mode_manager.cpp
@ -881,16 +912,35 @@ add_library(core STATIC
hle/service/os/mutex.h
hle/service/pcie/pcie.cpp
hle/service/pcie/pcie.h
hle/service/pctl/parental_control_service_factory.cpp
hle/service/pctl/parental_control_service_factory.h
hle/service/pctl/parental_control_service.cpp
hle/service/pctl/parental_control_service.h
hle/service/pctl/pctl.cpp
hle/service/pctl/pctl.h
hle/service/pctl/pctl_module.cpp
hle/service/pctl/pctl_module.h
hle/service/pctl/pctl_results.h
hle/service/pctl/pctl_types.h
hle/service/pcv/pcv.cpp
hle/service/pcv/pcv.h
hle/service/pm/pm.cpp
hle/service/pm/pm.h
hle/service/prepo/prepo.cpp
hle/service/prepo/prepo.h
hle/service/psc/ovln/ovln_types.h
hle/service/psc/ovln/receiver_service.cpp
hle/service/psc/ovln/receiver_service.h
hle/service/psc/ovln/receiver.cpp
hle/service/psc/ovln/receiver.h
hle/service/psc/ovln/sender_service.cpp
hle/service/psc/ovln/sender_service.h
hle/service/psc/ovln/sender.cpp
hle/service/psc/ovln/sender.h
hle/service/psc/pm_control.cpp
hle/service/psc/pm_control.h
hle/service/psc/pm_module.cpp
hle/service/psc/pm_module.h
hle/service/psc/pm_service.cpp
hle/service/psc/pm_service.h
hle/service/psc/psc.cpp
hle/service/psc/psc.h
hle/service/psc/time/alarms.cpp

View File

@ -43,6 +43,8 @@ public:
DeviceMemoryManager(const DeviceMemory& device_memory);
~DeviceMemoryManager();
static constexpr bool HAS_FLUSH_INVALIDATION = true;
void BindInterface(DeviceInterface* device_inter);
DAddr Allocate(size_t size);

View File

@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
auto* memory_device_inter = registered_processes[asid.id];
const auto release_pending = [&] {
if (uncache_bytes > 0) {
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false);
if (memory_device_inter != nullptr) {
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false);
}
uncache_bytes = 0;
}
if (cache_bytes > 0) {
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
cache_bytes, true);
if (memory_device_inter != nullptr) {
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
cache_bytes, true);
}
cache_bytes = 0;
}
};

View File

@ -23,6 +23,8 @@ enum class OpenDirectoryMode : u64 {
File = (1 << 1),
All = (Directory | File),
NotRequireFileSize = (1ULL << 31),
};
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
@ -36,4 +38,29 @@ enum class CreateOption : u8 {
BigFile = (1 << 0),
};
struct FileSystemAttribute {
u8 dir_entry_name_length_max_defined;
u8 file_entry_name_length_max_defined;
u8 dir_path_name_length_max_defined;
u8 file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x5);
u8 utf16_dir_entry_name_length_max_defined;
u8 utf16_file_entry_name_length_max_defined;
u8 utf16_dir_path_name_length_max_defined;
u8 utf16_file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x18);
s32 dir_entry_name_length_max;
s32 file_entry_name_length_max;
s32 dir_path_name_length_max;
s32 file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x5);
s32 utf16_dir_entry_name_length_max;
s32 utf16_file_entry_name_length_max;
s32 utf16_dir_path_name_length_max;
s32 utf16_file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x18);
INSERT_PADDING_WORDS_NOINIT(0x1);
};
static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
} // namespace FileSys

View File

@ -10,7 +10,7 @@ namespace FileSys {
constexpr size_t RequiredAlignment = alignof(u64);
void* AllocateUnsafe(size_t size) {
inline void* AllocateUnsafe(size_t size) {
// Allocate
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {
return ptr;
}
void DeallocateUnsafe(void* ptr, size_t size) {
inline void DeallocateUnsafe(void* ptr, size_t size) {
// Deallocate the pointer
::operator delete(ptr, std::align_val_t{RequiredAlignment});
}
void* Allocate(size_t size) {
inline void* Allocate(size_t size) {
return AllocateUnsafe(size);
}
void Deallocate(void* ptr, size_t size) {
inline void Deallocate(void* ptr, size_t size) {
// If the pointer is non-null, deallocate it
if (ptr != nullptr) {
DeallocateUnsafe(ptr, size);

View File

@ -381,7 +381,7 @@ public:
// Check that it's possible for us to remove a child
auto* p = m_write_buffer.Get();
s32 len = std::strlen(p);
s32 len = static_cast<s32>(std::strlen(p));
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
// Handle a trailing separator

View File

@ -426,9 +426,10 @@ public:
R_SUCCEED();
}
static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size,
bool is_windows_path, bool is_drive_relative_path,
bool allow_all_characters = false) {
static constexpr Result Normalize(char* dst, size_t* out_len, const char* path,
size_t max_out_size, bool is_windows_path,
bool is_drive_relative_path,
bool allow_all_characters = false) {
// Use StringTraits names for remainder of scope
using namespace StringTraits;

View File

@ -0,0 +1,175 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <fmt/format.h>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace FileSys {
using SaveDataId = u64;
using SystemSaveDataId = u64;
using SystemBcatSaveDataId = SystemSaveDataId;
using ProgramId = u64;
enum class SaveDataSpaceId : u8 {
System = 0,
User = 1,
SdSystem = 2,
Temporary = 3,
SdUser = 4,
ProperSystem = 100,
SafeMode = 101,
};
enum class SaveDataType : u8 {
System = 0,
Account = 1,
Bcat = 2,
Device = 3,
Temporary = 4,
Cache = 5,
SystemBcat = 6,
};
enum class SaveDataRank : u8 {
Primary = 0,
Secondary = 1,
};
struct SaveDataSize {
u64 normal;
u64 journal;
};
static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size.");
using UserId = u128;
static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable.");
static_assert(sizeof(UserId) == 0x10, "UserId has invalid size.");
constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
constexpr inline UserId InvalidUserId = {};
enum class SaveDataFlags : u32 {
None = (0 << 0),
KeepAfterResettingSystemSaveData = (1 << 0),
KeepAfterRefurbishment = (1 << 1),
KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
NeedsSecureDelete = (1 << 3),
};
enum class SaveDataMetaType : u8 {
None = 0,
Thumbnail = 1,
ExtensionContext = 2,
};
struct SaveDataMetaInfo {
u32 size;
SaveDataMetaType type;
INSERT_PADDING_BYTES(0xB);
};
static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>,
"Data type must be trivially copyable.");
static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size.");
struct SaveDataCreationInfo {
s64 size;
s64 journal_size;
s64 block_size;
u64 owner_id;
u32 flags;
SaveDataSpaceId space_id;
bool pseudo;
INSERT_PADDING_BYTES(0x1A);
};
static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>,
"Data type must be trivially copyable.");
static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size.");
struct SaveDataAttribute {
ProgramId program_id;
UserId user_id;
SystemSaveDataId system_save_data_id;
SaveDataType type;
SaveDataRank rank;
u16 index;
INSERT_PADDING_BYTES(0x1C);
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id, u16 index,
SaveDataRank rank) {
return {
.program_id = program_id,
.user_id = user_id,
.system_save_data_id = system_save_data_id,
.type = type,
.rank = rank,
.index = index,
};
}
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id, u16 index) {
return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
}
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id) {
return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
}
std::string DebugInfo() const {
return fmt::format(
"[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
"rank={}, index={}]",
program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type),
static_cast<u8>(rank), index);
}
};
static_assert(sizeof(SaveDataAttribute) == 0x40);
static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
}
constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank,
lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id,
rhs.type, rhs.rank, rhs.index);
}
constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return !(lhs == rhs);
}
struct SaveDataExtraData {
SaveDataAttribute attr;
u64 owner_id;
s64 timestamp;
u32 flags;
INSERT_PADDING_BYTES(4);
s64 available_size;
s64 journal_size;
s64 commit_id;
INSERT_PADDING_BYTES(0x190);
};
static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size.");
static_assert(std::is_trivially_copyable_v<SaveDataExtraData>,
"Data type must be trivially copyable.");
struct HashSalt {
static constexpr size_t Size = 32;
std::array<u8, Size> value;
};
static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
static_assert(sizeof(HashSalt) == HashSalt::Size);
} // namespace FileSys

View File

@ -19,6 +19,11 @@ constexpr int Strlen(const T* str) {
return length;
}
template <typename T>
constexpr int Strnlen(const T* str, std::size_t count) {
return Strnlen(str, static_cast<int>(count));
}
template <typename T>
constexpr int Strnlen(const T* str, int count) {
ASSERT(str != nullptr);
@ -32,6 +37,11 @@ constexpr int Strnlen(const T* str, int count) {
return length;
}
template <typename T>
constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
return Strncmp(lhs, rhs, static_cast<int>(count));
}
template <typename T>
constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
ASSERT(lhs != nullptr);
@ -51,6 +61,11 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
return l - r;
}
template <typename T>
static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
return Strlcpy<T>(dst, src, static_cast<int>(count));
}
template <typename T>
static constexpr int Strlcpy(T* dst, const T* src, int count) {
ASSERT(dst != nullptr);

View File

@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_directory.h"
#include "core/file_sys/fs_file.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"
namespace FileSys::Fsa {
class IDirectory {
public:
explicit IDirectory(VirtualDir backend_, OpenDirectoryMode mode)
: backend(std::move(backend_)) {
// TODO(DarkLordZach): Verify that this is the correct behavior.
// Build entry index now to save time later.
if (True(mode & OpenDirectoryMode::Directory)) {
BuildEntryIndex(backend->GetSubdirectories(), DirectoryEntryType::Directory);
}
if (True(mode & OpenDirectoryMode::File)) {
BuildEntryIndex(backend->GetFiles(), DirectoryEntryType::File);
}
}
virtual ~IDirectory() {}
Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
R_UNLESS(out_count != nullptr, ResultNullptrArgument);
if (max_entries == 0) {
*out_count = 0;
R_SUCCEED();
}
R_UNLESS(out_entries != nullptr, ResultNullptrArgument);
R_UNLESS(max_entries > 0, ResultInvalidArgument);
R_RETURN(this->DoRead(out_count, out_entries, max_entries));
}
Result GetEntryCount(s64* out) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetEntryCount(out));
}
private:
Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
const u64 actual_entries =
std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index);
const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
next_entry_index += actual_entries;
*out_count = actual_entries;
std::memcpy(out_entries, begin, range_size);
R_SUCCEED();
}
Result DoGetEntryCount(s64* out) {
*out = entries.size() - next_entry_index;
R_SUCCEED();
}
// TODO: Remove this when VFS is gone
template <typename T>
void BuildEntryIndex(const std::vector<T>& new_data, DirectoryEntryType type) {
entries.reserve(entries.size() + new_data.size());
for (const auto& new_entry : new_data) {
auto name = new_entry->GetName();
if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) {
continue;
}
entries.emplace_back(name, static_cast<s8>(type),
type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize());
}
}
VirtualDir backend;
std::vector<DirectoryEntry> entries;
u64 next_entry_index = 0;
};
} // namespace FileSys::Fsa

View File

@ -0,0 +1,167 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/overflow.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_file.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/fs_operate_range.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/result.h"
namespace FileSys::Fsa {
class IFile {
public:
explicit IFile(VirtualFile backend_) : backend(std::move(backend_)) {}
virtual ~IFile() {}
Result Read(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
// Check that we have an output pointer
R_UNLESS(out != nullptr, ResultNullptrArgument);
// If we have nothing to read, just succeed
if (size == 0) {
*out = 0;
R_SUCCEED();
}
// Check that the read is valid
R_UNLESS(buffer != nullptr, ResultNullptrArgument);
R_UNLESS(offset >= 0, ResultOutOfRange);
R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
// Do the read
R_RETURN(this->DoRead(out, offset, buffer, size, option));
}
Result Read(size_t* out, s64 offset, void* buffer, size_t size) {
R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None));
}
Result GetSize(s64* out) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetSize(out));
}
Result Flush() {
R_RETURN(this->DoFlush());
}
Result Write(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
// Handle the zero-size case
if (size == 0) {
if (option.HasFlushFlag()) {
R_TRY(this->Flush());
}
R_SUCCEED();
}
// Check the write is valid
R_UNLESS(buffer != nullptr, ResultNullptrArgument);
R_UNLESS(offset >= 0, ResultOutOfRange);
R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
R_RETURN(this->DoWrite(offset, buffer, size, option));
}
Result SetSize(s64 size) {
R_UNLESS(size >= 0, ResultOutOfRange);
R_RETURN(this->DoSetSize(size));
}
Result OperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
const void* src, size_t src_size) {
R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size));
}
Result OperateRange(OperationId op_id, s64 offset, s64 size) {
R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0));
}
protected:
Result DryRead(size_t* out, s64 offset, size_t size, const ReadOption& option,
OpenMode open_mode) {
// Check that we can read
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Read) != 0, ResultReadNotPermitted);
// Get the file size, and validate our offset
s64 file_size = 0;
R_TRY(this->DoGetSize(std::addressof(file_size)));
R_UNLESS(offset <= file_size, ResultOutOfRange);
*out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
R_SUCCEED();
}
Result DrySetSize(s64 size, OpenMode open_mode) {
// Check that we can write
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
R_SUCCEED();
}
Result DryWrite(bool* out_append, s64 offset, size_t size, const WriteOption& option,
OpenMode open_mode) {
// Check that we can write
R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
// Get the file size
s64 file_size = 0;
R_TRY(this->DoGetSize(&file_size));
// Determine if we need to append
*out_append = false;
if (file_size < offset + static_cast<s64>(size)) {
R_UNLESS(static_cast<u32>(open_mode & OpenMode::AllowAppend) != 0,
ResultFileExtensionWithoutOpenModeAllowAppend);
*out_append = true;
}
R_SUCCEED();
}
private:
Result DoRead(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
const auto read_size = backend->Read(static_cast<u8*>(buffer), size, offset);
*out = read_size;
R_SUCCEED();
}
Result DoGetSize(s64* out) {
*out = backend->GetSize();
R_SUCCEED();
}
Result DoFlush() {
// Exists for SDK compatibiltity -- No need to flush file.
R_SUCCEED();
}
Result DoWrite(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
const std::size_t written = backend->Write(static_cast<const u8*>(buffer), size, offset);
ASSERT_MSG(written == size,
"Could not write all bytes to file (requested={:016X}, actual={:016X}).", size,
written);
R_SUCCEED();
}
Result DoSetSize(s64 size) {
backend->Resize(size);
R_SUCCEED();
}
Result DoOperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
const void* src, size_t src_size) {
R_THROW(ResultNotImplemented);
}
VirtualFile backend;
};
} // namespace FileSys::Fsa

View File

@ -0,0 +1,206 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/fs_path.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/result.h"
#include "core/hle/service/filesystem/filesystem.h"
namespace FileSys::Fsa {
class IFile;
class IDirectory;
enum class QueryId : u32 {
SetConcatenationFileAttribute = 0,
UpdateMac = 1,
IsSignedSystemPartitionOnSdCardValid = 2,
QueryUnpreparedFileInformation = 3,
};
class IFileSystem {
public:
explicit IFileSystem(VirtualDir backend_) : backend{std::move(backend_)} {}
virtual ~IFileSystem() {}
Result CreateFile(const Path& path, s64 size, CreateOption option) {
R_UNLESS(size >= 0, ResultOutOfRange);
R_RETURN(this->DoCreateFile(path, size, static_cast<int>(option)));
}
Result CreateFile(const Path& path, s64 size) {
R_RETURN(this->CreateFile(path, size, CreateOption::None));
}
Result DeleteFile(const Path& path) {
R_RETURN(this->DoDeleteFile(path));
}
Result CreateDirectory(const Path& path) {
R_RETURN(this->DoCreateDirectory(path));
}
Result DeleteDirectory(const Path& path) {
R_RETURN(this->DoDeleteDirectory(path));
}
Result DeleteDirectoryRecursively(const Path& path) {
R_RETURN(this->DoDeleteDirectoryRecursively(path));
}
Result RenameFile(const Path& old_path, const Path& new_path) {
R_RETURN(this->DoRenameFile(old_path, new_path));
}
Result RenameDirectory(const Path& old_path, const Path& new_path) {
R_RETURN(this->DoRenameDirectory(old_path, new_path));
}
Result GetEntryType(DirectoryEntryType* out, const Path& path) {
R_RETURN(this->DoGetEntryType(out, path));
}
Result OpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
R_UNLESS(out_file != nullptr, ResultNullptrArgument);
R_UNLESS(static_cast<u32>(mode & OpenMode::ReadWrite) != 0, ResultInvalidOpenMode);
R_UNLESS(static_cast<u32>(mode & ~OpenMode::All) == 0, ResultInvalidOpenMode);
R_RETURN(this->DoOpenFile(out_file, path, mode));
}
Result OpenDirectory(VirtualDir* out_dir, const Path& path, OpenDirectoryMode mode) {
R_UNLESS(out_dir != nullptr, ResultNullptrArgument);
R_UNLESS(static_cast<u64>(mode & OpenDirectoryMode::All) != 0, ResultInvalidOpenMode);
R_UNLESS(static_cast<u64>(
mode & ~(OpenDirectoryMode::All | OpenDirectoryMode::NotRequireFileSize)) == 0,
ResultInvalidOpenMode);
R_RETURN(this->DoOpenDirectory(out_dir, path, mode));
}
Result Commit() {
R_RETURN(this->DoCommit());
}
Result GetFreeSpaceSize(s64* out, const Path& path) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetFreeSpaceSize(out, path));
}
Result GetTotalSpaceSize(s64* out, const Path& path) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetTotalSpaceSize(out, path));
}
Result CleanDirectoryRecursively(const Path& path) {
R_RETURN(this->DoCleanDirectoryRecursively(path));
}
Result GetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
R_UNLESS(out != nullptr, ResultNullptrArgument);
R_RETURN(this->DoGetFileTimeStampRaw(out, path));
}
Result QueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
const Path& path) {
R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path));
}
// These aren't accessible as commands
Result CommitProvisionally(s64 counter) {
R_RETURN(this->DoCommitProvisionally(counter));
}
Result Rollback() {
R_RETURN(this->DoRollback());
}
Result Flush() {
R_RETURN(this->DoFlush());
}
private:
Result DoCreateFile(const Path& path, s64 size, int flags) {
R_RETURN(backend.CreateFile(path.GetString(), size));
}
Result DoDeleteFile(const Path& path) {
R_RETURN(backend.DeleteFile(path.GetString()));
}
Result DoCreateDirectory(const Path& path) {
R_RETURN(backend.CreateDirectory(path.GetString()));
}
Result DoDeleteDirectory(const Path& path) {
R_RETURN(backend.DeleteDirectory(path.GetString()));
}
Result DoDeleteDirectoryRecursively(const Path& path) {
R_RETURN(backend.DeleteDirectoryRecursively(path.GetString()));
}
Result DoRenameFile(const Path& old_path, const Path& new_path) {
R_RETURN(backend.RenameFile(old_path.GetString(), new_path.GetString()));
}
Result DoRenameDirectory(const Path& old_path, const Path& new_path) {
R_RETURN(backend.RenameDirectory(old_path.GetString(), new_path.GetString()));
}
Result DoGetEntryType(DirectoryEntryType* out, const Path& path) {
R_RETURN(backend.GetEntryType(out, path.GetString()));
}
Result DoOpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
R_RETURN(backend.OpenFile(out_file, path.GetString(), mode));
}
Result DoOpenDirectory(VirtualDir* out_directory, const Path& path, OpenDirectoryMode mode) {
R_RETURN(backend.OpenDirectory(out_directory, path.GetString()));
}
Result DoCommit() {
R_THROW(ResultNotImplemented);
}
Result DoGetFreeSpaceSize(s64* out, const Path& path) {
R_THROW(ResultNotImplemented);
}
Result DoGetTotalSpaceSize(s64* out, const Path& path) {
R_THROW(ResultNotImplemented);
}
Result DoCleanDirectoryRecursively(const Path& path) {
R_RETURN(backend.CleanDirectoryRecursively(path.GetString()));
}
Result DoGetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
R_RETURN(backend.GetFileTimeStampRaw(out, path.GetString()));
}
Result DoQueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
const Path& path) {
R_THROW(ResultNotImplemented);
}
// These aren't accessible as commands
Result DoCommitProvisionally(s64 counter) {
R_THROW(ResultNotImplemented);
}
Result DoRollback() {
R_THROW(ResultNotImplemented);
}
Result DoFlush() {
R_THROW(ResultNotImplemented);
}
Service::FileSystem::VfsDirectoryServiceWrapper backend;
};
} // namespace FileSys::Fsa

View File

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/file_sys/fs_directory.h"
namespace FileSys::Sf {
struct Path {
char str[EntryNameLengthMax + 1];
static constexpr Path Encode(const char* p) {
Path path = {};
for (size_t i = 0; i < sizeof(path) - 1; i++) {
path.str[i] = p[i];
if (p[i] == '\x00') {
break;
}
}
return path;
}
static constexpr size_t GetPathLength(const Path& path) {
size_t len = 0;
for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
len++;
}
return len;
}
};
static_assert(std::is_trivially_copyable_v<Path>, "Path must be trivially copyable.");
using FspPath = Path;
} // namespace FileSys::Sf

View File

@ -3,6 +3,7 @@
#pragma once
#include <mutex>
#include <optional>
#include "core/crypto/aes_util.h"

View File

@ -14,48 +14,11 @@ namespace FileSys {
namespace {
void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is "
"SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
meta.zero_1);
}
if (meta.zero_2 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is "
"SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
meta.zero_2);
}
if (meta.zero_3 != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is "
"SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
meta.zero_3);
}
}
if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
"non-zero ({:016X}).",
meta.title_id);
}
if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
LOG_WARNING(Service_FS,
"Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
"non-zero ({:016X}{:016X})",
meta.user_id[1], meta.user_id[0]);
}
}
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage ||
(space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
(attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) &&
attr.title_id == 0 && attr.save_id == 0);
return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary ||
(space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User
(attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) &&
attr.program_id == 0 && attr.system_save_data_id == 0);
}
std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
@ -63,7 +26,7 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
// Only detect nand user saves.
const auto space_id_path = [space_id]() -> std::string_view {
switch (space_id) {
case SaveDataSpaceId::NandUser:
case SaveDataSpaceId::User:
return "/user/save";
default:
return "";
@ -79,9 +42,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
// Only detect account/device saves from the future location.
switch (type) {
case SaveDataType::SaveData:
case SaveDataType::Account:
return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
case SaveDataType::DeviceSaveData:
case SaveDataType::Device:
return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
default:
return "";
@ -90,13 +53,6 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
} // Anonymous namespace
std::string SaveDataAttribute::DebugInfo() const {
return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
"rank={}, index={}]",
title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
static_cast<u8>(rank), index);
}
SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
VirtualDir save_directory_)
: system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
@ -108,18 +64,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
SaveDataFactory::~SaveDataFactory() = default;
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
PrintSaveDataAttributeWarnings(meta);
const auto save_directory =
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
meta.user_id, meta.system_save_data_id);
return dir->CreateDirectoryRelative(save_directory);
}
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
const auto save_directory =
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
meta.user_id, meta.system_save_data_id);
auto out = dir->GetDirectoryRelative(save_directory);
@ -136,11 +90,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
switch (space) {
case SaveDataSpaceId::NandSystem:
case SaveDataSpaceId::System:
return "/system/";
case SaveDataSpaceId::NandUser:
case SaveDataSpaceId::User:
return "/user/";
case SaveDataSpaceId::TemporaryStorage:
case SaveDataSpaceId::Temporary:
return "/temp/";
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@ -153,7 +107,7 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
u128 user_id, u64 save_id) {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
if (type == SaveDataType::Account || type == SaveDataType::Device) {
if (title_id == 0) {
title_id = program_id;
}
@ -173,16 +127,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
std::string out = GetSaveDataSpaceIdPath(space);
switch (type) {
case SaveDataType::SystemSaveData:
case SaveDataType::System:
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
case SaveDataType::SaveData:
case SaveDataType::DeviceSaveData:
case SaveDataType::Account:
case SaveDataType::Device:
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
case SaveDataType::TemporaryStorage:
case SaveDataType::Temporary:
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
case SaveDataType::CacheStorage:
case SaveDataType::Cache:
return fmt::format("{}save/cache/{:016X}", out, title_id);
default:
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
@ -202,7 +156,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const {
const auto path =
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
@ -221,7 +175,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) const {
const auto path =
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());

View File

@ -7,6 +7,7 @@
#include <string>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/file_sys/fs_save_data_types.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"
@ -16,73 +17,6 @@ class System;
namespace FileSys {
enum class SaveDataSpaceId : u8 {
NandSystem = 0,
NandUser = 1,
SdCardSystem = 2,
TemporaryStorage = 3,
SdCardUser = 4,
ProperSystem = 100,
SafeMode = 101,
};
enum class SaveDataType : u8 {
SystemSaveData = 0,
SaveData = 1,
BcatDeliveryCacheStorage = 2,
DeviceSaveData = 3,
TemporaryStorage = 4,
CacheStorage = 5,
SystemBcat = 6,
};
enum class SaveDataRank : u8 {
Primary = 0,
Secondary = 1,
};
enum class SaveDataFlags : u32 {
None = (0 << 0),
KeepAfterResettingSystemSaveData = (1 << 0),
KeepAfterRefurbishment = (1 << 1),
KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
NeedsSecureDelete = (1 << 3),
};
struct SaveDataAttribute {
u64 title_id;
u128 user_id;
u64 save_id;
SaveDataType type;
SaveDataRank rank;
u16 index;
INSERT_PADDING_BYTES_NOINIT(4);
u64 zero_1;
u64 zero_2;
u64 zero_3;
std::string DebugInfo() const;
};
static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
struct SaveDataExtraData {
SaveDataAttribute attr;
u64 owner_id;
s64 timestamp;
SaveDataFlags flags;
INSERT_PADDING_BYTES_NOINIT(4);
s64 available_size;
s64 journal_size;
s64 commit_id;
std::array<u8, 0x190> unused;
};
static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
struct SaveDataSize {
u64 normal;
u64 journal;
};
constexpr const char* GetSaveDataSizeFileName() {
return ".yuzu_save_size";
}

View File

@ -44,15 +44,32 @@ public:
GuestMemory() = delete;
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: m_memory{memory}, m_addr{addr}, m_size{size} {
: m_memory{&memory}, m_addr{addr}, m_size{size} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (FLAGS & GuestMemoryFlags::Read) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
m_span_valid = true;
m_is_data_copy = true;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
m_span_valid = true;
m_is_data_copy = true;
}
}
} else if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup);
}
}
~GuestMemory() = default;
GuestMemory(GuestMemory&& rhs) = default;
GuestMemory& operator=(GuestMemory&& rhs) = default;
T* data() noexcept {
return m_data_span.data();
}
@ -109,8 +126,8 @@ public:
}
if (this->TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.FlushRegion(m_addr, this->size_bytes());
if constexpr (FLAGS & GuestMemoryFlags::Safe && M::HAS_FLUSH_INVALIDATION) {
m_memory->FlushRegion(m_addr, this->size_bytes());
}
} else {
if (backup) {
@ -123,9 +140,9 @@ public:
m_is_data_copy = true;
m_span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
m_memory->ReadBlock(m_addr, this->data(), this->size_bytes());
} else {
m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
m_memory->ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
}
}
return m_data_span;
@ -133,18 +150,19 @@ public:
void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlock(m_addr, write_data.data(), this->size_bytes());
} else {
m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
}
}
bool TrySetSpan() noexcept {
if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
if (u8* ptr = m_memory->GetSpan(m_addr, this->size_bytes()); ptr) {
m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
m_span_valid = true;
m_is_data_copy = false;
return true;
}
return false;
@ -159,7 +177,7 @@ protected:
return m_addr_changed;
}
M& m_memory;
M* m_memory;
u64 m_addr{};
size_t m_size{};
std::span<T> m_data_span{};
@ -175,17 +193,7 @@ public:
GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
this->m_data_span = *backup;
this->m_span_valid = true;
this->m_is_data_copy = true;
}
}
}
}
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {}
~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
@ -196,15 +204,17 @@ public:
if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlockCached(this->m_addr, this->data(),
this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlockUnsafe(this->m_addr, this->data(),
this->size_bytes());
}
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
(FLAGS & GuestMemoryFlags::Cached)) {
this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
this->m_memory->InvalidateRegion(this->m_addr, this->size_bytes());
}
}
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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));
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -3,82 +3,34 @@
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/savedata_factory.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::FileSystem {
template <typename T>
static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries,
const std::vector<T>& new_data, FileSys::DirectoryEntryType type) {
entries.reserve(entries.size() + new_data.size());
for (const auto& new_entry : new_data) {
auto name = new_entry->GetName();
if (type == FileSys::DirectoryEntryType::File &&
name == FileSys::GetSaveDataSizeFileName()) {
continue;
}
entries.emplace_back(name, static_cast<s8>(type),
type == FileSys::DirectoryEntryType::Directory ? 0
: new_entry->GetSize());
}
}
IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
FileSys::OpenDirectoryMode mode)
: ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
: ServiceFramework{system_, "IDirectory"},
backend(std::make_unique<FileSys::Fsa::IDirectory>(directory_, mode)) {
static const FunctionInfo functions[] = {
{0, &IDirectory::Read, "Read"},
{1, &IDirectory::GetEntryCount, "GetEntryCount"},
{0, D<&IDirectory::Read>, "Read"},
{1, D<&IDirectory::GetEntryCount>, "GetEntryCount"},
};
RegisterHandlers(functions);
// TODO(DarkLordZach): Verify that this is the correct behavior.
// Build entry index now to save time later.
if (True(mode & FileSys::OpenDirectoryMode::Directory)) {
BuildEntryIndex(entries, backend->GetSubdirectories(),
FileSys::DirectoryEntryType::Directory);
}
if (True(mode & FileSys::OpenDirectoryMode::File)) {
BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File);
}
}
void IDirectory::Read(HLERequestContext& ctx) {
Result IDirectory::Read(
Out<s64> out_count,
const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries) {
LOG_DEBUG(Service_FS, "called.");
// Calculate how many entries we can fit in the output buffer
const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>();
// Cap at total number of entries.
const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
// Determine data start and end
const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
const auto* end = reinterpret_cast<u8*>(entries.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(actual_entries);
R_RETURN(backend->Read(out_count, out_entries.data(), out_entries.size()));
}
void IDirectory::GetEntryCount(HLERequestContext& ctx) {
Result IDirectory::GetEntryCount(Out<s64> out_count) {
LOG_DEBUG(Service_FS, "called");
u64 count = entries.size() - next_entry_index;
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(count);
R_RETURN(backend->GetEntryCount(out_count));
}
} // namespace Service::FileSystem

View File

@ -3,7 +3,9 @@
#pragma once
#include "core/file_sys/fsa/fs_i_directory.h"
#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"
@ -15,16 +17,15 @@ namespace Service::FileSystem {
class IDirectory final : public ServiceFramework<IDirectory> {
public:
explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
explicit IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
FileSys::OpenDirectoryMode mode);
private:
FileSys::VirtualDir backend;
std::vector<FileSys::DirectoryEntry> entries;
u64 next_entry_index = 0;
std::unique_ptr<FileSys::Fsa::IDirectory> backend;
void Read(HLERequestContext& ctx);
void GetEntryCount(HLERequestContext& ctx);
Result Read(Out<s64> out_count,
const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries);
Result GetEntryCount(Out<s64> out_count);
};
} // namespace Service::FileSystem

View File

@ -2,126 +2,64 @@
// 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_file.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::FileSystem {
IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_)
: ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
IFile::IFile(Core::System& system_, FileSys::VirtualFile file_)
: ServiceFramework{system_, "IFile"}, backend{std::make_unique<FileSys::Fsa::IFile>(file_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IFile::Read, "Read"},
{1, &IFile::Write, "Write"},
{2, &IFile::Flush, "Flush"},
{3, &IFile::SetSize, "SetSize"},
{4, &IFile::GetSize, "GetSize"},
{0, D<&IFile::Read>, "Read"},
{1, D<&IFile::Write>, "Write"},
{2, D<&IFile::Flush>, "Flush"},
{3, D<&IFile::SetSize>, "SetSize"},
{4, D<&IFile::GetSize>, "GetSize"},
{5, nullptr, "OperateRange"},
{6, nullptr, "OperateRangeWithBuffer"},
};
// clang-format on
RegisterHandlers(functions);
}
void IFile::Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 option = rp.Pop<u64>();
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, 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;
}
Result IFile::Read(
FileSys::ReadOption option, Out<s64> out_size, s64 offset,
const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer,
s64 size) {
LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
size);
// Read the data from the Storage backend
std::vector<u8> output = backend->ReadBytes(length, offset);
// Write the data to memory
ctx.WriteBuffer(output);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(static_cast<u64>(output.size()));
R_RETURN(
backend->Read(reinterpret_cast<size_t*>(out_size.Get()), offset, out_buffer.data(), size));
}
void IFile::Write(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 option = rp.Pop<u64>();
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
Result IFile::Write(
const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
FileSys::WriteOption option, s64 offset, s64 size) {
LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
size);
LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, 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;
}
const auto data = ctx.ReadBuffer();
ASSERT_MSG(static_cast<s64>(data.size()) <= length,
"Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
length, data.size());
// Write the data to the Storage backend
const auto write_size =
static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
const std::size_t written = backend->Write(data.data(), write_size, offset);
ASSERT_MSG(static_cast<s64>(written) == length,
"Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
written);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_RETURN(backend->Write(offset, buffer.data(), size, option));
}
void IFile::Flush(HLERequestContext& ctx) {
Result IFile::Flush() {
LOG_DEBUG(Service_FS, "called");
// Exists for SDK compatibiltity -- No need to flush file.
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_RETURN(backend->Flush());
}
void IFile::SetSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 size = rp.Pop<u64>();
Result IFile::SetSize(s64 size) {
LOG_DEBUG(Service_FS, "called, size={}", size);
backend->Resize(size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_RETURN(backend->SetSize(size));
}
void IFile::GetSize(HLERequestContext& ctx) {
const u64 size = backend->GetSize();
LOG_DEBUG(Service_FS, "called, size={}", size);
Result IFile::GetSize(Out<s64> out_size) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(size);
R_RETURN(backend->GetSize(out_size));
}
} // namespace Service::FileSystem

View File

@ -3,6 +3,8 @@
#pragma once
#include "core/file_sys/fsa/fs_i_file.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/service.h"
@ -10,16 +12,21 @@ namespace Service::FileSystem {
class IFile final : public ServiceFramework<IFile> {
public:
explicit IFile(Core::System& system_, FileSys::VirtualFile backend_);
explicit IFile(Core::System& system_, FileSys::VirtualFile file_);
private:
FileSys::VirtualFile backend;
std::unique_ptr<FileSys::Fsa::IFile> backend;
void Read(HLERequestContext& ctx);
void Write(HLERequestContext& ctx);
void Flush(HLERequestContext& ctx);
void SetSize(HLERequestContext& ctx);
void GetSize(HLERequestContext& ctx);
Result Read(FileSys::ReadOption option, Out<s64> out_size, s64 offset,
const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure>
out_buffer,
s64 size);
Result Write(
const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
FileSys::WriteOption option, s64 offset, s64 size);
Result Flush();
Result SetSize(s64 size);
Result GetSize(Out<s64> out_size);
};
} // namespace Service::FileSystem

View File

@ -2,261 +2,172 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/string_util.h"
#include "core/file_sys/fssrv/fssrv_sf_path.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
#include "core/hle/service/filesystem/fsp/fs_i_file.h"
#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::FileSystem {
IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
: ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
size_)} {
IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_)
: ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>(
dir_)},
size_getter{std::move(size_getter_)} {
static const FunctionInfo functions[] = {
{0, &IFileSystem::CreateFile, "CreateFile"},
{1, &IFileSystem::DeleteFile, "DeleteFile"},
{2, &IFileSystem::CreateDirectory, "CreateDirectory"},
{3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
{4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
{5, &IFileSystem::RenameFile, "RenameFile"},
{0, D<&IFileSystem::CreateFile>, "CreateFile"},
{1, D<&IFileSystem::DeleteFile>, "DeleteFile"},
{2, D<&IFileSystem::CreateDirectory>, "CreateDirectory"},
{3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"},
{4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"},
{5, D<&IFileSystem::RenameFile>, "RenameFile"},
{6, nullptr, "RenameDirectory"},
{7, &IFileSystem::GetEntryType, "GetEntryType"},
{8, &IFileSystem::OpenFile, "OpenFile"},
{9, &IFileSystem::OpenDirectory, "OpenDirectory"},
{10, &IFileSystem::Commit, "Commit"},
{11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
{12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
{13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
{14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
{7, D<&IFileSystem::GetEntryType>, "GetEntryType"},
{8, D<&IFileSystem::OpenFile>, "OpenFile"},
{9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"},
{10, D<&IFileSystem::Commit>, "Commit"},
{11, D<&IFileSystem::GetFreeSpaceSize>, "GetFreeSpaceSize"},
{12, D<&IFileSystem::GetTotalSpaceSize>, "GetTotalSpaceSize"},
{13, D<&IFileSystem::CleanDirectoryRecursively>, "CleanDirectoryRecursively"},
{14, D<&IFileSystem::GetFileTimeStampRaw>, "GetFileTimeStampRaw"},
{15, nullptr, "QueryEntry"},
{16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
{16, D<&IFileSystem::GetFileSystemAttribute>, "GetFileSystemAttribute"},
};
RegisterHandlers(functions);
}
void IFileSystem::CreateFile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Result IFileSystem::CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
s32 option, s64 size) {
LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size);
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
const u64 file_mode = rp.Pop<u64>();
const u32 file_size = rp.Pop<u32>();
LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
file_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.CreateFile(name, file_size));
R_RETURN(backend->CreateFile(FileSys::Path(path->str), size));
}
void IFileSystem::DeleteFile(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. file={}", path->str);
LOG_DEBUG(Service_FS, "called. file={}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.DeleteFile(name));
R_RETURN(backend->DeleteFile(FileSys::Path(path->str)));
}
void IFileSystem::CreateDirectory(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
Result IFileSystem::CreateDirectory(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. directory={}", path->str);
LOG_DEBUG(Service_FS, "called. directory={}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.CreateDirectory(name));
R_RETURN(backend->CreateDirectory(FileSys::Path(path->str)));
}
void IFileSystem::DeleteDirectory(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
Result IFileSystem::DeleteDirectory(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. directory={}", path->str);
LOG_DEBUG(Service_FS, "called. directory={}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.DeleteDirectory(name));
R_RETURN(backend->DeleteDirectory(FileSys::Path(path->str)));
}
void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
Result IFileSystem::DeleteDirectoryRecursively(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. directory={}", path->str);
LOG_DEBUG(Service_FS, "called. directory={}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.DeleteDirectoryRecursively(name));
R_RETURN(backend->DeleteDirectoryRecursively(FileSys::Path(path->str)));
}
void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
Result IFileSystem::CleanDirectoryRecursively(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. Directory: {}", path->str);
LOG_DEBUG(Service_FS, "called. Directory: {}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.CleanDirectoryRecursively(name));
R_RETURN(backend->CleanDirectoryRecursively(FileSys::Path(path->str)));
}
void IFileSystem::RenameFile(HLERequestContext& ctx) {
const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
Result IFileSystem::RenameFile(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path) {
LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", old_path->str, new_path->str);
LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.RenameFile(src_name, dst_name));
R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));
}
void IFileSystem::OpenFile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>());
LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
Result IFileSystem::OpenFile(OutInterface<IFile> out_interface,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
u32 mode) {
LOG_DEBUG(Service_FS, "called. file={}, mode={}", path->str, mode);
FileSys::VirtualFile vfs_file{};
auto result = backend.OpenFile(&vfs_file, name, mode);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str),
static_cast<FileSys::OpenMode>(mode)));
auto file = std::make_shared<IFile>(system, vfs_file);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IFile>(std::move(file));
*out_interface = std::make_shared<IFile>(system, vfs_file);
R_SUCCEED();
}
void IFileSystem::OpenDirectory(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>();
LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
Result IFileSystem::OpenDirectory(OutInterface<IDirectory> out_interface,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
u32 mode) {
LOG_DEBUG(Service_FS, "called. directory={}, mode={}", path->str, mode);
FileSys::VirtualDir vfs_dir{};
auto result = backend.OpenDirectory(&vfs_dir, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str),
static_cast<FileSys::OpenDirectoryMode>(mode)));
auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDirectory>(std::move(directory));
*out_interface = std::make_shared<IDirectory>(system, vfs_dir,
static_cast<FileSys::OpenDirectoryMode>(mode));
R_SUCCEED();
}
void IFileSystem::GetEntryType(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
LOG_DEBUG(Service_FS, "called. file={}", name);
Result IFileSystem::GetEntryType(
Out<u32> out_type, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. file={}", path->str);
FileSys::DirectoryEntryType vfs_entry_type{};
auto result = backend.GetEntryType(&vfs_entry_type, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str)));
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(vfs_entry_type));
*out_type = static_cast<u32>(vfs_entry_type);
R_SUCCEED();
}
void IFileSystem::Commit(HLERequestContext& ctx) {
Result IFileSystem::Commit() {
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) {
Result IFileSystem::GetFreeSpaceSize(
Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(size.get_free_size());
*out_size = size_getter.get_free_size();
R_SUCCEED();
}
void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) {
Result IFileSystem::GetTotalSpaceSize(
Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(size.get_total_size());
*out_size = size_getter.get_total_size();
R_SUCCEED();
}
void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
Result IFileSystem::GetFileTimeStampRaw(
Out<FileSys::FileTimeStampRaw> out_timestamp,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", path->str);
FileSys::FileTimeStampRaw vfs_timestamp{};
auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str)));
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(vfs_timestamp);
*out_timestamp = vfs_timestamp;
R_SUCCEED();
}
void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) {
Result IFileSystem::GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute) {
LOG_WARNING(Service_FS, "(STUBBED) called");
struct FileSystemAttribute {
u8 dir_entry_name_length_max_defined;
u8 file_entry_name_length_max_defined;
u8 dir_path_name_length_max_defined;
u8 file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x5);
u8 utf16_dir_entry_name_length_max_defined;
u8 utf16_file_entry_name_length_max_defined;
u8 utf16_dir_path_name_length_max_defined;
u8 utf16_file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x18);
s32 dir_entry_name_length_max;
s32 file_entry_name_length_max;
s32 dir_path_name_length_max;
s32 file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x5);
s32 utf16_dir_entry_name_length_max;
s32 utf16_file_entry_name_length_max;
s32 utf16_dir_path_name_length_max;
s32 utf16_file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x18);
INSERT_PADDING_WORDS_NOINIT(0x1);
};
static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size");
FileSystemAttribute savedata_attribute{};
FileSys::FileSystemAttribute savedata_attribute{};
savedata_attribute.dir_entry_name_length_max_defined = true;
savedata_attribute.file_entry_name_length_max_defined = true;
savedata_attribute.dir_entry_name_length_max = 0x40;
savedata_attribute.file_entry_name_length_max = 0x40;
IPC::ResponseBuilder rb{ctx, 50};
rb.Push(ResultSuccess);
rb.PushRaw(savedata_attribute);
*out_attribute = savedata_attribute;
R_SUCCEED();
}
} // namespace Service::FileSystem

View File

@ -3,36 +3,58 @@
#pragma once
#include "common/common_funcs.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/fsa/fs_i_filesystem.h"
#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 {
struct Path;
}
namespace Service::FileSystem {
class IFile;
class IDirectory;
class IFileSystem final : public ServiceFramework<IFileSystem> {
public:
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_);
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_);
void CreateFile(HLERequestContext& ctx);
void DeleteFile(HLERequestContext& ctx);
void CreateDirectory(HLERequestContext& ctx);
void DeleteDirectory(HLERequestContext& ctx);
void DeleteDirectoryRecursively(HLERequestContext& ctx);
void CleanDirectoryRecursively(HLERequestContext& ctx);
void RenameFile(HLERequestContext& ctx);
void OpenFile(HLERequestContext& ctx);
void OpenDirectory(HLERequestContext& ctx);
void GetEntryType(HLERequestContext& ctx);
void Commit(HLERequestContext& ctx);
void GetFreeSpaceSize(HLERequestContext& ctx);
void GetTotalSpaceSize(HLERequestContext& ctx);
void GetFileTimeStampRaw(HLERequestContext& ctx);
void GetFileSystemAttribute(HLERequestContext& ctx);
Result CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, s32 option,
s64 size);
Result DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result CreateDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result DeleteDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result DeleteDirectoryRecursively(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result CleanDirectoryRecursively(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path);
Result OpenFile(OutInterface<IFile> out_interface,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode);
Result OpenDirectory(OutInterface<IDirectory> out_interface,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
u32 mode);
Result GetEntryType(Out<u32> out_type,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result Commit();
Result GetFreeSpaceSize(Out<s64> out_size,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result GetTotalSpaceSize(Out<s64> out_size,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result GetFileTimeStampRaw(Out<FileSys::FileTimeStampRaw> out_timestamp,
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
Result GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute);
private:
VfsDirectoryServiceWrapper backend;
SizeGetter size;
std::unique_ptr<FileSys::Fsa::IFileSystem> backend;
SizeGetter size_getter;
};
} // namespace Service::FileSystem

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(size);
LOG_DEBUG(Service_FS, "called, size={}", *out_size);
R_SUCCEED();
}
} // namespace Service::FileSystem

View File

@ -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

View File

@ -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);
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);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(flags);
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};
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);
const auto storage_id = rp.PopRaw<FileSys::StorageId>();
const auto title_id = rp.PopRaw<u64>();
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;
R_SUCCEED();
}
void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) {
const auto raw = ctx.ReadBufferCopy();
Result FSP_SRV::OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer) {
LOG_DEBUG(Service_FS, "called");
auto log = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(raw.data()), raw.size());
LOG_DEBUG(Service_FS, "called");
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");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushEnum(AccessLogVersion::Latest);
rb.Push(access_log_program_index);
}
void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) {
Result FSP_SRV::GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
Out<u32> out_access_log_program_index) {
LOG_DEBUG(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
*out_access_log_version = AccessLogVersion::Latest;
*out_access_log_program_index = access_log_program_index;
R_SUCCEED();
}
void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto index{rp.Pop<s32>()};
Result FSP_SRV::FlushAccessLogOnSdCard() {
LOG_DEBUG(Service_FS, "(STUBBED) called");
R_SUCCEED();
}
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});
*out_data_size = 0;
*out_journal_size = 0;
R_SUCCEED();
}
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);
}
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);
}
};
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

View File

@ -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;

View File

@ -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;

View File

@ -436,14 +436,14 @@ Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo(
Result IApplicationManagerInterface::GetApplicationRightsOnClient(
OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
Common::UUID account_id, u32 flags, u64 application_id) {
u32 flags, u64 application_id, Uid account_id) {
LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}",
flags, application_id, account_id.FormattedString());
flags, application_id, account_id.uuid.FormattedString());
if (!out_rights.empty()) {
ApplicationRightsOnClient rights{};
rights.application_id = application_id;
rights.uid = account_id;
rights.uid = account_id.uuid;
rights.flags = 0;
rights.flags2 = 0;

Some files were not shown because too many files have changed in this diff Show More