Revision control

Copy as Markdown

// 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 <QtMultimedia/private/qaudio_platform_implementation_support_p.h>
#include <QtMultimedia/private/qaudiosystem_p.h>
#include <QtMultimedia/private/qaudiosystem_platform_stream_support_p.h>
#include <QtMultimedia/private/qpipewire_audiostream_p.h>
#include <QtCore/qsemaphore.h>
#include <QtCore/qtclasshelpermacros.h>
QT_BEGIN_NAMESPACE
namespace QtPipeWire {
using namespace QtMultimediaPrivate;
class QPipewireAudioSink;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct QPipewireAudioSinkStream final : QPipewireAudioStream, QPlatformAudioSinkStream
{
using SampleFormat = QAudioFormat::SampleFormat;
using SinkType = QPipewireAudioSink;
QPipewireAudioSinkStream(QAudioDevice, const QAudioFormat &,
std::optional<qsizetype> ringbufferSize, QPipewireAudioSink *parent,
float volume, std::optional<NativePeriodFrames> nativePeriodFrames,
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<ObjectSerial> findSinkNodeSerial();
using QPlatformAudioSinkStream::m_format;
// QPipewireAudioStream overrides
void handleDeviceRemoved() override;
void processRingbuffer() noexcept Q_DECL_NONBLOCKING_FUNCTION override;
void processCallback() noexcept Q_DECL_NONBLOCKING_FUNCTION override;
void stateChanged(pw_stream_state /*old*/, pw_stream_state state,
const char * /*error*/) override;
void finalizeStream() override;
template <typename Functor>
void processHelper(Functor &&f);
void disconnectStream();
QSemaphore m_disconnectSemaphore;
std::atomic<ShutdownPolicy> m_shutdownPolicy{ ShutdownPolicy::DiscardRingbuffer };
QAutoResetEvent m_ringbufferDrained;
// process helpers
void queueBuffer(struct pw_buffer *b, uint64_t samplesWritten) noexcept Q_DECL_NONBLOCKING_FUNCTION;
// 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<AudioCallback> m_audioCallback;
QPipewireAudioSink *m_parent;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class QPipewireAudioSink final
: public QPlatformAudioSinkImplementation<QPipewireAudioSinkStream, QPipewireAudioSink>
{
using BaseClass =
QPlatformAudioSinkImplementation<QPipewireAudioSinkStream, QPipewireAudioSink>;
public:
QPipewireAudioSink(QAudioDevice, const QAudioFormat &, QObject *parent);
~QPipewireAudioSink() override;
void reportXRuns(int);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace QtPipeWire
QT_END_NAMESPACE
#endif