diff options
Diffstat (limited to 'src/audio_core/device')
-rw-r--r-- | src/audio_core/device/audio_buffer.h | 4 | ||||
-rw-r--r-- | src/audio_core/device/audio_buffers.h | 21 | ||||
-rw-r--r-- | src/audio_core/device/device_session.cpp | 64 | ||||
-rw-r--r-- | src/audio_core/device/device_session.h | 34 |
4 files changed, 90 insertions, 33 deletions
diff --git a/src/audio_core/device/audio_buffer.h b/src/audio_core/device/audio_buffer.h index cae7fa970..7128ef72a 100644 --- a/src/audio_core/device/audio_buffer.h +++ b/src/audio_core/device/audio_buffer.h @@ -8,6 +8,10 @@ namespace AudioCore { struct AudioBuffer { + /// Timestamp this buffer started playing. + u64 start_timestamp; + /// Timestamp this buffer should finish playing. + u64 end_timestamp; /// Timestamp this buffer completed playing. s64 played_timestamp; /// Game memory address for these samples. diff --git a/src/audio_core/device/audio_buffers.h b/src/audio_core/device/audio_buffers.h index 5d1979ea0..3dae1a3b7 100644 --- a/src/audio_core/device/audio_buffers.h +++ b/src/audio_core/device/audio_buffers.h @@ -36,7 +36,7 @@ public: * * @param buffer - The new buffer. */ - void AppendBuffer(AudioBuffer& buffer) { + void AppendBuffer(const AudioBuffer& buffer) { std::scoped_lock l{lock}; buffers[appended_index] = buffer; appended_count++; @@ -58,6 +58,7 @@ public: if (index < 0) { index += N; } + out_buffers.push_back(buffers[index]); registered_count++; registered_index = (registered_index + 1) % append_limit; @@ -87,10 +88,12 @@ public: /** * Release all registered buffers. * - * @param timestamp - The released timestamp for this buffer. + * @param core_timing - The CoreTiming instance + * @param session - The device session + * * @return Is the buffer was released. */ - bool ReleaseBuffers(Core::Timing::CoreTiming& core_timing, DeviceSession& session) { + bool ReleaseBuffers(const Core::Timing::CoreTiming& core_timing, const DeviceSession& session) { std::scoped_lock l{lock}; bool buffer_released{false}; while (registered_count > 0) { @@ -100,7 +103,7 @@ public: } // Check with the backend if this buffer can be released yet. - if (!session.IsBufferConsumed(buffers[index].tag)) { + if (!session.IsBufferConsumed(buffers[index])) { break; } @@ -280,6 +283,16 @@ public: return true; } + u64 GetNextTimestamp() const { + // Iterate backwards through the buffer queue, and take the most recent buffer's end + std::scoped_lock l{lock}; + auto index{appended_index - 1}; + if (index < 0) { + index += append_limit; + } + return buffers[index].end_timestamp; + } + private: /// Buffer lock mutable std::recursive_mutex lock{}; diff --git a/src/audio_core/device/device_session.cpp b/src/audio_core/device/device_session.cpp index 095fc96ce..995060414 100644 --- a/src/audio_core/device/device_session.cpp +++ b/src/audio_core/device/device_session.cpp @@ -7,11 +7,20 @@ #include "audio_core/device/device_session.h" #include "audio_core/sink/sink_stream.h" #include "core/core.h" +#include "core/core_timing.h" #include "core/memory.h" namespace AudioCore { -DeviceSession::DeviceSession(Core::System& system_) : system{system_} {} +using namespace std::literals; +constexpr auto INCREMENT_TIME{5ms}; + +DeviceSession::DeviceSession(Core::System& system_) + : system{system_}, thread_event{Core::Timing::CreateEvent( + "AudioOutSampleTick", + [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) { + return ThreadFunc(); + })} {} DeviceSession::~DeviceSession() { Finalize(); @@ -50,25 +59,26 @@ void DeviceSession::Finalize() { } void DeviceSession::Start() { - stream->SetPlayedSampleCount(played_sample_count); - stream->Start(); + if (stream) { + stream->Start(); + system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds::zero(), INCREMENT_TIME, + thread_event); + } } void DeviceSession::Stop() { if (stream) { - played_sample_count = stream->GetPlayedSampleCount(); stream->Stop(); + system.CoreTiming().UnscheduleEvent(thread_event, {}); } } -void DeviceSession::AppendBuffers(std::span<AudioBuffer> buffers) const { - auto& memory{system.Memory()}; - - for (size_t i = 0; i < buffers.size(); i++) { +void DeviceSession::AppendBuffers(std::span<const AudioBuffer> buffers) const { + for (const auto& buffer : buffers) { Sink::SinkBuffer new_buffer{ - .frames = buffers[i].size / (channel_count * sizeof(s16)), + .frames = buffer.size / (channel_count * sizeof(s16)), .frames_played = 0, - .tag = buffers[i].tag, + .tag = buffer.tag, .consumed = false, }; @@ -76,26 +86,22 @@ void DeviceSession::AppendBuffers(std::span<AudioBuffer> buffers) const { std::vector<s16> samples{}; stream->AppendBuffer(new_buffer, samples); } else { - std::vector<s16> samples(buffers[i].size / sizeof(s16)); - memory.ReadBlockUnsafe(buffers[i].samples, samples.data(), buffers[i].size); + std::vector<s16> samples(buffer.size / sizeof(s16)); + system.Memory().ReadBlockUnsafe(buffer.samples, samples.data(), buffer.size); stream->AppendBuffer(new_buffer, samples); } } } -void DeviceSession::ReleaseBuffer(AudioBuffer& buffer) const { +void DeviceSession::ReleaseBuffer(const AudioBuffer& buffer) const { if (type == Sink::StreamType::In) { - auto& memory{system.Memory()}; auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))}; - memory.WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size); + system.Memory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size); } } -bool DeviceSession::IsBufferConsumed(u64 tag) const { - if (stream) { - return stream->IsBufferConsumed(tag); - } - return true; +bool DeviceSession::IsBufferConsumed(const AudioBuffer& buffer) const { + return played_sample_count >= buffer.end_timestamp; } void DeviceSession::SetVolume(f32 volume) const { @@ -105,10 +111,22 @@ void DeviceSession::SetVolume(f32 volume) const { } u64 DeviceSession::GetPlayedSampleCount() const { - if (stream) { - return stream->GetPlayedSampleCount(); + return played_sample_count; +} + +std::optional<std::chrono::nanoseconds> DeviceSession::ThreadFunc() { + // Add 5ms of samples at a 48K sample rate. + played_sample_count += 48'000 * INCREMENT_TIME / 1s; + if (type == Sink::StreamType::Out) { + system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioOutManager, true); + } else { + system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioInManager, true); } - return 0; + return std::nullopt; +} + +void DeviceSession::SetRingSize(u32 ring_size) { + stream->SetRingSize(ring_size); } } // namespace AudioCore diff --git a/src/audio_core/device/device_session.h b/src/audio_core/device/device_session.h index 4a031b765..74f4dc085 100644 --- a/src/audio_core/device/device_session.h +++ b/src/audio_core/device/device_session.h @@ -3,6 +3,9 @@ #pragma once +#include <chrono> +#include <memory> +#include <optional> #include <span> #include "audio_core/common/common.h" @@ -11,9 +14,13 @@ namespace Core { class System; -} +namespace Timing { +struct EventType; +} // namespace Timing +} // namespace Core namespace AudioCore { + namespace Sink { class SinkStream; struct SinkBuffer; @@ -55,22 +62,23 @@ public: * * @param buffers - The buffers to play. */ - void AppendBuffers(std::span<AudioBuffer> buffers) const; + void AppendBuffers(std::span<const AudioBuffer> buffers) const; /** * (Audio In only) Pop samples from the backend, and write them back to this buffer's address. * * @param buffer - The buffer to write to. */ - void ReleaseBuffer(AudioBuffer& buffer) const; + void ReleaseBuffer(const AudioBuffer& buffer) const; /** * Check if the buffer for the given tag has been consumed by the backend. * - * @param tag - Unqiue tag of the buffer to check. + * @param buffer - the buffer to check. + * * @return true if the buffer has been consumed, otherwise false. */ - bool IsBufferConsumed(u64 tag) const; + bool IsBufferConsumed(const AudioBuffer& buffer) const; /** * Start this device session, starting the backend stream. @@ -96,6 +104,16 @@ public: */ u64 GetPlayedSampleCount() const; + /* + * CoreTiming callback to increment played_sample_count over time. + */ + std::optional<std::chrono::nanoseconds> ThreadFunc(); + + /* + * Set the size of the ring buffer. + */ + void SetRingSize(u32 ring_size); + private: /// System Core::System& system; @@ -118,9 +136,13 @@ private: /// Applet resource user id of this device session u64 applet_resource_user_id{}; /// Total number of samples played by this device session - u64 played_sample_count{}; + std::atomic<u64> played_sample_count{}; + /// Event increasing the played sample count every 5ms + std::shared_ptr<Core::Timing::EventType> thread_event; /// Is this session initialised? bool initialized{}; + /// Buffer queue + std::vector<AudioBuffer> buffer_queue{}; }; } // namespace AudioCore |