10#include <QtCore/qcoreapplication.h>
11#include <QtCore/qdebug.h>
12#include <QtCore/qloggingcategory.h>
23 std::optional<qsizetype> ringbufferSize,
24 QPipewireAudioSource *parent,
26 std::optional<int32_t> hardwareBufferFrames
42 m_xrunNotification = m_xrunOccurred.callOnActivated([
this] {
43 if (isStopRequested())
45 m_parent->reportXRuns(m_xrunCount.exchange(0));
53 createStream(StreamType::Ringbuffer);
55 Q_ASSERT(hasStream());
56 auto sourceNodeSerial = findSourceNodeSerial();
57 if (!sourceNodeSerial) {
64 bool connected = connectStream(*sourceNodeSerial, SPA_DIRECTION_INPUT);
70 createQIODeviceConnections(device);
73 m_self = shared_from_this();
74 QAudioContextManager::instance()->registerStreamReference(m_self);
81 QIODevice *device = createRingbufferReaderDevice();
83 bool started = start(device);
92 createStream(StreamType::Callback);
94 Q_ASSERT(hasStream());
95 auto sourceNodeSerial = findSourceNodeSerial();
96 if (!sourceNodeSerial) {
101 m_audioCallback = std::move(audioCallback);
103 bool connected = connectStream(*sourceNodeSerial, SPA_DIRECTION_INPUT);
110 m_self = shared_from_this();
120 unregisterDeviceObserver();
121 disconnectQIODeviceConnections();
123 finalizeQIODevice(shutdownPolicy);
124 if (shutdownPolicy == ShutdownPolicy::DiscardRingbuffer) {
127 bool streamDisconnected = m_streamDisconnected.try_acquire_for(5s);
128 if (!streamDisconnected)
129 qWarning() <<
"QPipewireAudioSourceStream::stop: m_streamDisconnected semaphore "
130 "timeout. This should not happen";
138 m_parent->updateStreamIdle(idle);
143 auto extraProperties = std::array{
144 spa_dict_item{ PW_KEY_MEDIA_CATEGORY,
"Capture" },
145 spa_dict_item{ PW_KEY_MEDIA_ROLE,
"Music" },
148 QString applicationName = qApp->applicationName();
149 if (applicationName.isNull())
150 applicationName = u"QPipewireAudioSource"_s;
152 QPipewireAudioStream::createStream(extraProperties, m_hardwareBufferFrames,
153 applicationName.toUtf8().constData(), streamType);
158 const QPipewireAudioDevicePrivate *device =
159 QAudioDevicePrivate::handle<QPipewireAudioDevicePrivate>(m_audioDevice);
161 QByteArray nodeName = device->nodeName();
162 auto ret = QAudioContextManager::deviceMonitor().findSourceNodeSerial(std::string_view{
164 size_t(nodeName.size()),
168 qWarning() <<
"Cannot find device: " << nodeName;
174 auto self = shared_from_this();
176 QPipewireAudioStream::disconnectStream();
178 QObject::disconnect(m_xrunNotification);
185 qCritical() <<
"pw_stream_dequeue_buffer failed";
191 qWarning() <<
"pw_stream_dequeue_buffer received null buffer";
214 qCritical() <<
"pw_stream_dequeue_buffer failed";
220 qWarning() <<
"pw_stream_dequeue_buffer received null buffer";
StrongIdType< uint64_t, ObjectSerialTag > ObjectSerial
bool start(QIODevice *device)
void stop(ShutdownPolicy)
QPipewireAudioSourceStream(QAudioDevice, const QAudioFormat &, std::optional< qsizetype > ringbufferSize, QPipewireAudioSource *parent, float volume, std::optional< int32_t > hardwareBufferFrames)
bool start(AudioCallback &&)
void updateStreamIdle(bool idle) override
QAudioFormat::SampleFormat SampleFormat