6#include <QtMultimedia/private/qpipewire_audiocontextmanager_p.h>
7#include <QtMultimedia/private/qpipewire_audiodevice_p.h>
8#include <QtMultimedia/private/qpipewire_support_p.h>
9#include <QtCore/qcoreapplication.h>
10#include <QtCore/qdebug.h>
11#include <QtCore/qloggingcategory.h>
24 std::optional<qsizetype> ringbufferSize,
25 QPipewireAudioSource *parent,
27 std::optional<NativePeriodFrames> nativePeriodFrames
43 m_xrunNotification = m_xrunOccurred.callOnActivated([
this] {
44 if (isStopRequested())
46 m_parent->reportXRuns(m_xrunCount.exchange(0));
52 Q_ASSERT(!m_xrunOccurred.thread() || m_xrunOccurred.thread()->isCurrentThread());
58 createStream(StreamType::Ringbuffer);
60 Q_ASSERT(hasStream());
61 auto sourceNodeSerial = findSourceNodeSerial();
62 if (!sourceNodeSerial) {
69 bool connected = connectStream(*sourceNodeSerial, SPA_DIRECTION_INPUT);
75 createQIODeviceConnections(device);
78 m_self = shared_from_this();
79 QAudioContextManager::instance()->registerStreamReference(m_self);
86 QIODevice *device = createRingbufferReaderDevice();
88 bool started = start(device);
97 createStream(StreamType::Callback);
99 Q_ASSERT(hasStream());
100 auto sourceNodeSerial = findSourceNodeSerial();
101 if (!sourceNodeSerial) {
106 m_audioCallback = std::move(audioCallback);
108 bool connected = connectStream(*sourceNodeSerial, SPA_DIRECTION_INPUT);
115 m_self = shared_from_this();
125 unregisterDeviceObserver();
126 disconnectQIODeviceConnections();
128 finalizeQIODevice(shutdownPolicy);
129 if (shutdownPolicy == ShutdownPolicy::DiscardRingbuffer) {
132 bool streamDisconnected = m_streamDisconnected.try_acquire_for(5s);
133 if (!streamDisconnected)
134 qWarning() <<
"QPipewireAudioSourceStream::stop: m_streamDisconnected semaphore "
135 "timeout. This should not happen";
143 m_parent->updateStreamIdle(idle);
148 auto extraProperties = std::array{
149 spa_dict_item{ PW_KEY_MEDIA_CATEGORY,
"Capture" },
150 spa_dict_item{ PW_KEY_MEDIA_ROLE,
"Music" },
153 QString applicationName = qApp->applicationName();
154 if (applicationName.isNull())
155 applicationName = u"QPipewireAudioSource"_s;
157 QPipewireAudioStream::createStream(extraProperties, m_nativePeriodFrames,
158 applicationName.toUtf8().constData(), streamType);
163 const QPipewireAudioDevicePrivate *device =
164 QAudioDevicePrivate::handle<QPipewireAudioDevicePrivate>(m_audioDevice);
166 QByteArray nodeName = device->nodeName();
167 auto ret = QAudioContextManager::deviceMonitor().findSourceNodeSerial(std::string_view{
169 size_t(nodeName.size()),
173 qWarning() <<
"Cannot find device: " << nodeName;
179 auto self = shared_from_this();
181 QPipewireAudioStream::disconnectStream();
183 QObject::disconnect(m_xrunNotification);
195 qCritical() <<
"pw_stream_dequeue_buffer failed";
201 qWarning() <<
"pw_stream_dequeue_buffer received null buffer";
224 qCritical() <<
"pw_stream_dequeue_buffer failed";
230 qWarning() <<
"pw_stream_dequeue_buffer received null buffer";
287 qDebug() <<
"XRuns occurred:" << numberOfXruns;
bool start(QIODevice *device)
void finalizeStream() override
void stop(ShutdownPolicy)
bool start(AudioCallback &&)
void updateStreamIdle(bool idle) override
QAudioFormat::SampleFormat SampleFormat
QPipewireAudioSourceStream(QAudioDevice, const QAudioFormat &, std::optional< qsizetype > ringbufferSize, QPipewireAudioSource *parent, float volume, std::optional< NativePeriodFrames > nativePeriodFrames)