Browse Source
Merge pull request #13100 from liamwhite/audio-ipc
Merge pull request #13100 from liamwhite/audio-ipc
audio: move to new ipcpull/15/merge
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
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