Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
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
/
qtmm_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
14
QT_BEGIN_NAMESPACE
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
125
QAudioSource::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
137
QAudioSource::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
158
QAudioSource::~QAudioSource()
159
{
160
delete
d;
161
}
162
163
static
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
194
void
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
232
QIODevice* 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
266
template
<
typename
T>
267
void
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
291
void
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
300
QAudioFormat 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
312
void
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
322
void
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
335
void
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
348
void
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
368
void
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
386
qsizetype 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
406
void
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
425
qsizetype 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
*/
451
void
QAudioSource::setNativePeriodFrameCount(qsizetype 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 %lld "
466
"(must be -1 or a power of 2 between 32 and 4096)"
,
467
qint64(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
*/
487
qsizetype QAudioSource::nativePeriodFrameCount()
const
488
{
489
std::optional hwbf = d ? d->nativePeriodFrames() : std::nullopt;
490
return
hwbf ? qsizetype(qToUnderlying(*hwbf)) : qsizetype(-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
502
qsizetype 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
517
qsizetype 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
*/
538
void
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
*/
554
qreal 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
564
qint64 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
574
qint64 QAudioSource::elapsedUSecs()
const
575
{
576
return
state() == QAudio::StoppedState ? 0 : d->elapsedTime.nsecsElapsed()/1000;
577
}
578
579
/*!
580
Returns the error state.
581
*/
582
583
QtAudio::Error QAudioSource::error()
const
584
{
585
return
d ? d->error() : QAudio::OpenError;
586
}
587
588
/*!
589
Returns the state of audio processing.
590
*/
591
592
QtAudio::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
606
QT_END_NAMESPACE
607
608
#
include
"moc_qaudiosource.cpp"
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
validateFormatAtStart
static bool validateFormatAtStart(QPlatformAudioSource *d)
Definition
qaudiosource.cpp:163
qtmultimedia
src
multimedia
audio
qaudiosource.cpp
Generated on
for Qt by
1.18.0