4#include <QtCore/qcoreapplication.h>
5#include <QtCore/qdebug.h>
6#include <QtCore/qmath.h>
7#include <private/qaudiohelpers_p.h>
27 pa_threaded_mainloop_signal(pulseEngine->
mainloop(), 0);
35 pa_stream_state_t
state = pa_stream_get_state(
stream);
38 case PA_STREAM_CREATING:
43 const pa_buffer_attr *buffer_attr = pa_stream_get_buffer_attr(
stream);
44 qCDebug(qLcPulseAudioIn) <<
"*** maxlength: " << buffer_attr->maxlength;
45 qCDebug(qLcPulseAudioIn) <<
"*** prebuf: " << buffer_attr->prebuf;
46 qCDebug(qLcPulseAudioIn) <<
"*** fragsize: " << buffer_attr->fragsize;
47 qCDebug(qLcPulseAudioIn) <<
"*** minreq: " << buffer_attr->minreq;
48 qCDebug(qLcPulseAudioIn) <<
"*** tlength: " << buffer_attr->tlength;
53 <<
"*** bytes_to_usec: " << pa_bytes_to_usec(buffer_attr->fragsize, &spec);
56 case PA_STREAM_TERMINATED:
58 case PA_STREAM_FAILED:
62 pa_threaded_mainloop_signal(pulseEngine->
mainloop(), 0);
71 qWarning() <<
"Got a buffer underflow!";
78 qWarning() <<
"Got a buffer overflow!";
91 pa_threaded_mainloop_signal(pulseEngine->
mainloop(), 0);
98 m_volume(
qreal(1.0f)),
106 m_stateMachine(*
this)
119 return m_stateMachine.
error();
124 return m_stateMachine.
state();
148 m_stateMachine.
start();
162 m_stateMachine.
start(
false);
173bool QPulseAudioSource::open()
181 || pa_context_get_state(pulseEngine->
context()) != PA_CONTEXT_READY) {
188 Q_ASSERT(spec.channels == channel_map.channels);
190 if (!pa_sample_spec_valid(&spec)) {
202 if (m_streamName.
isNull())
207 qCDebug(qLcPulseAudioIn) <<
"Format: " << spec.format;
208 qCDebug(qLcPulseAudioIn) <<
"Rate: " << spec.rate;
209 qCDebug(qLcPulseAudioIn) <<
"Channels: " << spec.channels;
210 qCDebug(qLcPulseAudioIn) <<
"Frame size: " << pa_frame_size(&spec);
215 m_stream = pa_stream_new(pulseEngine->
context(), m_streamName.
constData(), &spec, &channel_map);
226 pa_buffer_attr buffer_attr;
227 buffer_attr.maxlength =
static_cast<uint32_t
>(-1);
228 buffer_attr.prebuf =
static_cast<uint32_t
>(-1);
229 buffer_attr.tlength =
static_cast<uint32_t
>(-1);
230 buffer_attr.minreq =
static_cast<uint32_t
>(-1);
231 flags |= PA_STREAM_ADJUST_LATENCY;
233 if (m_bufferSize > 0)
234 buffer_attr.fragsize =
static_cast<uint32_t
>(m_bufferSize);
236 buffer_attr.fragsize =
static_cast<uint32_t
>(m_periodSize);
238 flags |= PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING;
240 int connectionResult = pa_stream_connect_record(m_stream, m_device.
data(), &buffer_attr,
241 static_cast<pa_stream_flags_t
>(
flags));
242 if (connectionResult < 0) {
243 qWarning() <<
"pa_stream_connect_record() failed!";
244 pa_stream_unref(m_stream);
259 while (pa_stream_get_state(m_stream) != PA_STREAM_READY)
260 pa_threaded_mainloop_wait(pulseEngine->
mainloop());
262 const pa_buffer_attr *actualBufferAttr = pa_stream_get_buffer_attr(m_stream);
263 m_periodSize = actualBufferAttr->fragsize;
264 m_periodTime = pa_bytes_to_usec(m_periodSize, &spec) / 1000;
265 if (actualBufferAttr->tlength !=
static_cast<uint32_t
>(-1))
266 m_bufferSize = actualBufferAttr->tlength;
271 &QPulseAudioSource::onPulseContextFailed);
274 m_timer.
start(m_periodTime,
this);
276 m_elapsedTimeOffset = 0;
282void QPulseAudioSource::close()
292 std::lock_guard
lock(*pulseEngine);
294 pa_stream_set_state_callback(m_stream,
nullptr,
nullptr);
295 pa_stream_set_read_callback(m_stream,
nullptr,
nullptr);
296 pa_stream_set_underflow_callback(m_stream,
nullptr,
nullptr);
297 pa_stream_set_overflow_callback(m_stream,
nullptr,
nullptr);
299 pa_stream_disconnect(m_stream);
300 pa_stream_unref(m_stream);
305 &QPulseAudioSource::onPulseContextFailed);
323 int bytes = pa_stream_readable_size(m_stream);
325 qWarning() <<
"pa_stream_readable_size() failed:" << currentError(m_stream);
341 if (!m_pullMode && !m_tempBuffer.
isEmpty()) {
342 readBytes =
qMin(
static_cast<int>(
len), m_tempBuffer.
size());
347 if (readBytes < m_tempBuffer.
size()) {
348 m_tempBuffer.
remove(0, readBytes);
352 m_tempBuffer.
clear();
355 while (pa_stream_readable_size(m_stream) > 0) {
356 size_t readLength = 0;
359 auto readableSize = pa_stream_readable_size(m_stream);
360 qCDebug(qLcPulseAudioIn) <<
"QPulseAudioSource::read -- " << readableSize
361 <<
" bytes available from pulse audio";
367 const void *audioBuffer;
372 if (pa_stream_peek(m_stream, &audioBuffer, &readLength) < 0) {
373 qWarning() <<
"pa_stream_peek() failed:" << currentError(m_stream);
381 applyVolume(audioBuffer, adjusted.
data(), readLength);
384 if (actualLength <
qint64(readLength)) {
390 actualLength =
qMin(
static_cast<int>(
len - readBytes),
static_cast<int>(readLength));
391 applyVolume(audioBuffer,
data + readBytes, actualLength);
394 qCDebug(qLcPulseAudioIn) <<
"QPulseAudioSource::read -- wrote " << actualLength
397 if (actualLength <
qint64(readLength)) {
398 int diff = readLength - actualLength;
399 int oldSize = m_tempBuffer.
size();
401 qCDebug(qLcPulseAudioIn) <<
"QPulseAudioSource::read -- appending " << diff
402 <<
" bytes of data to temp buffer";
404 m_tempBuffer.
resize(m_tempBuffer.
size() + diff);
405 applyVolume(
static_cast<const char *
>(audioBuffer) + actualLength,
406 m_tempBuffer.
data() + oldSize, diff);
411 readBytes += actualLength;
413 pa_stream_drop(m_stream);
416 if (!m_pullMode && readBytes >=
len)
420 qCDebug(qLcPulseAudioIn) <<
"QPulseAudioSource::read -- returning after reading " << readBytes
426void QPulseAudioSource::applyVolume(
const void *
src,
void *dest,
int len)
441 std::lock_guard
lock(*pulseEngine);
445 pulseEngine->
wait(operation.get());
448 m_timer.
start(m_periodTime,
this);
467 m_bufferSize =
value;
480 int result = pa_stream_get_time(m_stream, &usecs);
495 std::lock_guard
lock(*pulseEngine);
498 pulseEngine->
wait(operation.get());
510void QPulseAudioSource::userFeed()
536void QPulseAudioSource::onPulseContextFailed()
544 m_audioDevice = qobject_cast<QPulseAudioSource *>(audio);
566#include "moc_qpulseaudiosource_p.cpp"
DarwinBluetooth::LECBManagerNotifier * notifier
IOBluetoothDevice * device
QAudio::Error error() const
Notifier start(bool isActive=true)
Notifier updateActiveOrIdle(bool isActive, QAudio::Error error=QAudio::NoError)
QAudio::State state() const
Notifier stopOrUpdateError(QAudio::Error error=QAudio::NoError)
bool isActiveOrIdle() const
Notifier stop(QAudio::Error error=QAudio::NoError, bool shouldDrain=false, bool forceUpdateError=false)
void start(int msec, QObject *obj)
\obsolete Use chrono overload instead.
int timerId() const noexcept
Returns the timer's ID.
void stop()
Stops the timer.
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the 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.
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
QByteArray & remove(qsizetype index, qsizetype len)
Removes len bytes from the array, starting at index position pos, and returns a reference to the arra...
bool isNull() const noexcept
Returns true if this byte array is null; otherwise returns false.
\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.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
virtual void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object.
static QPulseAudioEngine * instance()
pa_threaded_mainloop * mainloop()
void wait(pa_operation *op)
QAudioFormat format() const override
QAudio::State state() const override
QPulseAudioSource(const QByteArray &device, QObject *parent)
QIODevice * m_audioSource
void setFormat(const QAudioFormat &format) override
QIODevice * start() override
qint64 read(char *data, qint64 len)
qint64 processedUSecs() const override
qsizetype bytesReady() const override
void timerEvent(QTimerEvent *event) override
This event handler can be reimplemented in a subclass to receive timer events for the object.
QAudio::Error error() const override
qsizetype bufferSize() const override
void setBufferSize(qsizetype value) override
void setVolume(qreal volume) override
qreal volume() const override
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void *src, void *dest, int len)
pa_channel_map channelMapForAudioFormat(const QAudioFormat &format)
pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format)
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
#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)
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei GLsizei GLenum format
static void inputStreamSuccessCallback(pa_stream *stream, int success, void *userdata)
static void inputStreamReadCallback(pa_stream *stream, size_t length, void *userdata)
static void inputStreamStateCallback(pa_stream *stream, void *userdata)
static void inputStreamOverflowCallback(pa_stream *stream, void *userdata)
QT_BEGIN_NAMESPACE const int SourcePeriodTimeMs
static void inputStreamUnderflowCallback(pa_stream *stream, void *userdata)
std::unique_ptr< pa_operation, PAOperationDeleter > PAOperationUPtr
#define QStringLiteral(str)
myObject disconnect()
[26]