diff options
| -rw-r--r-- | src/audio_core/cubeb_sink.cpp | 66 |
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 | ||
| 13 | namespace AudioCore { | 12 | namespace AudioCore { |
| 14 | 13 | ||
| 15 | class SinkStreamImpl final : public SinkStream { | 14 | class CubebSinkStream final : public SinkStream { |
| 16 | public: | 15 | public: |
| 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 | ¶ms, std::max(512u, minimum_latency), | 39 | ¶ms, 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() { | |||
| 151 | SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels, | 143 | SinkStream& 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 | ||
| 158 | long SinkStreamImpl::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, | 150 | long 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 | ||
| 185 | void SinkStreamImpl::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} | 171 | void CubebSinkStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {} |
| 186 | 172 | ||
| 187 | std::vector<std::string> ListCubebSinkDevices() { | 173 | std::vector<std::string> ListCubebSinkDevices() { |
| 188 | std::vector<std::string> device_list; | 174 | std::vector<std::string> device_list; |