4#ifndef QAUDIO_QIODEVICE_SUPPORT_P_H
5#define QAUDIO_QIODEVICE_SUPPORT_P_H
18#include <QtMultimedia/private/qaudio_alignment_support_p.h>
19#include <QtMultimedia/private/qaudio_qspan_support_p.h>
20#include <QtMultimedia/private/qaudioringbuffer_p.h>
21#include <QtMultimedia/private/qautoresetevent_p.h>
22#include <QtCore/qdebug.h>
23#include <QtCore/qglobal.h>
24#include <QtCore/qiodevice.h>
25#include <QtCore/qmutex.h>
26#include <QtCore/qspan.h>
40 setOpenMode(QIODevice::WriteOnly | QIODevice::Unbuffered);
42 m_bytesConsumed.callOnActivated([&] {
43 qint64 bytes = m_bytesConsumedFromRingbuffer.exchange(0, std::memory_order_relaxed);
45 emit bytesWritten(bytes);
51 m_bytesConsumedFromRingbuffer.fetch_add(bytes, std::memory_order_relaxed);
52 m_bytesConsumed.set();
58 QtPrivate::QAutoResetEvent m_bytesConsumed;
59 std::atomic<qint64> m_bytesConsumedFromRingbuffer{ 0 };
63template <
typename SampleType>
78 using namespace QtMultimediaPrivate;
81 int64_t usableLength = alignDown(len,
sizeof(SampleType));
82 auto readRegion = QSpan<
const SampleType>{
83 reinterpret_cast<
const SampleType *>(data),
84 qsizetype(usableLength /
sizeof(SampleType)),
87 qint64 bytesWritten = m_ringbuffer->write(readRegion) *
sizeof(SampleType);
97 Ringbuffer *
const m_ringbuffer;
101template <
typename SampleType>
115 using namespace QtMultimediaPrivate;
117 QSpan<std::byte> outputRegion = as_writable_bytes(QSpan{ data, qsizetype(maxlen) });
119 qsizetype maxSizeToRead = outputRegion.size_bytes() /
sizeof(SampleType);
121 int samplesConsumed = m_ringbuffer->consumeSome([&](
auto readRegion) {
122 QSpan readByteRegion = as_bytes(readRegion);
123 std::copy(readByteRegion.begin(), readByteRegion.end(), outputRegion.begin());
124 outputRegion = drop(outputRegion, readByteRegion.size());
129 return samplesConsumed *
sizeof(SampleType);
137 Ringbuffer *
const m_ringbuffer;
153 std::lock_guard guard{ m_mutex };
155 size_t bytesToRead = std::min<size_t>(m_deque.size(), maxlen);
156 std::copy_n(m_deque.begin(), bytesToRead, data);
158 m_deque.erase(m_deque.begin(), m_deque.begin() + bytesToRead);
159 return qint64(bytesToRead);
164 std::lock_guard guard{ m_mutex };
165 m_deque.insert(m_deque.end(), data, data + len);
175 return device.write(
reinterpret_cast<
const char *>(data.data()), data.size());
180 return device.read(
reinterpret_cast<
char *>(outputBuffer.data()), outputBuffer.size());
183template <
typename SampleType>
186 using namespace QtMultimediaPrivate;
188 int totalSamplesWritten = ringbuffer.produceSome([&](QSpan<SampleType> writeRegion) {
189 qint64 bytesAvailableInDevice = alignDown(device.bytesAvailable(),
sizeof(SampleType));
190 if (!bytesAvailableInDevice)
191 return QSpan<SampleType>{};
193 qint64 samplesAvailableInDevice = bytesAvailableInDevice /
sizeof(SampleType);
194 writeRegion = take(writeRegion, samplesAvailableInDevice);
196 qint64 bytesRead = readFromDevice(device, as_writable_bytes(writeRegion));
198 qWarning() <<
"pullFromQIODeviceToRingbuffer cannot read from QIODevice:"
199 << device.errorString();
200 return QSpan<SampleType>{};
203 return take(writeRegion, bytesRead /
sizeof(SampleType));
206 return totalSamplesWritten *
sizeof(SampleType);
209template <
typename SampleType>
212 using namespace QtMultimediaPrivate;
214 int totalSamplesWritten = ringbuffer.consumeSome([&](QSpan<SampleType> region) {
216 const quint64 bytesToWrite = [&] {
217 const qint64 deviceBytesToWrite = device.bytesToWrite();
218 return (deviceBytesToWrite > 0) ? alignDown(deviceBytesToWrite,
sizeof(SampleType))
219 : region.size_bytes();
222 QSpan<
const std::byte> bufferByteRegion = take(as_bytes(region), bytesToWrite);
223 int bytesWritten = writeToDevice(device, bufferByteRegion);
224 if (bytesWritten < 0) {
225 qWarning() <<
"pushToQIODeviceFromRingbuffer cannot push data to QIODevice:"
226 << device.errorString();
227 return QSpan<SampleType>{};
229 Q_ASSERT(isAligned(bytesWritten,
sizeof(SampleType)));
230 int samplesWritten = bytesWritten /
sizeof(SampleType);
231 return take(region, samplesWritten);
234 return totalSamplesWritten *
sizeof(SampleType);
qint64 readData(char *data, qint64 maxlen) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
qint64 bytesAvailable() const override
Returns the number of bytes that are available for reading.
QDequeIODevice(QObject *parent=nullptr)
qint64 writeData(const char *data, qint64 len) override
Writes up to maxSize bytes from data to the device.
qint64 readData(char *data, qint64 maxlen) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
QtPrivate::QAudioRingBuffer< SampleType > Ringbuffer
QIODeviceRingBufferReader(Ringbuffer *rb, QObject *parent=nullptr)
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
qint64 writeData(const char *, qint64) override
Writes up to maxSize bytes from data to the device.
qint64 bytesAvailable() const override
Returns the number of bytes that are available for reading.
QIODeviceRingBufferWriterBase(QObject *parent=nullptr)
void bytesConsumedFromRingbuffer(qint64 bytes)
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
QIODeviceRingBufferWriter(Ringbuffer *rb, QObject *parent=nullptr)
qint64 writeData(const char *data, qint64 len) override
Writes up to maxSize bytes from data to the device.
QtPrivate::QAudioRingBuffer< SampleType > Ringbuffer
qint64 bytesToWrite() const override
For buffered devices, this function returns the number of bytes waiting to be written.
qint64 readData(char *, qint64) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
qsizetype pullFromQIODeviceToRingbuffer(QIODevice &device, QAudioRingBuffer< SampleType > &ringbuffer)
qint64 readFromDevice(QIODevice &device, QSpan< std::byte > outputBuffer)
qint64 writeToDevice(QIODevice &device, QSpan< const std::byte > data)
qsizetype pushToQIODeviceFromRingbuffer(QIODevice &device, QAudioRingBuffer< SampleType > &ringbuffer)