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/qtmultimediaglobal.h>
19
20#include <QtMultimedia/qaudio.h>
21#include <QtMultimedia/qaudiodevice.h>
22#include <QtMultimedia/qaudioformat.h>
23#include <QtMultimedia/private/qaudiohelpers_p.h>
24#include <QtMultimedia/private/qaudio_rtsan_support_p.h>
25
26#include <QtCore/qelapsedtimer.h>
27#include <QtCore/qspan.h>
28#include <QtCore/private/qglobal_p.h>
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
355} // namespace QtMultimediaPrivate
356
357class Q_MULTIMEDIA_EXPORT QPlatformAudioEndpointBase : public QObject
358{
359 Q_OBJECT
360
361public:
362 explicit QPlatformAudioEndpointBase(QAudioDevice, const QAudioFormat &, QObject *parent);
363 ~QPlatformAudioEndpointBase() override;
364
365 // LATER: can we devirtualize these functions
366 QAudio::Error error() const { return m_error; }
367 virtual QAudio::State state() const { return m_inferredState; }
368 virtual void setError(QAudio::Error);
369
370 virtual bool isFormatSupported(const QAudioFormat &format) const;
371 QAudioFormat format() const { return m_format; }
372
373 virtual void setVolume(float volume) { m_volume = volume; }
374 float volume() const { return m_volume; }
375
376Q_SIGNALS:
377 void stateChanged(QtAudio::State);
378
379protected:
380 enum class EmitStateSignal : uint8_t
381 {
382 True,
383 False,
384 };
385
386 void updateStreamState(QAudio::State);
387 void updateStreamIdle(bool idle, EmitStateSignal = EmitStateSignal::True);
388
389 const QAudioDevice m_audioDevice;
390 const QAudioFormat m_format;
391
392private:
393 void inferState();
394
395 QAudio::State m_streamState = QAudio::StoppedState;
396 QAudio::State m_inferredState = QAudio::StoppedState;
397 QAudio::Error m_error{};
398 bool m_streamIsIdle = false;
399
400 float m_volume{ 1.f };
401};
402
403class Q_MULTIMEDIA_EXPORT QPlatformAudioSink : public QPlatformAudioEndpointBase
404{
405 Q_OBJECT
406
407public:
408 explicit QPlatformAudioSink(QAudioDevice, const QAudioFormat &, QObject *parent);
409 ~QPlatformAudioSink() override;
410
411 virtual void start(QIODevice *device) = 0;
412 virtual QIODevice* start() = 0;
413 virtual void stop() = 0;
414 virtual void reset() = 0;
415 virtual void suspend() = 0;
416 virtual void resume() = 0;
417 virtual qsizetype bytesFree() const = 0;
418 virtual void setBufferSize(qsizetype value) = 0;
419 virtual qsizetype bufferSize() const = 0;
420 virtual void setHardwareBufferFrames(int32_t) { }
421 virtual int32_t hardwareBufferFrames() { return -1; }
422 virtual qint64 processedUSecs() const = 0;
423
424 using AudioCallback = QtMultimediaPrivate::AudioSinkCallback;
425
426 virtual void start(AudioCallback &&) { }
427 virtual bool hasCallbackAPI() { return false; }
428
429 QElapsedTimer elapsedTime;
430
431 static QPlatformAudioSink *get(const QAudioSink &);
432
433 using AudioEndpointRole = QtMultimediaPrivate::AudioEndpointRole;
434 virtual void setRole(AudioEndpointRole) { }
435};
436
437class Q_MULTIMEDIA_EXPORT QPlatformAudioSource : public QPlatformAudioEndpointBase
438{
439 Q_OBJECT
440
441public:
442 explicit QPlatformAudioSource(QAudioDevice, const QAudioFormat &, QObject *parent);
443 ~QPlatformAudioSource() override;
444
445 virtual void start(QIODevice *device) = 0;
446 virtual QIODevice* start() = 0;
447 virtual void stop() = 0;
448 virtual void reset() = 0;
449 virtual void suspend() = 0;
450 virtual void resume() = 0;
451 virtual qsizetype bytesReady() const = 0;
452 virtual void setBufferSize(qsizetype value) = 0;
453 virtual void setHardwareBufferFrames(int32_t) { }
454 virtual int32_t hardwareBufferFrames() { return -1; }
455 virtual qsizetype bufferSize() const = 0;
456 virtual qint64 processedUSecs() const = 0;
457
458 using AudioCallback = QtMultimediaPrivate::AudioSourceCallback;
459
460 virtual void start(AudioCallback &&) { }
461 virtual bool hasCallbackAPI() { return false; }
462
463 QElapsedTimer elapsedTime;
464
465 static QPlatformAudioSource *get(const QAudioSource &);
466};
467
468// forward declarations
469namespace QtMultimediaPrivate {
472} // namespace QtMultimediaPrivate
473
474QT_END_NAMESPACE
475
476#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)
QDebug operator<<(QDebug debug, QIODevice::OpenMode modes)
static constexpr QAudioFormat::SampleFormat sample_format
static constexpr QAudioFormat::SampleFormat sample_format
static constexpr QAudioFormat::SampleFormat sample_format