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>
36template <
typename SampleType>
53 using namespace QtMultimediaPrivate;
56 int64_t usableLength = alignDown(len,
sizeof(SampleType));
58 QSpan<
const std::byte> dataRegion = as_bytes(QSpan{ data, qsizetype(usableLength) });
59 qint64 totalBytesWritten = 0;
62 int64_t remainingSamples = dataRegion.size() /
sizeof(SampleType);
63 auto writeRegion = m_ringbuffer->acquireWriteRegion(remainingSamples);
64 if (writeRegion.isEmpty())
67 QSpan<std::byte> writeByteRegion = as_writable_bytes(writeRegion);
68 int64_t bytesToWrite =
std::min(dataRegion.size(), writeByteRegion.size());
70 QSpan<
const std::byte> dataForChunk = take(dataRegion, bytesToWrite);
71 std::copy(dataForChunk.begin(), dataForChunk.end(), writeByteRegion.begin());
73 totalBytesWritten += bytesToWrite;
74 dataRegion = drop(dataRegion, bytesToWrite);
76 m_ringbuffer->releaseWriteRegion(
int(bytesToWrite /
sizeof(SampleType)));
77 }
while (!dataRegion.isEmpty());
79 if (totalBytesWritten)
82 return totalBytesWritten;
87 Ringbuffer *m_ringbuffer;
91template <
typename SampleType>
106 using namespace QtMultimediaPrivate;
108 QSpan<std::byte> outputRegion = as_writable_bytes(QSpan{ data, qsizetype(maxlen) });
110 qint64 totalBytesRead = 0;
112 while (!outputRegion.isEmpty()) {
113 qsizetype maxSizeToRead = outputRegion.size_bytes() /
sizeof(SampleType);
114 QSpan readRegion = m_ringbuffer->acquireReadRegion(
int(maxSizeToRead));
115 if (readRegion.isEmpty())
116 return totalBytesRead;
118 QSpan readByteRegion = as_bytes(readRegion);
119 std::copy(readByteRegion.begin(), readByteRegion.end(), outputRegion.begin());
121 outputRegion = drop(outputRegion, readByteRegion.size());
122 totalBytesRead += readByteRegion.size();
124 m_ringbuffer->releaseReadRegion(readRegion.size());
127 return totalBytesRead;
133 Ringbuffer *m_ringbuffer;
149 std::lock_guard guard{ m_mutex };
151 size_t bytesToRead = std::min<size_t>(m_deque.size(), maxlen);
152 std::copy_n(m_deque.begin(), bytesToRead, data);
154 m_deque.erase(m_deque.begin(), m_deque.begin() + bytesToRead);
155 return qint64(bytesToRead);
160 std::lock_guard guard{ m_mutex };
161 m_deque.insert(m_deque.end(), data, data + len);
171 return device.write(
reinterpret_cast<
const char *>(data.data()), data.size());
176 return device.read(
reinterpret_cast<
char *>(outputBuffer.data()), outputBuffer.size());
179template <
typename SampleType>
182 using namespace QtMultimediaPrivate;
184 qsizetype totalBytesWritten = 0;
187 qint64 bytesAvailableInDevice = alignDown(device.bytesAvailable(),
sizeof(SampleType));
188 if (!bytesAvailableInDevice)
189 return totalBytesWritten;
191 qint64 samplesAvailableInDevice = bytesAvailableInDevice /
sizeof(SampleType);
193 auto writeRegion = ringbuffer.acquireWriteRegion(samplesAvailableInDevice);
194 if (writeRegion.empty())
195 return totalBytesWritten;
197 qint64 bytesRead = readFromDevice(device, as_writable_bytes(writeRegion));
199 qWarning() <<
"pullFromQIODeviceToRingbuffer cannot read from QIODevice:"
200 << device.errorString();
201 return totalBytesWritten;
204 Q_ASSERT(bytesRead == writeRegion.size_bytes());
205 ringbuffer.releaseWriteRegion(writeRegion.size());
207 totalBytesWritten += writeRegion.size_bytes();
211template <
typename SampleType>
214 using namespace QtMultimediaPrivate;
215 qsizetype totalBytesWritten = 0;
218 auto ringbufferRegion = ringbuffer.acquireReadRegion(ringbuffer.size());
219 if (ringbufferRegion.empty())
220 return totalBytesWritten;
221 QSpan bufferByteRegion = as_bytes(ringbufferRegion);
223 int deviceBytesToWrite = device.bytesToWrite();
224 if (deviceBytesToWrite > 0) {
226 int bytesToWrite = alignDown(deviceBytesToWrite,
sizeof(SampleType));
227 bufferByteRegion = take(bufferByteRegion, bytesToWrite);
229 if (bufferByteRegion.empty())
230 return totalBytesWritten;
233 int bytesWritten = writeToDevice(device, bufferByteRegion);
234 if (bytesWritten < 0) {
235 qWarning() <<
"pushToQIODeviceFromRingbuffer cannot push data to QIODevice:"
236 << device.errorString();
237 return totalBytesWritten;
239 if (bytesWritten == 0)
240 return totalBytesWritten;
242 totalBytesWritten += bytesWritten;
243 Q_ASSERT(isAligned(bytesWritten,
sizeof(SampleType)));
244 int samplesWritten = bytesWritten /
sizeof(SampleType);
245 ringbuffer.releaseReadRegion(samplesWritten);
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...
QIODeviceRingBufferReader(Ringbuffer *rb, QObject *parent=nullptr)
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.
QIODeviceRingBufferWriter(Ringbuffer *rb, QObject *parent=nullptr)
qint64 writeData(const char *data, qint64 len) override
Writes up to maxSize bytes from data to the device.
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)