// Copyright (C) 2025 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QPIPEWIRE_AUDIOSINK_P_H #define QPIPEWIRE_AUDIOSINK_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QtPipeWire { using namespace QtMultimediaPrivate; class QPipewireAudioSink; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct QPipewireAudioSinkStream final : std::enable_shared_from_this, QPipewireAudioStream, QPlatformAudioSinkStream { using SampleFormat = QAudioFormat::SampleFormat; using SinkType = QPipewireAudioSink; QPipewireAudioSinkStream(QAudioDevice, const QAudioFormat &, std::optional ringbufferSize, QPipewireAudioSink *parent, float volume, std::optional hardwareBufferFrames, AudioEndpointRole); Q_DISABLE_COPY_MOVE(QPipewireAudioSinkStream) ~QPipewireAudioSinkStream(); bool open(); using QPlatformAudioSinkStream::bytesFree; using QPlatformAudioSinkStream::processedDuration; using QPlatformAudioSinkStream::ringbufferSizeInBytes; using QPlatformAudioSinkStream::setVolume; bool start(QIODevice *device); QIODevice *start(); bool start(AudioCallback); void stop(ShutdownPolicy); void updateStreamIdle(bool idle) override; private: void createStream(QPipewireAudioStream::StreamType); std::optional findSinkNodeSerial(); using QPlatformAudioSinkStream::m_format; // QPipewireAudioStream overrides void handleDeviceRemoved() override; void processRingbuffer() noexcept QT_MM_NONBLOCKING override; void processCallback() noexcept QT_MM_NONBLOCKING override; template void processHelper(Functor &&f); void stateChanged(pw_stream_state /*old*/, pw_stream_state state, const char * /*error*/) override; void disconnectStream(); QSemaphore m_disconnectSemaphore; std::shared_ptr m_self; std::atomic m_shutdownPolicy{ ShutdownPolicy::DiscardRingbuffer }; QAutoResetEvent m_ringbufferDrained; // process helpers void queueBuffer(struct pw_buffer *b, uint64_t samplesWritten) noexcept QT_MM_NONBLOCKING; // xrun detection void xrunOccurred(int /*xrunCount*/) override { m_xrunOccurred.set(); } QtPrivate::QAutoResetEvent m_xrunOccurred; QMetaObject::Connection m_xrunNotification; [[maybe_unused]] static void fakeXRun(); AudioEndpointRole m_role; std::optional m_audioCallback; QPipewireAudioSink *m_parent; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class QPipewireAudioSink final : public QPlatformAudioSinkImplementation { using BaseClass = QPlatformAudioSinkImplementation; public: QPipewireAudioSink(QAudioDevice, const QAudioFormat &, QObject *parent); void reportXRuns(int); }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } // namespace QtPipeWire QT_END_NAMESPACE #endif