Compare commits

..

7 Commits

Author SHA1 Message Date
2c3086dbc4 Android 257 2024-02-20 00:56:46 +00:00
a0858290a7 Merge yuzu-emu#13079 2024-02-20 00:56:45 +00:00
c5922492bd Merge yuzu-emu#13075 2024-02-20 00:56:45 +00:00
96a58ad0b9 Merge yuzu-emu#13000 2024-02-20 00:56:45 +00:00
cdd7141899 Merge yuzu-emu#12749 2024-02-20 00:56:45 +00:00
0c0ab815be Merge yuzu-emu#12461 2024-02-20 00:56:45 +00:00
fb0655414a Merge yuzu-emu#10529 2024-02-20 00:56:45 +00:00
159 changed files with 4438 additions and 5533 deletions

View File

@ -1,14 +1,11 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [10529](https://github.com/yuzu-emu/yuzu//pull/10529) | [`368bf2211`](https://github.com/yuzu-emu/yuzu//pull/10529/files) | caches: make critical reclamation less eager and possible in more cases | [liamwhite](https://github.com/liamwhite/) | Yes |
| [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 |
| [13081](https://github.com/yuzu-emu/yuzu//pull/13081) | [`197c4d325`](https://github.com/yuzu-emu/yuzu//pull/13081/files) | aoc: Migrate to use 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 |
| [13000](https://github.com/yuzu-emu/yuzu//pull/13000) | [`461eaca7e`](https://github.com/yuzu-emu/yuzu//pull/13000/files) | device_memory_manager: skip unregistered interfaces on invalidate | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13075](https://github.com/yuzu-emu/yuzu//pull/13075) | [`f46dc3168`](https://github.com/yuzu-emu/yuzu//pull/13075/files) | shader_recompiler: throw on missing geometry streams in geometry shaders | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13079](https://github.com/yuzu-emu/yuzu//pull/13079) | [`e462bff09`](https://github.com/yuzu-emu/yuzu//pull/13079/files) | vi: misc fixes | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.

View File

@ -121,7 +121,6 @@ else()
-Wno-attributes
-Wno-invalid-offsetof
-Wno-unused-parameter
-Wno-missing-field-initializers
)
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang

View File

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

View File

@ -6,8 +6,7 @@ package org.yuzu.yuzu_emu.features.settings.model
import org.yuzu.yuzu_emu.utils.NativeConfig
enum class StringSetting(override val key: String) : AbstractStringSetting {
DRIVER_PATH("driver_path"),
DEVICE_NAME("device_name");
DRIVER_PATH("driver_path");
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)

View File

@ -16,7 +16,6 @@ import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.utils.NativeConfig
/**
@ -91,7 +90,6 @@ abstract class SettingsItem(
const val TYPE_INPUT = 8
const val TYPE_INT_SINGLE_CHOICE = 9
const val TYPE_INPUT_PROFILE = 10
const val TYPE_STRING_INPUT = 11
const val FASTMEM_COMBINED = "fastmem_combined"
@ -110,7 +108,6 @@ abstract class SettingsItem(
// List of all general
val settingsItems = HashMap<String, SettingsItem>().apply {
put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
put(
SwitchSetting(
BooleanSetting.RENDERER_USE_SPEED_LIMIT,

View File

@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
class StringInputSetting(
setting: AbstractStringSetting,
@StringRes titleId: Int = 0,
titleString: String = "",
@StringRes descriptionId: Int = 0,
descriptionString: String = ""
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
override val type = TYPE_STRING_INPUT
fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal)
fun setSelectedValue(selection: String) =
(setting as AbstractStringSetting).setString(selection)
}

View File

@ -85,10 +85,6 @@ class SettingsAdapter(
InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
SettingsItem.TYPE_STRING_INPUT -> {
StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
else -> {
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
}
@ -396,15 +392,6 @@ class SettingsAdapter(
popup.show()
}
fun onStringInputClick(item: StringInputSetting, position: Int) {
SettingsDialogFragment.newInstance(
settingsViewModel,
item,
SettingsItem.TYPE_STRING_INPUT,
position
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
}
fun onLongClick(item: SettingsItem, position: Int): Boolean {
SettingsDialogFragment.newInstance(
settingsViewModel,

View File

@ -14,7 +14,6 @@ import androidx.fragment.app.activityViewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
@ -24,7 +23,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.utils.ParamPackage
import org.yuzu.yuzu_emu.utils.collect
@ -39,7 +37,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
private val settingsViewModel: SettingsViewModel by activityViewModels()
private lateinit var sliderBinding: DialogSliderBinding
private lateinit var stringInputBinding: DialogEditTextBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -134,18 +131,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
.create()
}
SettingsItem.TYPE_STRING_INPUT -> {
stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
val item = settingsViewModel.clickedItem as StringInputSetting
stringInputBinding.editText.setText(item.getSelectedValue())
MaterialAlertDialogBuilder(requireContext())
.setTitle(item.title)
.setView(stringInputBinding.root)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
.create()
}
SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
MaterialAlertDialogBuilder(requireContext())
@ -173,7 +158,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
): View? {
return when (type) {
SettingsItem.TYPE_SLIDER -> sliderBinding.root
SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root
else -> super.onCreateView(inflater, container, savedInstanceState)
}
}
@ -216,13 +200,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
val sliderSetting = settingsViewModel.clickedItem as SliderSetting
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
}
is StringInputSetting -> {
val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
stringInputSetting.setSelectedValue(
(stringInputBinding.editText.text ?: "").toString()
)
}
}
closeDialog()
}

View File

@ -23,7 +23,6 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.NativeConfig
@ -154,7 +153,6 @@ class SettingsFragmentPresenter(
private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
sl.apply {
add(StringSetting.DEVICE_NAME.key)
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
add(BooleanSetting.USE_DOCKED_MODE.key)
@ -780,7 +778,7 @@ class SettingsFragmentPresenter(
playerIndex: Int,
paramName: String,
stick: NativeAnalog,
defaultValue: Float
defaultValue: Int
): AbstractIntSetting =
object : AbstractIntSetting {
val params get() = NativeInput.getStickParam(playerIndex, stick)
@ -788,7 +786,7 @@ class SettingsFragmentPresenter(
override val key = ""
override fun getInt(needsGlobal: Boolean): Int =
(params.get(paramName, defaultValue) * 100).toInt()
(params.get(paramName, 0.15f) * 100).toInt()
override fun setInt(value: Int) {
val tempParams = params
@ -796,12 +794,12 @@ class SettingsFragmentPresenter(
NativeInput.setStickParam(playerIndex, stick, tempParams)
}
override val defaultValue = (defaultValue * 100).toInt()
override val defaultValue = defaultValue
override fun getValueAsString(needsGlobal: Boolean): String =
getInt(needsGlobal).toString()
override fun reset() = setInt(this.defaultValue)
override fun reset() = setInt(defaultValue)
}
private fun getExtraStickSettings(
@ -811,11 +809,11 @@ class SettingsFragmentPresenter(
val stickIsController =
NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
val modifierRangeSetting =
getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f)
getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50)
val stickRangeSetting =
getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f)
getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95)
val stickDeadzoneSetting =
getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f)
getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15)
val out = mutableListOf<SettingsItem>().apply {
if (stickIsController) {

View File

@ -1,45 +0,0 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var setting: StringInputSetting
override fun bind(item: SettingsItem) {
setting = item as StringInputSetting
binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.text = setting.description
binding.textSettingValue.setVisible(true)
binding.textSettingValue.text = setting.getSelectedValue()
binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
if (setting.isEditable) {
adapter.onStringInputClick(setting, bindingAdapterPosition)
}
}
override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) {
return adapter.onLongClick(setting, bindingAdapterPosition)
}
return false
}
}

View File

@ -292,9 +292,6 @@ 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();
@ -668,7 +665,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::User, FileSys::SaveDataType::Account, 1,
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1,
user_id->AsU128(), 0);
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
@ -836,8 +833,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::User, FileSys::SaveDataType::Account, program_id,
user_id->AsU128(), 0);
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
program_id, user_id->AsU128(), 0);
return Common::Android::ToJString(env, user_save_data_path);
}

View File

@ -102,50 +102,8 @@ 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);
@ -564,10 +522,36 @@ 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 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());
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());
return j_supported_indexes;
}

View File

@ -209,7 +209,6 @@
<string name="value_with_units">%1$s%2$s</string>
<!-- System settings strings -->
<string name="device_name">Device name</string>
<string name="use_docked_mode">Docked Mode</string>
<string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string>
<string name="emulated_region">Emulated region</string>

View File

@ -73,15 +73,16 @@ void Manager::BufferReleaseAndRegister() {
}
}
u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names,
[[maybe_unused]] const u32 max_count,
[[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.empty() && !names.empty()) {
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
if (input_devices.size() > 1) {
names.emplace_back("Uac");
return 1;
}
return 0;

View File

@ -60,11 +60,13 @@ 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::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count,
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(const OpusParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
Result OpusDecoder::Initialize(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(const OpusParametersEx& params,
R_SUCCEED();
}
Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
Result OpusDecoder::Initialize(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(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size);
Result Initialize(OpusMultiStreamParametersEx& 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(const OpusParameters& params, u32& out_size) {
Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) {
OpusParametersEx ex{
.sample_rate = params.sample_rate,
.channel_count = params.channel_count,
@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32&
R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) {
R_RETURN(GetWorkBufferSizeExEx(params, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) {
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params,
R_SUCCEED();
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params,
u32& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params,
u64& out_size) {
OpusMultiStreamParametersEx ex{
.sample_rate = params.sample_rate,
.channel_count = params.channel_count,
@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStream
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
const OpusMultiStreamParametersEx& params, u32& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params,
u64& out_size) {
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
}
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
const OpusMultiStreamParametersEx& params, u32& out_size) {
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params,
u64& 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,19 +22,17 @@ public:
return hardware_opus;
}
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);
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);
private:
Core::System& system;
HardwareOpus hardware_opus;
std::array<u32, MaxChannels> required_workbuffer_sizes{};
std::array<u64, MaxChannels> required_workbuffer_sizes{};
};
} // namespace AudioCore::OpusDecoder

View File

@ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_)
opus_decoder.SetSharedMemory(shared_memory);
}
u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
if (!opus_decoder.IsRunning()) {
return 0;
}
@ -55,10 +55,10 @@ u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
return 0;
}
return static_cast<u32>(shared_memory.dsp_return_data[0]);
return shared_memory.dsp_return_data[0];
}
u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
u64 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 @@ u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
return 0;
}
return static_cast<u32>(shared_memory.dsp_return_data[0]);
return shared_memory.dsp_return_data[0];
}
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
@ -94,9 +94,8 @@ 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,
const void* mappings, void* buffer,
u64 buffer_size) {
u32 stereo_stream_count, 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);
u32 GetWorkBufferSize(u32 channel);
u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
u64 GetWorkBufferSize(u32 channel);
u64 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,
const void* mappings, void* buffer, u64 buffer_size);
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_NOINIT(7);
/* 0x09 */ INSERT_PADDING_BYTES(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_NOINIT(7);
/* 0x11 */ INSERT_PADDING_BYTES(7);
/* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
}; // size = 0x118
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,

View File

@ -36,7 +36,8 @@ 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::span<AudioDeviceName> out_buffer) const {
u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
const size_t max_count) const {
std::span<const AudioDeviceName> names{};
if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
@ -45,18 +46,19 @@ u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) cons
names = device_names;
}
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))};
const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))};
for (u32 i = 0; i < out_count; i++) {
out_buffer[i] = names[i];
out_buffer.push_back(names[i]);
}
return out_count;
}
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()))};
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()))};
for (u32 i = 0; i < out_count; i++) {
out_buffer[i] = output_device_names[i];
out_buffer.push_back(output_device_names[i]);
}
return out_count;
}

View File

@ -36,18 +36,20 @@ 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::span<AudioDeviceName> out_buffer) const;
u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) 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::span<AudioDeviceName> out_buffer) const;
u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
/**
* Set the volume of all streams in the backend sink.

View File

@ -17,8 +17,9 @@ 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, Kernel::KProcess* process_handle,
const u64 applet_resource_user_id, const s32 session_id) {
const u64 transfer_memory_size, const u32 process_handle,
Kernel::KProcess& process, const u64 applet_resource_user_id,
const s32 session_id) {
if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio,
@ -29,7 +30,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
}
initialized = true;
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
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.
* @param process_handle - Process handle, also used for memory. Unused.
* @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,
Kernel::KProcess* process_handle, u64 applet_resource_user_id,
u32 process_handle, Kernel::KProcess& process, 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_,
Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_)
const u32 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,10 +8,6 @@
#include "common/common_types.h"
#include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer {
class BehaviorInfo;
class VoiceContext;
@ -43,8 +39,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,
Kernel::KProcess* process_handle, BehaviorInfo& behaviour);
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle,
BehaviorInfo& behaviour);
/**
* Update the voice channel resources.
@ -201,7 +197,7 @@ private:
/// Expected output size, see CheckConsumedSize
u64 expected_output_size;
/// Unused
Kernel::KProcess* process_handle;
u32 process_handle;
/// Behaviour
BehaviorInfo& behaviour;
};

View File

@ -8,11 +8,11 @@
namespace AudioCore::Renderer {
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_)
PoolMapper::PoolMapper(u32 process_handle_, bool force_map_)
: process_handle{process_handle_}, force_map{force_map_} {}
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_,
u32 pool_count_, bool force_map_)
PoolMapper::PoolMapper(u32 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,17 +106,15 @@ bool PoolMapper::IsForceMapEnabled() const {
return force_map;
}
Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
u32 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 nullptr;
return Kernel::Svc::CurrentProcess;
}
LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
// return Kernel::Svc::CurrentProcess;
return nullptr;
return Kernel::Svc::CurrentProcess;
}
bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr,
@ -149,14 +147,14 @@ bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const
}
bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
[[maybe_unused]] Kernel::KProcess* handle{};
[[maybe_unused]] u32 handle{0};
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,10 +10,6 @@
#include "common/common_types.h"
#include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer {
class AddressInfo;
@ -22,9 +18,9 @@ class AddressInfo;
*/
class PoolMapper {
public:
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);
explicit PoolMapper(u32 process_handle, bool force_map);
explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count,
bool force_map);
/**
* Clear the usage state for all given pools.
@ -102,7 +98,7 @@ public:
* @return CurrentProcessHandle if location == DSP,
* the PoolMapper's process_handle if location == CPU
*/
Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const;
u32 GetProcessHandle(const MemoryPoolInfo* pool) const;
/**
* Map the given region with the given handle. This is a no-op.
@ -171,7 +167,7 @@ public:
private:
/// Process handle for this mapper, used when location == CPU
Kernel::KProcess* process_handle{};
u32 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,
Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
s32 session_id_) {
u32 process_handle_, Kernel::KProcess& process_,
u64 applet_resource_user_id_, s32 session_id_) {
if (!CheckValidRevision(params.revision)) {
return Service::Audio::ResultInvalidRevision;
}
@ -119,6 +119,7 @@ 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_;
@ -131,8 +132,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
render_device = params.rendering_device;
execution_mode = params.execution_mode;
process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
transfer_memory_size);
process->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_handle,
applet_resource_user_id, process,
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.
* @param process_handle - Process handle, also used for memory. Unused.
* @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,
Kernel::KProcess* process_handle, u64 applet_resource_user_id,
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
s32 session_id);
/**
@ -278,7 +278,9 @@ private:
/// Does what locks do
std::mutex lock{};
/// Process this audio render is operating within, used for memory reads/writes.
Kernel::KProcess* process_handle{};
Kernel::KProcess* process{};
/// Handle for the process for this system, unused
u32 process_handle{};
/// Applet resource id for this system, unused
u64 applet_resource_user_id{};
/// Controls performance input and output

View File

@ -384,12 +384,6 @@ 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,8 +122,6 @@ 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,10 +38,6 @@ 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,7 +19,6 @@ 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,14 +58,9 @@ 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
@ -486,43 +481,31 @@ add_library(core STATIC
hle/service/am/service/system_applet_proxy.h
hle/service/am/service/window_controller.cpp
hle/service/am/service/window_controller.h
hle/service/aoc/addon_content_manager.cpp
hle/service/aoc/addon_content_manager.h
hle/service/aoc/purchase_event_manager.cpp
hle/service/aoc/purchase_event_manager.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
hle/service/apm/apm.h
hle/service/apm/apm_controller.cpp
hle/service/apm/apm_controller.h
hle/service/apm/apm_interface.cpp
hle/service/apm/apm_interface.h
hle/service/audio/audio_controller.cpp
hle/service/audio/audio_controller.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/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/errors.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/audio/hwopus.cpp
hle/service/audio/hwopus.h
hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h
hle/service/bcat/bcat.cpp
@ -612,10 +595,6 @@ 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
@ -624,7 +603,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_types.h
hle/service/filesystem/fsp/fsp_util.h
hle/service/filesystem/romfs_controller.cpp
hle/service/filesystem/romfs_controller.h
hle/service/filesystem/save_data_controller.cpp
@ -881,20 +860,8 @@ 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
@ -914,35 +881,16 @@ 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_results.h
hle/service/pctl/pctl_types.h
hle/service/pctl/pctl_module.cpp
hle/service/pctl/pctl_module.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

@ -23,8 +23,6 @@ enum class OpenDirectoryMode : u64 {
File = (1 << 1),
All = (Directory | File),
NotRequireFileSize = (1ULL << 31),
};
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
@ -38,29 +36,4 @@ 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);
inline void* AllocateUnsafe(size_t size) {
void* AllocateUnsafe(size_t size) {
// Allocate
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
@ -21,16 +21,16 @@ inline void* AllocateUnsafe(size_t size) {
return ptr;
}
inline void DeallocateUnsafe(void* ptr, size_t size) {
void DeallocateUnsafe(void* ptr, size_t size) {
// Deallocate the pointer
::operator delete(ptr, std::align_val_t{RequiredAlignment});
}
inline void* Allocate(size_t size) {
void* Allocate(size_t size) {
return AllocateUnsafe(size);
}
inline void Deallocate(void* ptr, size_t size) {
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 = static_cast<s32>(std::strlen(p));
s32 len = std::strlen(p);
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
// Handle a trailing separator

View File

@ -426,10 +426,9 @@ public:
R_SUCCEED();
}
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) {
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) {
// Use StringTraits names for remainder of scope
using namespace StringTraits;

View File

@ -1,175 +0,0 @@
// 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,11 +19,6 @@ 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);
@ -37,11 +32,6 @@ 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);
@ -61,11 +51,6 @@ 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

@ -1,91 +0,0 @@
// 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

@ -1,167 +0,0 @@
// 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

@ -1,206 +0,0 @@
// 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

@ -1,36 +0,0 @@
// 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,7 +3,6 @@
#pragma once
#include <mutex>
#include <optional>
#include "core/crypto/aes_util.h"

View File

@ -14,11 +14,48 @@ 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::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);
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);
}
std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
@ -26,7 +63,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::User:
case SaveDataSpaceId::NandUser:
return "/user/save";
default:
return "";
@ -42,9 +79,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
// Only detect account/device saves from the future location.
switch (type) {
case SaveDataType::Account:
case SaveDataType::SaveData:
return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
case SaveDataType::Device:
case SaveDataType::DeviceSaveData:
return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
default:
return "";
@ -53,6 +90,13 @@ 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_)} {
@ -64,16 +108,18 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
SaveDataFactory::~SaveDataFactory() = default;
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
meta.user_id, meta.system_save_data_id);
PrintSaveDataAttributeWarnings(meta);
const auto save_directory =
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_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.program_id,
meta.user_id, meta.system_save_data_id);
const auto save_directory =
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
auto out = dir->GetDirectoryRelative(save_directory);
@ -90,11 +136,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
switch (space) {
case SaveDataSpaceId::System:
case SaveDataSpaceId::NandSystem:
return "/system/";
case SaveDataSpaceId::User:
case SaveDataSpaceId::NandUser:
return "/user/";
case SaveDataSpaceId::Temporary:
case SaveDataSpaceId::TemporaryStorage:
return "/temp/";
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@ -107,7 +153,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::Account || type == SaveDataType::Device) {
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
if (title_id == 0) {
title_id = program_id;
}
@ -127,16 +173,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
std::string out = GetSaveDataSpaceIdPath(space);
switch (type) {
case SaveDataType::System:
case SaveDataType::SystemSaveData:
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
case SaveDataType::Account:
case SaveDataType::Device:
case SaveDataType::SaveData:
case SaveDataType::DeviceSaveData:
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
case SaveDataType::Temporary:
case SaveDataType::TemporaryStorage:
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
case SaveDataType::Cache:
case SaveDataType::CacheStorage:
return fmt::format("{}save/cache/{:016X}", out, title_id);
default:
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
@ -156,7 +202,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::User, type, title_id, user_id, 0);
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
@ -175,7 +221,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::User, type, title_id, user_id, 0);
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());

View File

@ -7,7 +7,6 @@
#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"
@ -17,6 +16,73 @@ 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

@ -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.program_id = m_applet->program_id;
attribute.title_id = m_applet->program_id;
attribute.user_id = user_id.AsU128();
attribute.type = FileSys::SaveDataType::Account;
attribute.type = FileSys::SaveDataType::SaveData;
FileSys::VirtualDir save_data{};
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
&save_data, FileSys::SaveDataSpaceId::User, attribute));
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
*out_size = 0;
R_SUCCEED();

View File

@ -1,223 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <numeric>
#include <vector>
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/aoc/addon_content_manager.h"
#include "core/hle/service/aoc/purchase_event_manager.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/loader/loader.h"
namespace Service::AOC {
static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
return FileSys::GetBaseTitleID(title_id) == base;
}
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
std::vector<u64> add_on_content;
const auto& rcu = system.GetContentProvider();
const auto list =
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
[](const FileSys::ContentProviderEntry& rce) { return rce.title_id; });
add_on_content.erase(
std::remove_if(
add_on_content.begin(), add_on_content.end(),
[&rcu](u64 tid) {
return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
Loader::ResultStatus::Success;
}),
add_on_content.end());
return add_on_content;
}
IAddOnContentManager::IAddOnContentManager(Core::System& system_)
: ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
service_context{system_, "aoc:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CountAddOnContentByApplicationId"},
{1, nullptr, "ListAddOnContentByApplicationId"},
{2, D<&IAddOnContentManager::CountAddOnContent>, "CountAddOnContent"},
{3, D<&IAddOnContentManager::ListAddOnContent>, "ListAddOnContent"},
{4, nullptr, "GetAddOnContentBaseIdByApplicationId"},
{5, D<&IAddOnContentManager::GetAddOnContentBaseId>, "GetAddOnContentBaseId"},
{6, nullptr, "PrepareAddOnContentByApplicationId"},
{7, D<&IAddOnContentManager::PrepareAddOnContent>, "PrepareAddOnContent"},
{8, D<&IAddOnContentManager::GetAddOnContentListChangedEvent>, "GetAddOnContentListChangedEvent"},
{9, nullptr, "GetAddOnContentLostErrorCode"},
{10, D<&IAddOnContentManager::GetAddOnContentListChangedEventWithProcessId>, "GetAddOnContentListChangedEventWithProcessId"},
{11, D<&IAddOnContentManager::NotifyMountAddOnContent>, "NotifyMountAddOnContent"},
{12, D<&IAddOnContentManager::NotifyUnmountAddOnContent>, "NotifyUnmountAddOnContent"},
{13, nullptr, "IsAddOnContentMountedForDebug"},
{50, D<&IAddOnContentManager::CheckAddOnContentMountStatus>, "CheckAddOnContentMountStatus"},
{100, D<&IAddOnContentManager::CreateEcPurchasedEventManager>, "CreateEcPurchasedEventManager"},
{101, D<&IAddOnContentManager::CreatePermanentEcPurchasedEventManager>, "CreatePermanentEcPurchasedEventManager"},
{110, nullptr, "CreateContentsServiceManager"},
{200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
{300, nullptr, "SetupHostAddOnContent"},
{301, nullptr, "GetRegisteredAddOnContentPath"},
{302, nullptr, "UpdateCachedList"},
};
// clang-format on
RegisterHandlers(functions);
aoc_change_event = service_context.CreateEvent("GetAddOnContentListChanged:Event");
}
IAddOnContentManager::~IAddOnContentManager() {
service_context.CloseEvent(aoc_change_event);
}
Result IAddOnContentManager::CountAddOnContent(Out<u32> out_count, ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
const auto current = system.GetApplicationProcessProgramID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
*out_count = 0;
R_SUCCEED();
}
*out_count = static_cast<u32>(
std::count_if(add_on_content.begin(), add_on_content.end(),
[current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); }));
R_SUCCEED();
}
Result IAddOnContentManager::ListAddOnContent(Out<u32> out_count,
OutBuffer<BufferAttr_HipcMapAlias> out_addons,
u32 offset, u32 count, ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id.pid);
const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
for (u64 content_id : add_on_content) {
if (FileSys::GetBaseTitleID(content_id) != current) {
continue;
}
out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
}
}
// TODO(DarkLordZach): Find the correct error code.
R_UNLESS(out.size() >= offset, ResultUnknown);
*out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
std::rotate(out.begin(), out.begin() + offset, out.end());
std::memcpy(out_addons.data(), out.data(), *out_count);
R_SUCCEED();
}
Result IAddOnContentManager::GetAddOnContentBaseId(Out<u64> out_title_id,
ClientProcessId process_id) {
LOG_DEBUG(Service_AOC, "called. process_id={}", process_id.pid);
const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
const auto res = pm.GetControlMetadata();
if (res.first == nullptr) {
*out_title_id = FileSys::GetAOCBaseTitleID(title_id);
R_SUCCEED();
}
*out_title_id = res.first->GetDLCBaseTitleId();
R_SUCCEED();
}
Result IAddOnContentManager::PrepareAddOnContent(s32 addon_index, ClientProcessId process_id) {
LOG_WARNING(Service_AOC, "(STUBBED) called with addon_index={}, process_id={}", addon_index,
process_id.pid);
R_SUCCEED();
}
Result IAddOnContentManager::GetAddOnContentListChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
*out_event = &aoc_change_event->GetReadableEvent();
R_SUCCEED();
}
Result IAddOnContentManager::GetAddOnContentListChangedEventWithProcessId(
OutCopyHandle<Kernel::KReadableEvent> out_event, ClientProcessId process_id) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
*out_event = &aoc_change_event->GetReadableEvent();
R_SUCCEED();
}
Result IAddOnContentManager::NotifyMountAddOnContent() {
LOG_WARNING(Service_AOC, "(STUBBED) called");
R_SUCCEED();
}
Result IAddOnContentManager::NotifyUnmountAddOnContent() {
LOG_WARNING(Service_AOC, "(STUBBED) called");
R_SUCCEED();
}
Result IAddOnContentManager::CheckAddOnContentMountStatus() {
LOG_WARNING(Service_AOC, "(STUBBED) called");
R_SUCCEED();
}
Result IAddOnContentManager::CreateEcPurchasedEventManager(
OutInterface<IPurchaseEventManager> out_interface) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
*out_interface = std::make_shared<IPurchaseEventManager>(system);
R_SUCCEED();
}
Result IAddOnContentManager::CreatePermanentEcPurchasedEventManager(
OutInterface<IPurchaseEventManager> out_interface) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
*out_interface = std::make_shared<IPurchaseEventManager>(system);
R_SUCCEED();
}
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("aoc:u", std::make_shared<IAddOnContentManager>(system));
ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::AOC

View File

@ -1,51 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Kernel {
class KEvent;
}
namespace Service::AOC {
class IPurchaseEventManager;
class IAddOnContentManager final : public ServiceFramework<IAddOnContentManager> {
public:
explicit IAddOnContentManager(Core::System& system);
~IAddOnContentManager() override;
Result CountAddOnContent(Out<u32> out_count, ClientProcessId process_id);
Result ListAddOnContent(Out<u32> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_addons,
u32 offset, u32 count, ClientProcessId process_id);
Result GetAddOnContentBaseId(Out<u64> out_title_id, ClientProcessId process_id);
Result PrepareAddOnContent(s32 addon_index, ClientProcessId process_id);
Result GetAddOnContentListChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetAddOnContentListChangedEventWithProcessId(
OutCopyHandle<Kernel::KReadableEvent> out_event, ClientProcessId process_id);
Result NotifyMountAddOnContent();
Result NotifyUnmountAddOnContent();
Result CheckAddOnContentMountStatus();
Result CreateEcPurchasedEventManager(OutInterface<IPurchaseEventManager> out_interface);
Result CreatePermanentEcPurchasedEventManager(
OutInterface<IPurchaseEventManager> out_interface);
private:
std::vector<u64> add_on_content;
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* aoc_change_event;
};
void LoopProcess(Core::System& system);
} // namespace Service::AOC

View File

@ -0,0 +1,340 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <numeric>
#include <vector>
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/aoc/aoc_u.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/loader/loader.h"
namespace Service::AOC {
constexpr Result ResultNoPurchasedProductInfoAvailable{ErrorModule::NIMShop, 400};
static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
return FileSys::GetBaseTitleID(title_id) == base;
}
static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
std::vector<u64> add_on_content;
const auto& rcu = system.GetContentProvider();
const auto list =
rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
[](const FileSys::ContentProviderEntry& rce) { return rce.title_id; });
add_on_content.erase(
std::remove_if(
add_on_content.begin(), add_on_content.end(),
[&rcu](u64 tid) {
return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
Loader::ResultStatus::Success;
}),
add_on_content.end());
return add_on_content;
}
class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
public:
explicit IPurchaseEventManager(Core::System& system_)
: ServiceFramework{system_, "IPurchaseEventManager"}, service_context{
system, "IPurchaseEventManager"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"},
{1, &IPurchaseEventManager::SetDeliveryTarget, "SetDeliveryTarget"},
{2, &IPurchaseEventManager::GetPurchasedEventReadableHandle, "GetPurchasedEventReadableHandle"},
{3, &IPurchaseEventManager::PopPurchasedProductInfo, "PopPurchasedProductInfo"},
{4, &IPurchaseEventManager::PopPurchasedProductInfoWithUid, "PopPurchasedProductInfoWithUid"},
};
// clang-format on
RegisterHandlers(functions);
purchased_event = service_context.CreateEvent("IPurchaseEventManager:PurchasedEvent");
}
~IPurchaseEventManager() override {
service_context.CloseEvent(purchased_event);
}
private:
void SetDefaultDeliveryTarget(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown_1 = rp.Pop<u64>();
[[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer();
LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SetDeliveryTarget(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown_1 = rp.Pop<u64>();
[[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer();
LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetPurchasedEventReadableHandle(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(purchased_event->GetReadableEvent());
}
void PopPurchasedProductInfo(HLERequestContext& ctx) {
LOG_DEBUG(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultNoPurchasedProductInfoAvailable);
}
void PopPurchasedProductInfoWithUid(HLERequestContext& ctx) {
LOG_DEBUG(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultNoPurchasedProductInfoAvailable);
}
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* purchased_event;
};
AOC_U::AOC_U(Core::System& system_)
: ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
service_context{system_, "aoc:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CountAddOnContentByApplicationId"},
{1, nullptr, "ListAddOnContentByApplicationId"},
{2, &AOC_U::CountAddOnContent, "CountAddOnContent"},
{3, &AOC_U::ListAddOnContent, "ListAddOnContent"},
{4, nullptr, "GetAddOnContentBaseIdByApplicationId"},
{5, &AOC_U::GetAddOnContentBaseId, "GetAddOnContentBaseId"},
{6, nullptr, "PrepareAddOnContentByApplicationId"},
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
{9, nullptr, "GetAddOnContentLostErrorCode"},
{10, &AOC_U::GetAddOnContentListChangedEventWithProcessId, "GetAddOnContentListChangedEventWithProcessId"},
{11, &AOC_U::NotifyMountAddOnContent, "NotifyMountAddOnContent"},
{12, &AOC_U::NotifyUnmountAddOnContent, "NotifyUnmountAddOnContent"},
{13, nullptr, "IsAddOnContentMountedForDebug"},
{50, &AOC_U::CheckAddOnContentMountStatus, "CheckAddOnContentMountStatus"},
{100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
{101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
{110, nullptr, "CreateContentsServiceManager"},
{200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
{300, nullptr, "SetupHostAddOnContent"},
{301, nullptr, "GetRegisteredAddOnContentPath"},
{302, nullptr, "UpdateCachedList"},
};
// clang-format on
RegisterHandlers(functions);
aoc_change_event = service_context.CreateEvent("GetAddOnContentListChanged:Event");
}
AOC_U::~AOC_U() {
service_context.CloseEvent(aoc_change_event);
}
void AOC_U::CountAddOnContent(HLERequestContext& ctx) {
struct Parameters {
u64 process_id;
};
static_assert(sizeof(Parameters) == 8);
IPC::RequestParser rp{ctx};
const auto params = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AOC, "called. process_id={}", params.process_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
const auto current = system.GetApplicationProcessProgramID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
rb.Push<u32>(0);
return;
}
rb.Push<u32>(static_cast<u32>(
std::count_if(add_on_content.begin(), add_on_content.end(),
[current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); })));
}
void AOC_U::ListAddOnContent(HLERequestContext& ctx) {
struct Parameters {
u32 offset;
u32 count;
u64 process_id;
};
static_assert(sizeof(Parameters) == 16);
IPC::RequestParser rp{ctx};
const auto [offset, count, process_id] = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id);
const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
for (u64 content_id : add_on_content) {
if (FileSys::GetBaseTitleID(content_id) != current) {
continue;
}
out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
}
}
if (out.size() < offset) {
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find the correct error code.
rb.Push(ResultUnknown);
return;
}
const auto out_count = static_cast<u32>(std::min<size_t>(out.size() - offset, count));
std::rotate(out.begin(), out.begin() + offset, out.end());
out.resize(out_count);
ctx.WriteBuffer(out);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(out_count);
}
void AOC_U::GetAddOnContentBaseId(HLERequestContext& ctx) {
struct Parameters {
u64 process_id;
};
static_assert(sizeof(Parameters) == 8);
IPC::RequestParser rp{ctx};
const auto params = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AOC, "called. process_id={}", params.process_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
const auto res = pm.GetControlMetadata();
if (res.first == nullptr) {
rb.Push(FileSys::GetAOCBaseTitleID(title_id));
return;
}
rb.Push(res.first->GetDLCBaseTitleId());
}
void AOC_U::PrepareAddOnContent(HLERequestContext& ctx) {
struct Parameters {
s32 addon_index;
u64 process_id;
};
static_assert(sizeof(Parameters) == 16);
IPC::RequestParser rp{ctx};
const auto [addon_index, process_id] = rp.PopRaw<Parameters>();
LOG_WARNING(Service_AOC, "(STUBBED) called with addon_index={}, process_id={}", addon_index,
process_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AOC_U::GetAddOnContentListChangedEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
}
void AOC_U::GetAddOnContentListChangedEventWithProcessId(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
}
void AOC_U::NotifyMountAddOnContent(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AOC_U::NotifyUnmountAddOnContent(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AOC_U::CheckAddOnContentMountStatus(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AOC_U::CreateEcPurchasedEventManager(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IPurchaseEventManager>(system);
}
void AOC_U::CreatePermanentEcPurchasedEventManager(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IPurchaseEventManager>(system);
}
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("aoc:u", std::make_shared<AOC_U>(system));
ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::AOC

View File

@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Kernel {
class KEvent;
}
namespace Service::AOC {
class AOC_U final : public ServiceFramework<AOC_U> {
public:
explicit AOC_U(Core::System& system);
~AOC_U() override;
private:
void CountAddOnContent(HLERequestContext& ctx);
void ListAddOnContent(HLERequestContext& ctx);
void GetAddOnContentBaseId(HLERequestContext& ctx);
void PrepareAddOnContent(HLERequestContext& ctx);
void GetAddOnContentListChangedEvent(HLERequestContext& ctx);
void GetAddOnContentListChangedEventWithProcessId(HLERequestContext& ctx);
void NotifyMountAddOnContent(HLERequestContext& ctx);
void NotifyUnmountAddOnContent(HLERequestContext& ctx);
void CheckAddOnContentMountStatus(HLERequestContext& ctx);
void CreateEcPurchasedEventManager(HLERequestContext& ctx);
void CreatePermanentEcPurchasedEventManager(HLERequestContext& ctx);
std::vector<u64> add_on_content;
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* aoc_change_event;
};
void LoopProcess(Core::System& system);
} // namespace Service::AOC

View File

@ -1,67 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/aoc/purchase_event_manager.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AOC {
constexpr Result ResultNoPurchasedProductInfoAvailable{ErrorModule::NIMShop, 400};
IPurchaseEventManager::IPurchaseEventManager(Core::System& system_)
: ServiceFramework{system_, "IPurchaseEventManager"}, service_context{system,
"IPurchaseEventManager"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IPurchaseEventManager::SetDefaultDeliveryTarget>, "SetDefaultDeliveryTarget"},
{1, D<&IPurchaseEventManager::SetDeliveryTarget>, "SetDeliveryTarget"},
{2, D<&IPurchaseEventManager::GetPurchasedEvent>, "GetPurchasedEvent"},
{3, D<&IPurchaseEventManager::PopPurchasedProductInfo>, "PopPurchasedProductInfo"},
{4, D<&IPurchaseEventManager::PopPurchasedProductInfoWithUid>, "PopPurchasedProductInfoWithUid"},
};
// clang-format on
RegisterHandlers(functions);
purchased_event = service_context.CreateEvent("IPurchaseEventManager:PurchasedEvent");
}
IPurchaseEventManager::~IPurchaseEventManager() {
service_context.CloseEvent(purchased_event);
}
Result IPurchaseEventManager::SetDefaultDeliveryTarget(
ClientProcessId process_id, InBuffer<BufferAttr_HipcMapAlias> in_buffer) {
LOG_WARNING(Service_AOC, "(STUBBED) called, process_id={}", process_id.pid);
R_SUCCEED();
}
Result IPurchaseEventManager::SetDeliveryTarget(u64 unknown,
InBuffer<BufferAttr_HipcMapAlias> in_buffer) {
LOG_WARNING(Service_AOC, "(STUBBED) called, unknown={}", unknown);
R_SUCCEED();
}
Result IPurchaseEventManager::GetPurchasedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_AOC, "called");
*out_event = &purchased_event->GetReadableEvent();
R_SUCCEED();
}
Result IPurchaseEventManager::PopPurchasedProductInfo() {
LOG_DEBUG(Service_AOC, "(STUBBED) called");
R_RETURN(ResultNoPurchasedProductInfoAvailable);
}
Result IPurchaseEventManager::PopPurchasedProductInfoWithUid() {
LOG_DEBUG(Service_AOC, "(STUBBED) called");
R_RETURN(ResultNoPurchasedProductInfoAvailable);
}
} // namespace Service::AOC

View File

@ -1,30 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/service.h"
namespace Service::AOC {
class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
public:
explicit IPurchaseEventManager(Core::System& system_);
~IPurchaseEventManager() override;
Result SetDefaultDeliveryTarget(ClientProcessId process_id,
InBuffer<BufferAttr_HipcMapAlias> in_buffer);
Result SetDeliveryTarget(u64 unknown, InBuffer<BufferAttr_HipcMapAlias> in_buffer);
Result GetPurchasedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result PopPurchasedProductInfo();
Result PopPurchasedProductInfoWithUid();
private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* purchased_event;
};
} // namespace Service::AOC

View File

@ -0,0 +1,393 @@
// 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

@ -0,0 +1,38 @@
// 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/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/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/server_manager.h"
#include "core/hle/service/service.h"
@ -19,16 +19,12 @@ 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("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));
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));
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, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
{3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
{2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
{3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
{4, nullptr, "IsTargetMute"},
{5, nullptr, "SetTargetMute"},
{6, nullptr, "IsTargetConnected"},
{7, nullptr, "SetDefaultTarget"},
{8, nullptr, "GetDefaultTarget"},
{9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
{10, D<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
{9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
{10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
{11, nullptr, "SetForceMutePolicy"},
{12, D<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
{13, D<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
{14, D<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
{12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
{13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
{14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
{15, nullptr, "SetOutputTarget"},
{16, nullptr, "SetInputTargetForceEnabled"},
{17, D<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
{18, D<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
{17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
{18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
{22, D<&IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent>, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
{22, nullptr, "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, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
{31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
{30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
{31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
{32, nullptr, "GetActiveOutputTarget"},
{33, nullptr, "GetTargetDeviceInfo"},
{34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
{34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
{35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{37, nullptr, "SetHearingProtectionSafeguardEnabled"},
@ -150,11 +150,6 @@ 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,7 +45,6 @@ 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

@ -1,163 +0,0 @@
// 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

@ -1,58 +0,0 @@
// 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

@ -1,146 +0,0 @@
// 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

@ -1,53 +0,0 @@
// 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

@ -1,125 +0,0 @@
// 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

@ -1,57 +0,0 @@
// 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

@ -1,146 +0,0 @@
// 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

@ -1,58 +0,0 @@
// 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

@ -1,101 +0,0 @@
// 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

@ -1,44 +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/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

@ -1,139 +0,0 @@
// 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

@ -1,54 +0,0 @@
// 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

@ -1,104 +0,0 @@
// 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

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

@ -0,0 +1,323 @@
// 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

@ -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_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,12 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
#include "core/hle/service/audio/audrec_a.h"
namespace Service::Audio {
IFinalOutputRecorderManagerForApplet::IFinalOutputRecorderManagerForApplet(Core::System& system_)
: ServiceFramework{system_, "audrec:a"} {
AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestSuspend"},
@ -17,6 +16,6 @@ IFinalOutputRecorderManagerForApplet::IFinalOutputRecorderManagerForApplet(Core:
RegisterHandlers(functions);
}
IFinalOutputRecorderManagerForApplet::~IFinalOutputRecorderManagerForApplet() = default;
AudRecA::~AudRecA() = default;
} // namespace Service::Audio

View File

@ -11,10 +11,10 @@ class System;
namespace Service::Audio {
class IFinalOutputRecorderManager final : public ServiceFramework<IFinalOutputRecorderManager> {
class AudRecA final : public ServiceFramework<AudRecA> {
public:
explicit IFinalOutputRecorderManager(Core::System& system_);
~IFinalOutputRecorderManager() override;
explicit AudRecA(Core::System& system_);
~AudRecA() override;
};
} // 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/final_output_recorder_manager.h"
#include "core/hle/service/audio/audrec_u.h"
namespace Service::Audio {
@ -30,14 +30,13 @@ public:
}
};
IFinalOutputRecorderManager::IFinalOutputRecorderManager(Core::System& system_)
: ServiceFramework{system_, "audrec:u"} {
AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} {
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFinalOutputRecorder"},
};
RegisterHandlers(functions);
}
IFinalOutputRecorderManager::~IFinalOutputRecorderManager() = default;
AudRecU::~AudRecU() = default;
} // namespace Service::Audio

View File

@ -11,11 +11,10 @@ class System;
namespace Service::Audio {
class IFinalOutputRecorderManagerForApplet final
: public ServiceFramework<IFinalOutputRecorderManagerForApplet> {
class AudRecU final : public ServiceFramework<AudRecU> {
public:
explicit IFinalOutputRecorderManagerForApplet(Core::System& system_);
~IFinalOutputRecorderManagerForApplet() override;
explicit AudRecU(Core::System& system_);
~AudRecU() override;
};
} // namespace Service::Audio

View File

@ -0,0 +1,552 @@
// 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

@ -0,0 +1,35 @@
// 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,145 +0,0 @@
// 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

@ -1,63 +0,0 @@
// 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

@ -1,156 +0,0 @@
// 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

@ -1,53 +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/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

@ -0,0 +1,502 @@
// 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

@ -0,0 +1,36 @@
// 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 (size > 0 && ctx.CanWriteBuffer(OutBufferIndex)) {
if (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,34 +3,82 @@
#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 {
IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
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_,
FileSys::OpenDirectoryMode mode)
: ServiceFramework{system_, "IDirectory"},
backend(std::make_unique<FileSys::Fsa::IDirectory>(directory_, mode)) {
: ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
{0, D<&IDirectory::Read>, "Read"},
{1, D<&IDirectory::GetEntryCount>, "GetEntryCount"},
{0, &IDirectory::Read, "Read"},
{1, &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);
}
}
Result IDirectory::Read(
Out<s64> out_count,
const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries) {
void IDirectory::Read(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called.");
R_RETURN(backend->Read(out_count, out_entries.data(), out_entries.size()));
// 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);
}
Result IDirectory::GetEntryCount(Out<s64> out_count) {
void IDirectory::GetEntryCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
R_RETURN(backend->GetEntryCount(out_count));
u64 count = entries.size() - next_entry_index;
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(count);
}
} // namespace Service::FileSystem

View File

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

View File

@ -2,64 +2,126 @@
// 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 file_)
: ServiceFramework{system_, "IFile"}, backend{std::make_unique<FileSys::Fsa::IFile>(file_)} {
// clang-format off
IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_)
: ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
{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"},
{0, &IFile::Read, "Read"},
{1, &IFile::Write, "Write"},
{2, &IFile::Flush, "Flush"},
{3, &IFile::SetSize, "SetSize"},
{4, &IFile::GetSize, "GetSize"},
{5, nullptr, "OperateRange"},
{6, nullptr, "OperateRangeWithBuffer"},
};
// clang-format on
RegisterHandlers(functions);
}
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);
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;
}
// Read the data from the Storage backend
R_RETURN(
backend->Read(reinterpret_cast<size_t*>(out_size.Get()), offset, out_buffer.data(), size));
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()));
}
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);
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>();
R_RETURN(backend->Write(offset, buffer.data(), size, option));
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);
}
Result IFile::Flush() {
void IFile::Flush(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
R_RETURN(backend->Flush());
// Exists for SDK compatibiltity -- No need to flush file.
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
Result IFile::SetSize(s64 size) {
void IFile::SetSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 size = rp.Pop<u64>();
LOG_DEBUG(Service_FS, "called, size={}", size);
R_RETURN(backend->SetSize(size));
backend->Resize(size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
Result IFile::GetSize(Out<s64> out_size) {
LOG_DEBUG(Service_FS, "called");
void IFile::GetSize(HLERequestContext& ctx) {
const u64 size = backend->GetSize();
LOG_DEBUG(Service_FS, "called, size={}", size);
R_RETURN(backend->GetSize(out_size));
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<u64>(size);
}
} // namespace Service::FileSystem

View File

@ -3,8 +3,6 @@
#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"
@ -12,21 +10,16 @@ namespace Service::FileSystem {
class IFile final : public ServiceFramework<IFile> {
public:
explicit IFile(Core::System& system_, FileSys::VirtualFile file_);
explicit IFile(Core::System& system_, FileSys::VirtualFile backend_);
private:
std::unique_ptr<FileSys::Fsa::IFile> backend;
FileSys::VirtualFile backend;
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);
void Read(HLERequestContext& ctx);
void Write(HLERequestContext& ctx);
void Flush(HLERequestContext& ctx);
void SetSize(HLERequestContext& ctx);
void GetSize(HLERequestContext& ctx);
};
} // namespace Service::FileSystem

View File

@ -2,172 +2,261 @@
// 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 dir_, SizeGetter size_getter_)
: ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>(
dir_)},
size_getter{std::move(size_getter_)} {
IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
: ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
size_)} {
static const FunctionInfo functions[] = {
{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"},
{0, &IFileSystem::CreateFile, "CreateFile"},
{1, &IFileSystem::DeleteFile, "DeleteFile"},
{2, &IFileSystem::CreateDirectory, "CreateDirectory"},
{3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
{4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
{5, &IFileSystem::RenameFile, "RenameFile"},
{6, nullptr, "RenameDirectory"},
{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"},
{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"},
{15, nullptr, "QueryEntry"},
{16, D<&IFileSystem::GetFileSystemAttribute>, "GetFileSystemAttribute"},
{16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
};
RegisterHandlers(functions);
}
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);
void IFileSystem::CreateFile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
R_RETURN(backend->CreateFile(FileSys::Path(path->str), 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));
}
Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. file={}", path->str);
void IFileSystem::DeleteFile(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
R_RETURN(backend->DeleteFile(FileSys::Path(path->str)));
LOG_DEBUG(Service_FS, "called. file={}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.DeleteFile(name));
}
Result IFileSystem::CreateDirectory(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. directory={}", path->str);
void IFileSystem::CreateDirectory(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
R_RETURN(backend->CreateDirectory(FileSys::Path(path->str)));
LOG_DEBUG(Service_FS, "called. directory={}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.CreateDirectory(name));
}
Result IFileSystem::DeleteDirectory(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. directory={}", path->str);
void IFileSystem::DeleteDirectory(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
R_RETURN(backend->DeleteDirectory(FileSys::Path(path->str)));
LOG_DEBUG(Service_FS, "called. directory={}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.DeleteDirectory(name));
}
Result IFileSystem::DeleteDirectoryRecursively(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. directory={}", path->str);
void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
R_RETURN(backend->DeleteDirectoryRecursively(FileSys::Path(path->str)));
LOG_DEBUG(Service_FS, "called. directory={}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.DeleteDirectoryRecursively(name));
}
Result IFileSystem::CleanDirectoryRecursively(
const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. Directory: {}", path->str);
void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
R_RETURN(backend->CleanDirectoryRecursively(FileSys::Path(path->str)));
LOG_DEBUG(Service_FS, "called. Directory: {}", name);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(backend.CleanDirectoryRecursively(name));
}
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);
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));
R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(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));
}
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);
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);
FileSys::VirtualFile vfs_file{};
R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str),
static_cast<FileSys::OpenMode>(mode)));
auto result = backend.OpenFile(&vfs_file, name, mode);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
*out_interface = std::make_shared<IFile>(system, vfs_file);
R_SUCCEED();
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));
}
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);
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);
FileSys::VirtualDir vfs_dir{};
R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str),
static_cast<FileSys::OpenDirectoryMode>(mode)));
auto result = backend.OpenDirectory(&vfs_dir, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
*out_interface = std::make_shared<IDirectory>(system, vfs_dir,
static_cast<FileSys::OpenDirectoryMode>(mode));
R_SUCCEED();
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));
}
Result IFileSystem::GetEntryType(
Out<u32> out_type, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called. file={}", path->str);
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);
FileSys::DirectoryEntryType vfs_entry_type{};
R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str)));
auto result = backend.GetEntryType(&vfs_entry_type, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
*out_type = static_cast<u32>(vfs_entry_type);
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(vfs_entry_type));
}
Result IFileSystem::Commit() {
void IFileSystem::Commit(HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
Result IFileSystem::GetFreeSpaceSize(
Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
*out_size = size_getter.get_free_size();
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(size.get_free_size());
}
Result IFileSystem::GetTotalSpaceSize(
Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
*out_size = size_getter.get_total_size();
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(size.get_total_size());
}
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);
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);
FileSys::FileTimeStampRaw vfs_timestamp{};
R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str)));
auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
if (result != ResultSuccess) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
*out_timestamp = vfs_timestamp;
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(vfs_timestamp);
}
Result IFileSystem::GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute) {
void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
FileSys::FileSystemAttribute savedata_attribute{};
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{};
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;
*out_attribute = savedata_attribute;
R_SUCCEED();
IPC::ResponseBuilder rb{ctx, 50};
rb.Push(ResultSuccess);
rb.PushRaw(savedata_attribute);
}
} // namespace Service::FileSystem

View File

@ -3,58 +3,36 @@
#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_types.h"
#include "core/hle/service/filesystem/fsp/fsp_util.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 dir_, SizeGetter size_getter_);
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_);
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);
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);
private:
std::unique_ptr<FileSys::Fsa::IFileSystem> backend;
SizeGetter size_getter;
VfsDirectoryServiceWrapper backend;
SizeGetter size;
};
} // namespace Service::FileSystem

View File

@ -1,33 +0,0 @@
// 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

@ -1,23 +0,0 @@
// 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

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