summaryrefslogtreecommitdiff
path: root/src/audio_core/device
diff options
context:
space:
mode:
authorGravatar Kelebek12022-08-01 02:58:13 +0100
committerGravatar Kelebek12022-09-02 04:43:04 +0100
commitea9ff71725113b8dbb159917c57aa536bba0cb53 (patch)
tree512cce0fea5eb511aa7803bc67f741815885bfcb /src/audio_core/device
parentMerge pull request #8752 from vonchenplus/rectangle_texture (diff)
downloadyuzu-ea9ff71725113b8dbb159917c57aa536bba0cb53.tar.gz
yuzu-ea9ff71725113b8dbb159917c57aa536bba0cb53.tar.xz
yuzu-ea9ff71725113b8dbb159917c57aa536bba0cb53.zip
Rework audio output, connecting AudioOut into coretiming to fix desync during heavy loads.
Diffstat (limited to 'src/audio_core/device')
-rw-r--r--src/audio_core/device/audio_buffer.h4
-rw-r--r--src/audio_core/device/audio_buffers.h13
-rw-r--r--src/audio_core/device/device_session.cpp52
-rw-r--r--src/audio_core/device/device_session.h27
4 files changed, 75 insertions, 21 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 @@
8namespace AudioCore { 8namespace AudioCore {
9 9
10struct AudioBuffer { 10struct AudioBuffer {
11 /// Timestamp this buffer started playing.
12 u64 start_timestamp;
13 /// Timestamp this buffer should finish playing.
14 u64 end_timestamp;
11 /// Timestamp this buffer completed playing. 15 /// Timestamp this buffer completed playing.
12 s64 played_timestamp; 16 s64 played_timestamp;
13 /// Game memory address for these samples. 17 /// 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..57c78d439 100644
--- a/src/audio_core/device/audio_buffers.h
+++ b/src/audio_core/device/audio_buffers.h
@@ -58,6 +58,7 @@ public:
58 if (index < 0) { 58 if (index < 0) {
59 index += N; 59 index += N;
60 } 60 }
61
61 out_buffers.push_back(buffers[index]); 62 out_buffers.push_back(buffers[index]);
62 registered_count++; 63 registered_count++;
63 registered_index = (registered_index + 1) % append_limit; 64 registered_index = (registered_index + 1) % append_limit;
@@ -100,7 +101,7 @@ public:
100 } 101 }
101 102
102 // Check with the backend if this buffer can be released yet. 103 // Check with the backend if this buffer can be released yet.
103 if (!session.IsBufferConsumed(buffers[index].tag)) { 104 if (!session.IsBufferConsumed(buffers[index])) {
104 break; 105 break;
105 } 106 }
106 107
@@ -280,6 +281,16 @@ public:
280 return true; 281 return true;
281 } 282 }
282 283
284 u64 GetNextTimestamp() const {
285 // Iterate backwards through the buffer queue, and take the most recent buffer's end
286 std::scoped_lock l{lock};
287 auto index{appended_index - 1};
288 if (index < 0) {
289 index += append_limit;
290 }
291 return buffers[index].end_timestamp;
292 }
293
283private: 294private:
284 /// Buffer lock 295 /// Buffer lock
285 mutable std::recursive_mutex lock{}; 296 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..c71c3a376 100644
--- a/src/audio_core/device/device_session.cpp
+++ b/src/audio_core/device/device_session.cpp
@@ -7,11 +7,20 @@
7#include "audio_core/device/device_session.h" 7#include "audio_core/device/device_session.h"
8#include "audio_core/sink/sink_stream.h" 8#include "audio_core/sink/sink_stream.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/core_timing.h"
10#include "core/memory.h" 11#include "core/memory.h"
11 12
12namespace AudioCore { 13namespace AudioCore {
13 14
14DeviceSession::DeviceSession(Core::System& system_) : system{system_} {} 15using namespace std::literals;
16constexpr auto INCREMENT_TIME{5ms};
17
18DeviceSession::DeviceSession(Core::System& system_)
19 : system{system_}, thread_event{Core::Timing::CreateEvent(
20 "AudioOutSampleTick",
21 [this](std::uintptr_t, s64 time, std::chrono::nanoseconds) {
22 return ThreadFunc();
23 })} {}
15 24
16DeviceSession::~DeviceSession() { 25DeviceSession::~DeviceSession() {
17 Finalize(); 26 Finalize();
@@ -50,20 +59,21 @@ void DeviceSession::Finalize() {
50} 59}
51 60
52void DeviceSession::Start() { 61void DeviceSession::Start() {
53 stream->SetPlayedSampleCount(played_sample_count); 62 if (stream) {
54 stream->Start(); 63 stream->Start();
64 system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds::zero(), INCREMENT_TIME,
65 thread_event);
66 }
55} 67}
56 68
57void DeviceSession::Stop() { 69void DeviceSession::Stop() {
58 if (stream) { 70 if (stream) {
59 played_sample_count = stream->GetPlayedSampleCount();
60 stream->Stop(); 71 stream->Stop();
72 system.CoreTiming().UnscheduleEvent(thread_event, {});
61 } 73 }
62} 74}
63 75
64void DeviceSession::AppendBuffers(std::span<AudioBuffer> buffers) const { 76void DeviceSession::AppendBuffers(std::span<AudioBuffer> buffers) const {
65 auto& memory{system.Memory()};
66
67 for (size_t i = 0; i < buffers.size(); i++) { 77 for (size_t i = 0; i < buffers.size(); i++) {
68 Sink::SinkBuffer new_buffer{ 78 Sink::SinkBuffer new_buffer{
69 .frames = buffers[i].size / (channel_count * sizeof(s16)), 79 .frames = buffers[i].size / (channel_count * sizeof(s16)),
@@ -77,7 +87,7 @@ void DeviceSession::AppendBuffers(std::span<AudioBuffer> buffers) const {
77 stream->AppendBuffer(new_buffer, samples); 87 stream->AppendBuffer(new_buffer, samples);
78 } else { 88 } else {
79 std::vector<s16> samples(buffers[i].size / sizeof(s16)); 89 std::vector<s16> samples(buffers[i].size / sizeof(s16));
80 memory.ReadBlockUnsafe(buffers[i].samples, samples.data(), buffers[i].size); 90 system.Memory().ReadBlockUnsafe(buffers[i].samples, samples.data(), buffers[i].size);
81 stream->AppendBuffer(new_buffer, samples); 91 stream->AppendBuffer(new_buffer, samples);
82 } 92 }
83 } 93 }
@@ -85,17 +95,13 @@ void DeviceSession::AppendBuffers(std::span<AudioBuffer> buffers) const {
85 95
86void DeviceSession::ReleaseBuffer(AudioBuffer& buffer) const { 96void DeviceSession::ReleaseBuffer(AudioBuffer& buffer) const {
87 if (type == Sink::StreamType::In) { 97 if (type == Sink::StreamType::In) {
88 auto& memory{system.Memory()};
89 auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))}; 98 auto samples{stream->ReleaseBuffer(buffer.size / sizeof(s16))};
90 memory.WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size); 99 system.Memory().WriteBlockUnsafe(buffer.samples, samples.data(), buffer.size);
91 } 100 }
92} 101}
93 102
94bool DeviceSession::IsBufferConsumed(u64 tag) const { 103bool DeviceSession::IsBufferConsumed(AudioBuffer& buffer) const {
95 if (stream) { 104 return played_sample_count >= buffer.end_timestamp;
96 return stream->IsBufferConsumed(tag);
97 }
98 return true;
99} 105}
100 106
101void DeviceSession::SetVolume(f32 volume) const { 107void DeviceSession::SetVolume(f32 volume) const {
@@ -105,10 +111,22 @@ void DeviceSession::SetVolume(f32 volume) const {
105} 111}
106 112
107u64 DeviceSession::GetPlayedSampleCount() const { 113u64 DeviceSession::GetPlayedSampleCount() const {
108 if (stream) { 114 return played_sample_count;
109 return stream->GetPlayedSampleCount(); 115}
116
117std::optional<std::chrono::nanoseconds> DeviceSession::ThreadFunc() {
118 // Add 5ms of samples at a 48K sample rate.
119 played_sample_count += 48'000 * INCREMENT_TIME / 1s;
120 if (type == Sink::StreamType::Out) {
121 system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioOutManager, true);
122 } else {
123 system.AudioCore().GetAudioManager().SetEvent(Event::Type::AudioInManager, true);
110 } 124 }
111 return 0; 125 return std::nullopt;
126}
127
128void DeviceSession::SetRingSize(u32 ring_size) {
129 stream->SetRingSize(ring_size);
112} 130}
113 131
114} // namespace AudioCore 132} // namespace AudioCore
diff --git a/src/audio_core/device/device_session.h b/src/audio_core/device/device_session.h
index 4a031b765..3414e2c06 100644
--- a/src/audio_core/device/device_session.h
+++ b/src/audio_core/device/device_session.h
@@ -3,6 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <chrono>
7#include <memory>
8#include <optional>
6#include <span> 9#include <span>
7 10
8#include "audio_core/common/common.h" 11#include "audio_core/common/common.h"
@@ -11,9 +14,13 @@
11 14
12namespace Core { 15namespace Core {
13class System; 16class System;
14} 17namespace Timing {
18struct EventType;
19} // namespace Timing
20} // namespace Core
15 21
16namespace AudioCore { 22namespace AudioCore {
23
17namespace Sink { 24namespace Sink {
18class SinkStream; 25class SinkStream;
19struct SinkBuffer; 26struct SinkBuffer;
@@ -70,7 +77,7 @@ public:
70 * @param tag - Unqiue tag of the buffer to check. 77 * @param tag - Unqiue tag of the buffer to check.
71 * @return true if the buffer has been consumed, otherwise false. 78 * @return true if the buffer has been consumed, otherwise false.
72 */ 79 */
73 bool IsBufferConsumed(u64 tag) const; 80 bool IsBufferConsumed(AudioBuffer& buffer) const;
74 81
75 /** 82 /**
76 * Start this device session, starting the backend stream. 83 * Start this device session, starting the backend stream.
@@ -96,6 +103,16 @@ public:
96 */ 103 */
97 u64 GetPlayedSampleCount() const; 104 u64 GetPlayedSampleCount() const;
98 105
106 /*
107 * CoreTiming callback to increment played_sample_count over time.
108 */
109 std::optional<std::chrono::nanoseconds> ThreadFunc();
110
111 /*
112 * Set the size of the ring buffer.
113 */
114 void SetRingSize(u32 ring_size);
115
99private: 116private:
100 /// System 117 /// System
101 Core::System& system; 118 Core::System& system;
@@ -118,9 +135,13 @@ private:
118 /// Applet resource user id of this device session 135 /// Applet resource user id of this device session
119 u64 applet_resource_user_id{}; 136 u64 applet_resource_user_id{};
120 /// Total number of samples played by this device session 137 /// Total number of samples played by this device session
121 u64 played_sample_count{}; 138 std::atomic<u64> played_sample_count{};
139 /// Event increasing the played sample count every 5ms
140 std::shared_ptr<Core::Timing::EventType> thread_event;
122 /// Is this session initialised? 141 /// Is this session initialised?
123 bool initialized{}; 142 bool initialized{};
143 /// Buffer queue
144 std::vector<AudioBuffer> buffer_queue{};
124}; 145};
125 146
126} // namespace AudioCore 147} // namespace AudioCore