output/PipeWire: use class RingBuffer instead of boost::lockfree::spsc_queue

This commit is contained in:
Max Kellermann
2023-01-22 12:42:42 +01:00
parent 7cb6c70bc2
commit 0b42018377

View File

@@ -28,6 +28,7 @@
#include "system/Error.hxx" #include "system/Error.hxx"
#include "util/BitReverse.hxx" #include "util/BitReverse.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/RingBuffer.hxx"
#include "util/ScopeExit.hxx" #include "util/ScopeExit.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include "Log.hxx" #include "Log.hxx"
@@ -52,8 +53,6 @@
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
#include <boost/lockfree/spsc_queue.hpp>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <numeric> #include <numeric>
@@ -81,8 +80,8 @@ class PipeWireOutput final : AudioOutput {
/** /**
* This buffer passes PCM data from Play() to Process(). * This buffer passes PCM data from Play() to Process().
*/ */
using RingBuffer = boost::lockfree::spsc_queue<std::byte>; using RingBuffer = ::RingBuffer<std::byte>;
RingBuffer *ring_buffer; RingBuffer ring_buffer;
uint32_t target_id = PW_ID_ANY; uint32_t target_id = PW_ID_ANY;
@@ -572,9 +571,7 @@ PipeWireOutput::Open(AudioFormat &audio_format)
interrupted = false; interrupted = false;
/* allocate a ring buffer of 0.5 seconds */ /* allocate a ring buffer of 0.5 seconds */
const std::size_t ring_buffer_size = ring_buffer = RingBuffer{frame_size * (audio_format.sample_rate / 2)};
frame_size * (audio_format.sample_rate / 2);
ring_buffer = new RingBuffer(ring_buffer_size);
const struct spa_pod *params[1]; const struct spa_pod *params[1];
@@ -626,7 +623,7 @@ PipeWireOutput::Close() noexcept
stream = nullptr; stream = nullptr;
} }
delete ring_buffer; ring_buffer = {};
} }
inline void inline void
@@ -774,25 +771,17 @@ PipeWireOutput::Process() noexcept
if (dest == nullptr) if (dest == nullptr)
return; return;
std::size_t max_frames = d.maxsize / frame_size; std::size_t chunk_size = frame_size;
#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE) #if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE)
if (use_dsd && dsd_interleave > 1) { if (use_dsd && dsd_interleave > 1) {
/* make sure we don't get partial interleave frames */ /* make sure we don't get partial interleave frames */
std::size_t interleave_size = frame_size * dsd_interleave; chunk_size *= dsd_interleave;
std::size_t available_bytes = ring_buffer->read_available();
std::size_t available_interleaves =
available_bytes / interleave_size;
std::size_t available_frames =
available_interleaves * dsd_interleave;
if (max_frames > available_frames)
max_frames = available_frames;
} }
#endif #endif
const std::size_t max_size = max_frames * frame_size; size_t nbytes = ring_buffer.ReadFramesTo({dest, d.maxsize}, chunk_size);
size_t nbytes = ring_buffer->pop(dest, max_size); assert(nbytes % chunk_size == 0);
assert(nbytes % frame_size == 0);
if (nbytes == 0) { if (nbytes == 0) {
if (drain_requested) { if (drain_requested) {
pw_stream_flush(stream, true); pw_stream_flush(stream, true);
@@ -800,8 +789,9 @@ PipeWireOutput::Process() noexcept
} }
/* buffer underrun: generate some silence */ /* buffer underrun: generate some silence */
PcmSilence({dest, max_size}, sample_format); std::size_t max_chunks = d.maxsize / chunk_size;
nbytes = max_size; nbytes = max_chunks * chunk_size;
PcmSilence({dest, nbytes}, sample_format);
LogWarning(pipewire_output_domain, "Decoder is too slow; playing silence to avoid xrun"); LogWarning(pipewire_output_domain, "Decoder is too slow; playing silence to avoid xrun");
} }
@@ -846,7 +836,7 @@ PipeWireOutput::Play(std::span<const std::byte> src)
CheckThrowError(); CheckThrowError();
std::size_t bytes_written = std::size_t bytes_written =
ring_buffer->push(src.data(), src.size()); ring_buffer.WriteFrom(src);
if (bytes_written > 0) { if (bytes_written > 0) {
drained = false; drained = false;
return bytes_written; return bytes_written;
@@ -902,7 +892,7 @@ PipeWireOutput::Cancel() noexcept
return; return;
/* clear MPD's ring buffer */ /* clear MPD's ring buffer */
ring_buffer->reset(); ring_buffer.Clear();
/* clear libpipewire's buffer */ /* clear libpipewire's buffer */
pw_stream_flush(stream, false); pw_stream_flush(stream, false);