4#ifndef QAUDIO_QIODEVICE_SUPPORT_P_H
5#define QAUDIO_QIODEVICE_SUPPORT_P_H
18#include <QtCore/qdebug.h>
19#include <QtCore/qglobal.h>
20#include <QtCore/qiodevice.h>
21#include <QtCore/qmutex.h>
22#include <QtCore/qspan.h>
24#include <QtMultimedia/private/qaudio_alignment_support_p.h>
25#include <QtMultimedia/private/qaudio_qspan_support_p.h>
26#include <QtMultimedia/private/qaudioringbuffer_p.h>
27#include <QtMultimedia/private/qautoresetevent_p.h>
41 setOpenMode(QIODevice::WriteOnly | QIODevice::Unbuffered);
43 m_bytesConsumed.callOnActivated([&] {
44 qint64 bytes = m_bytesConsumedFromRingbuffer.exchange(0, std::memory_order_relaxed);
46 emit bytesWritten(bytes);
52 m_bytesConsumedFromRingbuffer.fetch_add(bytes, std::memory_order_relaxed);
53 m_bytesConsumed.set();
59 QtPrivate::QAutoResetEvent m_bytesConsumed;
60 std::atomic<qint64> m_bytesConsumedFromRingbuffer{ 0 };
64template <
typename SampleType>
79 using namespace QtMultimediaPrivate;
82 int64_t usableLength = alignDown(len,
sizeof(SampleType));
83 auto readRegion = QSpan<
const SampleType>{
84 reinterpret_cast<
const SampleType *>(data),
85 qsizetype(usableLength /
sizeof(SampleType)),
88 qint64 bytesWritten = m_ringbuffer->write(readRegion) *
sizeof(SampleType);
98 Ringbuffer *
const m_ringbuffer;
102template <
typename SampleType>
116 using namespace QtMultimediaPrivate;
118 QSpan<std::byte> outputRegion = as_writable_bytes(QSpan{ data, qsizetype(maxlen) });
120 qsizetype maxSizeToRead = outputRegion.size_bytes() /
sizeof(SampleType);
122 int samplesConsumed = m_ringbuffer->consumeSome([&](
auto readRegion) {
123 QSpan readByteRegion = as_bytes(readRegion);
124 std::copy(readByteRegion.begin(), readByteRegion.end(), outputRegion.begin());
125 outputRegion = drop(outputRegion, readByteRegion.size());
130 return samplesConsumed *
sizeof(SampleType);
138 Ringbuffer *
const m_ringbuffer;
154 std::lock_guard guard{ m_mutex };
156 size_t bytesToRead = std::min<size_t>(m_deque.size(), maxlen);
157 std::copy_n(m_deque.begin(), bytesToRead, data);
159 m_deque.erase(m_deque.begin(), m_deque.begin() + bytesToRead);
160 return qint64(bytesToRead);
165 std::lock_guard guard{ m_mutex };
166 m_deque.insert(m_deque.end(), data, data + len);
176 return device.write(
reinterpret_cast<
const char *>(data.data()), data.size());
181 return device.read(
reinterpret_cast<
char *>(outputBuffer.data()), outputBuffer.size());
184template <
typename SampleType>
187 using namespace QtMultimediaPrivate;
189 int totalSamplesWritten = ringbuffer.produceSome([&](QSpan<SampleType> writeRegion) {
190 qint64 bytesAvailableInDevice = alignDown(device.bytesAvailable(),
sizeof(SampleType));
191 if (!bytesAvailableInDevice)
192 return QSpan<SampleType>{};
194 qint64 samplesAvailableInDevice = bytesAvailableInDevice /
sizeof(SampleType);
195 writeRegion = take(writeRegion, samplesAvailableInDevice);
197 qint64 bytesRead = readFromDevice(device, as_writable_bytes(writeRegion));
199 qWarning() <<
"pullFromQIODeviceToRingbuffer cannot read from QIODevice:"
200 << device.errorString();
201 return QSpan<SampleType>{};
204 return take(writeRegion, bytesRead /
sizeof(SampleType));
207 return totalSamplesWritten *
sizeof(SampleType);
210template <
typename SampleType>
213 using namespace QtMultimediaPrivate;
215 int totalSamplesWritten = ringbuffer.consumeSome([&](QSpan<SampleType> region) {
217 const quint64 bytesToWrite = [&] {
218 const qint64 deviceBytesToWrite = device.bytesToWrite();
219 return (deviceBytesToWrite > 0) ? alignDown(deviceBytesToWrite,
sizeof(SampleType))
220 : region.size_bytes();
223 QSpan<
const std::byte> bufferByteRegion = take(as_bytes(region), bytesToWrite);
224 int bytesWritten = writeToDevice(device, bufferByteRegion);
225 if (bytesWritten < 0) {
226 qWarning() <<
"pushToQIODeviceFromRingbuffer cannot push data to QIODevice:"
227 << device.errorString();
228 return QSpan<SampleType>{};
230 Q_ASSERT(isAligned(bytesWritten,
sizeof(SampleType)));
231 int samplesWritten = bytesWritten /
sizeof(SampleType);
232 return take(region, samplesWritten);
235 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)