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 <array>
29#include <variant>
30
31#include <stdlib.h>
32#if __has_include(<alloca.h>)
33# include <alloca.h>
34#endif
35#if __has_include(<malloc.h>)
36# include <malloc.h>
37#endif
38
39#if defined(Q_CC_MSVC) && !defined(alloca)
40# define alloca _alloca
41#endif
42
43QT_BEGIN_NAMESPACE
44
45class QIODevice;
46class QAudioSink;
47class QAudioSource;
48
50
53
54#if __cpp_lib_move_only_function
55
56template <typename SampleType>
58
59template <typename SampleType>
61
66
70
71template <typename V1, typename V2>
72struct variant_cat;
73
74template <typename... Ts1, typename... Ts2>
75struct variant_cat<std::variant<Ts1...>, std::variant<Ts2...>>
76{
77 using type = std::variant<Ts1..., Ts2...>;
78};
79
80template <typename V1, typename V2>
81using variant_cat_t = typename variant_cat<V1, V2>::type;
82
83#endif
84
85///////////////////////////////////////////////////////////////////////////////////////////////////
86
94
95///////////////////////////////////////////////////////////////////////////////////////////////////
96
97template <typename>
99
100template <>
101struct GetSampleTypeImpl<float>
102{
103 using type = float;
105};
106
107template <>
108struct GetSampleTypeImpl<int32_t>
109{
110 using type = int32_t;
112};
113template <>
114struct GetSampleTypeImpl<int16_t>
115{
116 using type = int16_t;
118};
119
120template <>
126
127template <typename T>
131
132template <typename T>
136
137#if __cpp_lib_move_only_function
138
139template <typename T>
141{
142};
143
144template <typename T>
146{
147};
148
149#endif
150
151template <typename SampleTypeOrCallbackType>
152using GetSampleType = typename GetSampleTypeImpl<SampleTypeOrCallbackType>::type;
153
154template <typename SampleTypeOrCallbackType>
156{
157 return GetSampleTypeImpl<SampleTypeOrCallbackType>::sample_format;
158}
159
160#if __cpp_lib_move_only_function
161using AudioSinkCallback =
165#else
168#endif
169
170template <typename Callback>
172{
173 if constexpr (std::is_same_v<Callback, AudioSinkCallback>) {
174 return std::forward<Callback>(cb);
175 } else {
176 return std::visit([](auto &&arg) -> AudioSinkCallback {
177 return arg;
178 }, std::forward<Callback>(cb));
179 }
180}
181template <typename Callback>
183{
184 if constexpr (std::is_same_v<Callback, AudioSourceCallback>) {
185 return std::forward<Callback>(cb);
186 } else {
187 return std::visit([](auto &&arg) -> AudioSourceCallback {
188 return arg;
189 }, std::forward<Callback>(cb));
190 }
191}
192
193template <typename AnyAudioCallback>
194constexpr bool validateAudioCallbackImpl(const AnyAudioCallback &audioCallback,
195 const QAudioFormat &format)
196{
197 bool isNonNullFunction = std::visit([](const auto &cb) {
198 return bool(cb);
199 }, audioCallback);
200
201 if (!isNonNullFunction)
202 return false;
203
204 bool hasCorrectFormat = std::visit([&](const auto &cb) {
205 return getSampleFormat<std::decay_t<decltype(cb)>>() == format.sampleFormat();
206 }, audioCallback);
207
208 return hasCorrectFormat;
209}
210
211constexpr bool validateAudioCallback(const AudioSinkCallback &audioCallback,
212 const QAudioFormat &format)
213{
214 return validateAudioCallbackImpl(audioCallback, format);
215}
216
217constexpr bool validateAudioCallback(const AudioSourceCallback &audioCallback,
218 const QAudioFormat &format)
219{
220 return validateAudioCallbackImpl(audioCallback, format);
221}
222
223// if the requested buffer is reasonably small (64kb, big enougth for 16 channels, 1024 frames,
224// float32) we can use a stack-allocated temporary buffer.
225// otherwise we allocate a heap buffer.
226template <size_t limit = 1024 * 64, typename Functor>
228{
230#ifdef alloca
231 std::byte *stackBuffer = reinterpret_cast<std::byte *>(alloca(bufferSize));
232 auto stackBufferSpan = QSpan<std::byte>{
235 };
236#else
238 auto stackBufferSpan = QSpan<std::byte>{
241 };
242#endif
243 return f(stackBufferSpan);
244 } else {
247 auto heapBufferSpan = QSpan<std::byte>{
248 heapBuffer.get(),
250 };
251 return f(heapBufferSpan);
252 }
253}
254
255template <bool IsSink>
256inline void
285
292
307
308// NB: we we provide two overloads for running audio callbacks based on the host buffer:
309// * if the host buffer is immutable, we need to apply the volume on a temporary buffer
310// * if the host buffer is mutable, we can apply the volume in-place (currently unused)
323
330
331template <typename HostBufferType>
350
351///////////////////////////////////////////////////////////////////////////////////////////////////
352
353} // namespace QtMultimediaPrivate
354
355class Q_MULTIMEDIA_EXPORT QPlatformAudioEndpointBase : public QObject
356{
357 Q_OBJECT
358
359public:
360 explicit QPlatformAudioEndpointBase(QAudioDevice, const QAudioFormat &, QObject *parent);
361 ~QPlatformAudioEndpointBase() override;
362
363 // LATER: can we devirtualize these functions
364 QAudio::Error error() const { return m_error; }
365 virtual QAudio::State state() const { return m_inferredState; }
366 virtual void setError(QAudio::Error);
367
368 virtual bool isFormatSupported(const QAudioFormat &format) const;
369 QAudioFormat format() const { return m_format; }
370
371 virtual void setVolume(float volume) { m_volume = volume; }
372 float volume() const { return m_volume; }
373
374Q_SIGNALS:
375 void stateChanged(QtAudio::State);
376
377protected:
378 enum class EmitStateSignal : uint8_t
379 {
380 True,
381 False,
382 };
383
384 void updateStreamState(QAudio::State);
385 void updateStreamIdle(bool idle, EmitStateSignal = EmitStateSignal::True);
386
387 const QAudioDevice m_audioDevice;
388 const QAudioFormat m_format;
389
390private:
391 void inferState();
392
393 QAudio::State m_streamState = QAudio::StoppedState;
394 QAudio::State m_inferredState = QAudio::StoppedState;
395 QAudio::Error m_error{};
396 bool m_streamIsIdle = false;
397
398 float m_volume{ 1.f };
399};
400
401class Q_MULTIMEDIA_EXPORT QPlatformAudioSink : public QPlatformAudioEndpointBase
402{
403 Q_OBJECT
404
405public:
406 explicit QPlatformAudioSink(QAudioDevice, const QAudioFormat &, QObject *parent);
407 ~QPlatformAudioSink() override;
408
409 virtual void start(QIODevice *device) = 0;
410 virtual QIODevice* start() = 0;
411 virtual void stop() = 0;
412 virtual void reset() = 0;
413 virtual void suspend() = 0;
414 virtual void resume() = 0;
415 virtual qsizetype bytesFree() const = 0;
416 virtual void setBufferSize(qsizetype value) = 0;
417 virtual qsizetype bufferSize() const = 0;
418 virtual void setHardwareBufferFrames(int32_t) { }
419 virtual int32_t hardwareBufferFrames() { return -1; }
420 virtual qint64 processedUSecs() const = 0;
421
422 using AudioCallback = QtMultimediaPrivate::AudioSinkCallback;
423
424 virtual void start(AudioCallback &&) { }
425 virtual bool hasCallbackAPI() { return false; }
426
427 QElapsedTimer elapsedTime;
428
429 static QPlatformAudioSink *get(const QAudioSink &);
430
431 using AudioEndpointRole = QtMultimediaPrivate::AudioEndpointRole;
432 virtual void setRole(AudioEndpointRole) { }
433};
434
435class Q_MULTIMEDIA_EXPORT QPlatformAudioSource : public QPlatformAudioEndpointBase
436{
437 Q_OBJECT
438
439public:
440 explicit QPlatformAudioSource(QAudioDevice, const QAudioFormat &, QObject *parent);
441 ~QPlatformAudioSource() override;
442
443 virtual void start(QIODevice *device) = 0;
444 virtual QIODevice* start() = 0;
445 virtual void stop() = 0;
446 virtual void reset() = 0;
447 virtual void suspend() = 0;
448 virtual void resume() = 0;
449 virtual qsizetype bytesReady() const = 0;
450 virtual void setBufferSize(qsizetype value) = 0;
451 virtual void setHardwareBufferFrames(int32_t) { }
452 virtual int32_t hardwareBufferFrames() { return -1; }
453 virtual qsizetype bufferSize() const = 0;
454 virtual qint64 processedUSecs() const = 0;
455
456 using AudioCallback = QtMultimediaPrivate::AudioSourceCallback;
457
458 virtual void start(AudioCallback &&) { }
459 virtual bool hasCallbackAPI() { return false; }
460
461 QElapsedTimer elapsedTime;
462
463 static QPlatformAudioSource *get(const QAudioSource &);
464};
465
466// forward declarations
467namespace QtMultimediaPrivate {
470} // namespace QtMultimediaPrivate
471
472QT_END_NAMESPACE
473
474#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