mirror of https://git.suyu.dev/suyu/suyu
commit
215e887be0
@ -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
|
|
Loading…
Reference in New Issue