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/qaudiohelpers_p.h>
19#include <QtMultimedia/private/qtmm_rtsan_support_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
51namespace QtMultimediaPrivate {
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
292
299
315
331
332// NB: we we provide two overloads for running audio callbacks based on the host buffer:
333// * if the host buffer is immutable, we need to apply the volume on a temporary buffer
334// * if the host buffer is mutable, we can apply the volume in-place (currently unused)
347
354
355template <typename HostBufferType>
375
376template <typename HostBufferType>
396
397///////////////////////////////////////////////////////////////////////////////////////////////////
398
400
401} // namespace QtMultimediaPrivate
402
403class Q_MULTIMEDIA_EXPORT QPlatformAudioEndpointBase : public QObject
404{
405 Q_OBJECT
406
407public:
408 using NativePeriodFrames = QtMultimediaPrivate::NativePeriodFrames;
409
410 explicit QPlatformAudioEndpointBase(QAudioDevice, const QAudioFormat &, QObject *parent);
411 ~QPlatformAudioEndpointBase() override;
412
413 // LATER: can we devirtualize these functions
414 QAudio::Error error() const { return m_error; }
415 virtual QAudio::State state() const { return m_inferredState; }
416 virtual void setError(QAudio::Error);
417
418 virtual bool isFormatSupported(const QAudioFormat &format) const;
419 QAudioFormat format() const { return m_format; }
420
421 virtual void setVolume(float volume) { m_volume = volume; }
422 float volume() const { return m_volume; }
423
424Q_SIGNALS:
425 void stateChanged(QtAudio::State);
426
427protected:
428 enum class EmitStateSignal : uint8_t
429 {
430 True,
431 False,
432 };
433
434 void updateStreamState(QAudio::State);
435 void updateStreamIdle(bool idle, EmitStateSignal = EmitStateSignal::True);
436
437 const QAudioDevice m_audioDevice;
438 const QAudioFormat m_format;
439
440private:
441 void inferState();
442
443 QAudio::State m_streamState = QAudio::StoppedState;
444 QAudio::State m_inferredState = QAudio::StoppedState;
445 QAudio::Error m_error{};
446 bool m_streamIsIdle = false;
447
448 float m_volume{ 1.f };
449};
450
451class Q_MULTIMEDIA_EXPORT QPlatformAudioSink : public QPlatformAudioEndpointBase
452{
453 Q_OBJECT
454
455public:
456 explicit QPlatformAudioSink(QAudioDevice, const QAudioFormat &, QObject *parent);
457 ~QPlatformAudioSink() override;
458
459 virtual void start(QIODevice *device) = 0;
460 virtual QIODevice* start() = 0;
461 virtual void stop() = 0;
462 virtual void reset() = 0;
463 virtual void suspend() = 0;
464 virtual void resume() = 0;
465 virtual qsizetype bytesFree() const = 0;
466 virtual void setBufferSize(qsizetype value) = 0;
467 virtual qsizetype bufferSize() const = 0;
468 virtual void setNativePeriodFrames(std::optional<NativePeriodFrames>) { }
469 virtual std::optional<NativePeriodFrames> nativePeriodFrames() { return std::nullopt; }
470 virtual qint64 processedUSecs() const = 0;
471
472 using AudioCallback = QtMultimediaPrivate::AudioSinkCallback;
473
474 virtual void start(AudioCallback &&) { }
475 virtual bool hasCallbackAPI() { return false; }
476
477 QElapsedTimer elapsedTime;
478
479 static QPlatformAudioSink *get(const QAudioSink &);
480
481 using AudioEndpointRole = QtMultimediaPrivate::AudioEndpointRole;
482 virtual void setRole(AudioEndpointRole) { }
483};
484
485class Q_MULTIMEDIA_EXPORT QPlatformAudioSource : public QPlatformAudioEndpointBase
486{
487 Q_OBJECT
488
489public:
490 explicit QPlatformAudioSource(QAudioDevice, const QAudioFormat &, QObject *parent);
491 ~QPlatformAudioSource() override;
492
493 virtual void start(QIODevice *device) = 0;
494 virtual QIODevice* start() = 0;
495 virtual void stop() = 0;
496 virtual void reset() = 0;
497 virtual void suspend() = 0;
498 virtual void resume() = 0;
499 virtual qsizetype bytesReady() const = 0;
500 virtual void setBufferSize(qsizetype value) = 0;
501 virtual void setNativePeriodFrames(std::optional<NativePeriodFrames>) { }
502 virtual std::optional<NativePeriodFrames> nativePeriodFrames() { return std::nullopt; }
503 virtual qsizetype bufferSize() const = 0;
504 virtual qint64 processedUSecs() const = 0;
505
506 using AudioCallback = QtMultimediaPrivate::AudioSourceCallback;
507
508 virtual void start(AudioCallback &&) { }
509 virtual bool hasCallbackAPI() { return false; }
510
511 QElapsedTimer elapsedTime;
512
513 static QPlatformAudioSource *get(const QAudioSource &);
514};
515
516// forward declarations
517namespace QtMultimediaPrivate {
520} // namespace QtMultimediaPrivate
521
522QT_END_NAMESPACE
523
524#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