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