Compare commits

..

2 Commits

Author SHA1 Message Date
lizzie 9af47ccc01 fix 2026-07-21 10:57:18 +00:00
lizzie 5244ee8533 [hle/ns] implement IReadOnlyApplicationControlDataInterface::ListApplicationIcon
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-07-21 10:56:12 +00:00
26 changed files with 271 additions and 261 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
namespace AudioCore {
AudioCore::AudioCore(Core::System& system) {
audio_manager.emplace(system);
audio_manager.emplace();
CreateSinks();
// Must be created after the sinks
adsp.emplace(system, *output_sink);
+15 -12
View File
@@ -15,12 +15,12 @@
namespace AudioCore::AudioIn {
Manager::Manager(Core::System& system) {
Manager::Manager(Core::System& system_) : system{system_} {
std::iota(session_ids.begin(), session_ids.end(), 0);
num_free_sessions = MaxInSessions;
}
Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
Result Manager::AcquireSessionId(size_t& session_id) {
if (num_free_sessions == 0) {
LOG_ERROR(Service_Audio, "All 4 AudioIn sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions;
@@ -31,7 +31,7 @@ Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
return ResultSuccess;
}
void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
void Manager::ReleaseSessionId(const size_t session_id) {
std::scoped_lock l{mutex};
LOG_DEBUG(Service_Audio, "Freeing AudioIn session {}", session_id);
session_ids[free_session_id] = session_id;
@@ -41,20 +41,21 @@ void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
applet_resource_user_ids[session_id] = 0;
}
Result Manager::LinkToManager(Core::System& system) {
Result Manager::LinkToManager() {
std::scoped_lock l{mutex};
if (!linked_to_manager) {
system.AudioCore().GetAudioManager().SetInManager(&Manager::BufferReleaseAndRegister);
system.AudioCore().GetAudioManager().SetInManager(std::bind(&Manager::BufferReleaseAndRegister, this));
linked_to_manager = true;
}
return ResultSuccess;
}
void Manager::Start(Core::System& system) {
void Manager::Start() {
if (sessions_started) {
return;
}
std::scoped_lock l{mutex};
for (auto& session : sessions) {
if (session) {
@@ -65,19 +66,21 @@ void Manager::Start(Core::System& system) {
sessions_started = true;
}
void Manager::BufferReleaseAndRegister(void *data, Core::System& system) noexcept {
Manager* this_ = (Manager*)data;
std::scoped_lock l{this_->mutex};
for (auto& session : this_->sessions) {
void Manager::BufferReleaseAndRegister() {
std::scoped_lock l{mutex};
for (auto& session : sessions) {
if (session != nullptr) {
session->ReleaseAndRegisterBuffers();
}
}
}
u32 Manager::GetDeviceNames(Core::System& system, std::span<Renderer::AudioDevice::AudioDeviceName> names, [[maybe_unused]] const bool filter) {
u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
[[maybe_unused]] const bool filter) {
std::scoped_lock l{mutex};
LinkToManager(system);
LinkToManager();
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
if (!input_devices.empty() && !names.empty()) {
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
+11 -10
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -33,29 +30,31 @@ public:
* @param session_id - Output session_id.
* @return Result code.
*/
Result AcquireSessionId(Core::System& system, size_t& session_id);
Result AcquireSessionId(size_t& session_id);
/**
* Release a session id on close.
*
* @param session_id - Session id to free.
*/
void ReleaseSessionId(Core::System& system, const size_t session_id);
void ReleaseSessionId(size_t session_id);
/**
* Link the audio in manager to the main audio manager.
*
* @return Result code.
*/
Result LinkToManager(Core::System& system);
Result LinkToManager();
/**
* Start the audio in manager.
*/
void Start(Core::System& system);
void Start();
/// @brief Callback function, called by the audio manager when the audio in event is signalled.
static void BufferReleaseAndRegister(void *data, Core::System& system) noexcept;
/**
* Callback function, called by the audio manager when the audio in event is signalled.
*/
void BufferReleaseAndRegister();
/**
* Get a list of audio in device names.
@@ -65,8 +64,10 @@ public:
*
* @return Number of names written.
*/
u32 GetDeviceNames(Core::System& system, std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
/// Core system
Core::System& system;
/// Array of session ids
std::array<size_t, MaxInSessions> session_ids{};
/// Array of resource user ids
+3 -3
View File
@@ -11,8 +11,8 @@
namespace AudioCore {
AudioManager::AudioManager(Core::System& system) {
thread = std::jthread([&](std::stop_token stop_token) {
AudioManager::AudioManager() {
thread = std::jthread([this](std::stop_token stop_token) {
Common::SetCurrentThreadName("AudioManager");
std::unique_lock l{events.GetAudioEventLock()};
events.ClearEvents();
@@ -25,7 +25,7 @@ AudioManager::AudioManager(Core::System& system) {
const auto event_type = Event::Type(i);
if (events.CheckAudioEventSet(event_type) || timed_out) {
if (buffer_events[i]) {
buffer_events[i](this, system);
buffer_events[i]();
}
}
events.SetAudioEvent(event_type, false);
+3 -6
View File
@@ -16,10 +16,6 @@
#include "audio_core/audio_event.h"
namespace Core {
class System;
}
union Result;
namespace AudioCore {
@@ -38,9 +34,10 @@ namespace AudioCore {
* This is only used by audio in and audio out.
*/
class AudioManager {
using BufferEventFunc = void (*)(void *data, Core::System& system) noexcept;
using BufferEventFunc = std::function<void()>;
public:
explicit AudioManager(Core::System& system);
explicit AudioManager();
/**
* Shutdown the audio manager.
+15 -10
View File
@@ -14,12 +14,12 @@
namespace AudioCore::AudioOut {
Manager::Manager(Core::System& system) {
Manager::Manager(Core::System& system_) : system{system_} {
std::iota(session_ids.begin(), session_ids.end(), 0);
num_free_sessions = MaxOutSessions;
}
Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
Result Manager::AcquireSessionId(size_t& session_id) {
if (num_free_sessions == 0) {
LOG_ERROR(Service_Audio, "All 12 Audio Out sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions;
@@ -30,7 +30,7 @@ Result Manager::AcquireSessionId(Core::System& system, size_t& session_id) {
return ResultSuccess;
}
void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
void Manager::ReleaseSessionId(const size_t session_id) {
std::scoped_lock l{mutex};
LOG_DEBUG(Service_Audio, "Freeing AudioOut session {}", session_id);
session_ids[free_session_id] = session_id;
@@ -40,17 +40,17 @@ void Manager::ReleaseSessionId(Core::System& system, const size_t session_id) {
applet_resource_user_ids[session_id] = 0;
}
Result Manager::LinkToManager(Core::System& system) {
Result Manager::LinkToManager() {
std::scoped_lock l{mutex};
if (!linked_to_manager) {
system.AudioCore().GetAudioManager().SetOutManager(&Manager::BufferReleaseAndRegister);
system.AudioCore().GetAudioManager().SetOutManager(std::bind(&Manager::BufferReleaseAndRegister, this));
linked_to_manager = true;
}
return ResultSuccess;
}
void Manager::Start(Core::System& system) {
void Manager::Start() {
if (sessions_started) {
return;
}
@@ -65,14 +65,19 @@ void Manager::Start(Core::System& system) {
sessions_started = true;
}
void Manager::BufferReleaseAndRegister(void *data, Core::System& system) noexcept {
Manager* this_ = (Manager*)data;
std::scoped_lock l{this_->mutex};
for (auto& session : this_->sessions) {
void Manager::BufferReleaseAndRegister() {
std::scoped_lock l{mutex};
for (auto& session : sessions) {
if (session != nullptr) {
session->ReleaseAndRegisterBuffers();
}
}
}
u32 Manager::GetAudioOutDeviceNames(
std::vector<Renderer::AudioDevice::AudioDeviceName>& names) const {
names.emplace_back("DeviceOut");
return 1;
}
} // namespace AudioCore::AudioOut
+15 -8
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -32,32 +29,42 @@ public:
* @param session_id - Output session_id.
* @return Result code.
*/
Result AcquireSessionId(Core::System& system, size_t& session_id);
Result AcquireSessionId(size_t& session_id);
/**
* Release a session id on close.
*
* @param session_id - Session id to free.
*/
void ReleaseSessionId(Core::System& system, const size_t session_id);
void ReleaseSessionId(size_t session_id);
/**
* Link this manager to the main audio manager.
*
* @return Result code.
*/
Result LinkToManager(Core::System& system);
Result LinkToManager();
/**
* Start the audio out manager.
*/
void Start(Core::System& system);
void Start();
/**
* Callback function, called by the audio manager when the audio out event is signalled.
*/
static void BufferReleaseAndRegister(void* data, Core::System& system) noexcept;
void BufferReleaseAndRegister();
/**
* Get a list of audio out device names.
*
* @param names - Output container to write names to.
* @return Number of names written.
*/
u32 GetAudioOutDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names) const;
/// Core system
Core::System& system;
/// Array of session ids
std::array<size_t, MaxOutSessions> session_ids{};
/// Array of resource user ids
+3 -8
View File
@@ -1,20 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/audio_render_manager.h"
#include "audio_core/common/audio_renderer_parameter.h"
#include "audio_core/renderer/system_manager.h"
#include "audio_core/common/feature_support.h"
#include "core/core.h"
namespace AudioCore::Renderer {
Manager::Manager(Core::System& system_)
: system_manager{std::make_unique<SystemManager>(system_)}
{
: system{system_}, system_manager{std::make_unique<SystemManager>(system)} {
std::iota(session_ids.begin(), session_ids.end(), 0);
}
@@ -64,11 +59,11 @@ u32 Manager::GetSessionCount() const {
return session_count;
}
bool Manager::AddSystem(Renderer::System& system_) {
bool Manager::AddSystem(System& system_) {
return system_manager->Add(system_);
}
bool Manager::RemoveSystem(Renderer::System& system_) {
bool Manager::RemoveSystem(System& system_) {
return system_manager->Remove(system_);
}
+4 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -74,7 +71,7 @@ public:
* @param system - The system to add.
* @return True if the system was successfully added, otherwise false.
*/
bool AddSystem(Renderer::System& system);
bool AddSystem(System& system);
/**
* Remove a renderer system from the manager.
@@ -82,7 +79,7 @@ public:
* @param system - The system to remove.
* @return True if the system was successfully removed, otherwise false.
*/
bool RemoveSystem(Renderer::System& system);
bool RemoveSystem(System& system);
/**
* Free a session id when the system wants to shut down.
@@ -92,6 +89,8 @@ public:
void ReleaseSessionId(s32 session_id);
private:
/// Core system
Core::System& system;
/// Session ids, -1 when in use
std::array<s32, MaxRendererSessions> session_ids{};
/// Number of active renderers
+22 -18
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -19,9 +16,8 @@ namespace AudioCore {
*/
class WorkbufferAllocator {
public:
explicit WorkbufferAllocator(std::span<u8> buffer_)
: buffer{buffer_}
{}
explicit WorkbufferAllocator(std::span<u8> buffer_, u64 size_)
: buffer{reinterpret_cast<u64>(buffer_.data())}, size{size_} {}
/**
* Allocate the given count of T elements, aligned to alignment.
@@ -33,31 +29,36 @@ public:
template <typename T>
std::span<T> Allocate(u64 count, u64 alignment) {
u64 out{0};
u64 byte_size = count * sizeof(T);
u64 byte_size{count * sizeof(T)};
if (byte_size > 0) {
auto current{uintptr_t(buffer.data()) + offset};
auto current{buffer + offset};
auto aligned_buffer{Common::AlignUp(current, alignment)};
if (aligned_buffer + byte_size <= uintptr_t(buffer.data()) + buffer.size()) {
if (aligned_buffer + byte_size <= buffer + size) {
out = aligned_buffer;
offset = byte_size - uintptr_t(buffer.data()) + aligned_buffer;
offset = byte_size - buffer + aligned_buffer;
} else {
LOG_ERROR(
Service_Audio,
"Allocated buffer was too small to hold new alloc.\nAllocator size={:08X}, "
"offset={:08X}.\nAttempting to allocate {:08X} with alignment={:02X}",
buffer.size(), offset, byte_size, alignment);
size, offset, byte_size, alignment);
count = 0;
}
}
return std::span<T>(reinterpret_cast<T*>(out), count);
}
/// @brief Align the current offset to the given alignment.
/// @param alignment - The required starting alignment.
/**
* Align the current offset to the given alignment.
*
* @param alignment - The required starting alignment.
*/
void Align(u64 alignment) {
auto current{uintptr_t(buffer.data()) + offset};
auto current{buffer + offset};
auto aligned_buffer{Common::AlignUp(current, alignment)};
offset = 0 - uintptr_t(buffer.data()) + aligned_buffer;
offset = 0 - buffer + aligned_buffer;
}
/**
@@ -75,7 +76,7 @@ public:
* @return The size of the current buffer.
*/
u64 GetSize() const {
return buffer.size();
return size;
}
/**
@@ -84,11 +85,14 @@ public:
* @return The remaining size left in the buffer.
*/
u64 GetRemainingSize() const {
return buffer.size() - offset;
return size - offset;
}
private:
const std::span<u8> buffer;
/// The buffer into which we are allocating.
u64 buffer;
/// Size of the buffer we're allocating to.
u64 size;
/// Current offset into the buffer, an error will be thrown if it exceeds size.
u64 offset{};
};
+20 -24
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,43 +8,42 @@
namespace AudioCore::AudioIn {
In::In(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}
, audio_system{system_, event, session_id_}
{}
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
session_id_} {}
void In::Free(Core::System& system) {
void In::Free() {
std::scoped_lock l{parent_mutex};
manager.ReleaseSessionId(system, audio_system.GetSessionId());
manager.ReleaseSessionId(system.GetSessionId());
}
System& In::GetSystem() {
return audio_system;
return system;
}
AudioIn::State In::GetState() {
std::scoped_lock l{parent_mutex};
return audio_system.GetState();
return system.GetState();
}
Result In::StartSystem() {
std::scoped_lock l{parent_mutex};
return audio_system.Start();
return system.Start();
}
void In::StartSession() {
std::scoped_lock l{parent_mutex};
audio_system.StartSession();
system.StartSession();
}
Result In::StopSystem() {
std::scoped_lock l{parent_mutex};
return audio_system.Stop();
return system.Stop();
}
Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
std::scoped_lock l{parent_mutex};
if (audio_system.AppendBuffer(buffer, tag)) {
if (system.AppendBuffer(buffer, tag)) {
return ResultSuccess;
}
return Service::Audio::ResultBufferCountReached;
@@ -55,20 +51,20 @@ Result In::AppendBuffer(const AudioInBuffer& buffer, u64 tag) {
void In::ReleaseAndRegisterBuffers() {
std::scoped_lock l{parent_mutex};
if (audio_system.GetState() == State::Started) {
audio_system.ReleaseBuffers();
audio_system.RegisterBuffers();
if (system.GetState() == State::Started) {
system.ReleaseBuffers();
system.RegisterBuffers();
}
}
bool In::FlushAudioInBuffers() {
std::scoped_lock l{parent_mutex};
return audio_system.FlushAudioInBuffers();
return system.FlushAudioInBuffers();
}
u32 In::GetReleasedBuffers(std::span<u64> tags) {
std::scoped_lock l{parent_mutex};
return audio_system.GetReleasedBuffers(tags);
return system.GetReleasedBuffers(tags);
}
Kernel::KReadableEvent& In::GetBufferEvent() {
@@ -78,27 +74,27 @@ Kernel::KReadableEvent& In::GetBufferEvent() {
f32 In::GetVolume() const {
std::scoped_lock l{parent_mutex};
return audio_system.GetVolume();
return system.GetVolume();
}
void In::SetVolume(f32 volume) {
std::scoped_lock l{parent_mutex};
audio_system.SetVolume(volume);
system.SetVolume(volume);
}
bool In::ContainsAudioBuffer(u64 tag) const {
std::scoped_lock l{parent_mutex};
return audio_system.ContainsAudioBuffer(tag);
return system.ContainsAudioBuffer(tag);
}
u32 In::GetBufferCount() const {
std::scoped_lock l{parent_mutex};
return audio_system.GetBufferCount();
return system.GetBufferCount();
}
u64 In::GetPlayedSampleCount() const {
std::scoped_lock l{parent_mutex};
return audio_system.GetPlayedSampleCount();
return system.GetPlayedSampleCount();
}
} // namespace AudioCore::AudioIn
+2 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -33,7 +30,7 @@ public:
/**
* Free this audio in from the audio in manager.
*/
void Free(Core::System& system);
void Free();
/**
* Get this audio in's system.
@@ -144,7 +141,7 @@ private:
/// Buffer event, signalled when buffers are ready to be released
Kernel::KEvent* event;
/// Main audio in system
System audio_system;
System system;
};
} // namespace AudioCore::AudioIn
+20 -24
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,43 +8,42 @@
namespace AudioCore::AudioOut {
Out::Out(Core::System& system_, Manager& manager_, Kernel::KEvent* event_, size_t session_id_)
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}
, audio_system{system_, event, session_id_}
{}
: manager{manager_}, parent_mutex{manager.mutex}, event{event_}, system{system_, event,
session_id_} {}
void Out::Free(Core::System& system) {
void Out::Free() {
std::scoped_lock l{parent_mutex};
manager.ReleaseSessionId(system, audio_system.GetSessionId());
manager.ReleaseSessionId(system.GetSessionId());
}
System& Out::GetSystem() {
return audio_system;
return system;
}
AudioOut::State Out::GetState() {
std::scoped_lock l{parent_mutex};
return audio_system.GetState();
return system.GetState();
}
Result Out::StartSystem() {
std::scoped_lock l{parent_mutex};
return audio_system.Start();
return system.Start();
}
void Out::StartSession() {
std::scoped_lock l{parent_mutex};
audio_system.StartSession();
system.StartSession();
}
Result Out::StopSystem() {
std::scoped_lock l{parent_mutex};
return audio_system.Stop();
return system.Stop();
}
Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
std::scoped_lock l{parent_mutex};
if (audio_system.AppendBuffer(buffer, tag)) {
if (system.AppendBuffer(buffer, tag)) {
return ResultSuccess;
}
return Service::Audio::ResultBufferCountReached;
@@ -55,20 +51,20 @@ Result Out::AppendBuffer(const AudioOutBuffer& buffer, const u64 tag) {
void Out::ReleaseAndRegisterBuffers() {
std::scoped_lock l{parent_mutex};
if (audio_system.GetState() == State::Started) {
audio_system.ReleaseBuffers();
audio_system.RegisterBuffers();
if (system.GetState() == State::Started) {
system.ReleaseBuffers();
system.RegisterBuffers();
}
}
bool Out::FlushAudioOutBuffers() {
std::scoped_lock l{parent_mutex};
return audio_system.FlushAudioOutBuffers();
return system.FlushAudioOutBuffers();
}
u32 Out::GetReleasedBuffers(std::span<u64> tags) {
std::scoped_lock l{parent_mutex};
return audio_system.GetReleasedBuffers(tags);
return system.GetReleasedBuffers(tags);
}
Kernel::KReadableEvent& Out::GetBufferEvent() {
@@ -78,27 +74,27 @@ Kernel::KReadableEvent& Out::GetBufferEvent() {
f32 Out::GetVolume() const {
std::scoped_lock l{parent_mutex};
return audio_system.GetVolume();
return system.GetVolume();
}
void Out::SetVolume(const f32 volume) {
std::scoped_lock l{parent_mutex};
audio_system.SetVolume(volume);
system.SetVolume(volume);
}
bool Out::ContainsAudioBuffer(const u64 tag) const {
std::scoped_lock l{parent_mutex};
return audio_system.ContainsAudioBuffer(tag);
return system.ContainsAudioBuffer(tag);
}
u32 Out::GetBufferCount() const {
std::scoped_lock l{parent_mutex};
return audio_system.GetBufferCount();
return system.GetBufferCount();
}
u64 Out::GetPlayedSampleCount() const {
std::scoped_lock l{parent_mutex};
return audio_system.GetPlayedSampleCount();
return system.GetPlayedSampleCount();
}
} // namespace AudioCore::AudioOut
+2 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -33,7 +30,7 @@ public:
/**
* Free this audio out from the audio out manager.
*/
void Free(Core::System& system);
void Free();
/**
* Get this audio out's system.
@@ -144,7 +141,7 @@ private:
/// Buffer event, signalled when buffers are ready to be released
Kernel::KEvent* event;
/// Main audio out system
System audio_system;
System system;
};
} // namespace AudioCore::AudioOut
+23 -18
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -16,48 +13,56 @@
namespace AudioCore::Renderer {
Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* rendered_event)
: system{system_}, manager{manager_}
, audio_system{system_, rendered_event}
{}
: core{system_}, manager{manager_}, system{system_, rendered_event} {}
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) {
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) {
if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(audio_system)) {
LOG_ERROR(Service_Audio, "Both Audio Render sessions are in use, cannot create any more");
if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio,
"Both Audio Render sessions are in use, cannot create any more");
return Service::Audio::ResultOutOfSessions;
}
system_registered = true;
}
initialized = true;
audio_system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, applet_resource_user_id, session_id);
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
applet_resource_user_id, session_id);
return ResultSuccess;
}
void Renderer::Finalize() {
auto const session_id{audio_system.GetSessionId()};
audio_system.Finalize();
auto session_id{system.GetSessionId()};
system.Finalize();
if (system_registered) {
manager.RemoveSystem(audio_system);
manager.RemoveSystem(system);
system_registered = false;
}
manager.ReleaseSessionId(session_id);
}
System& Renderer::GetSystem() {
return audio_system;
return system;
}
void Renderer::Start() {
audio_system.Start();
system.Start();
}
void Renderer::Stop() {
audio_system.Stop();
system.Stop();
}
Result Renderer::RequestUpdate(std::span<const u8> input, std::span<u8> performance, std::span<u8> output) {
return audio_system.Update(input, performance, output);
Result Renderer::RequestUpdate(std::span<const u8> input, std::span<u8> performance,
std::span<u8> output) {
return system.Update(input, performance, output);
}
} // namespace AudioCore::Renderer
+2 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -87,7 +84,7 @@ public:
private:
/// System core
Core::System& system;
Core::System& core;
/// Manager this renderer is registered with
Manager& manager;
/// Is the audio renderer initialized?
@@ -95,7 +92,7 @@ private:
/// Is the system registered with the manager?
bool system_registered{};
/// Audio render system, main driver of audio rendering
System audio_system;
System system;
};
} // namespace Renderer
+1 -1
View File
@@ -145,7 +145,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
PoolMapper pool_mapper(process_handle, false);
pool_mapper.InitializeSystemPool(memory_pool_info, workbuffer.get(), workbuffer_size);
WorkbufferAllocator allocator({workbuffer.get(), workbuffer_size});
WorkbufferAllocator allocator({workbuffer.get(), workbuffer_size}, workbuffer_size);
samples_workbuffer =
allocator.Allocate<s32>((voice_channels + mix_buffer_count) * sample_count, 0x10);
+1 -1
View File
@@ -50,7 +50,7 @@ IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
}
IAudioIn::~IAudioIn() {
impl->Free(system);
impl->Free();
service_context.CloseEvent(event);
process->Close(system.Kernel());
}
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -68,7 +65,7 @@ Result IAudioInManager::OpenAudioInAuto(
Result IAudioInManager::ListAudioInsAutoFiltered(
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
LOG_DEBUG(Service_Audio, "called");
*out_count = impl->GetDeviceNames(system, out_audio_ins, true);
*out_count = impl->GetDeviceNames(out_audio_ins, true);
R_SUCCEED();
}
@@ -93,8 +90,8 @@ Result IAudioInManager::OpenAudioInProtocolSpecified(
size_t new_session_id{};
R_TRY(impl->LinkToManager(system));
R_TRY(impl->AcquireSessionId(system, 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);
+1 -1
View File
@@ -46,7 +46,7 @@ IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
}
IAudioOut::~IAudioOut() {
impl->Free(system);
impl->Free();
service_context.CloseEvent(event);
process->Close(system.Kernel());
}
@@ -77,8 +77,8 @@ Result IAudioOutManager::OpenAudioOutAuto(
}
size_t new_session_id{};
R_TRY(impl->LinkToManager(system));
R_TRY(impl->AcquireSessionId(system, 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,
@@ -137,7 +137,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{405, nullptr, "ListApplicationControlCacheEntryInfo"},
{406, nullptr, "GetApplicationControlProperty"},
{407, &IApplicationManagerInterface::ListApplicationTitle, "ListApplicationTitle"},
{408, nullptr, "ListApplicationIcon"},
{408, &IApplicationManagerInterface::ListApplicationIcon, "ListApplicationIcon"},
{411, nullptr, "Unknown411"}, //19.0.0+
{412, nullptr, "Unknown412"}, //19.0.0+
{413, nullptr, "Unknown413"}, //19.0.0+
@@ -848,4 +848,9 @@ void IApplicationManagerInterface::ListApplicationTitle(HLERequestContext& ctx)
IReadOnlyApplicationControlDataInterface(system).ListApplicationTitle(ctx);
}
void IApplicationManagerInterface::ListApplicationIcon(HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
IReadOnlyApplicationControlDataInterface(system).ListApplicationIcon(ctx);
}
} // namespace Service::NS
@@ -75,6 +75,7 @@ public:
u64 application_id);
void ListApplicationTitle(HLERequestContext& ctx);
void ListApplicationIcon(HLERequestContext& ctx);
private:
KernelHelpers::ServiceContext service_context;
@@ -14,12 +14,16 @@
#include <stb_image_resize.h>
#include <stb_image_write.h>
#include "common/logging.h"
#include "common/settings.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/result.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns_types.h"
#include "core/hle/service/ns/ns_results.h"
@@ -75,24 +79,26 @@ void SanitizeJPEGImageSize(std::vector<u8>& image) {
// IAsyncValue implementation for ListApplicationTitle
// https://switchbrew.org/wiki/NS_services#ListApplicationTitle
class IAsyncValueForListApplicationTitle final : public ServiceFramework<IAsyncValueForListApplicationTitle> {
class IAsyncValue final : public ServiceFramework<IAsyncValue> {
public:
explicit IAsyncValueForListApplicationTitle(Core::System& system_, s32 offset, s32 size)
: ServiceFramework{system_, "IAsyncValue"}, service_context{system_, "IAsyncValue"},
data_offset{offset}, data_size{size} {
explicit IAsyncValue(Core::System& system_, s32 offset, s32 size)
: ServiceFramework{system_, "IAsyncValue"}
, service_context{system_, "IAsyncValue"}
, data_offset{offset}
, data_size{size}
{
static const FunctionInfo functions[] = {
{0, &IAsyncValueForListApplicationTitle::GetSize, "GetSize"},
{1, &IAsyncValueForListApplicationTitle::Get, "Get"},
{2, &IAsyncValueForListApplicationTitle::Cancel, "Cancel"},
{3, &IAsyncValueForListApplicationTitle::GetErrorContext, "GetErrorContext"},
{0, D<&IAsyncValue::GetSize>, "GetSize"},
{1, D<&IAsyncValue::Get>, "Get"},
{2, D<&IAsyncValue::Cancel>, "Cancel"},
{3, D<&IAsyncValue::GetErrorContext>, "GetErrorContext"},
};
RegisterHandlers(functions);
completion_event = service_context.CreateEvent("IAsyncValue:Completion");
completion_event->GetReadableEvent().Signal(system.Kernel());
}
~IAsyncValueForListApplicationTitle() override {
~IAsyncValue() override {
service_context.CloseEvent(completion_event);
}
@@ -101,35 +107,24 @@ public:
}
private:
void GetSize(HLERequestContext& ctx) {
Result GetSize(Out<s64> out_data_size) {
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s64>(data_size);
*out_data_size = data_size;
R_SUCCEED();
}
void Get(HLERequestContext& ctx) {
Result Get(OutBuffer<BufferAttr_HipcMapAlias> out_data_offset) {
LOG_DEBUG(Service_NS, "called");
std::vector<u8> buffer(sizeof(s32));
std::memcpy(buffer.data(), &data_offset, sizeof(s32));
ctx.WriteBuffer(buffer);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
std::memcpy(out_data_offset.data(), &data_offset, sizeof(s32));
R_SUCCEED();
}
void Cancel(HLERequestContext& ctx) {
Result Cancel() {
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
void GetErrorContext(HLERequestContext& ctx) {
Result GetErrorContext() {
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* completion_event{};
s32 data_offset;
@@ -147,6 +142,7 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa
{3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{4, nullptr, "SelectApplicationDesiredLanguage"},
{5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData2>, "GetApplicationControlData"},
{10, &IReadOnlyApplicationControlDataInterface::ListApplicationIcon, "ListApplicationIcon"},
{13, &IReadOnlyApplicationControlDataInterface::ListApplicationTitle, "ListApplicationTitle"},
{19, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData3>, "GetApplicationControlData"},
};
@@ -163,8 +159,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}",
application_control_source, application_id);
const FileSys::PatchManager pm{application_id, system.GetFileSystemController(),
system.GetContentProvider()};
const FileSys::PatchManager pm{application_id, system.GetFileSystemController(), system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
const auto size = out_buffer.size();
@@ -172,8 +167,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
const auto total_size = sizeof(FileSys::RawNACP) + icon_size;
if (size < total_size) {
LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
size);
LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)", size);
R_THROW(ResultUnknown);
}
@@ -181,8 +175,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
const auto bytes = control.first->GetRawBytes();
std::memcpy(out_buffer.data(), bytes.data(), bytes.size());
} else {
LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero",
application_id);
LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero", application_id);
std::memset(out_buffer.data(), 0, sizeof(FileSys::RawNACP));
}
@@ -207,15 +200,12 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage(
// Convert to application language, get priority list
const auto application_language = ConvertToApplicationLanguage(language_code);
if (application_language == std::nullopt) {
LOG_ERROR(Service_NS, "Could not convert application language! language_code={}",
language_code);
LOG_ERROR(Service_NS, "Could not convert application language! language_code={}", language_code);
R_THROW(Service::NS::ResultApplicationLanguageNotFound);
}
const auto priority_list = GetApplicationLanguagePriorityList(*application_language);
if (!priority_list) {
LOG_ERROR(Service_NS,
"Could not find application language priorities! application_language={}",
*application_language);
LOG_ERROR(Service_NS, "Could not find application language priorities! application_language={}", *application_language);
R_THROW(Service::NS::ResultApplicationLanguageNotFound);
}
@@ -259,8 +249,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData2(
const auto nacp_size = sizeof(FileSys::RawNACP);
if (size < nacp_size) {
LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min={:08X})",
size, nacp_size);
LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min={:08X})", size, nacp_size);
R_THROW(ResultUnknown);
}
@@ -311,63 +300,83 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData2(
R_SUCCEED();
}
void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestContext& ctx) {
/*
IPC::RequestParser rp{ctx};
auto control_source = rp.PopRaw<u8>();
rp.Skip(7, false);
auto transfer_memory_size = rp.Pop<u64>();
*/
void IReadOnlyApplicationControlDataInterface::ListApplicationIcon(HLERequestContext& ctx) {
LOG_WARNING(Service_NS, "(stubbed)");
const auto app_ids_buffer = ctx.ReadBuffer();
const size_t app_count = app_ids_buffer.size() / sizeof(u64);
std::vector<u64> application_ids(app_count);
if (app_count > 0) {
std::memcpy(application_ids.data(), app_ids_buffer.data(), app_count * sizeof(u64));
}
const u64 app_count = app_ids_buffer.size() / sizeof(u64);
auto t_mem_obj = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(ctx.GetCopyHandle(0));
auto* t_mem = t_mem_obj.GetPointerUnsafe();
constexpr size_t title_entry_size = sizeof(FileSys::LanguageEntry);
const size_t total_data_size = app_count * title_entry_size;
constexpr s32 data_offset = 0;
size_t out_length = 0;
if (t_mem != nullptr && app_count > 0) {
auto& memory = system.ApplicationMemory();
const auto t_mem_address = t_mem->GetSourceAddress();
// u64 - app count
memory.WriteBlock(t_mem_address + out_length, &app_count, sizeof(u64));
out_length += sizeof(u64);
// [list of u64] - size of icons
for (size_t i = 0; i < app_count; ++i) {
const u64 app_id = application_ids[i];
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(),
system.GetContentProvider()};
const u64 app_id = app_ids_buffer[i];
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
FileSys::LanguageEntry entry{};
if (control.first != nullptr) {
entry = control.first->GetLanguageEntry();
u64 full_size = control.second->GetSize();
memory.WriteBlock(t_mem_address + out_length, &full_size, sizeof(u64));
out_length += sizeof(u64);
}
// [list of raw icon data]
std::vector<u8> full_icon_data;
for (size_t i = 0; i < app_count; ++i) {
const u64 app_id = app_ids_buffer[i];
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
auto const full_size = control.second->GetSize();
if (full_size > 0) {
full_icon_data.resize(full_size);
control.second->Read(full_icon_data.data(), full_size, 0);
memory.WriteBlock(t_mem_address + out_length, full_icon_data.data(), full_size);
out_length += full_size;
}
const size_t offset = i * title_entry_size;
memory.WriteBlock(t_mem_address + offset, &entry, title_entry_size);
}
}
auto async_value = std::make_shared<IAsyncValueForListApplicationTitle>(
system, data_offset, static_cast<s32>(total_data_size));
auto async_value = std::make_shared<IAsyncValue>(system, 0, s32(out_length));
IPC::ResponseBuilder rb{ctx, 2, 1, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(ctx, async_value->ReadableEvent());
rb.PushIpcInterface(ctx, std::move(async_value));
}
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData3(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_flags_a, Out<u32> out_flags_b,
Out<u32> out_actual_size, ApplicationControlSource application_control_source, u8 flag1, u8 flag2, u64 application_id) {
void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestContext& ctx) {
const auto app_ids_buffer = ctx.ReadBuffer();
const size_t app_count = app_ids_buffer.size() / sizeof(u64);
auto t_mem_obj = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(ctx.GetCopyHandle(0));
auto* t_mem = t_mem_obj.GetPointerUnsafe();
constexpr size_t title_entry_size = sizeof(FileSys::LanguageEntry);
const size_t total_data_size = app_count * title_entry_size;
constexpr s32 data_offset = 0;
if (t_mem != nullptr && app_count > 0) {
auto& memory = system.ApplicationMemory();
const auto t_mem_address = t_mem->GetSourceAddress();
for (size_t i = 0; i < app_count; ++i) {
const u64 app_id = app_ids_buffer[i];
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
FileSys::LanguageEntry entry{};
if (control.first != nullptr) {
entry = control.first->GetLanguageEntry();
}
const size_t offset = i * title_entry_size;
memory.WriteBlock(t_mem_address + offset, &entry, title_entry_size);
}
}
auto async_value = std::make_shared<IAsyncValue>(system, data_offset, s32(total_data_size));
IPC::ResponseBuilder rb{ctx, 2, 1, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(ctx, async_value->ReadableEvent());
rb.PushIpcInterface(ctx, std::move(async_value));
}
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData3(OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_flags_a, Out<u32> out_flags_b, Out<u32> out_actual_size, ApplicationControlSource application_control_source, u8 flag1, u8 flag2, u64 application_id) {
LOG_INFO(Service_NS, "called with control_source={}, flags=({:02X},{:02X}), application_id={:016X}",
application_control_source, flag1, flag2, application_id);
@@ -34,6 +34,7 @@ public:
u8 flag1,
u8 flag2,
u64 application_id);
void ListApplicationIcon(HLERequestContext& ctx);
void ListApplicationTitle(HLERequestContext& ctx);
Result GetApplicationControlData3(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -16,10 +16,8 @@ IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::S
static const FunctionInfo functions[] = {
{0, D<&IReadOnlyApplicationRecordInterface::HasApplicationRecord>, "HasApplicationRecord"},
{1, nullptr, "NotifyApplicationFailure"},
{2, D<&IReadOnlyApplicationRecordInterface::IsDataCorruptedResult>,
"IsDataCorruptedResult"},
{3, D<&IReadOnlyApplicationRecordInterface::ListApplicationRecord>,
"ListApplicationRecord"},
{2, D<&IReadOnlyApplicationRecordInterface::IsDataCorruptedResult>, "IsDataCorruptedResult"},
{3, D<&IReadOnlyApplicationRecordInterface::ListApplicationRecord>, "ListApplicationRecord"},
};
// clang-format on