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);
33 pa_stream_state_t
state = pa_stream_get_state(
stream);
38 case PA_STREAM_CREATING:
40 case PA_STREAM_READY: {
43 const pa_buffer_attr *buffer_attr = pa_stream_get_buffer_attr(
stream);
44 qDebug() <<
"*** maxlength: " << buffer_attr->maxlength;
45 qDebug() <<
"*** prebuf: " << buffer_attr->prebuf;
46 qDebug() <<
"*** fragsize: " << buffer_attr->fragsize;
47 qDebug() <<
"*** minreq: " << buffer_attr->minreq;
48 qDebug() <<
"*** tlength: " << buffer_attr->tlength;
51 qDebug() <<
"*** bytes_to_usec: " << pa_bytes_to_usec(buffer_attr->fragsize, &spec);
55 case PA_STREAM_TERMINATED:
57 case PA_STREAM_FAILED:
61 pa_threaded_mainloop_signal(pulseEngine->
mainloop(), 0);
70 qWarning() <<
"Got a buffer underflow!";
77 qWarning() <<
"Got a buffer overflow!";
90 pa_threaded_mainloop_signal(pulseEngine->
mainloop(), 0);
98 , m_deviceState(
QAudio::StoppedState)
99 , m_volume(
qreal(1.0f))
102 , m_bytesAvailable(0)
109 m_timer =
new QTimer(
this);
216bool QPulseAudioSource::open()
223 if (!pulseEngine->
context() || pa_context_get_state(pulseEngine->
context()) != PA_CONTEXT_READY) {
231 Q_ASSERT(spec.channels == channel_map.channels);
233 if (!pa_sample_spec_valid(&spec)) {
246 if (m_streamName.
isNull())
251 qDebug() <<
"Rate: " << spec.rate;
252 qDebug() <<
"Channels: " << spec.channels;
253 qDebug() <<
"Frame size: " << pa_frame_size(&spec);
258 m_stream = pa_stream_new(pulseEngine->
context(), m_streamName.
constData(), &spec, &channel_map);
269 pa_buffer_attr buffer_attr;
270 buffer_attr.maxlength = (uint32_t) -1;
271 buffer_attr.prebuf = (uint32_t) -1;
272 buffer_attr.tlength = (uint32_t) -1;
273 buffer_attr.minreq = (uint32_t) -1;
274 flags |= PA_STREAM_ADJUST_LATENCY;
276 if (m_bufferSize > 0)
277 buffer_attr.fragsize = (uint32_t) m_bufferSize;
279 buffer_attr.fragsize = (uint32_t) m_periodSize;
281 flags |= PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING;
282 if (pa_stream_connect_record(m_stream, m_device.
data(), &buffer_attr, (pa_stream_flags_t)
flags) < 0) {
283 qWarning() <<
"pa_stream_connect_record() failed!";
284 pa_stream_unref(m_stream);
298 while (pa_stream_get_state(m_stream) != PA_STREAM_READY)
299 pa_threaded_mainloop_wait(pulseEngine->
mainloop());
301 const pa_buffer_attr *actualBufferAttr = pa_stream_get_buffer_attr(m_stream);
302 m_periodSize = actualBufferAttr->fragsize;
303 m_periodTime = pa_bytes_to_usec(m_periodSize, &spec) / 1000;
304 if (actualBufferAttr->tlength != (uint32_t)-1)
305 m_bufferSize = actualBufferAttr->tlength;
312 m_timer->
start(m_periodTime);
314 m_elapsedTimeOffset = 0;
320void QPulseAudioSource::close()
330 std::lock_guard
lock(*pulseEngine);
332 pa_stream_set_state_callback(m_stream,
nullptr,
nullptr);
333 pa_stream_set_read_callback(m_stream,
nullptr,
nullptr);
334 pa_stream_set_underflow_callback(m_stream,
nullptr,
nullptr);
335 pa_stream_set_overflow_callback(m_stream,
nullptr,
nullptr);
337 pa_stream_disconnect(m_stream);
338 pa_stream_unref(m_stream);
351int QPulseAudioSource::checkBytesReady()
354 m_bytesAvailable = 0;
356 m_bytesAvailable = pa_stream_readable_size(m_stream);
359 return m_bytesAvailable;
364 return qMax(m_bytesAvailable, 0);
371 m_bytesAvailable = checkBytesReady();
379 if (!m_pullMode && !m_tempBuffer.
isEmpty()) {
380 readBytes =
qMin(
static_cast<int>(
len), m_tempBuffer.
size());
385 if (readBytes < m_tempBuffer.
size()) {
386 m_tempBuffer.
remove(0, readBytes);
390 m_tempBuffer.
clear();
393 while (pa_stream_readable_size(m_stream) > 0) {
394 size_t readLength = 0;
397 qDebug() <<
"QPulseAudioSource::read -- " << pa_stream_readable_size(m_stream) <<
" bytes available from pulse audio";
403 const void *audioBuffer;
408 if (pa_stream_peek(m_stream, &audioBuffer, &readLength) < 0) {
418 applyVolume(audioBuffer, adjusted.
data(), readLength);
421 if (actualLength <
qint64(readLength)) {
430 actualLength =
qMin(
static_cast<int>(
len - readBytes),
static_cast<int>(readLength));
431 applyVolume(audioBuffer,
data + readBytes, actualLength);
435 qDebug() <<
"QPulseAudioSource::read -- wrote " << actualLength <<
" to client";
438 if (actualLength <
qint64(readLength)) {
440 qDebug() <<
"QPulseAudioSource::read -- appending " << readLength - actualLength <<
" bytes of data to temp buffer";
442 int diff = readLength - actualLength;
443 int oldSize = m_tempBuffer.
size();
444 m_tempBuffer.
resize(m_tempBuffer.
size() + diff);
445 applyVolume(
static_cast<const char *
>(audioBuffer) + actualLength, m_tempBuffer.
data() + oldSize, diff);
450 readBytes += actualLength;
452 pa_stream_drop(m_stream);
455 if (!m_pullMode && readBytes >=
len)
460 qDebug() <<
"QPulseAudioSource::read -- returning after reading " << readBytes <<
" bytes";
466void QPulseAudioSource::applyVolume(
const void *
src,
void *dest,
int len)
481 std::lock_guard
lock(*pulseEngine);
484 pulseEngine->
wait(operation.get());
487 m_timer->
start(m_periodTime);
509 m_bufferSize =
value;
522 int result = pa_stream_get_time(m_stream, &usecs);
540 std::lock_guard
lock(*pulseEngine);
543 pulseEngine->
wait(operation.get());
547void QPulseAudioSource::userFeed()
558bool QPulseAudioSource::deviceReady()
570 m_bytesAvailable = checkBytesReady();
581 m_bytesAvailable = 0;
584void QPulseAudioSource::onPulseContextFailed()
594 m_audioDevice = qobject_cast<QPulseAudioSource*>(audio);
616#include "moc_qpulseaudiosource_p.cpp"
IOBluetoothDevice * device
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.
static void processEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Processes some pending events for the calling thread according to the specified flags.
\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
static QPulseAudioEngine * instance()
pa_threaded_mainloop * mainloop()
void wait(pa_operation *op)
QAudio::Error m_errorState
QAudioFormat format() const override
QAudio::State state() const override
QAudio::State m_deviceState
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
QAudio::Error error() const override
qsizetype bufferSize() const override
void setBufferSize(qsizetype value) override
void setVolume(qreal volume) override
qreal volume() const override
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
QByteArray toUtf8() const &
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void stop()
Stops the timer.
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void *src, void *dest, int len)
The QAudio namespace contains enums used by the audio classes.
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...
static QString sampleFormatToQString(pa_sample_format format)
pa_channel_map channelMapForAudioFormat(const QAudioFormat &format)
pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format)
static QString stateToQString(pa_stream_state_t state)
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr const T & qMax(const T &a, const T &b)
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLenum GLsizei length
GLbitfield GLuint64 timeout
[4]
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
QLatin1StringView QLatin1String
myObject disconnect()
[26]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent