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
qaudio_platform_implementation_support_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 QAUDIO_PLATFORM_IMPLEMENTATION_SUPPORT_P_H
5#define QAUDIO_PLATFORM_IMPLEMENTATION_SUPPORT_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/qtmultimediaglobal.h>
19
20#include <QtMultimedia/private/qaudiosystem_p.h>
21#include <QtMultimedia/private/qaudiosystem_platform_stream_support_p.h>
22
23QT_BEGIN_NAMESPACE
24
25namespace QtMultimediaPrivate {
26
27///////////////////////////////////////////////////////////////////////////////////////////////////
28
29#ifdef __cpp_concepts
30// clang-format off
31template <typename T>
35{
37 T,
39 const QAudioFormat&,
41 typename T::SinkType*,
42 float,
45 >;
46
47 { t.open() } -> std::same_as<bool>;
48
49 { t.start() } -> std::same_as<QIODevice *>;
50 { t.start(device) } -> std::same_as<bool>;
51 { t.start(std::move(callback)) } -> std::same_as<bool>;
52
53 { t.suspend() } -> std::same_as<void>;
54 { t.resume() } -> std::same_as<void>;
55 { t.stop(shutdownPolicy) } -> std::same_as<void>;
56
57 { t.setVolume(0.0f) } -> std::same_as<void>;
58 { t.bytesFree() } -> std::same_as<quint64>;
59
61};
62
63// clang-format on
64# define STREAM_TYPE_ARG QPlatformSinkStream StreamType
65#else
66# define STREAM_TYPE_ARG typename StreamType
67#endif
68
69template <STREAM_TYPE_ARG, typename DerivedType = void>
71{
72public:
73 QPlatformAudioSinkImplementation(QAudioDevice device, const QAudioFormat &format,
74 QObject *parent);
76
77 void start(QIODevice *device) override;
78 void start(AudioCallback &&) override;
79 QIODevice *start() override;
80
83
86
87 qsizetype bytesFree() const override;
88 void setBufferSize(qsizetype value) override;
89 qsizetype bufferSize() const override;
92 qint64 processedUSecs() const override;
93
94 void setVolume(float volume) override;
96 void setRole(AudioEndpointRole role) override;
97
98protected:
100
102 friend StreamType;
104
108
110
113};
114
115template <STREAM_TYPE_ARG, typename DerivedType>
117 QAudioDevice device, const QAudioFormat &format, QObject *parent)
119{
120}
121
122template <STREAM_TYPE_ARG, typename DerivedType>
127
128template <STREAM_TYPE_ARG, typename DerivedType>
129void QPlatformAudioSinkImplementation<StreamType, DerivedType>::start(QIODevice *device)
130{
131 if (!device) {
132 setError(QAudio::IOError);
133 return;
134 }
135
136 if (m_stream) {
137 qWarning("QAudioSink::start() called while already started");
138 return;
139 }
140
141 m_stream = std::make_shared<StreamType>(m_audioDevice, m_format, m_internalBufferSize,
142 static_cast<ConcreteSinkType *>(this), volume(),
143 m_hardwareBufferFrames, m_role);
144
145 if (!m_stream->open())
147
148 bool started = m_stream->start(device);
149 if (!started)
151
152 updateStreamState(QAudio::ActiveState);
153}
154
155
156template <STREAM_TYPE_ARG, typename DerivedType>
158{
159 m_stream->requestStop();
160 setError(QAudio::OpenError);
161 m_stream = {};
162}
163
164
165template <STREAM_TYPE_ARG, typename DerivedType>
166void QPlatformAudioSinkImplementation<StreamType, DerivedType>::start(AudioCallback &&audioCallback)
167{
168 using namespace QtMultimediaPrivate;
169 if (m_stream) {
170 qWarning("QAudioSink::start() called while already started");
171 return;
172 }
173
174 m_stream = std::make_shared<StreamType>(m_audioDevice, m_format, m_internalBufferSize,
175 static_cast<ConcreteSinkType *>(this), volume(),
176 m_hardwareBufferFrames, m_role);
177
178 if (!m_stream->open())
180
181 bool started = m_stream->start(std::move(audioCallback));
182 if (!started)
184
185 updateStreamState(QAudio::ActiveState);
186}
187
188template <STREAM_TYPE_ARG, typename DerivedType>
190{
191 if (m_stream) {
192 qWarning("QAudioSink::start() called while already started");
193 return nullptr;
194 }
195
196 m_stream = std::make_shared<StreamType>(m_audioDevice, m_format, m_internalBufferSize,
197 static_cast<ConcreteSinkType *>(this), volume(),
198 m_hardwareBufferFrames, m_role);
199
200 if (!m_stream->open()) {
202 return nullptr;
203 }
204
205 QIODevice *device = m_stream->start();
206 if (!device) {
208 return nullptr;
209 }
210
211 QObject::connect(device, &QIODevice::readyRead, this, [this] {
212 updateStreamIdle(false);
213 });
214 updateStreamIdle(true);
215 updateStreamState(QAudio::ActiveState);
216 return device;
217}
218
219template <STREAM_TYPE_ARG, typename DerivedType>
220void QPlatformAudioSinkImplementation<StreamType, DerivedType>::stop()
221{
222 if (m_stream) {
223 m_stream->stop(ShutdownPolicy::DrainRingbuffer);
224 m_stream = {};
225 updateStreamState(QAudio::StoppedState);
226 }
227}
228
229template <STREAM_TYPE_ARG, typename DerivedType>
230void QPlatformAudioSinkImplementation<StreamType, DerivedType>::reset()
231{
232 if (m_stream) {
233 m_stream->stop(ShutdownPolicy::DiscardRingbuffer);
234 m_stream = {};
235 updateStreamState(QAudio::StoppedState);
236 }
237}
238
239template <STREAM_TYPE_ARG, typename DerivedType>
240void QPlatformAudioSinkImplementation<StreamType, DerivedType>::suspend()
241{
242 if (m_stream) {
243 m_stream->suspend();
244 updateStreamState(QAudio::SuspendedState);
245 }
246}
247
248template <STREAM_TYPE_ARG, typename DerivedType>
249void QPlatformAudioSinkImplementation<StreamType, DerivedType>::resume()
250{
251 if (m_stream) {
252 updateStreamState(QAudio::ActiveState);
253 m_stream->resume();
254 }
255}
256
257template <STREAM_TYPE_ARG, typename DerivedType>
258qsizetype QPlatformAudioSinkImplementation<StreamType, DerivedType>::bytesFree() const
259{
260 if (m_stream)
261 return m_stream->bytesFree();
262 return 0;
263}
264
265template <STREAM_TYPE_ARG, typename DerivedType>
266void QPlatformAudioSinkImplementation<StreamType, DerivedType>::setBufferSize(qsizetype value)
267{
268 m_internalBufferSize = value;
269}
270
271template <STREAM_TYPE_ARG, typename DerivedType>
273{
274 if (m_stream)
275 return m_stream->ringbufferSizeInBytes();
276
277 return QPlatformAudioIOStream::inferRingbufferBytes(m_internalBufferSize,
278 m_hardwareBufferFrames, m_format);
279}
280
281template <STREAM_TYPE_ARG, typename DerivedType>
282void QPlatformAudioSinkImplementation<StreamType, DerivedType>::setHardwareBufferFrames(int32_t arg)
283{
284 if (arg > 0)
285 m_hardwareBufferFrames = arg;
286 else
287 m_hardwareBufferFrames = std::nullopt;
288}
289
290template <STREAM_TYPE_ARG, typename DerivedType>
292{
293 return m_hardwareBufferFrames.value_or(-1);
294}
295
296template <STREAM_TYPE_ARG, typename DerivedType>
298{
299 if (m_stream)
300 return m_stream->processedDuration().count();
301
302 return 0;
303}
304
305template <STREAM_TYPE_ARG, typename DerivedType>
306void QPlatformAudioSinkImplementation<StreamType, DerivedType>::setVolume(float volume)
307{
308 QPlatformAudioEndpointBase::setVolume(volume);
309 if (m_stream)
310 m_stream->setVolume(volume);
311}
312
313template <STREAM_TYPE_ARG, typename DerivedType>
314bool QPlatformAudioSinkImplementation<StreamType, DerivedType>::hasCallbackAPI()
315{
316 return true;
317}
318
319template <STREAM_TYPE_ARG, typename DerivedType>
320void QPlatformAudioSinkImplementation<StreamType, DerivedType>::setRole(AudioEndpointRole role)
321{
322 m_role = role;
323}
324
325#undef STREAM_TYPE_ARG
326
327///////////////////////////////////////////////////////////////////////////////////////////////////
328
329#ifdef __cpp_concepts
330// clang-format off
331template <typename T>
334{
336 T,
338 const QAudioFormat&,
340 typename T::SourceType*,
341 float,
343 >;
344
345 { t.open() } -> std::same_as<bool>;
346
347 { t.start() } -> std::same_as<QIODevice *>;
348 { t.start(device) } -> std::same_as<bool>;
349
350 { t.suspend() } -> std::same_as<void>;
351 { t.resume() } -> std::same_as<void>;
352 { t.stop(shutdownPolicy) } -> std::same_as<void>;
353
354 { t.setVolume(0.0f) } -> std::same_as<void>;
355 { t.bytesReady() } -> std::same_as<qsizetype>;
356 { t.deviceIsRingbufferReader() } -> std::same_as<bool>;
357
359};
360
361// clang-format on
362# define STREAM_TYPE_ARG QPlatformSourceStream StreamType
363#else
364# define STREAM_TYPE_ARG typename StreamType
365#endif
366
367template <STREAM_TYPE_ARG, typename DerivedType = void>
409
410template <STREAM_TYPE_ARG, typename DerivedType>
412 QAudioDevice device, const QAudioFormat &format, QObject *parent)
414{
415}
416
417template <STREAM_TYPE_ARG, typename DerivedType>
422
423template <STREAM_TYPE_ARG, typename DerivedType>
425{
426 m_stream->requestStop();
427 setError(QAudio::OpenError);
428 m_stream = {};
429}
430
431template <STREAM_TYPE_ARG, typename DerivedType>
432void QPlatformAudioSourceImplementation<StreamType, DerivedType>::start(QIODevice *device)
433{
434 if (!device) {
435 setError(QAudio::IOError);
436 return;
437 }
438
439 if (m_stream) {
440 qWarning("QAudioSource::start() called while already started");
441 return;
442 }
443
444 m_stream = std::make_shared<StreamType>(m_audioDevice, m_format, m_internalBufferSize,
445 static_cast<ConcreteSourceType *>(this), volume(),
446 m_hardwareBufferFrames);
447
448 if (!m_stream->open())
450
451 bool started = m_stream->start(device);
452 if (!started)
454
455 updateStreamState(QAudio::ActiveState);
456}
457
458template <STREAM_TYPE_ARG, typename DerivedType>
460{
461 if (m_stream) {
462 qWarning("QAudioSource::start() called while already started");
463 return nullptr;
464 }
465
466 m_stream = std::make_shared<StreamType>(m_audioDevice, m_format, m_internalBufferSize,
467 static_cast<ConcreteSourceType *>(this), volume(),
468 m_hardwareBufferFrames);
469
470 if (!m_stream->open()) {
472 return nullptr;
473 }
474
475 QIODevice *device = m_stream->start();
476 if (!device) {
478 return nullptr;
479 }
480
481 QObject::connect(device, &QIODevice::readyRead, this, [this] {
482 updateStreamIdle(false);
483 });
484 updateStreamIdle(true, EmitStateSignal::False);
485 updateStreamState(QAudio::ActiveState);
486 return device;
487}
488
489template <STREAM_TYPE_ARG, typename DerivedType>
490void QPlatformAudioSourceImplementation<StreamType, DerivedType>::stop()
491{
492 if (!m_stream)
493 return;
494
495 if (m_stream->deviceIsRingbufferReader())
496 // we own the qiodevice, so let's keep it alive to allow users to drain the ringbuffer
497 m_retiredStream = m_stream;
498
499 m_stream->stop(ShutdownPolicy::DrainRingbuffer);
500 m_stream = {};
501 updateStreamState(QAudio::StoppedState);
502}
503
504template <STREAM_TYPE_ARG, typename DerivedType>
505void QPlatformAudioSourceImplementation<StreamType, DerivedType>::reset()
506{
507 m_retiredStream = {};
508
509 if (!m_stream)
510 return;
511
512 m_stream->stop(ShutdownPolicy::DiscardRingbuffer);
513 m_stream = {};
514 updateStreamState(QAudio::StoppedState);
515}
516
517template <STREAM_TYPE_ARG, typename DerivedType>
518void QPlatformAudioSourceImplementation<StreamType, DerivedType>::suspend()
519{
520 if (m_stream) {
521 m_stream->suspend();
522 updateStreamState(QAudio::SuspendedState);
523 }
524}
525
526template <STREAM_TYPE_ARG, typename DerivedType>
527void QPlatformAudioSourceImplementation<StreamType, DerivedType>::resume()
528{
529 if (m_stream) {
530 updateStreamState(QAudio::ActiveState);
531 m_stream->resume();
532 }
533}
534
535template <STREAM_TYPE_ARG, typename DerivedType>
537{
538 return m_stream ? m_stream->bytesReady() : 0;
539}
540
541template <STREAM_TYPE_ARG, typename DerivedType>
542void QPlatformAudioSourceImplementation<StreamType, DerivedType>::setBufferSize(qsizetype value)
543{
544 m_internalBufferSize = value;
545}
546
547template <STREAM_TYPE_ARG, typename DerivedType>
549{
550 if (m_stream)
551 return m_stream->ringbufferSizeInBytes();
552
553 return QPlatformAudioIOStream::inferRingbufferBytes(m_internalBufferSize,
554 m_hardwareBufferFrames, m_format);
555}
556
557template <STREAM_TYPE_ARG, typename DerivedType>
559 int32_t arg)
560{
561 if (arg > 0)
562 m_hardwareBufferFrames = arg;
563 else
564 m_hardwareBufferFrames = std::nullopt;
565}
566
567template <STREAM_TYPE_ARG, typename DerivedType>
569{
570 return m_hardwareBufferFrames.value_or(-1);
571}
572
573template <STREAM_TYPE_ARG, typename DerivedType>
575{
576 return m_stream ? m_stream->processedDuration().count() : 0;
577}
578
579template <STREAM_TYPE_ARG, typename DerivedType>
580void QPlatformAudioSourceImplementation<StreamType, DerivedType>::setVolume(float volume)
581{
582 QPlatformAudioEndpointBase::setVolume(volume);
583 if (m_stream)
584 m_stream->setVolume(volume);
585}
586
587///////////////////////////////////////////////////////////////////////////////////////////////////
588
589template <STREAM_TYPE_ARG, typename DerivedType = void>
591 : public QPlatformAudioSourceImplementation<StreamType, DerivedType>
592{
593protected:
594 using BaseClass = QPlatformAudioSourceImplementation<StreamType, DerivedType>;
595 using BaseClass::BaseClass;
596 using BaseClass::start;
597
598 QT_WARNING_PUSH
599 QT_WARNING_DISABLE_CLANG("-Woverloaded-virtual")
602 bool hasCallbackAPI() override { return true; }
603};
604
605template <STREAM_TYPE_ARG, typename DerivedType>
606void QPlatformAudioSourceImplementationWithCallback<StreamType, DerivedType>::start(
607 QPlatformAudioSource::AudioCallback &&audioCallback)
608{
609 using namespace QtMultimediaPrivate;
610
611 BaseClass::m_stream = std::make_shared<StreamType>(
612 BaseClass::m_audioDevice, BaseClass::m_format, BaseClass::m_internalBufferSize,
613 static_cast<typename BaseClass::ConcreteSourceType *>(this), BaseClass::volume(),
614 BaseClass::m_hardwareBufferFrames);
615
616 if (!BaseClass::m_stream->open())
617 return BaseClass::handleStreamOpenError();
618
619 bool started = BaseClass::m_stream->start(std::move(audioCallback));
620 if (!started)
621 return BaseClass::handleStreamOpenError();
622
623 BaseClass::updateStreamState(QAudio::ActiveState);
624}
625
626#undef STREAM_TYPE_ARG
627
628} // namespace QtMultimediaPrivate
629
630QT_END_NAMESPACE
631
632#endif // QAUDIO_PLATFORM_IMPLEMENTATION_SUPPORT_P_H
QPlatformAudioSinkImplementation(QAudioDevice device, const QAudioFormat &format, QObject *parent)
QPlatformAudioSourceImplementation(QAudioDevice device, const QAudioFormat &format, QObject *parent)