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.cpp
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
5
6#include <QtMultimedia/private/qaudio_rtsan_support_p.h>
7#include <QtMultimedia/private/qaudiosystem_p.h>
8#include <QtMultimedia/private/qmemory_resource_tlsf_p.h>
9#include <QtCore/q20map.h>
10#include <QtCore/qcoreapplication.h>
11#include <QtCore/qdebug.h>
12#include <QtCore/qmutex.h>
13#include <QtCore/qthread.h>
14
15#include <mutex>
16
17#ifdef Q_CC_MINGW
18// mingw-13.1 seems to have a false positive when using std::function inside a std::variant
19QT_WARNING_PUSH
20QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
21#endif
22
23QT_BEGIN_NAMESPACE
24
25namespace QtMultimediaPrivate {
26
27using namespace QtPrivate;
28using namespace std::chrono_literals;
29
30///////////////////////////////////////////////////////////////////////////////////////////////////
31
78
80{
81 m_sink.reset();
82
83 // consume the ringbuffers
84 m_appToRt.consumeAll([](auto) {
85 });
86 m_rtToApp.consumeAll([](auto) {
87 });
88}
89
91{
92 auto lock = std::lock_guard{ m_mutex };
93
94 // TODO: where do we expect reampling to happen?
96
97 if (m_voices.empty())
98 m_sink.resume();
99
101
103 std::move(voice),
104 });
105}
106
108{
109 stop(voice->voiceId());
110}
111
117
119{
120 auto lock = std::lock_guard{ m_mutex };
121
122 if (visitorIsTrivial) {
124 voiceId,
125 std::move(fn),
126 });
127
128 } else {
130 voiceId,
131 std::move(fn),
132 });
133 }
134}
135
141
143{
146
148
151 };
152
153 for (const SharedVoice &voice : m_rtVoiceRegistry) {
154 Q_ASSERT(voice.use_count() >= 2); // voice in both m_rtVoiceRegistry and m_voices
155
159 }
160
161 if (!finishedVoices.empty()) {
163 for (const SharedVoice &voice : finishedVoices) {
166 if (stopSent)
167 sendNotification = true;
168 }
169 });
170 }
171
172 // TODO: we should probably (soft)clip the output buffer
173
177}
178
180{
181 bool notifyApp = false;
182
183#if __cpp_lib_erase_if >= 202002L
184 using std::erase_if;
185#else
186 auto erase_if = [](auto &c, auto &&pred) {
187 auto old_size = c.size();
188 for (auto first = c.begin(), last = c.end(); first != last;) {
189 if (pred(*first))
190 first = c.erase(first);
191 else
192 ++first;
193 }
194 return old_size - c.size();
195 };
196#endif
199 bool voiceIsActive = voice->isActive();
200 if (!voiceIsActive)
202
203 return !voiceIsActive;
204 });
205 });
206
207 if (notifyApp)
209}
210
212{
214 for (RtCommand &cmd : commands) {
215 std::visit([&](auto cmd) {
217 }, std::move(cmd));
218 }
219 });
220}
221
223{
226 });
227}
228
230{
232 if (it == m_rtVoiceRegistry.end())
233 return;
234
237
239 std::move(voice),
240 });
241 if (emitNotify)
243}
244
246{
248 if (it == m_rtVoiceRegistry.end())
249 return;
250
251 cmd.callback(**it);
252
253 // send callback back to application for destruction
256 });
257 if (emitNotify)
259}
260
262{
264 if (it == m_rtVoiceRegistry.end())
265 return;
266
267 cmd.callback(**it);
268}
269
271{
273 {
274 auto lock = std::lock_guard{ m_mutex };
277 std::visit([&](auto notification) {
279 }, std::move(notification));
280 }
281 });
282
285 }
286
287 // emit voiceFinished outside of the lock
290}
291
293{
295 if (m_voices.empty())
296 m_sink.suspend();
298}
299
301{
302 // nop (just making sure to delete on the application thread);
303}
304
306{
307 // first write all pending commands from overflow buffer
309
310 bool written = m_appToRt.produceOne([&] {
311 return std::move(cmd);
312 });
313
314 if (written)
315 return;
316
318
322 });
323}
324
326{
327 // first write all pending commands from overflow buffer
329
330 bool written = m_rtToApp.produceOne([&] {
331 return std::move(cmd);
332 });
333
334 if (written)
335 return true;
336
338
339 return emitNotification;
340}
341
343{
344 while (!m_appToRtOverflowBuffer.empty()) {
346 bool written = m_appToRt.produceOne([&] {
348 });
349 if (!written)
350 return;
351
353 }
354}
355
357{
358 bool emitNotification = false;
359 while (!m_rtToAppOverflowBuffer.empty()) {
361
362 // first write all pending commands from overflow buffer
363 bool written = m_rtToApp.produceOne([&] {
365 });
366 if (!written)
367 break;
368
370 emitNotification = true;
371 }
372
373 return emitNotification;
374}
375
376} // namespace QtMultimediaPrivate
377
378QT_END_NAMESPACE
379
380#ifdef Q_CC_MINGW
381QT_WARNING_POP
382#endif
383
384#include "moc_qrtaudioengine_p.cpp"