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
qaudiosource.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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#include "qaudiosource.h"
5
6#include <QtMultimedia/private/qaudio_alignment_support_p.h>
7#include <QtMultimedia/private/qaudiohelpers_p.h>
8#include <QtMultimedia/private/qaudiosystem_p.h>
9#include <QtMultimedia/private/qplatformaudiodevices_p.h>
10#include <QtMultimedia/private/qplatformmediaintegration_p.h>
11#include <QtMultimedia/qaudio.h>
12#include <QtMultimedia/qaudiodevice.h>
13
15
16/*!
17 \class QAudioSource
18 \brief The QAudioSource class provides an interface for receiving audio data from an audio input
19 device.
20
21 \inmodule QtMultimedia
22 \ingroup multimedia
23 \ingroup multimedia_audio
24
25 You can construct an audio input with the system's
26 default audio input device. It is also possible to
27 create QAudioSource with a specific QAudioDevice. When
28 you create the audio input, you should also send in the
29 QAudioFormat to be used for the recording (see the QAudioFormat
30 class description for details).
31
32 QAudioSink can be used in two different modes:
33 \list
34 \li Using a QIODevice from an application thread
35 \li Using a callback-based interface from the audio thread
36 \endlist
37
38 \section1 QIODevice interface
39
40 QAudioSource lets you record audio with an audio input device. The
41 default constructor of this class will use the systems default
42 audio device, but you can also specify a QAudioDevice for a
43 specific device. You also need to pass in the QAudioFormat in
44 which you wish to record.
45
46 Starting up the QAudioSource is simply a matter of calling start()
47 with a QIODevice opened for writing. For instance, to record to a
48 file, you can:
49
50 \snippet multimedia-snippets/audio.cpp Audio input class members
51
52 \snippet multimedia-snippets/audio.cpp Audio input setup
53
54 This will start recording if the format specified is supported by
55 the input device (you can check this with
56 QAudioDevice::isFormatSupported(). In case there are any
57 snags, use the error() function to check what went wrong. We stop
58 recording in the \c stopRecording() slot.
59
60 \snippet multimedia-snippets/audio.cpp Audio input stop recording
61
62 At any point in time, QAudioSource will be in one of four states:
63 active, suspended, stopped, or idle. These states are specified by
64 the QtAudio::State enum.
65
66 QAudioSource provides several ways of measuring the time that has
67 passed since the start() of the recording. The \c processedUSecs()
68 function returns the length of the stream in microseconds written,
69 i.e., it leaves out the times the audio input was suspended or idle.
70 The elapsedUSecs() function returns the time elapsed since start() was called regardless of
71 which states the QAudioSource has been in.
72
73 \section2 Threading model and buffering
74
75 The QIODevice interface is designed to be used from the application thread.
76 A wait-free ringbuffer is used to communicate to the audio thread. The size
77 of this ringbuffer can be configured with setBufferSize() and defaults to
78 250ms. The state of this buffer can be queried with bytesFree(). If the
79 ringbuffer is full because the application does not read from the QIODevice in time,
80 the state will change to QtAudio::IdleState and resume to QtAudio::ActiveState
81 once the application has read data from the QIODevice. Note that this state change will drop
82 audio data, so you should always read from the QIODevice as fast as possible to avoid dropouts.
83
84 \section1 Callback interface
85
86 The preferred way to achieve low audio latencies is to use the callback based interface.
87 It allows you to read audio data directly from the audio device without having to go through
88 a QIODevice. This is done by calling start() with a callback function that will be called
89 from the audio thread. This callback function will be called with a QSpan<const SampleType>
90 whenever the audio backend produces data.
91
92 \snippet multimedia-snippets/audio.cpp Audio callback capture class members
93 \snippet multimedia-snippets/audio.cpp Audio callback capture setup peak meter
94
95 Unlike the QIODevice-based interface, the QAudioSource can only be in the states active,
96 suspendend and stopped. The setBufferSize() API is not available when using the callback,
97 the size of the callback argument is determined by the audio backend.
98
99 \qtmmaudiocallbacksupportednote
100 \qtmmaudiocallbacknote
101
102
103 \section1 State and error handling
104
105 State changes are reported through the stateChanged() signal. You can request a state change
106 directly through suspend(), resume(), stop(), reset(), and start().
107
108 The QAudioSource will enter the \l{QtAudio::}{StoppedState} when an error is encountered.
109 The \l{QtAudio::Error}{error type} can be retrieved error() function. Please see the
110 QtAudio::Error enum for a description of the possible errors that are reported. Calling stop()
111 or reset() will reset the error state to \l{QtAudio::Error}{NoError}.
112
113 \snippet multimedia-snippets/audio.cpp Audio input state changed
114
115 \sa QAudioSink, QAudioDevice
116*/
117
118/*!
119 Construct a new audio input and attach it to \a parent.
120 The default audio input device is used with the output
121 \a format parameters. If \a format is default-initialized,
122 the format will be set to the preferred format of the audio device.
123*/
124
125QAudioSource::QAudioSource(const QAudioFormat &format, QObject *parent)
126 : QAudioSource({}, format, parent)
127{
128}
129
130/*!
131 Construct a new audio input and attach it to \a parent.
132 The device referenced by \a audioDevice is used with the input
133 \a format parameters. If \a format is default-initialized,
134 the format will be set to the preferred format of \a audioDevice.
135*/
136
137QAudioSource::QAudioSource(const QAudioDevice &audioDevice, const QAudioFormat &format, QObject *parent):
138 QObject(parent)
139{
140 d = QPlatformMediaIntegration::instance()->audioDevices()->audioInputDevice(format, audioDevice,
141 this);
142 if (d)
143 connect(d, &QPlatformAudioSource::stateChanged, this, &QAudioSource::stateChanged);
144 else
145 qWarning("No audio device detected");
146}
147
148/*!
149 \fn bool QAudioSource::isNull() const
150
151 Returns \c true if the audio source is \c null, otherwise returns \c false.
152*/
153
154/*!
155 Destroy this audio input.
156*/
157
158QAudioSource::~QAudioSource()
159{
160 delete d;
161}
162
163static bool validateFormatAtStart(QPlatformAudioSource *d)
164{
165 if (!d->format().isValid()) {
166 qWarning() << "QAudioSource::start: QAudioFormat not valid";
167 d->setError(QAudio::OpenError);
168 return false;
169 }
170
171 if (!d->isFormatSupported(d->format())) {
172 qWarning() << "QAudioSource::start: QAudioFormat not supported by QAudioDevice";
173 d->setError(QAudio::OpenError);
174 return false;
175 }
176 return true;
177};
178
179/*!
180 Starts transferring audio data from the system's audio input to the \a device.
181 The \a device must have been opened in the \l{QIODevice::WriteOnly}{WriteOnly},
182 \l{QIODevice::Append}{Append} or \l{QIODevice::ReadWrite}{ReadWrite} modes.
183
184 If the QAudioSource is able to successfully get audio data, state() returns
185 either QtAudio::ActiveState or QtAudio::IdleState, error() returns QtAudio::NoError
186 and the stateChanged() signal is emitted.
187
188 If a problem occurs during this process, error() returns QtAudio::OpenError,
189 state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
190
191 \sa QIODevice {QAudioSource#Callback interface}{QIODevice interface}
192*/
193
194void QAudioSource::start(QIODevice* device)
195{
196 if (!d)
197 return;
198
199 d->setError(QAudio::NoError);
200
201 if (!device->isWritable()) {
202 qWarning() << "QAudioSource::start: QIODevice is not writable";
203 d->setError(QAudio::OpenError);
204 return;
205 }
206
207 if (!validateFormatAtStart(d))
208 return;
209
210 d->elapsedTime.start();
211 d->start(device);
212}
213
214/*!
215 Returns a pointer to the internal QIODevice being used to transfer data from
216 the system's audio input. The device will already be open and
217 \l{QIODevice::read()}{read()} can read data directly from it.
218
219 \note The pointer will become invalid after the stream is stopped or
220 if you start another stream.
221
222 If the QAudioSource is able to access the system's audio device, state() returns
223 QtAudio::IdleState, error() returns QtAudio::NoError
224 and the stateChanged() signal is emitted.
225
226 If a problem occurs during this process, error() returns QtAudio::OpenError,
227 state() returns QtAudio::StoppedState and the stateChanged() signal is emitted.
228
229 \sa QIODevice {QAudioSource#Callback interface}{QIODevice interface}
230*/
231
232QIODevice* QAudioSource::start()
233{
234 if (!d)
235 return nullptr;
236
237 d->setError(QAudio::NoError);
238
239 if (!validateFormatAtStart(d))
240 return nullptr;
241
242 d->elapsedTime.start();
243 return d->start();
244}
245
246/*!
247 \fn template <typename Callback, QtAudio::if_audio_source_callback<Callback> = true> void QAudioSource::start(Callback &&)
248
249 Starts the QAudioSource with a callback function that will be called on a soft-realtime audio
250 thread. The callback is a callable that takes a QSpan<const SampleType> as an argument,
251 SampleType has to match the QAudioFormat::SampleFormat of the QAudioSource's format. The span
252 contains the interleaved audio data.
253
254 If the QAudioSource is able to successfully start, error() returns QtAudio::NoError.
255
256 If a problem occurs during this process, error() returns QtAudio::OpenError, state() returns
257 QtAudio::StoppedState and the stateChanged() signal is emitted.
258
259 \qtmmaudiocallbacksupportednote
260 \qtmmaudiocallbacknote
261
262 \sa {QAudioSource#Callback interface}{Callback interface}
263 \since 6.11
264 */
265
266template <typename T>
267void QAudioSource::startImpl(T &&callback)
268{
269 if (!d)
270 return;
271
272 if (!d->hasCallbackAPI()) {
273 qWarning() << "QAudioSource::start: Callback API not supported on this platform";
274 d->setError(QAudio::OpenError);
275 return;
276 }
277
278 using namespace QtMultimediaPrivate;
279 if (!validateAudioCallback(callback, format())) {
280 d->setError(QAudio::OpenError);
281 return;
282 }
283
284 if (!validateFormatAtStart(d))
285 return;
286
287 d->elapsedTime.start();
288 d->start(std::forward<T>(callback));
289}
290
291void QAudioSource::startABIImpl(QtAudioPrivate::AudioSourceCallback &&callback)
292{
293 return QAudioSource::startImpl(QtMultimediaPrivate::asAudioSourceCallback(std::move(callback)));
294}
295
296/*!
297 Returns the QAudioFormat being used.
298*/
299
300QAudioFormat QAudioSource::format() const
301{
302 return d ? d->format() : QAudioFormat();
303}
304
305/*!
306 Stops the audio input, detaching from the system resource.
307
308 Sets error() to QtAudio::NoError, state() to QtAudio::StoppedState and
309 emit stateChanged() signal.
310*/
311
312void QAudioSource::stop()
313{
314 if (d)
315 d->stop();
316}
317
318/*!
319 Drops all audio data in the buffers, resets buffers to zero.
320*/
321
322void QAudioSource::reset()
323{
324 if (d)
325 d->reset();
326}
327
328/*!
329 Stops processing audio data, preserving buffered audio data.
330
331 Sets error() to QtAudio::NoError, state() to QtAudio::SuspendedState and
332 emit stateChanged() signal.
333*/
334
335void QAudioSource::suspend()
336{
337 if (d)
338 d->suspend();
339}
340
341/*!
342 Resumes processing audio data after a suspend().
343
344 Sets state() to the state the sink had when suspend() was called. This function does nothing if
345 the audio sink's state is not QtAudio::SuspendedState.
346*/
347
348void QAudioSource::resume()
349{
350 if (d)
351 d->resume();
352}
353
354/*!
355 Sets the audio buffer size to \a value bytes.
356
357 \note This function can be called anytime before start(), calls to this
358 are ignored after start(). It should not be assumed that the buffer size
359 set is the actual buffer size used, calling bufferSize() anytime after start()
360 will return the actual buffer size being used.
361
362 The bufferFrameCount() and bufferSize() properties denote the ringbuffer size
363 when using the QIODevice APIs. The native period size is controlled via setNativePeriodFrameCount().
364
365 \sa setBufferFrameCount
366*/
367
368void QAudioSource::setBufferSize(qsizetype value)
369{
370 if (d)
371 d->setBufferSize(value);
372}
373
374/*!
375 Returns the audio buffer size in bytes.
376
377 If called before \l start(), returns platform default value.
378 If called before \c start() but \l setBufferSize() or \l setBufferFrameCount() was called prior, returns
379 value set by \c setBufferSize() or \c setBufferFrameCount(). If called after \c start(), returns the actual
380 buffer size being used. This may not be what was set previously by
381 \c setBufferSize() or \c setBufferFrameCount().
382
383 \sa bufferFrameCount
384*/
385
386qsizetype QAudioSource::bufferSize() const
387{
388 return d ? d->bufferSize() : 0;
389}
390
391/*!
392 Sets the audio buffer size to \a value in frame count.
393
394 \note This function can be called anytime before start(). Calls to this
395 are ignored after start(). It should not be assumed that the buffer size
396 set is the actual buffer size used - call bufferFrameCount() anytime
397 after start() to return the actual buffer size being used.
398
399 The bufferFrameCount() and bufferSize() properties denote the ringbuffer size
400 when using the QIODevice APIs. The native period size is controlled via setNativePeriodFrameCount().
401
402 \sa setBufferSize
403 \since 6.10
404*/
405
406void QAudioSource::setBufferFrameCount(qsizetype value)
407{
408 if (d)
409 setBufferSize(d->format().bytesForFrames(value));
410}
411
412/*!
413 Returns the audio buffer size in frames.
414
415 If called before \l start(), returns platform default value.
416 If called before \c start() but \l setBufferSize() or \l setBufferFrameCount() was called prior, returns
417 value set by \c setBufferSize() or \c setBufferFrameCount(). If called after \c start(), returns the actual
418 buffer size being used. This may not be what was set previously by
419 \c setBufferSize() or \c setBufferFrameCount().
420
421 \sa bufferSize
422 \since 6.10
423*/
424
425qsizetype QAudioSource::bufferFrameCount() const
426{
427 return d ? d->format().framesForBytes(bufferSize()) : 0;
428}
429
430/*!
431 Sets the native period frame count to \a frameCount.
432
433 Tunes the audio buffer size used by the operating system and hardware. By default (when not set),
434 the system uses a platform-dependent value, typically 1024 frames (~23ms at 44100 Hz).
435
436 Use smaller values (64-256) to reduce latency, or larger values (2048-4096) to reduce the risk of
437 buffer overruns (dropouts).
438
439 Valid values are powers of 2 between 32 and 4096 (inclusive), or -1 to unset. Can only be called
440 when the audio source is stopped.
441
442 Maps to platform-specific settings: \c{kAudioDevicePropertyBufferFrameSize} (macOS),
443 \c{IAudioClient::bufferDuration} (Windows), \c{PW_KEY_NODE_FORCE_QUANTUM} (PipeWire/Linux),
444 and \c{AAudioStreamBuilder_setBufferCapacityInFrames} (Android).
445
446 \note This is separate from the ringbuffer configured with setBufferSize() or setBufferFrameCount().
447
448 \since 6.12
449 \sa nativePeriodFrameCount
450*/
451void QAudioSource::setNativePeriodFrameCount(int frameCount)
452{
453 if (!d)
454 return;
455
456 if (frameCount != -1) {
457 // Check if stopped
458 if (state() != QAudio::StoppedState) {
459 qWarning("QAudioSource::setNativePeriodFrameCount: can only be set when stopped");
460 return;
461 }
462
463 if (frameCount < 32 || frameCount > 4096
464 || !QtMultimediaPrivate::isPowerOfTwo(frameCount)) {
465 qWarning("QAudioSource::setNativePeriodFrameCount: invalid frame count %d "
466 "(must be -1 or a power of 2 between 32 and 4096)",
467 frameCount);
468 return;
469 }
470 }
471
472 if (frameCount != -1)
473 d->setNativePeriodFrames(QtMultimediaPrivate::NativePeriodFrames(frameCount));
474 else
475 d->setNativePeriodFrames(std::nullopt);
476}
477
478/*!
479 Returns the native period frame count.
480
481 Returns -1 if not set, otherwise returns the value previously set with
482 setNativePeriodFrameCount().
483
484 \since 6.12
485 \sa setNativePeriodFrameCount
486*/
487int QAudioSource::nativePeriodFrameCount() const
488{
489 std::optional hwbf = d ? d->nativePeriodFrames() : std::nullopt;
490 return hwbf ? qToUnderlying(*hwbf) : -1;
491}
492
493/*!
494 Returns the amount of audio data available to read in bytes.
495
496 \note returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
497 state, otherwise returns zero.
498
499 \sa framesAvailable
500*/
501
502qsizetype QAudioSource::bytesAvailable() const
503{
504 return d ? d->bytesReady() : 0;
505}
506
507/*!
508 Returns the amount of audio data available to read in frames.
509
510 Note: returned value is only valid while in QtAudio::ActiveState or QtAudio::IdleState
511 state, otherwise returns zero.
512
513 \sa bytesAvailable
514 \since 6.10
515*/
516
517qsizetype QAudioSource::framesAvailable() const
518{
519
520 return d ? d->format().framesForBytes(bytesAvailable()) : 0;
521}
522
523/*!
524 Sets the input volume to \a volume.
525
526 The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this
527 range will be clamped.
528
529 If the device does not support adjusting the input
530 volume then \a volume will be ignored and the input
531 volume will remain at 1.0.
532
533 The default volume is \c 1.0.
534
535 \note Adjustments to the volume will change the volume of this audio stream, not the global
536 volume.
537*/
538void QAudioSource::setVolume(qreal volume)
539{
540 if (!d)
541 return;
542
543 std::optional<float> newVolume = QAudioHelperInternal::sanitizeVolume(volume, this->volume());
544 if (newVolume)
545 d->setVolume(*newVolume);
546}
547
548/*!
549 Returns the input volume.
550
551 If the device does not support adjusting the input volume
552 the returned value will be 1.0.
553*/
554qreal QAudioSource::volume() const
555{
556 return d ? d->volume() : 1.0;
557}
558
559/*!
560 Returns the amount of audio data processed since start()
561 was called in microseconds.
562*/
563
564qint64 QAudioSource::processedUSecs() const
565{
566 return d ? d->processedUSecs() : 0;
567}
568
569/*!
570 Returns the microseconds since start() was called, including time in Idle and
571 Suspend states.
572*/
573
574qint64 QAudioSource::elapsedUSecs() const
575{
576 return state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
577}
578
579/*!
580 Returns the error state.
581*/
582
583QtAudio::Error QAudioSource::error() const
584{
585 return d ? d->error() : QAudio::OpenError;
586}
587
588/*!
589 Returns the state of audio processing.
590*/
591
592QtAudio::State QAudioSource::state() const
593{
594 return d ? d->state() : QAudio::StoppedState;
595}
596
597/*!
598 \fn QAudioSource::stateChanged(QtAudio::State state)
599 This signal is emitted when the device \a state has changed.
600
601 \note The QtAudio namespace was named QAudio up to and including Qt 6.6.
602 String-based connections to this signal have to use \c{QAudio::State} as
603 the parameter type: \c{connect(source, SIGNAL(stateChanged(QAudio::State)), ...);}
604*/
605
606QT_END_NAMESPACE
607
608#include "moc_qaudiosource.cpp"
Combined button and popup list for selecting options.
static bool validateFormatAtStart(QPlatformAudioSource *d)