20#include <QtCore/QDataStream>
21#include <QtCore/qtimer.h>
23#include <private/qaudiohelpers_p.h>
27#include <audioclient.h>
28#include <mmdeviceapi.h>
58 m_timer->
callOnTimeout(
this, &QWindowsAudioSource::pullCaptureClient);
91 if (m_format !=
fmt) {
92 qWarning() <<
"Cannot set a new audio format, in the current state ("
93 << m_deviceState <<
")";
105 if (
state != m_deviceState) {
110 m_audioClient->Start();
111 qCDebug(qLcAudioSource) <<
"Audio client started";
113 }
else if (wasActive && !
isActive) {
115 m_audioClient->Stop();
116 qCDebug(qLcAudioSource) <<
"Audio client stopped";
119 m_deviceState =
state;
123 if (
error != m_errorState) {
124 m_errorState =
error;
129QByteArray QWindowsAudioSource::readCaptureClientBuffer()
131 UINT32 actualFrames = 0;
132 BYTE *
data =
nullptr;
134 HRESULT hr = m_captureClient->GetBuffer(&
data, &actualFrames, &
flags,
nullptr,
nullptr);
141 if (actualFrames == 0)
145 if (
flags & AUDCLNT_BUFFERFLAGS_SILENT) {
155 hr = m_captureClient->ReleaseBuffer(actualFrames);
165void QWindowsAudioSource::schedulePull()
170 if (!allocated || !inUse) {
175 if (*inUse > *allocated / 2) {
179 m_timer->
start(timeToHalfBuffer / 1000);
184void QWindowsAudioSource::pullCaptureClient()
186 qCDebug(qLcAudioSource) <<
"Pull captureClient";
188 auto out = readCaptureClientBuffer();
194 if (written !=
out.size())
195 qCDebug(qLcAudioSource) <<
"Did not write all data to the output";
198 m_clientBufferResidue +=
out;
208 qCDebug(qLcAudioSource) <<
"start(ioDevice)";
228 qCDebug(qLcAudioSource) <<
"start()";
251bool QWindowsAudioSource::open()
253 HRESULT hr = m_device->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER,
254 nullptr, (
void**)m_audioClient.GetAddressOf());
256 qCWarning(qLcAudioSource) <<
"Failed to activate audio device" << errorString(hr);
261 hr = m_audioClient->GetMixFormat(pwfx.
address());
268 qCWarning(qLcAudioSource) <<
"Failed to set up resampler";
272 if (m_bufferSize == 0)
277 hr = m_audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, requestedDuration, 0, pwfx.
get(),
286 if (!framesAllocated) {
287 qCWarning(qLcAudioSource) <<
"Failed to get audio client buffer size";
294 hr = m_audioClient->GetService(__uuidof(IAudioCaptureClient), (
void**)m_captureClient.GetAddressOf());
296 qCWarning(qLcAudioSource) <<
"Failed to obtain audio client rendering service" <<
errorString(hr);
303void QWindowsAudioSource::close()
305 qCDebug(qLcAudioSource) <<
"close()";
311 m_clientBufferResidue.
clear();
312 m_captureClient.Reset();
313 m_audioClient.Reset();
314 m_clientSink =
nullptr;
327 return clientBufferSize + m_clientBufferResidue.
size();
339 if (
data ==
nullptr ||
len < 0)
343 if (!m_clientBufferResidue.
isEmpty()) {
344 auto copyLen =
qMin(m_clientBufferResidue.
size(),
len);
345 memcpy(
data, m_clientBufferResidue.
data(), copyLen);
354 auto out = readCaptureClientBuffer();
355 if (!
out.isEmpty()) {
360 m_clientBufferResidue =
QByteArray{
out.data() + copyLen,
out.size() - copyLen };
369 qCDebug(qLcAudioSource) <<
"resume()";
378 m_bufferSize =
value;
396 qCDebug(qLcAudioSource) <<
"suspend";
IOBluetoothDevice * device
qint64 readData(char *data, qint64 len) 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.
qint64 writeData(const char *, qint64) override
Writes up to maxSize bytes from data to the device.
OurSink(QWindowsAudioSource &source)
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
void clear()
Clears the contents of the byte array and makes it null.
\inmodule QtCore \reentrant
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
void readyRead()
This signal is emitted once every time new data is available for reading from the device's current re...
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
void setSingleShot(bool singleShot)
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void stop()
Stops the timer.
QMetaObject::Connection callOnTimeout(Args &&...args)
void setTimerType(Qt::TimerType atype)
qint64 processedUSecs() const override
qsizetype bufferSize() const override
qreal volume() const override
qint64 read(char *data, qint64 len)
void setVolume(qreal volume) override
QWindowsAudioSource(ComPtr< IMMDevice > device, QObject *parent)
void setFormat(const QAudioFormat &fmt) override
QAudio::State state() const override
qsizetype bytesReady() const override
void setBufferSize(qsizetype value) override
QAudio::Error error() const override
QAudioFormat format() const override
QIODevice * start() override
bool setup(const QAudioFormat &in, const QAudioFormat &out)
QAudioFormat inputFormat() const
QByteArray resample(const QByteArrayView &in)
quint64 totalOutputBytes() const
QAudioFormat outputFormat() const
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void *src, void *dest, int len)
State
\value ActiveState Audio data is being processed, this state is set after start() is called and while...
Error
\value NoError No errors have occurred \value OpenError An error occurred opening the audio device \v...
Combined button and popup list for selecting options.
std::optional< quint32 > audioClientFramesInUse(IAudioClient *client)
std::optional< quint32 > audioClientFramesAllocated(IAudioClient *client)
QAudioFormat waveFormatExToFormat(const WAVEFORMATEX &in)
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qBound(const T &min, const T &val, const T &max)
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLsizei GLsizei GLchar * source
QVideoFrameFormat::PixelFormat fmt
QTextStream out(stdout)
[7]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent