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_AUDIOSTREAM_P_H
#define QPIPEWIRE_AUDIOSTREAM_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/qaudiosystem_p.h>
#include <QtMultimedia/private/qpipewire_audiodevicemonitor_p.h>
#include <QtMultimedia/private/qpipewire_support_p.h>
#include <QtMultimedia/qaudioformat.h>
#include <QtCore/qglobal.h>
#include <pipewire/stream.h>
QT_BEGIN_NAMESPACE
namespace QtPipeWire {
using QtMultimediaPrivate::NativePeriodFrames;
struct QPipewireAudioStream : std::enable_shared_from_this<QPipewireAudioStream>
{
protected:
explicit QPipewireAudioStream(const QAudioFormat &);
~QPipewireAudioStream();
Q_DISABLE_COPY_MOVE(QPipewireAudioStream)
const QAudioFormat m_format;
enum class StreamType : uint8_t
{
Ringbuffer,
Callback,
};
// stream control
void createStream(QSpan<spa_dict_item> extraProperties,
std::optional<NativePeriodFrames> nativePeriodFrames, const char *streamName,
StreamType = StreamType::Ringbuffer);
bool connectStream(ObjectSerial target, spa_direction);
void disconnectStream();
void resetStream();
public:
void suspend();
void resume();
bool hasStream() const;
protected:
// stream callbacks
virtual void processRingbuffer() = 0;
virtual void processCallback() = 0;
virtual void stateChanged(pw_stream_state oldState, pw_stream_state state,
const char *error) = 0;
// stream members
pw_stream_events stream_events{};
PwStreamHandle m_stream;
// device observer
[[nodiscard]] bool registerDeviceObserver(ObjectSerial);
void unregisterDeviceObserver();
virtual void handleDeviceRemoved() = 0;
SharedObjectRemoveObserver m_deviceRemovalObserver;
// xrun detector
// CAVEAT: has to be called at the beginning of a render callback
// streams will have to increment m_totalNumberOfFrames internally
void performXRunDetection(uint64_t framesPerBuffer) noexcept Q_DECL_NONBLOCKING_FUNCTION;
virtual void xrunOccurred(int xrunCount) = 0;
uint64_t m_expectedNextTick{};
std::atomic_bool m_skipNextTickDiscontinuity{ true };
std::atomic_int m_xrunCount{ 0 };
// total samples delivered from/sent to the backend
void addFramesHandled(uint64_t);
uint64_t m_totalNumberOfFrames{};
friend class QAudioContextManager; // to access m_self
std::shared_ptr<QPipewireAudioStream> m_self;
virtual void finalizeStream() = 0;
};
} // namespace QtPipeWire
QT_END_NAMESPACE
#endif