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
qrtaudioengine_p.h
Go to the documentation of this file.
1
// Copyright (C) 2025 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
QRTAUDIOENGINE_P_H
5
#
define
QRTAUDIOENGINE_P_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
/
qaudioringbuffer_p
.
h
>
19
#
include
<
QtMultimedia
/
private
/
qaudiosystem_p
.
h
>
20
#
include
<
QtMultimedia
/
private
/
qautoresetevent_p
.
h
>
21
#
include
<
QtMultimedia
/
private
/
qtmm_pmr_p
.
h
>
22
#
include
<
QtMultimedia
/
qaudiosink
.
h
>
23
#
include
<
QtMultimedia
/
qtmultimediaglobal
.
h
>
24
#
include
<
QtCore
/
qmutex
.
h
>
25
#
include
<
QtCore
/
qtclasshelpermacros
.
h
>
26
#
include
<
QtCore
/
qtimer
.
h
>
27
28
#
include
<
cstdint
>
29
#
include
<
deque
>
30
#
include
<
set
>
31
#
include
<
variant
>
32
#
include
<
vector
>
33
34
QT_BEGIN_NAMESPACE
35
36
namespace
QtMultimediaPrivate
{
37
38
///////////////////////////////////////////////////////////////////////////////////////////////////
39
40
// ID to uniquely identify a voice
41
enum
class
VoiceId
:
uint64_t
42
{
43
};
44
45
enum
class
VoicePlayResult
:
uint8_t
46
{
47
Playing
,
48
Finished
,
49
};
50
51
///////////////////////////////////////////////////////////////////////////////////////////////////
52
53
class
Q_MULTIMEDIA_EXPORT
QRtAudioEngineVoice
54
{
55
public
:
56
using
VoicePlayResult
=
QtMultimediaPrivate
::
VoicePlayResult
;
57
using
VoiceId
=
QtMultimediaPrivate
::
VoiceId
;
58
59
explicit
QRtAudioEngineVoice
(
VoiceId
id
) :
m_voiceId
{
id
} { }
60
Q_DISABLE_COPY_MOVE
(
QRtAudioEngineVoice
)
61
virtual
~
QRtAudioEngineVoice
() =
default
;
62
63
// once play() returns finished or isActive is false, the QAudioPlaybackEngine will stop the
64
// voice
65
//
66
// additive mixing constraint: QRtAudioEngine zero-fills the output buffer once per callback
67
// and then invokes play() on every active voice with that same buffer, so implementations
68
// must mix additively (e.g. `+=`) rather than overwrite/clear its contents.
69
[[
nodiscard
]]
virtual
VoicePlayResult
play
(
QSpan
<
float
>)
noexcept
Q_DECL_NONBLOCKING_FUNCTION
= 0;
70
virtual
bool
isActive
()
noexcept
Q_DECL_NONBLOCKING_FUNCTION
= 0;
71
72
virtual
const
QAudioFormat
&
format
()
noexcept
= 0;
73
74
VoiceId
voiceId
()
const
{
return
m_voiceId
; }
75
76
private
:
77
const
VoiceId
m_voiceId
;
78
};
79
80
struct
QRtAudioEngineVoiceCompare
:
std
::
less
<
uint64_t
>
81
{
82
using
std
::less<uint64_t>::operator();
83
template
<
typename
Lhs,
typename
Rhs>
84
bool
operator
()(
const
Lhs &lhs,
const
Rhs &rhs)
const
85
{
86
return
operator()(
getId
(
lhs
)
,
getId
(
rhs
)
);
87
}
88
89
static
uint64_t
getId
(
VoiceId
arg) {
return
qToUnderlying(arg); }
90
static
uint64_t
getId
(
const
QRtAudioEngineVoice &arg) {
return
getId
(
arg.voiceId()
)
; }
91
static
uint64_t
getId
(
const
std::shared_ptr<QRtAudioEngineVoice> &arg) {
return
getId
(
*arg
)
; }
92
93
using
is_transparent
=
std
::
true_type
;
94
};
95
96
///////////////////////////////////////////////////////////////////////////////////////////////////
97
98
namespace
Impl
{
99
template
<
typename
T>
100
struct
visitor_arg
;
101
102
template
<
typename
R,
typename
Arg>
103
struct
visitor_arg
<R(Arg)>
104
{
105
using
type
= Arg;
106
};
107
108
template
<
typename
R,
typename
Arg>
109
struct
visitor_arg
<R (*)(Arg)>
110
{
111
using
type
= Arg;
112
};
113
114
template
<
typename
F>
115
struct
visitor_arg
:
visitor_arg
<
decltype
(&F::operator())>
116
{
117
};
118
119
template
<
typename
C,
typename
R,
typename
Arg>
120
struct
visitor_arg
<R (
C
::*)(Arg)
const
>
121
{
122
using
type
= Arg;
123
};
124
125
template
<
typename
C,
typename
R,
typename
Arg>
126
struct
visitor_arg
<R (
C
::*)(Arg)>
127
{
128
using
type
= Arg;
129
};
130
131
}
// namespace Impl
132
133
template
<
typename
F>
134
using
visitor_arg_t
=
typename
Impl
::
visitor_arg
<F>::
type
;
135
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137
138
// playback engine for QRtAudioEngineVoice instances
139
// keeps a QAudioSink alive, but in a suspended state if no voices are playing
140
class
Q_MULTIMEDIA_EXPORT QRtAudioEngine
final
:
public
QObject
141
{
142
public
:
143
using
RtVoiceVisitor
=
std
::
function
<
void
(
QRtAudioEngineVoice
&)>;
144
using
SharedVoice
=
std
::
shared_ptr
<
QRtAudioEngineVoice
>;
145
146
Q_OBJECT
147
148
// commands (app->rt)
149
struct
PlayCommand
150
{
151
SharedVoice
voice
;
152
};
153
154
struct
StopCommand
155
{
156
const
VoiceId
voiceId
;
157
};
158
159
// visitors are sent back to the non-rt thread, so that they are destroyed in a safe context
160
struct
VisitCommand
161
{
162
const
VoiceId
voiceId
;
163
RtVoiceVisitor
callback
;
164
};
165
166
// "trivial" visitors are not sent back to the non-rt thread
167
struct
VisitCommandTrivial
168
{
169
const
VoiceId
voiceId
;
170
RtVoiceVisitor
callback
;
171
};
172
173
using
RtCommand
=
std
::
variant
<
PlayCommand
,
StopCommand
,
VisitCommand
,
VisitCommandTrivial
>;
174
175
// notifications (rt->app)
176
struct
StopNotification
177
{
178
SharedVoice
voice
;
179
};
180
181
struct
VisitReply
182
{
183
RtVoiceVisitor
callback
;
184
};
185
186
using
Notification
=
std
::
variant
<
StopNotification
,
VisitReply
>;
187
188
public
:
189
enum
class
MoveToApplicationThread
:
bool
{
190
No
,
191
Yes
,
192
};
193
194
QRtAudioEngine
(
const
QAudioDevice
&,
const
QAudioFormat
&,
195
std
::
optional
<
AudioEndpointRole
> =
std
::
nullopt
,
196
std
::
optional
<
NativePeriodFrames
>
nativePeriodFrames
=
std
::
nullopt
);
197
QRtAudioEngine
(
MoveToApplicationThread
,
const
QAudioDevice
&,
const
QAudioFormat
&,
198
std
::
optional
<
AudioEndpointRole
> =
std
::
nullopt
,
199
std
::
optional
<
NativePeriodFrames
>
nativePeriodFrames
=
std
::
nullopt
);
200
Q_DISABLE_COPY_MOVE
(
QRtAudioEngine
)
201
~
QRtAudioEngine
()
override
;
202
203
// play/stop/visitVoiceRT are thread-safe
204
void
play
(
SharedVoice
);
205
void
stop
(
const
SharedVoice
&);
206
void
stop
(
VoiceId
);
207
208
template
<
typename
Visitor
>
209
void
visitVoiceRt
(
VoiceId
id
,
Visitor
visitor
)
210
{
211
using
visitorArg
=
visitor_arg_t
<
Visitor
>;
212
static_assert
(
std
::
is_reference_v
<
visitorArg
>);
213
214
// we need to prevent that the visitor function is going to be destroyed on the real-time
215
// thread, unless:
216
// * it can be trivially destroyed
217
// * it is sufficiently small to fit into the small-buffer-optimization of std::function.
218
// we don't know what the value is, so we are conservative and assume only the size of a
219
// pointer (we could relax it with something like std::inplace_function)
220
constexpr
size_t
smallBufferOptimizationEstimate
= 2 *
sizeof
(
void
*);
221
constexpr
bool
visitorIsTrivial
=
std
::
is_trivially_destructible_v
<
std
::
decay_t
<
Visitor
>>
222
&&
sizeof
(
Visitor
) <=
smallBufferOptimizationEstimate
;
223
224
auto
wrapped
= [
visitor
=
std
::
move
(
visitor
)](
QRtAudioEngineVoice
&
voice
)
mutable
{
225
visitor
(
static_cast
<
visitorArg
>(
voice
));
226
};
227
visitVoiceRt
(
id
,
RtVoiceVisitor
{
wrapped
},
visitorIsTrivial
);
228
}
229
230
template
<
typename
Visitor
>
231
void
visitVoiceRt
(
const
SharedVoice
&
voice
,
Visitor
visitor
)
232
{
233
visitVoiceRt
(
voice
->
voiceId
(),
std
::
move
(
visitor
));
234
}
235
236
static
VoiceId
allocateVoiceId
();
237
238
std
::
unique_ptr
<
pmr
::
memory_resource
> &
rtMemoryResource
() {
return
m_rtMemoryPool
; }
239
240
// testing
241
QAudioSink
&
audioSink
() {
return
m_sink
; }
242
const
auto
&
voices
()
const
{
return
m_voices
; }
243
void
pumpAudioCallback
(
QSpan
<
float
>
buffer
) {
audioCallback
(
buffer
); }
244
245
// will return QtAudio::Stopped sink cannot be started or an error occurred
246
QtAudio
::
State
audioState
()
const
;
247
248
Q_SIGNALS
:
249
void
stateChanged
(
QtAudio
::
State
);
250
void
voiceFinished
(
VoiceId
);
251
252
private
:
253
void
visitVoiceRt
(
VoiceId
,
RtVoiceVisitor
,
bool
visitorIsTrivial
);
254
255
void
audioCallback
(
QSpan
<
float
>)
noexcept
Q_DECL_NONBLOCKING_FUNCTION
;
256
void
cleanupRetiredVoices
()
noexcept
Q_DECL_NONBLOCKING_FUNCTION
;
257
258
void
runRtCommands
()
noexcept
Q_DECL_NONBLOCKING_FUNCTION
;
259
void
runRtCommand
(
PlayCommand
)
noexcept
Q_DECL_NONBLOCKING_FUNCTION
;
260
void
runRtCommand
(
StopCommand
)
noexcept
Q_DECL_NONBLOCKING_FUNCTION
;
261
void
runRtCommand
(
VisitCommand
)
noexcept
Q_DECL_NONBLOCKING_FUNCTION
;
262
void
runRtCommand
(
VisitCommandTrivial
)
noexcept
Q_DECL_NONBLOCKING_FUNCTION
;
263
264
void
runNonRtNotifications
();
265
void
runNonRtNotification
(
StopNotification
);
266
void
runNonRtNotification
(
VisitReply
);
267
268
QAudioSink
m_sink
;
269
270
QMutex
m_mutex
;
271
272
// Application side
273
std
::
set
<
SharedVoice
,
QRtAudioEngineVoiceCompare
>
m_voices
;
274
275
// Rt memory
276
// Note: when the memory pool is exhausted, we fall back to the system allocator. Not great for
277
// real-time uses, but a simple fallback strategy
278
static
constexpr
size_t
poolSize
= 128 * 1024;
// 128kb
279
std
::
unique_ptr
<
pmr
::
memory_resource
>
m_rtMemoryPool
;
280
281
// Voice registry on the real-time thread:
282
// invariant: every voice in m_rtVoiceRegistry is also in m_voices
283
using
VoiceRegistry
=
std
::
set
<
SharedVoice
,
QRtAudioEngineVoiceCompare
,
284
pmr
::
polymorphic_allocator
<
SharedVoice
>>;
285
VoiceRegistry
m_rtVoiceRegistry
{
286
m_rtMemoryPool
.
get
(),
287
};
288
289
// rt/nrt communication
290
static
constexpr
size_t
commandBuffersSize
= 2048;
291
QtPrivate
::
QAudioRingBuffer
<
RtCommand
>
m_appToRt
{
commandBuffersSize
};
292
QtPrivate
::
QAudioRingBuffer
<
Notification
>
m_rtToApp
{
commandBuffersSize
};
293
std
::
deque
<
RtCommand
>
m_appToRtOverflowBuffer
;
294
std
::
deque
<
Notification
,
pmr
::
polymorphic_allocator
<
Notification
>>
m_rtToAppOverflowBuffer
{
295
m_rtMemoryPool
.
get
(),
296
};
297
void
sendAppToRtCommand
(
RtCommand
cmd
);
298
bool
sendRtToAppNotification
(
Notification
cmd
);
299
void
sendPendingRtCommands
();
300
bool
sendPendingAppNotifications
();
301
QTimer
m_pendingCommandsTimer
;
302
303
QtPrivate
::
QAutoResetEvent
m_notificationEvent
;
304
std
::
vector
<
VoiceId
>
m_finishedVoices
;
305
};
306
307
}
// namespace QtMultimediaPrivate
308
309
QT_END_NAMESPACE
310
311
#
endif
// QRTAUDIOENGINE_P_H
QtMultimediaPrivate::QRtAudioEngineVoice
Definition
qrtaudioengine_p.h:54
QtMultimediaPrivate::Impl
Definition
qrtaudioengine_p.h:98
QtMultimediaPrivate::impl
Definition
qaudiosystem_p.h:257
QtMultimediaPrivate::visitor_arg_t
typename Impl::visitor_arg< F >::type visitor_arg_t
Definition
qrtaudioengine_p.h:134
QtMultimediaPrivate::VoiceId
VoiceId
Definition
qrtaudioengine_p.h:42
QtMultimediaPrivate::VoicePlayResult
VoicePlayResult
Definition
qrtaudioengine_p.h:46
QtMultimediaPrivate::VoicePlayResult::Finished
@ Finished
Definition
qrtaudioengine_p.h:48
QtMultimediaPrivate::VoicePlayResult::Playing
@ Playing
Definition
qrtaudioengine_p.h:47
QtMultimediaPrivate::sinkStateToEngineState
static QtAudio::State sinkStateToEngineState(QtAudio::State state)
Definition
qrtaudioengine.cpp:30
std
[33]
Definition
src_corelib_tools_qhash.cpp:421
QtMultimediaPrivate::Impl::visitor_arg< R(Arg)>
Definition
qrtaudioengine_p.h:104
QtMultimediaPrivate::Impl::visitor_arg< R(Arg)>::type
Arg type
Definition
qrtaudioengine_p.h:105
QtMultimediaPrivate::Impl::visitor_arg< R(C::*)(Arg) const >
Definition
qrtaudioengine_p.h:121
QtMultimediaPrivate::Impl::visitor_arg< R(C::*)(Arg) const >::type
Arg type
Definition
qrtaudioengine_p.h:122
QtMultimediaPrivate::Impl::visitor_arg< R(*)(Arg)>
Definition
qrtaudioengine_p.h:110
QtMultimediaPrivate::Impl::visitor_arg< R(*)(Arg)>::type
Arg type
Definition
qrtaudioengine_p.h:111
QtMultimediaPrivate::Impl::visitor_arg
Definition
qrtaudioengine_p.h:116
QtMultimediaPrivate::QRtAudioEngineVoiceCompare
Definition
qrtaudioengine_p.h:81
QtMultimediaPrivate::QRtAudioEngineVoiceCompare::getId
static uint64_t getId(VoiceId arg)
Definition
qrtaudioengine_p.h:89
QtMultimediaPrivate::QRtAudioEngineVoiceCompare::getId
static uint64_t getId(const QRtAudioEngineVoice &arg)
Definition
qrtaudioengine_p.h:90
QtMultimediaPrivate::QRtAudioEngineVoiceCompare::operator()
bool operator()(const Lhs &lhs, const Rhs &rhs) const
Definition
qrtaudioengine_p.h:84
qtmultimedia
src
multimedia
audio
qrtaudioengine_p.h
Generated on
for Qt by
1.16.1