2022-07-16 22:48:45 +00:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
#include "audio_core/audio_core.h"
|
|
|
|
#include "audio_core/audio_manager.h"
|
|
|
|
#include "audio_core/device/audio_buffer.h"
|
|
|
|
#include "audio_core/device/device_session.h"
|
|
|
|
#include "audio_core/sink/sink_stream.h"
|
|
|
|
#include "core/core.h"
|
2022-08-01 01:58:13 +00:00
|
|
|
#include "core/core_timing.h"
|
2023-12-25 06:32:16 +00:00
|
|
|
#include "core/guest_memory.h"
|
2023-12-31 19:55:15 +00:00
|
|
|
#include "core/memory.h"
|
2022-07-16 22:48:45 +00:00
|
|
|
|
2024-01-12 14:35:08 +00:00
|
|
|
#include "core/hle/kernel/k_process.h"
|
|
|
|
|
2022-07-16 22:48:45 +00:00
|
|
|
namespace AudioCore {
|
|
|
|
|
2022-08-01 01:58:13 +00:00
|
|
|
using namespace std::literals;
|
|
|
|
constexpr auto INCREMENT_TIME{5ms};
|
|
|
|
|
|
|
|
DeviceSession::DeviceSession(Core::System& system_)
|
|
|
|
: system{system_}, thread_event{Core::Timing::CreateEvent(
|
|
|
|
"AudioOutSampleTick",
|
2023-12-23 18:58:09 +00:00
|
|
|
[this](s64 time, std::chrono::nanoseconds) { return ThreadFunc(); })} {}
|
2022-07-16 22:48:45 +00:00
|
|
|
|
|
|
|
DeviceSession::~DeviceSession() {
|
|
|
|
Finalize();
|
|
|
|
}
|
|
|
|
|
|
|
|
Result DeviceSession::Initialize(std::string_view name_, SampleFormat sample_format_,
|
2024-01-12 14:35:08 +00:00
|
|
|
u16 channel_count_, size_t session_id_, Kernel::KProcess* handle_,
|
2022-07-16 22:48:45 +00:00
|
|
|
u64 applet_resource_user_id_, Sink::StreamType type_) {
|
|
|
|
if (stream) {
|
|
|
|
Finalize();
|
|
|
|
}
|
|
|
|
name = fmt::format("{}-{}", name_, session_id_);
|
|
|
|
type = type_;
|
|
|
|
sample_format = sample_format_;
|
|
|
|
channel_count = channel_count_;
|
|
|
|
session_id = session_id_;
|
|
|
|
handle = handle_;
|
2024-01-12 14:35:08 +00:00
|
|
|
handle->Open();
|
2022-07-16 22:48:45 +00:00
|
|
|
applet_resource_user_id = applet_resource_user_id_;
|
|
|
|
|
|
|
|
if (type == Sink::StreamType::In) {
|
|
|
|
sink = &system.AudioCore().GetInputSink();
|
|
|
|
} else {
|
|
|
|
sink = &system.AudioCore().GetOutputSink();
|
|
|
|
}
|
|
|
|
stream = sink->AcquireSinkStream(system, channel_count, name, type);
|
|
|
|
initialized = true;
|
|
|
|
return ResultSuccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceSession::Finalize() {
|
|
|
|
if (initialized) {
|
|
|
|
Stop();
|
|
|
|
sink->CloseStream(stream);
|
|
|
|
stream = nullptr;
|
|
|
|
}
|
2024-01-12 14:35:08 +00:00
|
|
|
|
|
|
|
if (handle) {
|
|
|
|
handle->Close();
|
|
|
|
handle = nullptr;
|
|
|
|
}
|
2022-07-16 22:48:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceSession::Start() {
|
2022-08-01 01:58:13 +00:00
|
|
|
if (stream) {
|
|
|
|
stream->Start();
|
|
|
|
system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds::zero(), INCREMENT_TIME,
|
|
|
|
thread_event);
|
|
|
|
}
|
2022-07-16 22:48:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceSession::Stop() {
|
|
|
|
if (stream) {
|
|
|
|
stream->Stop();
|
2022-08-01 01:58:13 +00:00
|
|
|
system.CoreTiming().UnscheduleEvent(thread_event, {});
|
2022-07-16 22:48:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-16 16:01:35 +00:00
|
|
|
void DeviceSession::ClearBuffers() {
|
|
|
|
if (stream) {
|
|
|
|
stream->ClearQueue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-23 13:45:54 +00:00
|
|
|
void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) {
|
2022-09-16 13:32:55 +00:00
|
|
|
for (const auto& buffer : buffers) {
|
2022-07-16 22:48:45 +00:00
|
|
|
Sink::SinkBuffer new_buffer{
|
2022-09-16 13:32:55 +00:00
|
|
|
.frames = buffer.size / (channel_count * sizeof(s16)),
|
2022-07-16 22:48:45 +00:00
|
|
|
.frames_played = 0,
|
2022-09-16 13:32:55 +00:00
|
|
|
.tag = buffer.tag,
|
2022-07-16 22:48:45 +00:00
|
|
|
.consumed = false,
|
|
|
|
};
|
|
|
|
|
2023-05-23 13:45:54 +00:00
|
|
|
tmp_samples.resize_destructive(buffer.size / sizeof(s16));
|
2022-07-16 22:48:45 +00:00
|
|
|
if (type == Sink::StreamType::In) {
|
2023-05-23 13:45:54 +00:00
|
|
|
stream->AppendBuffer(new_buffer, tmp_samples);
|
2022-07-16 22:48:45 +00:00
|
|
|
} else {
|
2023-05-28 23:35:51 +00:00
|
|
|
Core::Memory::CpuGuestMemory<s16, Core::Memory::GuestMemoryFlags::UnsafeRead> samples(
|
2024-01-12 14:35:08 +00:00
|
|
|
handle->GetMemory(), buffer.samples, buffer.size / sizeof(s16));
|
2023-05-28 23:35:51 +00:00
|
|
|
stream->AppendBuffer(new_buffer, samples);
|
2022-07-16 22:48:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-16 13:29:28 +00:00
|
|
|
void DeviceSession::ReleaseBuffer(const AudioBuffer& buffer) const {
|
2022-07-16 22:48:45 +00:00
|
|
|
if (type == Sink::StreamType::In) {
|
|
|
|
auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))};
|
2024-01-12 14:35:08 +00:00
|
|
|
handle->GetMemory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size);
|
2022-07-16 22:48:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-16 13:29:28 +00:00
|
|
|
bool DeviceSession::IsBufferConsumed(const AudioBuffer& buffer) const {
|
2022-08-01 01:58:13 +00:00
|
|
|
return played_sample_count >= buffer.end_timestamp;
|
2022-07-16 22:48:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceSession::SetVolume(f32 volume) const {
|
|
|
|
if (stream) {
|
|
|
|
stream->SetSystemVolume(volume);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 DeviceSession::GetPlayedSampleCount() const {
|
2022-08-01 01:58:13 +00:00
|
|
|
return played_sample_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<std::chrono::nanoseconds> DeviceSession::ThreadFunc() {
|
2023-03-18 20:52:02 +00:00
|
|
|
played_sample_count = stream->GetExpectedPlayedSampleCount();
|
2022-08-01 01:58:13 +00:00
|
|
|
if (type == Sink::StreamType::Out) {
|
|
|
|
system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioOutManager, true);
|
|
|
|
} else {
|
|
|
|
system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioInManager, true);
|
2022-07-16 22:48:45 +00:00
|
|
|
}
|
2022-08-01 01:58:13 +00:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeviceSession::SetRingSize(u32 ring_size) {
|
|
|
|
stream->SetRingSize(ring_size);
|
2022-07-16 22:48:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace AudioCore
|