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