committed by
GitHub
59 changed files with 1882 additions and 2056 deletions
-
1src/CMakeLists.txt
-
7src/audio_core/audio_in_manager.cpp
-
4src/audio_core/audio_in_manager.h
-
6src/audio_core/device/audio_buffers.h
-
6src/audio_core/opus/decoder.cpp
-
6src/audio_core/opus/decoder.h
-
18src/audio_core/opus/decoder_manager.cpp
-
16src/audio_core/opus/decoder_manager.h
-
13src/audio_core/opus/hardware_opus.cpp
-
6src/audio_core/opus/hardware_opus.h
-
4src/audio_core/opus/parameters.h
-
14src/audio_core/renderer/audio_device.cpp
-
6src/audio_core/renderer/audio_device.h
-
7src/audio_core/renderer/audio_renderer.cpp
-
4src/audio_core/renderer/audio_renderer.h
-
2src/audio_core/renderer/behavior/info_updater.cpp
-
10src/audio_core/renderer/behavior/info_updater.h
-
18src/audio_core/renderer/memory/pool_mapper.cpp
-
14src/audio_core/renderer/memory/pool_mapper.h
-
10src/audio_core/renderer/system.cpp
-
8src/audio_core/renderer/system.h
-
8src/audio_core/sink/oboe_sink.cpp
-
4src/common/string_util.cpp
-
1src/common/string_util.h
-
38src/core/CMakeLists.txt
-
393src/core/hle/service/audio/audin_u.cpp
-
38src/core/hle/service/audio/audin_u.h
-
28src/core/hle/service/audio/audio.cpp
-
31src/core/hle/service/audio/audio_controller.cpp
-
1src/core/hle/service/audio/audio_controller.h
-
163src/core/hle/service/audio/audio_device.cpp
-
58src/core/hle/service/audio/audio_device.h
-
146src/core/hle/service/audio/audio_in.cpp
-
53src/core/hle/service/audio/audio_in.h
-
125src/core/hle/service/audio/audio_in_manager.cpp
-
57src/core/hle/service/audio/audio_in_manager.h
-
146src/core/hle/service/audio/audio_out.cpp
-
58src/core/hle/service/audio/audio_out.h
-
101src/core/hle/service/audio/audio_out_manager.cpp
-
44src/core/hle/service/audio/audio_out_manager.h
-
139src/core/hle/service/audio/audio_renderer.cpp
-
54src/core/hle/service/audio/audio_renderer.h
-
104src/core/hle/service/audio/audio_renderer_manager.cpp
-
37src/core/hle/service/audio/audio_renderer_manager.h
-
323src/core/hle/service/audio/audout_u.cpp
-
37src/core/hle/service/audio/audout_u.h
-
552src/core/hle/service/audio/audren_u.cpp
-
35src/core/hle/service/audio/audren_u.h
-
7src/core/hle/service/audio/final_output_recorder_manager.cpp
-
6src/core/hle/service/audio/final_output_recorder_manager.h
-
7src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
-
7src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
-
145src/core/hle/service/audio/hardware_opus_decoder.cpp
-
63src/core/hle/service/audio/hardware_opus_decoder.h
-
156src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
-
53src/core/hle/service/audio/hardware_opus_decoder_manager.h
-
502src/core/hle/service/audio/hwopus.cpp
-
36src/core/hle/service/audio/hwopus.h
-
2src/core/hle/service/cmif_serialization.h
@ -1,393 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "audio_core/in/audio_in_system.h"
|
|||
#include "audio_core/renderer/audio_device.h"
|
|||
#include "common/common_funcs.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "common/scratch_buffer.h"
|
|||
#include "common/string_util.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hle/kernel/k_event.h"
|
|||
#include "core/hle/service/audio/audin_u.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::AudioIn; |
|||
|
|||
class IAudioIn final : public ServiceFramework<IAudioIn> { |
|||
public: |
|||
explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, |
|||
const std::string& device_name, const AudioInParameter& in_params, |
|||
Kernel::KProcess* handle, u64 applet_resource_user_id) |
|||
: ServiceFramework{system_, "IAudioIn"}, |
|||
service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, |
|||
process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IAudioIn::GetAudioInState, "GetAudioInState"}, |
|||
{1, &IAudioIn::Start, "Start"}, |
|||
{2, &IAudioIn::Stop, "Stop"}, |
|||
{3, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBuffer"}, |
|||
{4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"}, |
|||
{5, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffer"}, |
|||
{6, &IAudioIn::ContainsAudioInBuffer, "ContainsAudioInBuffer"}, |
|||
{7, &IAudioIn::AppendAudioInBuffer, "AppendUacInBuffer"}, |
|||
{8, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBufferAuto"}, |
|||
{9, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffersAuto"}, |
|||
{10, &IAudioIn::AppendAudioInBuffer, "AppendUacInBufferAuto"}, |
|||
{11, &IAudioIn::GetAudioInBufferCount, "GetAudioInBufferCount"}, |
|||
{12, &IAudioIn::SetDeviceGain, "SetDeviceGain"}, |
|||
{13, &IAudioIn::GetDeviceGain, "GetDeviceGain"}, |
|||
{14, &IAudioIn::FlushAudioInBuffers, "FlushAudioInBuffers"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
|
|||
process->Open(); |
|||
|
|||
if (impl->GetSystem() |
|||
.Initialize(device_name, in_params, handle, applet_resource_user_id) |
|||
.IsError()) { |
|||
LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!"); |
|||
} |
|||
} |
|||
|
|||
~IAudioIn() override { |
|||
impl->Free(); |
|||
service_context.CloseEvent(event); |
|||
process->Close(); |
|||
} |
|||
|
|||
[[nodiscard]] std::shared_ptr<In> GetImpl() { |
|||
return impl; |
|||
} |
|||
|
|||
private: |
|||
void GetAudioInState(HLERequestContext& ctx) { |
|||
const auto state = static_cast<u32>(impl->GetState()); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. State={}", state); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(state); |
|||
} |
|||
|
|||
void Start(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto result = impl->StartSystem(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void Stop(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto result = impl->StopSystem(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void AppendAudioInBuffer(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
u64 tag = rp.PopRaw<u64>(); |
|||
|
|||
const auto in_buffer_size{ctx.GetReadBufferSize()}; |
|||
if (in_buffer_size < sizeof(AudioInBuffer)) { |
|||
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!"); |
|||
} |
|||
|
|||
const auto& in_buffer = ctx.ReadBuffer(); |
|||
AudioInBuffer buffer{}; |
|||
std::memcpy(&buffer, in_buffer.data(), sizeof(AudioInBuffer)); |
|||
|
|||
[[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()}; |
|||
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag); |
|||
|
|||
auto result = impl->AppendBuffer(buffer, tag); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void RegisterBufferEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto& buffer_event = impl->GetBufferEvent(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(buffer_event); |
|||
} |
|||
|
|||
void GetReleasedAudioInBuffer(HLERequestContext& ctx) { |
|||
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); |
|||
released_buffer.resize_destructive(write_buffer_size); |
|||
released_buffer[0] = 0; |
|||
|
|||
const auto count = impl->GetReleasedBuffers(released_buffer); |
|||
|
|||
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers", |
|||
impl->GetSystem().GetSessionId(), count); |
|||
|
|||
ctx.WriteBuffer(released_buffer); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(count); |
|||
} |
|||
|
|||
void ContainsAudioInBuffer(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const u64 tag{rp.Pop<u64>()}; |
|||
const auto buffer_queued{impl->ContainsAudioBuffer(tag)}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(buffer_queued); |
|||
} |
|||
|
|||
void GetAudioInBufferCount(HLERequestContext& ctx) { |
|||
const auto buffer_count = impl->GetBufferCount(); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(buffer_count); |
|||
} |
|||
|
|||
void SetDeviceGain(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const auto volume{rp.Pop<f32>()}; |
|||
LOG_DEBUG(Service_Audio, "called. Gain {}", volume); |
|||
|
|||
impl->SetVolume(volume); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void GetDeviceGain(HLERequestContext& ctx) { |
|||
auto volume{impl->GetVolume()}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Gain {}", volume); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(volume); |
|||
} |
|||
|
|||
void FlushAudioInBuffers(HLERequestContext& ctx) { |
|||
bool flushed{impl->FlushAudioInBuffers()}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(flushed); |
|||
} |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
Kernel::KEvent* event; |
|||
Kernel::KProcess* process; |
|||
std::shared_ptr<AudioCore::AudioIn::In> impl; |
|||
Common::ScratchBuffer<u64> released_buffer; |
|||
}; |
|||
|
|||
AudInU::AudInU(Core::System& system_) |
|||
: ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"}, |
|||
impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &AudInU::ListAudioIns, "ListAudioIns"}, |
|||
{1, &AudInU::OpenAudioIn, "OpenAudioIn"}, |
|||
{2, &AudInU::ListAudioIns, "ListAudioInsAuto"}, |
|||
{3, &AudInU::OpenAudioIn, "OpenAudioInAuto"}, |
|||
{4, &AudInU::ListAudioInsAutoFiltered, "ListAudioInsAutoFiltered"}, |
|||
{5, &AudInU::OpenAudioInProtocolSpecified, "OpenAudioInProtocolSpecified"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
AudInU::~AudInU() = default; |
|||
|
|||
void AudInU::ListAudioIns(HLERequestContext& ctx) { |
|||
using namespace AudioCore::Renderer; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
const auto write_count = |
|||
static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); |
|||
std::vector<AudioDevice::AudioDeviceName> device_names{}; |
|||
|
|||
u32 out_count{0}; |
|||
if (write_count > 0) { |
|||
out_count = impl->GetDeviceNames(device_names, write_count, false); |
|||
ctx.WriteBuffer(device_names); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(out_count); |
|||
} |
|||
|
|||
void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) { |
|||
using namespace AudioCore::Renderer; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
const auto write_count = |
|||
static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); |
|||
std::vector<AudioDevice::AudioDeviceName> device_names{}; |
|||
|
|||
u32 out_count{0}; |
|||
if (write_count > 0) { |
|||
out_count = impl->GetDeviceNames(device_names, write_count, true); |
|||
ctx.WriteBuffer(device_names); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(out_count); |
|||
} |
|||
|
|||
void AudInU::OpenAudioIn(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
auto in_params{rp.PopRaw<AudioInParameter>()}; |
|||
auto applet_resource_user_id{rp.PopRaw<u64>()}; |
|||
const auto device_name_data{ctx.ReadBuffer()}; |
|||
auto device_name = Common::StringFromBuffer(device_name_data); |
|||
auto handle{ctx.GetCopyHandle(0)}; |
|||
|
|||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; |
|||
if (process.IsNull()) { |
|||
LOG_ERROR(Service_Audio, "Failed to get process handle"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
std::scoped_lock l{impl->mutex}; |
|||
auto link{impl->LinkToManager()}; |
|||
if (link.IsError()) { |
|||
LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(link); |
|||
return; |
|||
} |
|||
|
|||
size_t new_session_id{}; |
|||
auto result{impl->AcquireSessionId(new_session_id)}; |
|||
if (result.IsError()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
return; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, |
|||
impl->num_free_sessions); |
|||
|
|||
auto audio_in = |
|||
std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, |
|||
process.GetPointerUnsafe(), applet_resource_user_id); |
|||
impl->sessions[new_session_id] = audio_in->GetImpl(); |
|||
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; |
|||
|
|||
auto& out_system = impl->sessions[new_session_id]->GetSystem(); |
|||
AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(), |
|||
.channel_count = out_system.GetChannelCount(), |
|||
.sample_format = |
|||
static_cast<u32>(out_system.GetSampleFormat()), |
|||
.state = static_cast<u32>(out_system.GetState())}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6, 0, 1}; |
|||
|
|||
std::string out_name{out_system.GetName()}; |
|||
ctx.WriteBuffer(out_name); |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw<AudioInParameterInternal>(out_params); |
|||
rb.PushIpcInterface<IAudioIn>(audio_in); |
|||
} |
|||
|
|||
void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
auto protocol_specified{rp.PopRaw<u64>()}; |
|||
auto in_params{rp.PopRaw<AudioInParameter>()}; |
|||
auto applet_resource_user_id{rp.PopRaw<u64>()}; |
|||
const auto device_name_data{ctx.ReadBuffer()}; |
|||
auto device_name = Common::StringFromBuffer(device_name_data); |
|||
auto handle{ctx.GetCopyHandle(0)}; |
|||
|
|||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; |
|||
if (process.IsNull()) { |
|||
LOG_ERROR(Service_Audio, "Failed to get process handle"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
std::scoped_lock l{impl->mutex}; |
|||
auto link{impl->LinkToManager()}; |
|||
if (link.IsError()) { |
|||
LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(link); |
|||
return; |
|||
} |
|||
|
|||
size_t new_session_id{}; |
|||
auto result{impl->AcquireSessionId(new_session_id)}; |
|||
if (result.IsError()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
return; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, |
|||
impl->num_free_sessions); |
|||
|
|||
auto audio_in = |
|||
std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, |
|||
process.GetPointerUnsafe(), applet_resource_user_id); |
|||
impl->sessions[new_session_id] = audio_in->GetImpl(); |
|||
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; |
|||
|
|||
auto& out_system = impl->sessions[new_session_id]->GetSystem(); |
|||
AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(), |
|||
.channel_count = out_system.GetChannelCount(), |
|||
.sample_format = |
|||
static_cast<u32>(out_system.GetSampleFormat()), |
|||
.state = static_cast<u32>(out_system.GetState())}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6, 0, 1}; |
|||
|
|||
std::string out_name{out_system.GetName()}; |
|||
if (protocol_specified == 0) { |
|||
if (out_system.IsUac()) { |
|||
out_name = "UacIn"; |
|||
} else { |
|||
out_name = "DeviceIn"; |
|||
} |
|||
} |
|||
|
|||
ctx.WriteBuffer(out_name); |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw<AudioInParameterInternal>(out_params); |
|||
rb.PushIpcInterface<IAudioIn>(audio_in); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -1,38 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/audio_in_manager.h" |
|||
#include "audio_core/in/audio_in.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} |
|||
|
|||
namespace AudioCore::AudioOut { |
|||
class Manager; |
|||
class In; |
|||
} // namespace AudioCore::AudioOut |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class AudInU final : public ServiceFramework<AudInU> { |
|||
public: |
|||
explicit AudInU(Core::System& system_); |
|||
~AudInU() override; |
|||
|
|||
private: |
|||
void ListAudioIns(HLERequestContext& ctx); |
|||
void ListAudioInsAutoFiltered(HLERequestContext& ctx); |
|||
void OpenInOutImpl(HLERequestContext& ctx); |
|||
void OpenAudioIn(HLERequestContext& ctx); |
|||
void OpenAudioInProtocolSpecified(HLERequestContext& ctx); |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
std::unique_ptr<AudioCore::AudioIn::Manager> impl; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,163 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "audio_core/audio_core.h"
|
|||
#include "common/string_util.h"
|
|||
#include "core/hle/service/audio/audio_device.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::Renderer; |
|||
|
|||
IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision, |
|||
u32 device_num) |
|||
: ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"}, |
|||
impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)}, |
|||
event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} { |
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"}, |
|||
{1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"}, |
|||
{2, D<&IAudioDevice::GetAudioDeviceOutputVolume>, "GetAudioDeviceOutputVolume"}, |
|||
{3, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioDeviceName"}, |
|||
{4, D<&IAudioDevice::QueryAudioDeviceSystemEvent>, "QueryAudioDeviceSystemEvent"}, |
|||
{5, D<&IAudioDevice::GetActiveChannelCount>, "GetActiveChannelCount"}, |
|||
{6, D<&IAudioDevice::ListAudioDeviceNameAuto>, "ListAudioDeviceNameAuto"}, |
|||
{7, D<&IAudioDevice::SetAudioDeviceOutputVolumeAuto>, "SetAudioDeviceOutputVolumeAuto"}, |
|||
{8, D<&IAudioDevice::GetAudioDeviceOutputVolumeAuto>, "GetAudioDeviceOutputVolumeAuto"}, |
|||
{10, D<&IAudioDevice::GetActiveAudioDeviceNameAuto>, "GetActiveAudioDeviceNameAuto"}, |
|||
{11, D<&IAudioDevice::QueryAudioDeviceInputEvent>, "QueryAudioDeviceInputEvent"}, |
|||
{12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"}, |
|||
{13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"}, |
|||
{14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"}, |
|||
}; |
|||
RegisterHandlers(functions); |
|||
|
|||
event->Signal(); |
|||
} |
|||
|
|||
IAudioDevice::~IAudioDevice() { |
|||
service_context.CloseEvent(event); |
|||
} |
|||
|
|||
Result IAudioDevice::ListAudioDeviceName( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) { |
|||
R_RETURN(this->ListAudioDeviceNameAuto(out_names, out_count)); |
|||
} |
|||
|
|||
Result IAudioDevice::SetAudioDeviceOutputVolume( |
|||
InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume) { |
|||
R_RETURN(this->SetAudioDeviceOutputVolumeAuto(name, volume)); |
|||
} |
|||
|
|||
Result IAudioDevice::GetAudioDeviceOutputVolume( |
|||
Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name) { |
|||
R_RETURN(this->GetAudioDeviceOutputVolumeAuto(out_volume, name)); |
|||
} |
|||
|
|||
Result IAudioDevice::GetActiveAudioDeviceName( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name) { |
|||
R_RETURN(this->GetActiveAudioDeviceNameAuto(out_name)); |
|||
} |
|||
|
|||
Result IAudioDevice::ListAudioDeviceNameAuto( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names, |
|||
Out<s32> out_count) { |
|||
*out_count = impl->ListAudioDeviceName(out_names); |
|||
|
|||
std::string out{}; |
|||
for (s32 i = 0; i < *out_count; i++) { |
|||
std::string a{}; |
|||
u32 j = 0; |
|||
while (out_names[i].name[j] != '\0') { |
|||
a += out_names[i].name[j]; |
|||
j++; |
|||
} |
|||
out += "\n\t" + a; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "called.\nNames={}", out); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioDevice::SetAudioDeviceOutputVolumeAuto( |
|||
InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume) { |
|||
R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer); |
|||
|
|||
const std::string device_name = Common::StringFromBuffer(name[0].name); |
|||
LOG_DEBUG(Service_Audio, "called. name={}, volume={}", device_name, volume); |
|||
|
|||
if (device_name == "AudioTvOutput") { |
|||
impl->SetDeviceVolumes(volume); |
|||
} |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioDevice::GetAudioDeviceOutputVolumeAuto( |
|||
Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name) { |
|||
R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer); |
|||
|
|||
const std::string device_name = Common::StringFromBuffer(name[0].name); |
|||
LOG_DEBUG(Service_Audio, "called. Name={}", device_name); |
|||
|
|||
*out_volume = 1.0f; |
|||
if (device_name == "AudioTvOutput") { |
|||
*out_volume = impl->GetDeviceVolume(device_name); |
|||
} |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioDevice::GetActiveAudioDeviceNameAuto( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name) { |
|||
R_UNLESS(!out_name.empty(), Audio::ResultInsufficientBuffer); |
|||
out_name[0] = AudioDevice::AudioDeviceName("AudioTvOutput"); |
|||
LOG_DEBUG(Service_Audio, "(STUBBED) called"); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioDevice::QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { |
|||
LOG_DEBUG(Service_Audio, "(STUBBED) called"); |
|||
event->Signal(); |
|||
*out_event = &event->GetReadableEvent(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioDevice::QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { |
|||
LOG_DEBUG(Service_Audio, "(STUBBED) called"); |
|||
*out_event = &event->GetReadableEvent(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioDevice::QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
*out_event = &event->GetReadableEvent(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioDevice::GetActiveChannelCount(Out<u32> out_active_channel_count) { |
|||
*out_active_channel_count = system.AudioCore().GetOutputSink().GetSystemChannels(); |
|||
LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", *out_active_channel_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioDevice::ListAudioOutputDeviceName( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) { |
|||
*out_count = impl->ListAudioOutputDeviceName(out_names); |
|||
|
|||
std::string out{}; |
|||
for (s32 i = 0; i < *out_count; i++) { |
|||
std::string a{}; |
|||
u32 j = 0; |
|||
while (out_names[i].name[j] != '\0') { |
|||
a += out_names[i].name[j]; |
|||
j++; |
|||
} |
|||
out += "\n\t" + a; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "called.\nNames={}", out); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,58 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/renderer/audio_device.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Kernel { |
|||
class KReadableEvent; |
|||
} |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
using AudioCore::Renderer::AudioDevice; |
|||
|
|||
class IAudioDevice final : public ServiceFramework<IAudioDevice> { |
|||
|
|||
public: |
|||
explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision, |
|||
u32 device_num); |
|||
~IAudioDevice() override; |
|||
|
|||
private: |
|||
Result ListAudioDeviceName( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, |
|||
Out<s32> out_count); |
|||
Result SetAudioDeviceOutputVolume( |
|||
InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume); |
|||
Result GetAudioDeviceOutputVolume( |
|||
Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name); |
|||
Result GetActiveAudioDeviceName( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name); |
|||
Result ListAudioDeviceNameAuto( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names, |
|||
Out<s32> out_count); |
|||
Result SetAudioDeviceOutputVolumeAuto( |
|||
InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume); |
|||
Result GetAudioDeviceOutputVolumeAuto( |
|||
Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name); |
|||
Result GetActiveAudioDeviceNameAuto( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name); |
|||
Result QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); |
|||
Result QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); |
|||
Result QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); |
|||
Result GetActiveChannelCount(Out<u32> out_active_channel_count); |
|||
Result ListAudioOutputDeviceName( |
|||
OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, |
|||
Out<s32> out_count); |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
std::unique_ptr<AudioCore::Renderer::AudioDevice> impl; |
|||
Kernel::KEvent* event; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,146 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/audio/audio_in.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::AudioIn; |
|||
|
|||
IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id, |
|||
const std::string& device_name, const AudioInParameter& in_params, |
|||
Kernel::KProcess* handle, u64 applet_resource_user_id) |
|||
: ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"}, |
|||
event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_, |
|||
manager, event, |
|||
session_id)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IAudioIn::GetAudioInState>, "GetAudioInState"}, |
|||
{1, D<&IAudioIn::Start>, "Start"}, |
|||
{2, D<&IAudioIn::Stop>, "Stop"}, |
|||
{3, D<&IAudioIn::AppendAudioInBuffer>, "AppendAudioInBuffer"}, |
|||
{4, D<&IAudioIn::RegisterBufferEvent>, "RegisterBufferEvent"}, |
|||
{5, D<&IAudioIn::GetReleasedAudioInBuffers>, "GetReleasedAudioInBuffers"}, |
|||
{6, D<&IAudioIn::ContainsAudioInBuffer>, "ContainsAudioInBuffer"}, |
|||
{7, D<&IAudioIn::AppendAudioInBuffer>, "AppendUacInBuffer"}, |
|||
{8, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendAudioInBufferAuto"}, |
|||
{9, D<&IAudioIn::GetReleasedAudioInBuffersAuto>, "GetReleasedAudioInBuffersAuto"}, |
|||
{10, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendUacInBufferAuto"}, |
|||
{11, D<&IAudioIn::GetAudioInBufferCount>, "GetAudioInBufferCount"}, |
|||
{12, D<&IAudioIn::SetDeviceGain>, "SetDeviceGain"}, |
|||
{13, D<&IAudioIn::GetDeviceGain>, "GetDeviceGain"}, |
|||
{14, D<&IAudioIn::FlushAudioInBuffers>, "FlushAudioInBuffers"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
|
|||
process->Open(); |
|||
|
|||
if (impl->GetSystem() |
|||
.Initialize(device_name, in_params, handle, applet_resource_user_id) |
|||
.IsError()) { |
|||
LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!"); |
|||
} |
|||
} |
|||
|
|||
IAudioIn::~IAudioIn() { |
|||
impl->Free(); |
|||
service_context.CloseEvent(event); |
|||
process->Close(); |
|||
} |
|||
|
|||
Result IAudioIn::GetAudioInState(Out<u32> out_state) { |
|||
*out_state = static_cast<u32>(impl->GetState()); |
|||
LOG_DEBUG(Service_Audio, "called. state={}", *out_state); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioIn::Start() { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(impl->StartSystem()); |
|||
} |
|||
|
|||
Result IAudioIn::Stop() { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(impl->StopSystem()); |
|||
} |
|||
|
|||
Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer, |
|||
u64 buffer_client_ptr) { |
|||
R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr)); |
|||
} |
|||
|
|||
Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer, |
|||
u64 buffer_client_ptr) { |
|||
if (buffer.empty()) { |
|||
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!"); |
|||
R_THROW(Audio::ResultInsufficientBuffer); |
|||
} |
|||
|
|||
[[maybe_unused]] const auto session_id{impl->GetSystem().GetSessionId()}; |
|||
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", session_id, |
|||
buffer_client_ptr); |
|||
|
|||
R_RETURN(impl->AppendBuffer(buffer[0], buffer_client_ptr)); |
|||
} |
|||
|
|||
Result IAudioIn::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
*out_event = &impl->GetBufferEvent(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioIn::GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, |
|||
Out<u32> out_count) { |
|||
R_RETURN(this->GetReleasedAudioInBuffersAuto(out_audio_buffer, out_count)); |
|||
} |
|||
|
|||
Result IAudioIn::GetReleasedAudioInBuffersAuto( |
|||
OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) { |
|||
|
|||
if (!out_audio_buffer.empty()) { |
|||
out_audio_buffer[0] = 0; |
|||
} |
|||
*out_count = impl->GetReleasedBuffers(out_audio_buffer); |
|||
|
|||
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers", |
|||
impl->GetSystem().GetSessionId(), *out_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioIn::ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) { |
|||
*out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr, |
|||
*out_contains_buffer); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioIn::GetAudioInBufferCount(Out<u32> out_buffer_count) { |
|||
*out_buffer_count = impl->GetBufferCount(); |
|||
LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioIn::SetDeviceGain(f32 device_gain) { |
|||
impl->SetVolume(device_gain); |
|||
LOG_DEBUG(Service_Audio, "called. Gain {}", device_gain); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioIn::GetDeviceGain(Out<f32> out_device_gain) { |
|||
*out_device_gain = impl->GetVolume(); |
|||
LOG_DEBUG(Service_Audio, "called. Gain {}", *out_device_gain); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioIn::FlushAudioInBuffers(Out<bool> out_flushed) { |
|||
*out_flushed = impl->FlushAudioInBuffers(); |
|||
LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,53 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/in/audio_in.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class IAudioIn final : public ServiceFramework<IAudioIn> { |
|||
public: |
|||
explicit IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager, |
|||
size_t session_id, const std::string& device_name, |
|||
const AudioCore::AudioIn::AudioInParameter& in_params, |
|||
Kernel::KProcess* handle, u64 applet_resource_user_id); |
|||
~IAudioIn() override; |
|||
|
|||
std::shared_ptr<AudioCore::AudioIn::In> GetImpl() { |
|||
return impl; |
|||
} |
|||
|
|||
Result GetAudioInState(Out<u32> out_state); |
|||
Result Start(); |
|||
Result Stop(); |
|||
Result AppendAudioInBuffer( |
|||
InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer, |
|||
u64 buffer_client_ptr); |
|||
Result AppendAudioInBufferAuto( |
|||
InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer, |
|||
u64 buffer_client_ptr); |
|||
Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); |
|||
Result GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, |
|||
Out<u32> out_count); |
|||
Result GetReleasedAudioInBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, |
|||
Out<u32> out_count); |
|||
Result ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr); |
|||
Result GetAudioInBufferCount(Out<u32> out_buffer_count); |
|||
Result SetDeviceGain(f32 device_gain); |
|||
Result GetDeviceGain(Out<f32> out_device_gain); |
|||
Result FlushAudioInBuffers(Out<bool> out_flushed); |
|||
|
|||
private: |
|||
Kernel::KProcess* process; |
|||
KernelHelpers::ServiceContext service_context; |
|||
Kernel::KEvent* event; |
|||
std::shared_ptr<AudioCore::AudioIn::In> impl; |
|||
Common::ScratchBuffer<u64> released_buffer; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,125 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/string_util.h"
|
|||
#include "core/hle/service/audio/audio_in.h"
|
|||
#include "core/hle/service/audio/audio_in_manager.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::AudioIn; |
|||
|
|||
IAudioInManager::IAudioInManager(Core::System& system_) |
|||
: ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>( |
|||
system_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IAudioInManager::ListAudioIns>, "ListAudioIns"}, |
|||
{1, D<&IAudioInManager::OpenAudioIn>, "OpenAudioIn"}, |
|||
{2, D<&IAudioInManager::ListAudioIns>, "ListAudioInsAuto"}, |
|||
{3, D<&IAudioInManager::OpenAudioIn>, "OpenAudioInAuto"}, |
|||
{4, D<&IAudioInManager::ListAudioInsAutoFiltered>, "ListAudioInsAutoFiltered"}, |
|||
{5, D<&IAudioInManager::OpenAudioInProtocolSpecified>, "OpenAudioInProtocolSpecified"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IAudioInManager::~IAudioInManager() = default; |
|||
|
|||
Result IAudioInManager::ListAudioIns( |
|||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, Out<u32> out_count) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count)); |
|||
} |
|||
|
|||
Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal, |
|||
Out<SharedPointer<IAudioIn>> out_audio_in, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, |
|||
AudioInParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, |
|||
ClientAppletResourceUserId aruid) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name, |
|||
name, {}, parameter, process_handle, aruid)); |
|||
} |
|||
|
|||
Result IAudioInManager::ListAudioInsAuto( |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count)); |
|||
} |
|||
|
|||
Result IAudioInManager::OpenAudioInAuto( |
|||
Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name, |
|||
name, {}, parameter, process_handle, aruid)); |
|||
} |
|||
|
|||
Result IAudioInManager::ListAudioInsAutoFiltered( |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
*out_count = impl->GetDeviceNames(out_audio_ins, true); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioInManager::OpenAudioInProtocolSpecified( |
|||
Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol, |
|||
AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle, |
|||
ClientAppletResourceUserId aruid) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
if (!process_handle) { |
|||
LOG_ERROR(Service_Audio, "Failed to get process handle"); |
|||
R_THROW(ResultUnknown); |
|||
} |
|||
if (name.empty() || out_name.empty()) { |
|||
LOG_ERROR(Service_Audio, "Invalid buffers"); |
|||
R_THROW(ResultUnknown); |
|||
} |
|||
|
|||
std::scoped_lock l{impl->mutex}; |
|||
|
|||
size_t new_session_id{}; |
|||
|
|||
R_TRY(impl->LinkToManager()); |
|||
R_TRY(impl->AcquireSessionId(new_session_id)); |
|||
|
|||
LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id, |
|||
impl->num_free_sessions); |
|||
|
|||
const auto device_name = Common::StringFromBuffer(name[0].name); |
|||
*out_audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, |
|||
parameter, process_handle.Get(), aruid.pid); |
|||
impl->sessions[new_session_id] = (*out_audio_in)->GetImpl(); |
|||
impl->applet_resource_user_ids[new_session_id] = aruid.pid; |
|||
|
|||
auto& out_system = impl->sessions[new_session_id]->GetSystem(); |
|||
*out_parameter_internal = |
|||
AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(), |
|||
.channel_count = out_system.GetChannelCount(), |
|||
.sample_format = static_cast<u32>(out_system.GetSampleFormat()), |
|||
.state = static_cast<u32>(out_system.GetState())}; |
|||
|
|||
out_name[0] = AudioDeviceName(out_system.GetName()); |
|||
|
|||
if (protocol == Protocol{}) { |
|||
if (out_system.IsUac()) { |
|||
out_name[0] = AudioDeviceName("UacIn"); |
|||
} else { |
|||
out_name[0] = AudioDeviceName("DeviceIn"); |
|||
} |
|||
} |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,57 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/audio_in_manager.h" |
|||
#include "audio_core/in/audio_in_system.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName; |
|||
using Protocol = std::array<u32, 2>; |
|||
|
|||
class IAudioIn; |
|||
|
|||
class IAudioInManager final : public ServiceFramework<IAudioInManager> { |
|||
public: |
|||
explicit IAudioInManager(Core::System& system_); |
|||
~IAudioInManager() override; |
|||
|
|||
private: |
|||
Result ListAudioIns(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, |
|||
Out<u32> out_count); |
|||
Result OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, |
|||
Out<SharedPointer<IAudioIn>> out_audio_in, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, |
|||
AudioCore::AudioIn::AudioInParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, |
|||
ClientAppletResourceUserId aruid); |
|||
|
|||
Result ListAudioInsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, |
|||
Out<u32> out_count); |
|||
Result OpenAudioInAuto(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, |
|||
Out<SharedPointer<IAudioIn>> out_audio_in, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, |
|||
AudioCore::AudioIn::AudioInParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, |
|||
ClientAppletResourceUserId aruid); |
|||
|
|||
Result ListAudioInsAutoFiltered( |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count); |
|||
Result OpenAudioInProtocolSpecified( |
|||
Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal, |
|||
Out<SharedPointer<IAudioIn>> out_audio_in, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol, |
|||
AudioCore::AudioIn::AudioInParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid); |
|||
|
|||
std::unique_ptr<AudioCore::AudioIn::Manager> impl; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,146 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "audio_core/out/audio_out.h"
|
|||
#include "audio_core/out/audio_out_system.h"
|
|||
#include "core/hle/kernel/k_process.h"
|
|||
#include "core/hle/service/audio/audio_out.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
#include "core/hle/service/kernel_helpers.h"
|
|||
#include "core/hle/service/service.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::AudioOut; |
|||
|
|||
IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id, |
|||
const std::string& device_name, const AudioOutParameter& in_params, |
|||
Kernel::KProcess* handle, u64 applet_resource_user_id) |
|||
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, |
|||
event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, |
|||
impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { |
|||
|
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IAudioOut::GetAudioOutState>, "GetAudioOutState"}, |
|||
{1, D<&IAudioOut::Start>, "Start"}, |
|||
{2, D<&IAudioOut::Stop>, "Stop"}, |
|||
{3, D<&IAudioOut::AppendAudioOutBuffer>, "AppendAudioOutBuffer"}, |
|||
{4, D<&IAudioOut::RegisterBufferEvent>, "RegisterBufferEvent"}, |
|||
{5, D<&IAudioOut::GetReleasedAudioOutBuffers>, "GetReleasedAudioOutBuffers"}, |
|||
{6, D<&IAudioOut::ContainsAudioOutBuffer>, "ContainsAudioOutBuffer"}, |
|||
{7, D<&IAudioOut::AppendAudioOutBufferAuto>, "AppendAudioOutBufferAuto"}, |
|||
{8, D<&IAudioOut::GetReleasedAudioOutBuffersAuto>, "GetReleasedAudioOutBuffersAuto"}, |
|||
{9, D<&IAudioOut::GetAudioOutBufferCount>, "GetAudioOutBufferCount"}, |
|||
{10, D<&IAudioOut::GetAudioOutPlayedSampleCount>, "GetAudioOutPlayedSampleCount"}, |
|||
{11, D<&IAudioOut::FlushAudioOutBuffers>, "FlushAudioOutBuffers"}, |
|||
{12, D<&IAudioOut::SetAudioOutVolume>, "SetAudioOutVolume"}, |
|||
{13, D<&IAudioOut::GetAudioOutVolume>, "GetAudioOutVolume"}, |
|||
}; |
|||
// clang-format on
|
|||
RegisterHandlers(functions); |
|||
|
|||
process->Open(); |
|||
} |
|||
|
|||
IAudioOut::~IAudioOut() { |
|||
impl->Free(); |
|||
service_context.CloseEvent(event); |
|||
process->Close(); |
|||
} |
|||
|
|||
Result IAudioOut::GetAudioOutState(Out<u32> out_state) { |
|||
*out_state = static_cast<u32>(impl->GetState()); |
|||
LOG_DEBUG(Service_Audio, "called. state={}", *out_state); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOut::Start() { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(impl->StartSystem()); |
|||
} |
|||
|
|||
Result IAudioOut::Stop() { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(impl->StopSystem()); |
|||
} |
|||
|
|||
Result IAudioOut::AppendAudioOutBuffer( |
|||
InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) { |
|||
R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr)); |
|||
} |
|||
|
|||
Result IAudioOut::AppendAudioOutBufferAuto( |
|||
InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) { |
|||
if (audio_out_buffer.empty()) { |
|||
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!"); |
|||
R_THROW(Audio::ResultInsufficientBuffer); |
|||
} |
|||
|
|||
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", |
|||
impl->GetSystem().GetSessionId(), buffer_client_ptr); |
|||
R_RETURN(impl->AppendBuffer(audio_out_buffer[0], buffer_client_ptr)); |
|||
} |
|||
|
|||
Result IAudioOut::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
*out_event = &impl->GetBufferEvent(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOut::GetReleasedAudioOutBuffers( |
|||
OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, Out<u32> out_count) { |
|||
R_RETURN(this->GetReleasedAudioOutBuffersAuto(out_audio_buffer, out_count)); |
|||
} |
|||
|
|||
Result IAudioOut::GetReleasedAudioOutBuffersAuto( |
|||
OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) { |
|||
|
|||
if (!out_audio_buffer.empty()) { |
|||
out_audio_buffer[0] = 0; |
|||
} |
|||
*out_count = impl->GetReleasedBuffers(out_audio_buffer); |
|||
|
|||
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers", |
|||
impl->GetSystem().GetSessionId(), *out_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOut::ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) { |
|||
*out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr, |
|||
*out_contains_buffer); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOut::GetAudioOutBufferCount(Out<u32> out_buffer_count) { |
|||
*out_buffer_count = impl->GetBufferCount(); |
|||
LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOut::GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count) { |
|||
*out_played_sample_count = impl->GetPlayedSampleCount(); |
|||
LOG_DEBUG(Service_Audio, "called. Played samples={}", *out_played_sample_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOut::FlushAudioOutBuffers(Out<bool> out_flushed) { |
|||
*out_flushed = impl->FlushAudioOutBuffers(); |
|||
LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOut::SetAudioOutVolume(f32 volume) { |
|||
LOG_DEBUG(Service_Audio, "called. Volume={}", volume); |
|||
impl->SetVolume(volume); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOut::GetAudioOutVolume(Out<f32> out_volume) { |
|||
*out_volume = impl->GetVolume(); |
|||
LOG_DEBUG(Service_Audio, "called. Volume={}", *out_volume); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,58 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/audio_out_manager.h" |
|||
#include "audio_core/out/audio_out_system.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Kernel { |
|||
class KReadableEvent; |
|||
} |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class IAudioOut : public ServiceFramework<IAudioOut> { |
|||
public: |
|||
explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, |
|||
size_t session_id, const std::string& device_name, |
|||
const AudioCore::AudioOut::AudioOutParameter& in_params, |
|||
Kernel::KProcess* handle, u64 applet_resource_user_id); |
|||
~IAudioOut() override; |
|||
|
|||
std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { |
|||
return impl; |
|||
} |
|||
|
|||
Result GetAudioOutState(Out<u32> out_state); |
|||
Result Start(); |
|||
Result Stop(); |
|||
Result AppendAudioOutBuffer( |
|||
InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, |
|||
u64 buffer_client_ptr); |
|||
Result AppendAudioOutBufferAuto( |
|||
InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, |
|||
u64 buffer_client_ptr); |
|||
Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); |
|||
Result GetReleasedAudioOutBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, |
|||
Out<u32> out_count); |
|||
Result GetReleasedAudioOutBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, |
|||
Out<u32> out_count); |
|||
Result ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr); |
|||
Result GetAudioOutBufferCount(Out<u32> out_buffer_count); |
|||
Result GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count); |
|||
Result FlushAudioOutBuffers(Out<bool> out_flushed); |
|||
Result SetAudioOutVolume(f32 volume); |
|||
Result GetAudioOutVolume(Out<f32> out_volume); |
|||
|
|||
private: |
|||
KernelHelpers::ServiceContext service_context; |
|||
Kernel::KEvent* event; |
|||
Kernel::KProcess* process; |
|||
std::shared_ptr<AudioCore::AudioOut::Out> impl; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,101 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/string_util.h"
|
|||
#include "core/hle/service/audio/audio_out.h"
|
|||
#include "core/hle/service/audio/audio_out_manager.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
#include "core/memory.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::AudioOut; |
|||
|
|||
IAudioOutManager::IAudioOutManager(Core::System& system_) |
|||
: ServiceFramework{system_, "audout:u"}, impl{std::make_unique<Manager>(system_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"}, |
|||
{1, D<&IAudioOutManager::OpenAudioOut>, "OpenAudioOut"}, |
|||
{2, D<&IAudioOutManager::ListAudioOutsAuto>, "ListAudioOutsAuto"}, |
|||
{3, D<&IAudioOutManager::OpenAudioOutAuto>, "OpenAudioOutAuto"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IAudioOutManager::~IAudioOutManager() = default; |
|||
|
|||
Result IAudioOutManager::ListAudioOuts( |
|||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, Out<u32> out_count) { |
|||
R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count)); |
|||
} |
|||
|
|||
Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal, |
|||
Out<SharedPointer<IAudioOut>> out_audio_out, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, |
|||
AudioOutParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, |
|||
ClientAppletResourceUserId aruid) { |
|||
R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name, |
|||
parameter, process_handle, aruid)); |
|||
} |
|||
|
|||
Result IAudioOutManager::ListAudioOutsAuto( |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, Out<u32> out_count) { |
|||
if (!out_audio_outs.empty()) { |
|||
out_audio_outs[0] = AudioDeviceName("DeviceOut"); |
|||
*out_count = 1; |
|||
LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut"); |
|||
} else { |
|||
*out_count = 0; |
|||
LOG_DEBUG(Service_Audio, "called. Empty buffer passed in."); |
|||
} |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioOutManager::OpenAudioOutAuto( |
|||
Out<AudioOutParameterInternal> out_parameter_internal, |
|||
Out<SharedPointer<IAudioOut>> out_audio_out, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) { |
|||
if (!process_handle) { |
|||
LOG_ERROR(Service_Audio, "Failed to get process handle"); |
|||
R_THROW(ResultUnknown); |
|||
} |
|||
if (name.empty() || out_name.empty()) { |
|||
LOG_ERROR(Service_Audio, "Invalid buffers"); |
|||
R_THROW(ResultUnknown); |
|||
} |
|||
|
|||
size_t new_session_id{}; |
|||
R_TRY(impl->LinkToManager()); |
|||
R_TRY(impl->AcquireSessionId(new_session_id)); |
|||
|
|||
const auto device_name = Common::StringFromBuffer(name[0].name); |
|||
LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, |
|||
impl->num_free_sessions); |
|||
|
|||
auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, |
|||
parameter, process_handle.Get(), aruid.pid); |
|||
R_TRY(audio_out->GetImpl()->GetSystem().Initialize(device_name, parameter, process_handle.Get(), |
|||
aruid.pid)); |
|||
|
|||
*out_audio_out = audio_out; |
|||
impl->sessions[new_session_id] = audio_out->GetImpl(); |
|||
impl->applet_resource_user_ids[new_session_id] = aruid.pid; |
|||
|
|||
auto& out_system = impl->sessions[new_session_id]->GetSystem(); |
|||
*out_parameter_internal = |
|||
AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(), |
|||
.channel_count = out_system.GetChannelCount(), |
|||
.sample_format = static_cast<u32>(out_system.GetSampleFormat()), |
|||
.state = static_cast<u32>(out_system.GetState())}; |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,44 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/audio_out_manager.h" |
|||
#include "audio_core/out/audio_out.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName; |
|||
class IAudioOut; |
|||
|
|||
class IAudioOutManager final : public ServiceFramework<IAudioOutManager> { |
|||
public: |
|||
explicit IAudioOutManager(Core::System& system_); |
|||
~IAudioOutManager() override; |
|||
|
|||
private: |
|||
Result ListAudioOuts(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, |
|||
Out<u32> out_count); |
|||
Result OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal, |
|||
Out<SharedPointer<IAudioOut>> out_audio_out, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name, |
|||
AudioCore::AudioOut::AudioOutParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, |
|||
ClientAppletResourceUserId aruid); |
|||
Result ListAudioOutsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, |
|||
Out<u32> out_count); |
|||
Result OpenAudioOutAuto( |
|||
Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal, |
|||
Out<SharedPointer<IAudioOut>> out_audio_out, |
|||
OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name, |
|||
InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, |
|||
AudioCore::AudioOut::AudioOutParameter parameter, |
|||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid); |
|||
|
|||
std::unique_ptr<AudioCore::AudioOut::Manager> impl; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,139 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/audio/audio_renderer.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::Renderer; |
|||
|
|||
IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_, |
|||
AudioCore::AudioRendererParameterInternal& params, |
|||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, |
|||
Kernel::KProcess* process_handle_, u64 applet_resource_user_id, |
|||
s32 session_id) |
|||
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, |
|||
rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, |
|||
impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{ |
|||
process_handle_} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"}, |
|||
{1, D<&IAudioRenderer::GetSampleCount>, "GetSampleCount"}, |
|||
{2, D<&IAudioRenderer::GetMixBufferCount>, "GetMixBufferCount"}, |
|||
{3, D<&IAudioRenderer::GetState>, "GetState"}, |
|||
{4, D<&IAudioRenderer::RequestUpdate>, "RequestUpdate"}, |
|||
{5, D<&IAudioRenderer::Start>, "Start"}, |
|||
{6, D<&IAudioRenderer::Stop>, "Stop"}, |
|||
{7, D<&IAudioRenderer::QuerySystemEvent>, "QuerySystemEvent"}, |
|||
{8, D<&IAudioRenderer::SetRenderingTimeLimit>, "SetRenderingTimeLimit"}, |
|||
{9, D<&IAudioRenderer::GetRenderingTimeLimit>, "GetRenderingTimeLimit"}, |
|||
{10, D<&IAudioRenderer::RequestUpdateAuto>, "RequestUpdateAuto"}, |
|||
{11, nullptr, "ExecuteAudioRendererRendering"}, |
|||
{12, D<&IAudioRenderer::SetVoiceDropParameter>, "SetVoiceDropParameter"}, |
|||
{13, D<&IAudioRenderer::GetVoiceDropParameter>, "GetVoiceDropParameter"}, |
|||
}; |
|||
// clang-format on
|
|||
RegisterHandlers(functions); |
|||
|
|||
process_handle->Open(); |
|||
impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, |
|||
applet_resource_user_id, session_id); |
|||
} |
|||
|
|||
IAudioRenderer::~IAudioRenderer() { |
|||
impl->Finalize(); |
|||
service_context.CloseEvent(rendered_event); |
|||
process_handle->Close(); |
|||
} |
|||
|
|||
Result IAudioRenderer::GetSampleRate(Out<u32> out_sample_rate) { |
|||
*out_sample_rate = impl->GetSystem().GetSampleRate(); |
|||
LOG_DEBUG(Service_Audio, "called. Sample rate {}", *out_sample_rate); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::GetSampleCount(Out<u32> out_sample_count) { |
|||
*out_sample_count = impl->GetSystem().GetSampleCount(); |
|||
LOG_DEBUG(Service_Audio, "called. Sample count {}", *out_sample_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::GetState(Out<u32> out_state) { |
|||
*out_state = !impl->GetSystem().IsActive(); |
|||
LOG_DEBUG(Service_Audio, "called, state {}", *out_state); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::GetMixBufferCount(Out<u32> out_mix_buffer_count) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
*out_mix_buffer_count = impl->GetSystem().GetMixBufferCount(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer, |
|||
OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer, |
|||
InBuffer<BufferAttr_HipcMapAlias> input) { |
|||
R_RETURN(this->RequestUpdateAuto(out_buffer, out_performance_buffer, input)); |
|||
} |
|||
|
|||
Result IAudioRenderer::RequestUpdateAuto( |
|||
OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, |
|||
OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer, |
|||
InBuffer<BufferAttr_HipcAutoSelect> input) { |
|||
LOG_TRACE(Service_Audio, "called"); |
|||
|
|||
const auto result = impl->RequestUpdate(input, out_performance_buffer, out_buffer); |
|||
if (result.IsFailure()) { |
|||
LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.GetDescription()); |
|||
} |
|||
|
|||
R_RETURN(result); |
|||
} |
|||
|
|||
Result IAudioRenderer::Start() { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
impl->Start(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::Stop() { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
impl->Stop(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_UNLESS(impl->GetSystem().GetExecutionMode() != AudioCore::ExecutionMode::Manual, |
|||
Audio::ResultNotSupported); |
|||
*out_event = &rendered_event->GetReadableEvent(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::SetRenderingTimeLimit(u32 rendering_time_limit) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
impl->GetSystem().SetRenderingTimeLimit(rendering_time_limit); |
|||
; |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::GetRenderingTimeLimit(Out<u32> out_rendering_time_limit) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
*out_rendering_time_limit = impl->GetSystem().GetRenderingTimeLimit(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::SetVoiceDropParameter(f32 voice_drop_parameter) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
impl->GetSystem().SetVoiceDropParameter(voice_drop_parameter); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRenderer::GetVoiceDropParameter(Out<f32> out_voice_drop_parameter) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
*out_voice_drop_parameter = impl->GetSystem().GetVoiceDropParameter(); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,54 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/renderer/audio_renderer.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Kernel { |
|||
class KReadableEvent; |
|||
} |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { |
|||
public: |
|||
explicit IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_, |
|||
AudioCore::AudioRendererParameterInternal& params, |
|||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, |
|||
Kernel::KProcess* process_handle_, u64 applet_resource_user_id, |
|||
s32 session_id); |
|||
~IAudioRenderer() override; |
|||
|
|||
private: |
|||
Result GetSampleRate(Out<u32> out_sample_rate); |
|||
Result GetSampleCount(Out<u32> out_sample_count); |
|||
Result GetState(Out<u32> out_state); |
|||
Result GetMixBufferCount(Out<u32> out_mix_buffer_count); |
|||
Result RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer, |
|||
OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer, |
|||
InBuffer<BufferAttr_HipcMapAlias> input); |
|||
Result RequestUpdateAuto(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, |
|||
OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer, |
|||
InBuffer<BufferAttr_HipcAutoSelect> input); |
|||
Result Start(); |
|||
Result Stop(); |
|||
Result QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); |
|||
Result SetRenderingTimeLimit(u32 rendering_time_limit); |
|||
Result GetRenderingTimeLimit(Out<u32> out_rendering_time_limit); |
|||
Result SetVoiceDropParameter(f32 voice_drop_parameter); |
|||
Result GetVoiceDropParameter(Out<f32> out_voice_drop_parameter); |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
Kernel::KEvent* rendered_event; |
|||
AudioCore::Renderer::Manager& manager; |
|||
std::unique_ptr<AudioCore::Renderer::Renderer> impl; |
|||
Kernel::KProcess* process_handle; |
|||
Common::ScratchBuffer<u8> output_buffer; |
|||
Common::ScratchBuffer<u8> performance_buffer; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,104 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "audio_core/audio_render_manager.h"
|
|||
#include "audio_core/common/feature_support.h"
|
|||
#include "core/hle/kernel/k_process.h"
|
|||
#include "core/hle/kernel/k_transfer_memory.h"
|
|||
#include "core/hle/service/audio/audio_device.h"
|
|||
#include "core/hle/service/audio/audio_renderer.h"
|
|||
#include "core/hle/service/audio/audio_renderer_manager.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
|
|||
namespace Service::Audio { |
|||
|
|||
using namespace AudioCore::Renderer; |
|||
|
|||
IAudioRendererManager::IAudioRendererManager(Core::System& system_) |
|||
: ServiceFramework{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"}, |
|||
{1, D<&IAudioRendererManager::GetWorkBufferSize>, "GetWorkBufferSize"}, |
|||
{2, D<&IAudioRendererManager::GetAudioDeviceService>, "GetAudioDeviceService"}, |
|||
{3, nullptr, "OpenAudioRendererForManualExecution"}, |
|||
{4, D<&IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo>, "GetAudioDeviceServiceWithRevisionInfo"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IAudioRendererManager::~IAudioRendererManager() = default; |
|||
|
|||
Result IAudioRendererManager::OpenAudioRenderer( |
|||
Out<SharedPointer<IAudioRenderer>> out_audio_renderer, |
|||
AudioCore::AudioRendererParameterInternal parameter, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size, |
|||
InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) { |
|||
LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!"); |
|||
R_THROW(Audio::ResultOutOfSessions); |
|||
} |
|||
|
|||
const auto session_id{impl->GetSessionId()}; |
|||
if (session_id == -1) { |
|||
LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!"); |
|||
R_THROW(Audio::ResultOutOfSessions); |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id, |
|||
impl->GetSessionCount()); |
|||
|
|||
*out_audio_renderer = |
|||
std::make_shared<IAudioRenderer>(system, *impl, parameter, tmem_handle.Get(), tmem_size, |
|||
process_handle.Get(), aruid.pid, session_id); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRendererManager::GetWorkBufferSize(Out<u64> out_size, |
|||
AudioCore::AudioRendererParameterInternal params) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
R_TRY(impl->GetWorkBufferSize(params, *out_size)) |
|||
|
|||
std::string output_info{}; |
|||
output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision)); |
|||
output_info += |
|||
fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count); |
|||
output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}", |
|||
static_cast<u32>(params.execution_mode), params.voice_drop_enabled); |
|||
output_info += fmt::format( |
|||
"\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos " |
|||
"{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External " |
|||
"Context {:04X}", |
|||
params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos, |
|||
params.splitter_destinations, params.voices, params.perf_frames, |
|||
params.external_context_size); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}", |
|||
output_info, *out_size); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRendererManager::GetAudioDeviceService( |
|||
Out<SharedPointer<IAudioDevice>> out_audio_device, ClientAppletResourceUserId aruid) { |
|||
LOG_DEBUG(Service_Audio, "called, aruid={:#x}", aruid.pid); |
|||
*out_audio_device = std::make_shared<IAudioDevice>( |
|||
system, aruid.pid, Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo( |
|||
Out<SharedPointer<IAudioDevice>> out_audio_device, u32 revision, |
|||
ClientAppletResourceUserId aruid) { |
|||
LOG_DEBUG(Service_Audio, "called, revision={} aruid={:#x}", AudioCore::GetRevisionNum(revision), |
|||
aruid.pid); |
|||
*out_audio_device = |
|||
std::make_shared<IAudioDevice>(system, aruid.pid, revision, num_audio_devices++); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,37 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/audio_render_manager.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class IAudioDevice; |
|||
class IAudioRenderer; |
|||
|
|||
class IAudioRendererManager final : public ServiceFramework<IAudioRendererManager> { |
|||
public: |
|||
explicit IAudioRendererManager(Core::System& system_); |
|||
~IAudioRendererManager() override; |
|||
|
|||
private: |
|||
Result OpenAudioRenderer(Out<SharedPointer<IAudioRenderer>> out_audio_renderer, |
|||
AudioCore::AudioRendererParameterInternal parameter, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size, |
|||
InCopyHandle<Kernel::KProcess> process_handle, |
|||
ClientAppletResourceUserId aruid); |
|||
Result GetWorkBufferSize(Out<u64> out_size, |
|||
AudioCore::AudioRendererParameterInternal parameter); |
|||
Result GetAudioDeviceService(Out<SharedPointer<IAudioDevice>> out_audio_device, |
|||
ClientAppletResourceUserId aruid); |
|||
Result GetAudioDeviceServiceWithRevisionInfo(Out<SharedPointer<IAudioDevice>> out_audio_device, |
|||
u32 revision, ClientAppletResourceUserId aruid); |
|||
|
|||
std::unique_ptr<AudioCore::Renderer::Manager> impl; |
|||
u32 num_audio_devices{0}; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -1,323 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include <array>
|
|||
#include <cstring>
|
|||
#include <vector>
|
|||
|
|||
#include "audio_core/out/audio_out_system.h"
|
|||
#include "audio_core/renderer/audio_device.h"
|
|||
#include "common/common_funcs.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "common/scratch_buffer.h"
|
|||
#include "common/string_util.h"
|
|||
#include "common/swap.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hle/kernel/k_event.h"
|
|||
#include "core/hle/service/audio/audout_u.h"
|
|||
#include "core/hle/service/audio/errors.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/memory.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::AudioOut; |
|||
|
|||
class IAudioOut final : public ServiceFramework<IAudioOut> { |
|||
public: |
|||
explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, |
|||
size_t session_id, const std::string& device_name, |
|||
const AudioOutParameter& in_params, Kernel::KProcess* handle, |
|||
u64 applet_resource_user_id) |
|||
: ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, |
|||
event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, |
|||
impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { |
|||
|
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, |
|||
{1, &IAudioOut::Start, "Start"}, |
|||
{2, &IAudioOut::Stop, "Stop"}, |
|||
{3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"}, |
|||
{4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"}, |
|||
{5, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffers"}, |
|||
{6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"}, |
|||
{7, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBufferAuto"}, |
|||
{8, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffersAuto"}, |
|||
{9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"}, |
|||
{10, &IAudioOut::GetAudioOutPlayedSampleCount, "GetAudioOutPlayedSampleCount"}, |
|||
{11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"}, |
|||
{12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"}, |
|||
{13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"}, |
|||
}; |
|||
// clang-format on
|
|||
RegisterHandlers(functions); |
|||
|
|||
process->Open(); |
|||
} |
|||
|
|||
~IAudioOut() override { |
|||
impl->Free(); |
|||
service_context.CloseEvent(event); |
|||
process->Close(); |
|||
} |
|||
|
|||
[[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { |
|||
return impl; |
|||
} |
|||
|
|||
private: |
|||
void GetAudioOutState(HLERequestContext& ctx) { |
|||
const auto state = static_cast<u32>(impl->GetState()); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. State={}", state); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(state); |
|||
} |
|||
|
|||
void Start(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto result = impl->StartSystem(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void Stop(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto result = impl->StopSystem(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void AppendAudioOutBuffer(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
u64 tag = rp.PopRaw<u64>(); |
|||
|
|||
const auto in_buffer_size{ctx.GetReadBufferSize()}; |
|||
if (in_buffer_size < sizeof(AudioOutBuffer)) { |
|||
LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!"); |
|||
} |
|||
|
|||
const auto& in_buffer = ctx.ReadBuffer(); |
|||
AudioOutBuffer buffer{}; |
|||
std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer)); |
|||
|
|||
LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", |
|||
impl->GetSystem().GetSessionId(), tag); |
|||
|
|||
auto result = impl->AppendBuffer(buffer, tag); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void RegisterBufferEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto& buffer_event = impl->GetBufferEvent(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(buffer_event); |
|||
} |
|||
|
|||
void GetReleasedAudioOutBuffers(HLERequestContext& ctx) { |
|||
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); |
|||
released_buffer.resize_destructive(write_buffer_size); |
|||
released_buffer[0] = 0; |
|||
|
|||
const auto count = impl->GetReleasedBuffers(released_buffer); |
|||
|
|||
ctx.WriteBuffer(released_buffer); |
|||
|
|||
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers", |
|||
impl->GetSystem().GetSessionId(), count); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(count); |
|||
} |
|||
|
|||
void ContainsAudioOutBuffer(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const u64 tag{rp.Pop<u64>()}; |
|||
const auto buffer_queued{impl->ContainsAudioBuffer(tag)}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(buffer_queued); |
|||
} |
|||
|
|||
void GetAudioOutBufferCount(HLERequestContext& ctx) { |
|||
const auto buffer_count = impl->GetBufferCount(); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(buffer_count); |
|||
} |
|||
|
|||
void GetAudioOutPlayedSampleCount(HLERequestContext& ctx) { |
|||
const auto samples_played = impl->GetPlayedSampleCount(); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(samples_played); |
|||
} |
|||
|
|||
void FlushAudioOutBuffers(HLERequestContext& ctx) { |
|||
bool flushed{impl->FlushAudioOutBuffers()}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(flushed); |
|||
} |
|||
|
|||
void SetAudioOutVolume(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto volume = rp.Pop<f32>(); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Volume={}", volume); |
|||
|
|||
impl->SetVolume(volume); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void GetAudioOutVolume(HLERequestContext& ctx) { |
|||
const auto volume = impl->GetVolume(); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Volume={}", volume); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(volume); |
|||
} |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
Kernel::KEvent* event; |
|||
Kernel::KProcess* process; |
|||
std::shared_ptr<AudioCore::AudioOut::Out> impl; |
|||
Common::ScratchBuffer<u64> released_buffer; |
|||
}; |
|||
|
|||
AudOutU::AudOutU(Core::System& system_) |
|||
: ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"}, |
|||
impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &AudOutU::ListAudioOuts, "ListAudioOuts"}, |
|||
{1, &AudOutU::OpenAudioOut, "OpenAudioOut"}, |
|||
{2, &AudOutU::ListAudioOuts, "ListAudioOutsAuto"}, |
|||
{3, &AudOutU::OpenAudioOut, "OpenAudioOutAuto"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
AudOutU::~AudOutU() = default; |
|||
|
|||
void AudOutU::ListAudioOuts(HLERequestContext& ctx) { |
|||
using namespace AudioCore::Renderer; |
|||
|
|||
std::scoped_lock l{impl->mutex}; |
|||
|
|||
const auto write_count = |
|||
static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); |
|||
std::vector<AudioDevice::AudioDeviceName> device_names{}; |
|||
if (write_count > 0) { |
|||
device_names.emplace_back("DeviceOut"); |
|||
LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut"); |
|||
} else { |
|||
LOG_DEBUG(Service_Audio, "called. Empty buffer passed in."); |
|||
} |
|||
|
|||
ctx.WriteBuffer(device_names); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u32>(static_cast<u32>(device_names.size())); |
|||
} |
|||
|
|||
void AudOutU::OpenAudioOut(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
auto in_params{rp.PopRaw<AudioOutParameter>()}; |
|||
auto applet_resource_user_id{rp.PopRaw<u64>()}; |
|||
const auto device_name_data{ctx.ReadBuffer()}; |
|||
auto device_name = Common::StringFromBuffer(device_name_data); |
|||
auto handle{ctx.GetCopyHandle(0)}; |
|||
|
|||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; |
|||
if (process.IsNull()) { |
|||
LOG_ERROR(Service_Audio, "Failed to get process handle"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
auto link{impl->LinkToManager()}; |
|||
if (link.IsError()) { |
|||
LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(link); |
|||
return; |
|||
} |
|||
|
|||
size_t new_session_id{}; |
|||
auto result{impl->AcquireSessionId(new_session_id)}; |
|||
if (result.IsError()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
return; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, |
|||
impl->num_free_sessions); |
|||
|
|||
auto audio_out = |
|||
std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params, |
|||
process.GetPointerUnsafe(), applet_resource_user_id); |
|||
result = audio_out->GetImpl()->GetSystem().Initialize( |
|||
device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id); |
|||
if (result.IsError()) { |
|||
LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
return; |
|||
} |
|||
|
|||
impl->sessions[new_session_id] = audio_out->GetImpl(); |
|||
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; |
|||
|
|||
auto& out_system = impl->sessions[new_session_id]->GetSystem(); |
|||
AudioOutParameterInternal out_params{.sample_rate = out_system.GetSampleRate(), |
|||
.channel_count = out_system.GetChannelCount(), |
|||
.sample_format = |
|||
static_cast<u32>(out_system.GetSampleFormat()), |
|||
.state = static_cast<u32>(out_system.GetState())}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6, 0, 1}; |
|||
|
|||
ctx.WriteBuffer(out_system.GetName()); |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw<AudioOutParameterInternal>(out_params); |
|||
rb.PushIpcInterface<IAudioOut>(audio_out); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -1,37 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/audio_out_manager.h" |
|||
#include "audio_core/out/audio_out.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} |
|||
|
|||
namespace AudioCore::AudioOut { |
|||
class Manager; |
|||
class Out; |
|||
} // namespace AudioCore::AudioOut |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class IAudioOut; |
|||
|
|||
class AudOutU final : public ServiceFramework<AudOutU> { |
|||
public: |
|||
explicit AudOutU(Core::System& system_); |
|||
~AudOutU() override; |
|||
|
|||
private: |
|||
void ListAudioOuts(HLERequestContext& ctx); |
|||
void OpenAudioOut(HLERequestContext& ctx); |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
std::unique_ptr<AudioCore::AudioOut::Manager> impl; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -1,552 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include <array>
|
|||
#include <memory>
|
|||
|
|||
#include "audio_core/audio_core.h"
|
|||
#include "audio_core/common/audio_renderer_parameter.h"
|
|||
#include "audio_core/common/feature_support.h"
|
|||
#include "audio_core/renderer/audio_device.h"
|
|||
#include "audio_core/renderer/audio_renderer.h"
|
|||
#include "audio_core/renderer/voice/voice_info.h"
|
|||
#include "common/alignment.h"
|
|||
#include "common/bit_util.h"
|
|||
#include "common/common_funcs.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "common/polyfill_ranges.h"
|
|||
#include "common/scratch_buffer.h"
|
|||
#include "common/string_util.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hle/kernel/k_event.h"
|
|||
#include "core/hle/kernel/k_process.h"
|
|||
#include "core/hle/kernel/k_transfer_memory.h"
|
|||
#include "core/hle/service/audio/audren_u.h"
|
|||
#include "core/hle/service/audio/errors.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/memory.h"
|
|||
|
|||
using namespace AudioCore::Renderer; |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { |
|||
public: |
|||
explicit IAudioRenderer(Core::System& system_, Manager& manager_, |
|||
AudioCore::AudioRendererParameterInternal& params, |
|||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, |
|||
u32 process_handle, Kernel::KProcess& process_, |
|||
u64 applet_resource_user_id, s32 session_id) |
|||
: ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, |
|||
rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, |
|||
impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, |
|||
{1, &IAudioRenderer::GetSampleCount, "GetSampleCount"}, |
|||
{2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"}, |
|||
{3, &IAudioRenderer::GetState, "GetState"}, |
|||
{4, &IAudioRenderer::RequestUpdate, "RequestUpdate"}, |
|||
{5, &IAudioRenderer::Start, "Start"}, |
|||
{6, &IAudioRenderer::Stop, "Stop"}, |
|||
{7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, |
|||
{8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"}, |
|||
{9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"}, |
|||
{10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"}, |
|||
{11, nullptr, "ExecuteAudioRendererRendering"}, |
|||
{12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"}, |
|||
{13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"}, |
|||
}; |
|||
// clang-format on
|
|||
RegisterHandlers(functions); |
|||
|
|||
process.Open(); |
|||
impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process, |
|||
applet_resource_user_id, session_id); |
|||
} |
|||
|
|||
~IAudioRenderer() override { |
|||
impl->Finalize(); |
|||
service_context.CloseEvent(rendered_event); |
|||
process.Close(); |
|||
} |
|||
|
|||
private: |
|||
void GetSampleRate(HLERequestContext& ctx) { |
|||
const auto sample_rate{impl->GetSystem().GetSampleRate()}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(sample_rate); |
|||
} |
|||
|
|||
void GetSampleCount(HLERequestContext& ctx) { |
|||
const auto sample_count{impl->GetSystem().GetSampleCount()}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(sample_count); |
|||
} |
|||
|
|||
void GetState(HLERequestContext& ctx) { |
|||
const u32 state{!impl->GetSystem().IsActive()}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called, state {}", state); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(state); |
|||
} |
|||
|
|||
void GetMixBufferCount(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
const auto buffer_count{impl->GetSystem().GetMixBufferCount()}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(buffer_count); |
|||
} |
|||
|
|||
void RequestUpdate(HLERequestContext& ctx) { |
|||
LOG_TRACE(Service_Audio, "called"); |
|||
|
|||
const auto input{ctx.ReadBuffer(0)}; |
|||
|
|||
// These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
|
|||
// checking size 0. Performance size is 0 for most games.
|
|||
|
|||
auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0}; |
|||
if (is_buffer_b) { |
|||
const auto buffersB{ctx.BufferDescriptorB()}; |
|||
output_buffer.resize_destructive(buffersB[0].Size()); |
|||
performance_buffer.resize_destructive(buffersB[1].Size()); |
|||
} else { |
|||
const auto buffersC{ctx.BufferDescriptorC()}; |
|||
output_buffer.resize_destructive(buffersC[0].Size()); |
|||
performance_buffer.resize_destructive(buffersC[1].Size()); |
|||
} |
|||
|
|||
auto result = impl->RequestUpdate(input, performance_buffer, output_buffer); |
|||
|
|||
if (result.IsSuccess()) { |
|||
if (is_buffer_b) { |
|||
ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0); |
|||
ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1); |
|||
} else { |
|||
ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0); |
|||
ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1); |
|||
} |
|||
} else { |
|||
LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", |
|||
result.GetDescription()); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void Start(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
impl->Start(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void Stop(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
impl->Stop(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void QuerySystemEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(Audio::ResultNotSupported); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(rendered_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void SetRenderingTimeLimit(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
auto limit = rp.PopRaw<u32>(); |
|||
|
|||
auto& system_ = impl->GetSystem(); |
|||
system_.SetRenderingTimeLimit(limit); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void GetRenderingTimeLimit(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto& system_ = impl->GetSystem(); |
|||
auto time = system_.GetRenderingTimeLimit(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(time); |
|||
} |
|||
|
|||
void ExecuteAudioRendererRendering(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
} |
|||
|
|||
void SetVoiceDropParameter(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
auto voice_drop_param{rp.Pop<f32>()}; |
|||
|
|||
auto& system_ = impl->GetSystem(); |
|||
system_.SetVoiceDropParameter(voice_drop_param); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void GetVoiceDropParameter(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto& system_ = impl->GetSystem(); |
|||
auto voice_drop_param{system_.GetVoiceDropParameter()}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(voice_drop_param); |
|||
} |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
Kernel::KEvent* rendered_event; |
|||
Manager& manager; |
|||
std::unique_ptr<Renderer> impl; |
|||
Kernel::KProcess& process; |
|||
Common::ScratchBuffer<u8> output_buffer; |
|||
Common::ScratchBuffer<u8> performance_buffer; |
|||
}; |
|||
|
|||
class IAudioDevice final : public ServiceFramework<IAudioDevice> { |
|||
|
|||
public: |
|||
explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision, |
|||
u32 device_num) |
|||
: ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"}, |
|||
impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)}, |
|||
event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} { |
|||
static const FunctionInfo functions[] = { |
|||
{0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, |
|||
{1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, |
|||
{2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"}, |
|||
{3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"}, |
|||
{4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"}, |
|||
{5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"}, |
|||
{6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"}, |
|||
{7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"}, |
|||
{8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"}, |
|||
{10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"}, |
|||
{11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"}, |
|||
{12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"}, |
|||
{13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"}, |
|||
{14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"}, |
|||
}; |
|||
RegisterHandlers(functions); |
|||
|
|||
event->Signal(); |
|||
} |
|||
|
|||
~IAudioDevice() override { |
|||
service_context.CloseEvent(event); |
|||
} |
|||
|
|||
private: |
|||
void ListAudioDeviceName(HLERequestContext& ctx) { |
|||
const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>(); |
|||
|
|||
std::vector<AudioDevice::AudioDeviceName> out_names{}; |
|||
|
|||
const u32 out_count = impl->ListAudioDeviceName(out_names, in_count); |
|||
|
|||
std::string out{}; |
|||
for (u32 i = 0; i < out_count; i++) { |
|||
std::string a{}; |
|||
u32 j = 0; |
|||
while (out_names[i].name[j] != '\0') { |
|||
a += out_names[i].name[j]; |
|||
j++; |
|||
} |
|||
out += "\n\t" + a; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "called.\nNames={}", out); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
|
|||
ctx.WriteBuffer(out_names); |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.Push(out_count); |
|||
} |
|||
|
|||
void SetAudioDeviceOutputVolume(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const f32 volume = rp.Pop<f32>(); |
|||
|
|||
const auto device_name_buffer = ctx.ReadBuffer(); |
|||
const std::string name = Common::StringFromBuffer(device_name_buffer); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume); |
|||
|
|||
if (name == "AudioTvOutput") { |
|||
impl->SetDeviceVolumes(volume); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void GetAudioDeviceOutputVolume(HLERequestContext& ctx) { |
|||
const auto device_name_buffer = ctx.ReadBuffer(); |
|||
const std::string name = Common::StringFromBuffer(device_name_buffer); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Name={}", name); |
|||
|
|||
f32 volume{1.0f}; |
|||
if (name == "AudioTvOutput") { |
|||
volume = impl->GetDeviceVolume(name); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(volume); |
|||
} |
|||
|
|||
void GetActiveAudioDeviceName(HLERequestContext& ctx) { |
|||
const auto write_size = ctx.GetWriteBufferSize(); |
|||
std::string out_name{"AudioTvOutput"}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name); |
|||
|
|||
out_name.resize(write_size); |
|||
|
|||
ctx.WriteBuffer(out_name); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "(STUBBED) called"); |
|||
|
|||
event->Signal(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(event->GetReadableEvent()); |
|||
} |
|||
|
|||
void GetActiveChannelCount(HLERequestContext& ctx) { |
|||
const auto& sink{system.AudioCore().GetOutputSink()}; |
|||
u32 channel_count{sink.GetSystemChannels()}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u32>(channel_count); |
|||
} |
|||
|
|||
void QueryAudioDeviceInputEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(event->GetReadableEvent()); |
|||
} |
|||
|
|||
void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(event->GetReadableEvent()); |
|||
} |
|||
|
|||
void ListAudioOutputDeviceName(HLERequestContext& ctx) { |
|||
const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>(); |
|||
|
|||
std::vector<AudioDevice::AudioDeviceName> out_names{}; |
|||
|
|||
const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count); |
|||
|
|||
std::string out{}; |
|||
for (u32 i = 0; i < out_count; i++) { |
|||
std::string a{}; |
|||
u32 j = 0; |
|||
while (out_names[i].name[j] != '\0') { |
|||
a += out_names[i].name[j]; |
|||
j++; |
|||
} |
|||
out += "\n\t" + a; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "called.\nNames={}", out); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
|
|||
ctx.WriteBuffer(out_names); |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.Push(out_count); |
|||
} |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
std::unique_ptr<AudioDevice> impl; |
|||
Kernel::KEvent* event; |
|||
}; |
|||
|
|||
AudRenU::AudRenU(Core::System& system_) |
|||
: ServiceFramework{system_, "audren:u"}, |
|||
service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, |
|||
{1, &AudRenU::GetWorkBufferSize, "GetWorkBufferSize"}, |
|||
{2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"}, |
|||
{3, nullptr, "OpenAudioRendererForManualExecution"}, |
|||
{4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
AudRenU::~AudRenU() = default; |
|||
|
|||
void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
AudioCore::AudioRendererParameterInternal params; |
|||
rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params); |
|||
rp.Skip(1, false); |
|||
auto transfer_memory_size = rp.Pop<u64>(); |
|||
auto applet_resource_user_id = rp.Pop<u64>(); |
|||
auto transfer_memory_handle = ctx.GetCopyHandle(0); |
|||
auto process_handle = ctx.GetCopyHandle(1); |
|||
|
|||
if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) { |
|||
LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(Audio::ResultOutOfSessions); |
|||
return; |
|||
} |
|||
|
|||
auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()}; |
|||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; |
|||
|
|||
const auto session_id{impl->GetSessionId()}; |
|||
if (session_id == -1) { |
|||
LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(Audio::ResultOutOfSessions); |
|||
return; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id, |
|||
impl->GetSessionCount()); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(), |
|||
transfer_memory_size, process_handle, *process, |
|||
applet_resource_user_id, session_id); |
|||
} |
|||
|
|||
void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) { |
|||
AudioCore::AudioRendererParameterInternal params; |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params); |
|||
|
|||
u64 size{0}; |
|||
auto result = impl->GetWorkBufferSize(params, size); |
|||
|
|||
std::string output_info{}; |
|||
output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision)); |
|||
output_info += |
|||
fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count); |
|||
output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}", |
|||
static_cast<u32>(params.execution_mode), params.voice_drop_enabled); |
|||
output_info += fmt::format( |
|||
"\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos " |
|||
"{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External " |
|||
"Context {:04X}", |
|||
params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos, |
|||
params.splitter_destinations, params.voices, params.perf_frames, |
|||
params.external_context_size); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}", |
|||
output_info, size); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(result); |
|||
rb.Push<u64>(size); |
|||
} |
|||
|
|||
void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const auto applet_resource_user_id = rp.Pop<u64>(); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, |
|||
::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++); |
|||
} |
|||
|
|||
void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) { |
|||
LOG_ERROR(Service_Audio, "called. Implement me!"); |
|||
} |
|||
|
|||
void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) { |
|||
struct Parameters { |
|||
u32 revision; |
|||
u64 applet_resource_user_id; |
|||
}; |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>(); |
|||
|
|||
LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}", |
|||
AudioCore::GetRevisionNum(revision), applet_resource_user_id); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision, |
|||
num_audio_devices++); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -1,35 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/audio_render_manager.h" |
|||
#include "common/scratch_buffer.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} |
|||
|
|||
namespace Service::Audio { |
|||
class IAudioRenderer; |
|||
|
|||
class AudRenU final : public ServiceFramework<AudRenU> { |
|||
public: |
|||
explicit AudRenU(Core::System& system_); |
|||
~AudRenU() override; |
|||
|
|||
private: |
|||
void OpenAudioRenderer(HLERequestContext& ctx); |
|||
void GetWorkBufferSize(HLERequestContext& ctx); |
|||
void GetAudioDeviceService(HLERequestContext& ctx); |
|||
void OpenAudioRendererForManualExecution(HLERequestContext& ctx); |
|||
void GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx); |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
std::unique_ptr<AudioCore::Renderer::Manager> impl; |
|||
u32 num_audio_devices{0}; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,145 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/audio/hardware_opus_decoder.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
|
|||
namespace Service::Audio { |
|||
|
|||
using namespace AudioCore::OpusDecoder; |
|||
|
|||
IHardwareOpusDecoder::IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus) |
|||
: ServiceFramework{system_, "IHardwareOpusDecoder"}, |
|||
impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IHardwareOpusDecoder::DecodeInterleavedOld>, "DecodeInterleavedOld"}, |
|||
{1, D<&IHardwareOpusDecoder::SetContext>, "SetContext"}, |
|||
{2, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld>, "DecodeInterleavedForMultiStreamOld"}, |
|||
{3, D<&IHardwareOpusDecoder::SetContextForMultiStream>, "SetContextForMultiStream"}, |
|||
{4, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfOld>, "DecodeInterleavedWithPerfOld"}, |
|||
{5, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld>, "DecodeInterleavedForMultiStreamWithPerfOld"}, |
|||
{6, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld>, "DecodeInterleavedWithPerfAndResetOld"}, |
|||
{7, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld>, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"}, |
|||
{8, D<&IHardwareOpusDecoder::DecodeInterleaved>, "DecodeInterleaved"}, |
|||
{9, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStream>, "DecodeInterleavedForMultiStream"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IHardwareOpusDecoder::~IHardwareOpusDecoder() = default; |
|||
|
|||
Result IHardwareOpusDecoder::Initialize(const OpusParametersEx& params, |
|||
Kernel::KTransferMemory* transfer_memory, |
|||
u64 transfer_memory_size) { |
|||
return impl->Initialize(params, transfer_memory, transfer_memory_size); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::Initialize(const OpusMultiStreamParametersEx& params, |
|||
Kernel::KTransferMemory* transfer_memory, |
|||
u64 transfer_memory_size) { |
|||
return impl->Initialize(params, transfer_memory, transfer_memory_size); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data) { |
|||
R_TRY(impl->DecodeInterleaved(out_data_size, nullptr, out_sample_count, opus_data, out_pcm_data, |
|||
false)); |
|||
LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size, |
|||
*out_sample_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(impl->SetContext(decoder_context)); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, Out<u32> out_data_size, |
|||
Out<u32> out_sample_count, InBuffer<BufferAttr_HipcMapAlias> opus_data) { |
|||
R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, nullptr, out_sample_count, opus_data, |
|||
out_pcm_data, false)); |
|||
LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size, |
|||
*out_sample_count); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::SetContextForMultiStream( |
|||
InBuffer<BufferAttr_HipcMapAlias> decoder_context) { |
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
R_RETURN(impl->SetContext(decoder_context)); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::DecodeInterleavedWithPerfOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data) { |
|||
R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data, |
|||
out_pcm_data, false)); |
|||
LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size, |
|||
*out_sample_count, *out_time_taken); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data) { |
|||
R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count, |
|||
opus_data, out_pcm_data, false)); |
|||
LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size, |
|||
*out_sample_count, *out_time_taken); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) { |
|||
R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data, |
|||
out_pcm_data, reset)); |
|||
LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset, |
|||
*out_data_size, *out_sample_count, *out_time_taken); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) { |
|||
R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count, |
|||
opus_data, out_pcm_data, reset)); |
|||
LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset, |
|||
*out_data_size, *out_sample_count, *out_time_taken); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::DecodeInterleaved( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data, |
|||
bool reset) { |
|||
R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data, |
|||
out_pcm_data, reset)); |
|||
LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset, |
|||
*out_data_size, *out_sample_count, *out_time_taken); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoder::DecodeInterleavedForMultiStream( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data, |
|||
bool reset) { |
|||
R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count, |
|||
opus_data, out_pcm_data, reset)); |
|||
LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset, |
|||
*out_data_size, *out_sample_count, *out_time_taken); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,63 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/opus/decoder.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> { |
|||
public: |
|||
explicit IHardwareOpusDecoder(Core::System& system_, |
|||
AudioCore::OpusDecoder::HardwareOpus& hardware_opus); |
|||
~IHardwareOpusDecoder() override; |
|||
|
|||
Result Initialize(const AudioCore::OpusDecoder::OpusParametersEx& params, |
|||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size); |
|||
Result Initialize(const AudioCore::OpusDecoder::OpusMultiStreamParametersEx& params, |
|||
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size); |
|||
|
|||
private: |
|||
Result DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data); |
|||
Result SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context); |
|||
Result DecodeInterleavedForMultiStreamOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data); |
|||
Result SetContextForMultiStream(InBuffer<BufferAttr_HipcMapAlias> decoder_context); |
|||
Result DecodeInterleavedWithPerfOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data); |
|||
Result DecodeInterleavedForMultiStreamWithPerfOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data); |
|||
Result DecodeInterleavedWithPerfAndResetOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset); |
|||
Result DecodeInterleavedForMultiStreamWithPerfAndResetOld( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset); |
|||
Result DecodeInterleaved( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data, |
|||
bool reset); |
|||
Result DecodeInterleavedForMultiStream( |
|||
OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data, |
|||
Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken, |
|||
InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data, |
|||
bool reset); |
|||
|
|||
std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl; |
|||
Common::ScratchBuffer<u8> output_data; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -0,0 +1,156 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/audio/hardware_opus_decoder.h"
|
|||
#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
|
|||
#include "core/hle/service/cmif_serialization.h"
|
|||
|
|||
namespace Service::Audio { |
|||
|
|||
using namespace AudioCore::OpusDecoder; |
|||
|
|||
IHardwareOpusDecoderManager::IHardwareOpusDecoderManager(Core::System& system_) |
|||
: ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoder>, "OpenHardwareOpusDecoder"}, |
|||
{1, D<&IHardwareOpusDecoderManager::GetWorkBufferSize>, "GetWorkBufferSize"}, |
|||
{2, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream>, "OpenOpusDecoderForMultiStream"}, |
|||
{3, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream>, "GetWorkBufferSizeForMultiStream"}, |
|||
{4, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx>, "OpenHardwareOpusDecoderEx"}, |
|||
{5, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeEx>, "GetWorkBufferSizeEx"}, |
|||
{6, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx>, "OpenHardwareOpusDecoderForMultiStreamEx"}, |
|||
{7, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx>, "GetWorkBufferSizeForMultiStreamEx"}, |
|||
{8, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeExEx>, "GetWorkBufferSizeExEx"}, |
|||
{9, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx>, "GetWorkBufferSizeForMultiStreamExEx"}, |
|||
}; |
|||
// clang-format on
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IHardwareOpusDecoderManager::~IHardwareOpusDecoderManager() = default; |
|||
|
|||
Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoder( |
|||
Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParameters params, u32 tmem_size, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle) { |
|||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}", |
|||
params.sample_rate, params.channel_count, tmem_size); |
|||
|
|||
auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; |
|||
OpusParametersEx ex{ |
|||
.sample_rate = params.sample_rate, |
|||
.channel_count = params.channel_count, |
|||
.use_large_frame_size = false, |
|||
}; |
|||
R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size)); |
|||
|
|||
*out_decoder = decoder; |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::GetWorkBufferSize(Out<u32> out_size, OpusParameters params) { |
|||
R_TRY(impl.GetWorkBufferSize(params, *out_size)); |
|||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size {:#x}", |
|||
params.sample_rate, params.channel_count, *out_size); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream( |
|||
Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, |
|||
InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle) { |
|||
LOG_DEBUG(Service_Audio, |
|||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " |
|||
"transfer_memory_size {:#x}", |
|||
params->sample_rate, params->channel_count, params->total_stream_count, |
|||
params->stereo_stream_count, tmem_size); |
|||
|
|||
auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; |
|||
|
|||
OpusMultiStreamParametersEx ex{ |
|||
.sample_rate = params->sample_rate, |
|||
.channel_count = params->channel_count, |
|||
.total_stream_count = params->total_stream_count, |
|||
.stereo_stream_count = params->stereo_stream_count, |
|||
.use_large_frame_size = false, |
|||
.mappings{}, |
|||
}; |
|||
std::memcpy(ex.mappings.data(), params->mappings.data(), sizeof(params->mappings)); |
|||
R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size)); |
|||
|
|||
*out_decoder = decoder; |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream( |
|||
Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params) { |
|||
R_TRY(impl.GetWorkBufferSizeForMultiStream(*params, *out_size)); |
|||
LOG_DEBUG(Service_Audio, "size {:#x}", *out_size); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx( |
|||
Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParametersEx params, u32 tmem_size, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle) { |
|||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}", |
|||
params.sample_rate, params.channel_count, tmem_size); |
|||
|
|||
auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; |
|||
R_TRY(decoder->Initialize(params, tmem_handle.Get(), tmem_size)); |
|||
|
|||
*out_decoder = decoder; |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(Out<u32> out_size, |
|||
OpusParametersEx params) { |
|||
R_TRY(impl.GetWorkBufferSizeEx(params, *out_size)); |
|||
LOG_DEBUG(Service_Audio, "size {:#x}", *out_size); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx( |
|||
Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, |
|||
InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle) { |
|||
LOG_DEBUG(Service_Audio, |
|||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " |
|||
"use_large_frame_size {}" |
|||
"transfer_memory_size {:#x}", |
|||
params->sample_rate, params->channel_count, params->total_stream_count, |
|||
params->stereo_stream_count, params->use_large_frame_size, tmem_size); |
|||
|
|||
auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; |
|||
|
|||
R_TRY(decoder->Initialize(*params, tmem_handle.Get(), tmem_size)); |
|||
|
|||
*out_decoder = decoder; |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx( |
|||
Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) { |
|||
R_TRY(impl.GetWorkBufferSizeForMultiStreamEx(*params, *out_size)); |
|||
LOG_DEBUG(Service_Audio, |
|||
"sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} " |
|||
"use_large_frame_size {} -- returned size {:#x}", |
|||
params->sample_rate, params->channel_count, params->total_stream_count, |
|||
params->stereo_stream_count, params->use_large_frame_size, *out_size); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::GetWorkBufferSizeExEx(Out<u32> out_size, |
|||
OpusParametersEx params) { |
|||
R_TRY(impl.GetWorkBufferSizeExEx(params, *out_size)); |
|||
LOG_DEBUG(Service_Audio, "size {:#x}", *out_size); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx( |
|||
Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) { |
|||
R_TRY(impl.GetWorkBufferSizeForMultiStreamExEx(*params, *out_size)); |
|||
LOG_DEBUG(Service_Audio, "size {:#x}", *out_size); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
} // namespace Service::Audio
|
|||
@ -0,0 +1,53 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/opus/decoder_manager.h" |
|||
#include "core/hle/service/cmif_types.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class IHardwareOpusDecoder; |
|||
|
|||
using AudioCore::OpusDecoder::OpusMultiStreamParameters; |
|||
using AudioCore::OpusDecoder::OpusMultiStreamParametersEx; |
|||
using AudioCore::OpusDecoder::OpusParameters; |
|||
using AudioCore::OpusDecoder::OpusParametersEx; |
|||
|
|||
class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { |
|||
public: |
|||
explicit IHardwareOpusDecoderManager(Core::System& system_); |
|||
~IHardwareOpusDecoderManager() override; |
|||
|
|||
private: |
|||
Result OpenHardwareOpusDecoder(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, |
|||
OpusParameters params, u32 tmem_size, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle); |
|||
Result GetWorkBufferSize(Out<u32> out_size, OpusParameters params); |
|||
Result OpenHardwareOpusDecoderForMultiStream( |
|||
Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, |
|||
InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle); |
|||
Result GetWorkBufferSizeForMultiStream( |
|||
Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params); |
|||
Result OpenHardwareOpusDecoderEx(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, |
|||
OpusParametersEx params, u32 tmem_size, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle); |
|||
Result GetWorkBufferSizeEx(Out<u32> out_size, OpusParametersEx params); |
|||
Result OpenHardwareOpusDecoderForMultiStreamEx( |
|||
Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, |
|||
InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size, |
|||
InCopyHandle<Kernel::KTransferMemory> tmem_handle); |
|||
Result GetWorkBufferSizeForMultiStreamEx( |
|||
Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params); |
|||
Result GetWorkBufferSizeExEx(Out<u32> out_size, OpusParametersEx params); |
|||
Result GetWorkBufferSizeForMultiStreamExEx( |
|||
Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params); |
|||
|
|||
Core::System& system; |
|||
AudioCore::OpusDecoder::OpusDecoderManager impl; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
@ -1,502 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include <memory>
|
|||
#include <vector>
|
|||
|
|||
#include "audio_core/opus/decoder.h"
|
|||
#include "audio_core/opus/parameters.h"
|
|||
#include "common/assert.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "common/scratch_buffer.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hle/service/audio/hwopus.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::Audio { |
|||
using namespace AudioCore::OpusDecoder; |
|||
|
|||
class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> { |
|||
public: |
|||
explicit IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus) |
|||
: ServiceFramework{system_, "IHardwareOpusDecoder"}, |
|||
impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IHardwareOpusDecoder::DecodeInterleavedOld, "DecodeInterleavedOld"}, |
|||
{1, &IHardwareOpusDecoder::SetContext, "SetContext"}, |
|||
{2, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld, "DecodeInterleavedForMultiStreamOld"}, |
|||
{3, &IHardwareOpusDecoder::SetContextForMultiStream, "SetContextForMultiStream"}, |
|||
{4, &IHardwareOpusDecoder::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"}, |
|||
{5, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld, "DecodeInterleavedForMultiStreamWithPerfOld"}, |
|||
{6, &IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld, "DecodeInterleavedWithPerfAndResetOld"}, |
|||
{7, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"}, |
|||
{8, &IHardwareOpusDecoder::DecodeInterleaved, "DecodeInterleaved"}, |
|||
{9, &IHardwareOpusDecoder::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, |
|||
u64 transfer_memory_size) { |
|||
return impl->Initialize(params, transfer_memory, transfer_memory_size); |
|||
} |
|||
|
|||
Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory, |
|||
u64 transfer_memory_size) { |
|||
return impl->Initialize(params, transfer_memory, transfer_memory_size); |
|||
} |
|||
|
|||
private: |
|||
void DecodeInterleavedOld(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
output_data.resize_destructive(ctx.GetWriteBufferSize()); |
|||
|
|||
u32 size{}; |
|||
u32 sample_count{}; |
|||
auto result = |
|||
impl->DecodeInterleaved(&size, nullptr, &sample_count, input_data, output_data, false); |
|||
|
|||
LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count); |
|||
|
|||
ctx.WriteBuffer(output_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
rb.Push(sample_count); |
|||
} |
|||
|
|||
void SetContext(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
auto result = impl->SetContext(input_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void DecodeInterleavedForMultiStreamOld(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
output_data.resize_destructive(ctx.GetWriteBufferSize()); |
|||
|
|||
u32 size{}; |
|||
u32 sample_count{}; |
|||
auto result = impl->DecodeInterleavedForMultiStream(&size, nullptr, &sample_count, |
|||
input_data, output_data, false); |
|||
|
|||
LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count); |
|||
|
|||
ctx.WriteBuffer(output_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
rb.Push(sample_count); |
|||
} |
|||
|
|||
void SetContextForMultiStream(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "called"); |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
auto result = impl->SetContext(input_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void DecodeInterleavedWithPerfOld(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
output_data.resize_destructive(ctx.GetWriteBufferSize()); |
|||
|
|||
u32 size{}; |
|||
u32 sample_count{}; |
|||
u64 time_taken{}; |
|||
auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data, |
|||
output_data, false); |
|||
|
|||
LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size, |
|||
sample_count, time_taken); |
|||
|
|||
ctx.WriteBuffer(output_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
rb.Push(sample_count); |
|||
rb.Push(time_taken); |
|||
} |
|||
|
|||
void DecodeInterleavedForMultiStreamWithPerfOld(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
output_data.resize_destructive(ctx.GetWriteBufferSize()); |
|||
|
|||
u32 size{}; |
|||
u32 sample_count{}; |
|||
u64 time_taken{}; |
|||
auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count, |
|||
input_data, output_data, false); |
|||
|
|||
LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size, |
|||
sample_count, time_taken); |
|||
|
|||
ctx.WriteBuffer(output_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
rb.Push(sample_count); |
|||
rb.Push(time_taken); |
|||
} |
|||
|
|||
void DecodeInterleavedWithPerfAndResetOld(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto reset{rp.Pop<bool>()}; |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
output_data.resize_destructive(ctx.GetWriteBufferSize()); |
|||
|
|||
u32 size{}; |
|||
u32 sample_count{}; |
|||
u64 time_taken{}; |
|||
auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data, |
|||
output_data, reset); |
|||
|
|||
LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}", |
|||
reset, size, sample_count, time_taken); |
|||
|
|||
ctx.WriteBuffer(output_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
rb.Push(sample_count); |
|||
rb.Push(time_taken); |
|||
} |
|||
|
|||
void DecodeInterleavedForMultiStreamWithPerfAndResetOld(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto reset{rp.Pop<bool>()}; |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
output_data.resize_destructive(ctx.GetWriteBufferSize()); |
|||
|
|||
u32 size{}; |
|||
u32 sample_count{}; |
|||
u64 time_taken{}; |
|||
auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count, |
|||
input_data, output_data, reset); |
|||
|
|||
LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}", |
|||
reset, size, sample_count, time_taken); |
|||
|
|||
ctx.WriteBuffer(output_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
rb.Push(sample_count); |
|||
rb.Push(time_taken); |
|||
} |
|||
|
|||
void DecodeInterleaved(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto reset{rp.Pop<bool>()}; |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
output_data.resize_destructive(ctx.GetWriteBufferSize()); |
|||
|
|||
u32 size{}; |
|||
u32 sample_count{}; |
|||
u64 time_taken{}; |
|||
auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data, |
|||
output_data, reset); |
|||
|
|||
LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}", |
|||
reset, size, sample_count, time_taken); |
|||
|
|||
ctx.WriteBuffer(output_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
rb.Push(sample_count); |
|||
rb.Push(time_taken); |
|||
} |
|||
|
|||
void DecodeInterleavedForMultiStream(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto reset{rp.Pop<bool>()}; |
|||
|
|||
auto input_data{ctx.ReadBuffer(0)}; |
|||
output_data.resize_destructive(ctx.GetWriteBufferSize()); |
|||
|
|||
u32 size{}; |
|||
u32 sample_count{}; |
|||
u64 time_taken{}; |
|||
auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count, |
|||
input_data, output_data, reset); |
|||
|
|||
LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}", |
|||
reset, size, sample_count, time_taken); |
|||
|
|||
ctx.WriteBuffer(output_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
rb.Push(sample_count); |
|||
rb.Push(time_taken); |
|||
} |
|||
|
|||
std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl; |
|||
Common::ScratchBuffer<u8> output_data; |
|||
}; |
|||
|
|||
void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto params = rp.PopRaw<OpusParameters>(); |
|||
auto transfer_memory_size{rp.Pop<u32>()}; |
|||
auto transfer_memory_handle{ctx.GetCopyHandle(0)}; |
|||
auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; |
|||
|
|||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}", |
|||
params.sample_rate, params.channel_count, transfer_memory_size); |
|||
|
|||
auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())}; |
|||
|
|||
OpusParametersEx ex{ |
|||
.sample_rate = params.sample_rate, |
|||
.channel_count = params.channel_count, |
|||
.use_large_frame_size = false, |
|||
}; |
|||
auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(result); |
|||
rb.PushIpcInterface(decoder); |
|||
} |
|||
|
|||
void HwOpus::GetWorkBufferSize(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
auto params = rp.PopRaw<OpusParameters>(); |
|||
|
|||
u64 size{}; |
|||
auto result = impl.GetWorkBufferSize(params, size); |
|||
|
|||
LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size 0x{:X}", |
|||
params.sample_rate, params.channel_count, size); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(result); |
|||
rb.Push(size); |
|||
} |
|||
|
|||
void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
auto input{ctx.ReadBuffer()}; |
|||
OpusMultiStreamParameters params; |
|||
std::memcpy(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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
|
|||
@ -1,36 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "audio_core/opus/decoder_manager.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} |
|||
|
|||
namespace Service::Audio { |
|||
|
|||
class HwOpus final : public ServiceFramework<HwOpus> { |
|||
public: |
|||
explicit HwOpus(Core::System& system_); |
|||
~HwOpus() override; |
|||
|
|||
private: |
|||
void OpenHardwareOpusDecoder(HLERequestContext& ctx); |
|||
void GetWorkBufferSize(HLERequestContext& ctx); |
|||
void OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx); |
|||
void GetWorkBufferSizeForMultiStream(HLERequestContext& ctx); |
|||
void OpenHardwareOpusDecoderEx(HLERequestContext& ctx); |
|||
void GetWorkBufferSizeEx(HLERequestContext& ctx); |
|||
void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx); |
|||
void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx); |
|||
void GetWorkBufferSizeExEx(HLERequestContext& ctx); |
|||
void GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx); |
|||
|
|||
Core::System& system; |
|||
AudioCore::OpusDecoder::OpusDecoderManager impl; |
|||
}; |
|||
|
|||
} // namespace Service::Audio |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue