Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qaudiosystem_p.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QAUDIOSYSTEM_H
5#define QAUDIOSYSTEM_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtMultimedia/private/qaudio_rtsan_support_p.h>
19#include <QtMultimedia/private/qaudiohelpers_p.h>
20#include <QtMultimedia/qaudio.h>
21#include <QtMultimedia/qaudiodevice.h>
22#include <QtMultimedia/qaudioformat.h>
23#include <QtMultimedia/qtmultimediaglobal.h>
24#include <QtCore/private/qglobal_p.h>
25#include <QtCore/qelapsedtimer.h>
26#include <QtCore/qspan.h>
27
28#include <optional>
29
30#include <array>
31#include <variant>
32
33#include <stdlib.h>
34#if __has_include(<alloca.h>)
35# include <alloca.h>
36#endif
37#if __has_include(<malloc.h>)
38# include <malloc.h>
39#endif
40
41#if defined(Q_CC_MSVC) && !defined(alloca)
42# define alloca _alloca
43#endif
44
45QT_BEGIN_NAMESPACE
46
47class QIODevice;
48class QAudioSink;
49class QAudioSource;
50
52
55
56#if __cpp_lib_move_only_function
57
58template <typename SampleType>
60
61template <typename SampleType>
63
68
72
73template <typename V1, typename V2>
74struct variant_cat;
75
76template <typename... Ts1, typename... Ts2>
77struct variant_cat<std::variant<Ts1...>, std::variant<Ts2...>>
78{
79 using type = std::variant<Ts1..., Ts2...>;
80};
81
82template <typename V1, typename V2>
83using variant_cat_t = typename variant_cat<V1, V2>::type;
84
85#endif
86
87///////////////////////////////////////////////////////////////////////////////////////////////////
88
96
97///////////////////////////////////////////////////////////////////////////////////////////////////
98
99template <typename>
101
102template <>
103struct GetSampleTypeImpl<float>
104{
105 using type = float;
107};
108
109template <>
110struct GetSampleTypeImpl<int32_t>
111{
112 using type = int32_t;
114};
115template <>
116struct GetSampleTypeImpl<int16_t>
117{
118 using type = int16_t;
120};
121
122template <>
128
129template <typename T>
133
134template <typename T>
138
139#if __cpp_lib_move_only_function
140
141template <typename T>
143{
144};
145
146template <typename T>
148{
149};
150
151#endif
152
153template <typename SampleTypeOrCallbackType>
154using GetSampleType = typename GetSampleTypeImpl<SampleTypeOrCallbackType>::type;
155
156template <typename SampleTypeOrCallbackType>
158{
159 return GetSampleTypeImpl<SampleTypeOrCallbackType>::sample_format;
160}
161
162#if __cpp_lib_move_only_function
163using AudioSinkCallback =
167#else
170#endif
171
172template <typename Callback>
174{
175 if constexpr (std::is_same_v<Callback, AudioSinkCallback>) {
176 return std::forward<Callback>(cb);
177 } else {
178 return std::visit([](auto &&arg) -> AudioSinkCallback {
179 return arg;
180 }, std::forward<Callback>(cb));
181 }
182}
183template <typename Callback>
185{
186 if constexpr (std::is_same_v<Callback, AudioSourceCallback>) {
187 return std::forward<Callback>(cb);
188 } else {
189 return std::visit([](auto &&arg) -> AudioSourceCallback {
190 return arg;
191 }, std::forward<Callback>(cb));
192 }
193}
194
195template <typename AnyAudioCallback>
196constexpr bool validateAudioCallbackImpl(const AnyAudioCallback &audioCallback,
197 const QAudioFormat &format)
198{
199 bool isNonNullFunction = std::visit([](const auto &cb) {
200 return bool(cb);
201 }, audioCallback);
202
203 if (!isNonNullFunction)
204 return false;
205
206 bool hasCorrectFormat = std::visit([&](const auto &cb) {
207 return getSampleFormat<std::decay_t<decltype(cb)>>() == format.sampleFormat();
208 }, audioCallback);
209
210 return hasCorrectFormat;
211}
212
213constexpr bool validateAudioCallback(const AudioSinkCallback &audioCallback,
214 const QAudioFormat &format)
215{
216 return validateAudioCallbackImpl(audioCallback, format);
217}
218
219constexpr bool validateAudioCallback(const AudioSourceCallback &audioCallback,
220 const QAudioFormat &format)
221{
222 return validateAudioCallbackImpl(audioCallback, format);
223}
224
225// if the requested buffer is reasonably small (64kb, big enougth for 16 channels, 1024 frames,
226// float32) we can use a stack-allocated temporary buffer.
227// otherwise we allocate a heap buffer.
228template <size_t limit = 1024 * 64, typename Functor>
230{
232#ifdef alloca
233 std::byte *stackBuffer = reinterpret_cast<std::byte *>(alloca(bufferSize));
234 auto stackBufferSpan = QSpan<std::byte>{
237 };
238#else
240 auto stackBufferSpan = QSpan<std::byte>{
243 };
244#endif
245 return f(stackBufferSpan);
246 } else {
249 auto heapBufferSpan = QSpan<std::byte>{
250 heapBuffer.get(),
252 };
253 return f(heapBufferSpan);
254 }
255}
256
257template <bool IsSink>
258inline void
287
294
309
310// NB: we we provide two overloads for running audio callbacks based on the host buffer:
311// * if the host buffer is immutable, we need to apply the volume on a temporary buffer
312// * if the host buffer is mutable, we can apply the volume in-place (currently unused)
325
332
333template <typename HostBufferType>
352
353///////////////////////////////////////////////////////////////////////////////////////////////////
354
356
357} // namespace QtMultimediaPrivate
358
359class Q_MULTIMEDIA_EXPORT QPlatformAudioEndpointBase : public QObject
360{
361 Q_OBJECT
362
363public:
364 using NativePeriodFrames = QtMultimediaPrivate::NativePeriodFrames;
365
366 explicit QPlatformAudioEndpointBase(QAudioDevice, const QAudioFormat &, QObject *parent);
367 ~QPlatformAudioEndpointBase() override;
368
369 // LATER: can we devirtualize these functions
370 QAudio::Error error() const { return m_error; }
371 virtual QAudio::State state() const { return m_inferredState; }
372 virtual void setError(QAudio::Error);
373
374 virtual bool isFormatSupported(const QAudioFormat &format) const;
375 QAudioFormat format() const { return m_format; }
376
377 virtual void setVolume(float volume) { m_volume = volume; }
378 float volume() const { return m_volume; }
379
380Q_SIGNALS:
381 void stateChanged(QtAudio::State);
382
383protected:
384 enum class EmitStateSignal : uint8_t
385 {
386 True,
387 False,
388 };
389
390 void updateStreamState(QAudio::State);
391 void updateStreamIdle(bool idle, EmitStateSignal = EmitStateSignal::True);
392
393 const QAudioDevice m_audioDevice;
394 const QAudioFormat m_format;
395
396private:
397 void inferState();
398
399 QAudio::State m_streamState = QAudio::StoppedState;
400 QAudio::State m_inferredState = QAudio::StoppedState;
401 QAudio::Error m_error{};
402 bool m_streamIsIdle = false;
403
404 float m_volume{ 1.f };
405};
406
407class Q_MULTIMEDIA_EXPORT QPlatformAudioSink : public QPlatformAudioEndpointBase
408{
409 Q_OBJECT
410
411public:
412 explicit QPlatformAudioSink(QAudioDevice, const QAudioFormat &, QObject *parent);
413 ~QPlatformAudioSink() override;
414
415 virtual void start(QIODevice *device) = 0;
416 virtual QIODevice* start() = 0;
417 virtual void stop() = 0;
418 virtual void reset() = 0;
419 virtual void suspend() = 0;
420 virtual void resume() = 0;
421 virtual qsizetype bytesFree() const = 0;
422 virtual void setBufferSize(qsizetype value) = 0;
423 virtual qsizetype bufferSize() const = 0;
424 virtual void setNativePeriodFrames(std::optional<NativePeriodFrames>) { }
425 virtual std::optional<NativePeriodFrames> nativePeriodFrames() { return std::nullopt; }
426 virtual qint64 processedUSecs() const = 0;
427
428 using AudioCallback = QtMultimediaPrivate::AudioSinkCallback;
429
430 virtual void start(AudioCallback &&) { }
431 virtual bool hasCallbackAPI() { return false; }
432
433 QElapsedTimer elapsedTime;
434
435 static QPlatformAudioSink *get(const QAudioSink &);
436
437 using AudioEndpointRole = QtMultimediaPrivate::AudioEndpointRole;
438 virtual void setRole(AudioEndpointRole) { }
439};
440
441class Q_MULTIMEDIA_EXPORT QPlatformAudioSource : public QPlatformAudioEndpointBase
442{
443 Q_OBJECT
444
445public:
446 explicit QPlatformAudioSource(QAudioDevice, const QAudioFormat &, QObject *parent);
447 ~QPlatformAudioSource() override;
448
449 virtual void start(QIODevice *device) = 0;
450 virtual QIODevice* start() = 0;
451 virtual void stop() = 0;
452 virtual void reset() = 0;
453 virtual void suspend() = 0;
454 virtual void resume() = 0;
455 virtual qsizetype bytesReady() const = 0;
456 virtual void setBufferSize(qsizetype value) = 0;
457 virtual void setNativePeriodFrames(std::optional<NativePeriodFrames>) { }
458 virtual std::optional<NativePeriodFrames> nativePeriodFrames() { return std::nullopt; }
459 virtual qsizetype bufferSize() const = 0;
460 virtual qint64 processedUSecs() const = 0;
461
462 using AudioCallback = QtMultimediaPrivate::AudioSourceCallback;
463
464 virtual void start(AudioCallback &&) { }
465 virtual bool hasCallbackAPI() { return false; }
466
467 QElapsedTimer elapsedTime;
468
469 static QPlatformAudioSource *get(const QAudioSource &);
470};
471
472// forward declarations
473namespace QtMultimediaPrivate {
476} // namespace QtMultimediaPrivate
477
478QT_END_NAMESPACE
479
480#endif // QAUDIOSYSTEM_H
Combined button and popup list for selecting options.
AudioSinkCallback asAudioSinkCallback(Callback &&cb)
constexpr bool validateAudioCallback(const AudioSinkCallback &audioCallback, const QAudioFormat &format)
typename GetSampleTypeImpl< SampleTypeOrCallbackType >::type GetSampleType
AudioSourceCallback asAudioSourceCallback(Callback &&cb)
static constexpr QAudioFormat::SampleFormat getSampleFormat()
constexpr bool validateAudioCallbackImpl(const AnyAudioCallback &audioCallback, const QAudioFormat &format)
#define __has_include(x)
static constexpr QAudioFormat::SampleFormat sample_format
static constexpr QAudioFormat::SampleFormat sample_format
static constexpr QAudioFormat::SampleFormat sample_format