summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar MerryMage2018-09-08 14:55:11 +0100
committerGravatar MerryMage2018-09-08 18:56:38 +0100
commit6d9dd1dc6dacbba9907e7c4e92e2d9d111ef44f4 (patch)
treec7f883a8e1045db05a80003d4f63a616602e4c7f /src
parentcommon: Implement a ring buffer (diff)
downloadyuzu-6d9dd1dc6dacbba9907e7c4e92e2d9d111ef44f4.tar.gz
yuzu-6d9dd1dc6dacbba9907e7c4e92e2d9d111ef44f4.tar.xz
yuzu-6d9dd1dc6dacbba9907e7c4e92e2d9d111ef44f4.zip
cubeb_sink: Use RingBuffer
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/cubeb_sink.cpp66
1 files changed, 26 insertions, 40 deletions
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 0f77fd162..552bcd051 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -4,18 +4,17 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring> 6#include <cstring>
7#include <mutex>
8
9#include "audio_core/cubeb_sink.h" 7#include "audio_core/cubeb_sink.h"
10#include "audio_core/stream.h" 8#include "audio_core/stream.h"
11#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/ring_buffer.h"
12 11
13namespace AudioCore { 12namespace AudioCore {
14 13
15class SinkStreamImpl final : public SinkStream { 14class CubebSinkStream final : public SinkStream {
16public: 15public:
17 SinkStreamImpl(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device, 16 CubebSinkStream(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
18 const std::string& name) 17 const std::string& name)
19 : ctx{ctx}, num_channels{num_channels_} { 18 : ctx{ctx}, num_channels{num_channels_} {
20 19
21 if (num_channels == 6) { 20 if (num_channels == 6) {
@@ -38,7 +37,7 @@ public:
38 37
39 if (cubeb_stream_init(ctx, &stream_backend, name.c_str(), nullptr, nullptr, output_device, 38 if (cubeb_stream_init(ctx, &stream_backend, name.c_str(), nullptr, nullptr, output_device,
40 &params, std::max(512u, minimum_latency), 39 &params, std::max(512u, minimum_latency),
41 &SinkStreamImpl::DataCallback, &SinkStreamImpl::StateCallback, 40 &CubebSinkStream::DataCallback, &CubebSinkStream::StateCallback,
42 this) != CUBEB_OK) { 41 this) != CUBEB_OK) {
43 LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream"); 42 LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream");
44 return; 43 return;
@@ -50,7 +49,7 @@ public:
50 } 49 }
51 } 50 }
52 51
53 ~SinkStreamImpl() { 52 ~CubebSinkStream() {
54 if (!ctx) { 53 if (!ctx) {
55 return; 54 return;
56 } 55 }
@@ -63,33 +62,27 @@ public:
63 } 62 }
64 63
65 void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) override { 64 void EnqueueSamples(u32 num_channels, const std::vector<s16>& samples) override {
66 if (!ctx) {
67 return;
68 }
69
70 std::lock_guard lock{queue_mutex};
71
72 queue.reserve(queue.size() + samples.size() * GetNumChannels());
73
74 if (is_6_channel) { 65 if (is_6_channel) {
75 // Downsample 6 channels to 2 66 // Downsample 6 channels to 2
76 const size_t sample_count_copy_size = samples.size() * 2; 67 const size_t sample_count_copy_size = samples.size() * 2;
77 queue.reserve(sample_count_copy_size); 68 std::vector<s16> buf;
69 buf.reserve(sample_count_copy_size);
78 for (size_t i = 0; i < samples.size(); i += num_channels) { 70 for (size_t i = 0; i < samples.size(); i += num_channels) {
79 queue.push_back(samples[i]); 71 buf.push_back(samples[i]);
80 queue.push_back(samples[i + 1]); 72 buf.push_back(samples[i + 1]);
81 } 73 }
82 } else { 74 queue.Push(buf);
83 // Copy as-is 75 return;
84 std::copy(samples.begin(), samples.end(), std::back_inserter(queue));
85 } 76 }
77
78 queue.Push(samples);
86 } 79 }
87 80
88 size_t SamplesInQueue(u32 num_channels) const { 81 size_t SamplesInQueue(u32 num_channels) const override {
89 if (!ctx) 82 if (!ctx)
90 return 0; 83 return 0;
91 84
92 return queue.size() / num_channels; 85 return queue.Size() / num_channels;
93 } 86 }
94 87
95 u32 GetNumChannels() const { 88 u32 GetNumChannels() const {
@@ -104,8 +97,7 @@ private:
104 u32 num_channels{}; 97 u32 num_channels{};
105 bool is_6_channel{}; 98 bool is_6_channel{};
106 99
107 std::mutex queue_mutex; 100 Common::RingBuffer<s16, 0x10000> queue;
108 std::vector<s16> queue;
109 101
110 static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, 102 static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
111 void* output_buffer, long num_frames); 103 void* output_buffer, long num_frames);
@@ -151,38 +143,32 @@ CubebSink::~CubebSink() {
151SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels, 143SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels,
152 const std::string& name) { 144 const std::string& name) {
153 sink_streams.push_back( 145 sink_streams.push_back(
154 std::make_unique<SinkStreamImpl>(ctx, sample_rate, num_channels, output_device, name)); 146 std::make_unique<CubebSinkStream>(ctx, sample_rate, num_channels, output_device, name));
155 return *sink_streams.back(); 147 return *sink_streams.back();
156} 148}
157 149
158long SinkStreamImpl::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, 150long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
159 void* output_buffer, long num_frames) { 151 void* output_buffer, long num_frames) {
160 SinkStreamImpl* impl = static_cast<SinkStreamImpl*>(user_data); 152 CubebSinkStream* impl = static_cast<CubebSinkStream*>(user_data);
161 u8* buffer = reinterpret_cast<u8*>(output_buffer); 153 u8* buffer = reinterpret_cast<u8*>(output_buffer);
162 154
163 if (!impl) { 155 if (!impl) {
164 return {}; 156 return {};
165 } 157 }
166 158
167 std::lock_guard lock{impl->queue_mutex}; 159 const size_t max_samples_to_write = impl->GetNumChannels() * num_frames;
168 160 const size_t samples_written = impl->queue.Pop(buffer, max_samples_to_write);
169 const size_t frames_to_write{
170 std::min(impl->queue.size() / impl->GetNumChannels(), static_cast<size_t>(num_frames))};
171
172 memcpy(buffer, impl->queue.data(), frames_to_write * sizeof(s16) * impl->GetNumChannels());
173 impl->queue.erase(impl->queue.begin(),
174 impl->queue.begin() + frames_to_write * impl->GetNumChannels());
175 161
176 if (frames_to_write < num_frames) { 162 if (samples_written < max_samples_to_write) {
177 // Fill the rest of the frames with silence 163 // Fill the rest of the frames with silence
178 memset(buffer + frames_to_write * sizeof(s16) * impl->GetNumChannels(), 0, 164 std::memset(buffer + samples_written * sizeof(s16), 0,
179 (num_frames - frames_to_write) * sizeof(s16) * impl->GetNumChannels()); 165 (max_samples_to_write - samples_written) * sizeof(s16));
180 } 166 }
181 167
182 return num_frames; 168 return num_frames;
183} 169}
184 170
185void SinkStreamImpl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} 171void CubebSinkStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {}
186 172
187std::vector<std::string> ListCubebSinkDevices() { 173std::vector<std::string> ListCubebSinkDevices() {
188 std::vector<std::string> device_list; 174 std::vector<std::string> device_list;